Jump to content

Recommended Posts

I can see that Mad Pascal's units are getting more procedures and functions that make programming of games easier. This can be a "killer feature". I am also impressed with the inline assembly capabilities.

 

Is there a possibility to create screen code string/character literals? This would allow fast and convenient drawing of strings with the System.Move procedure. Or maybe this can be done with inline assembly... dta d'text' if needed?

Link to comment
https://forums.atariage.com/topic/240919-mad-pascal/page/10/#findComment-3802796
Share on other sites

  • 2 weeks later...

http://mads.atari8.info

 

Mad Pascal 1.5.0

 

- LONGWORD, DWORD, UINT32, LONGINT
- ShortReal (fixed point Q8., Real (fixed point Q24., Single (32bit IEEE-754)
- unit SYSTEM (const SINGLE): NaN, Infinity, NegInfinity
- unit SYSTEM (type SINGLE): SIN, COS, ABS, SQRT, ISQRT, ROUND, TRUNC
- unit MATH (type SINGLE): LOG2, LOG10, LOGN, IsNaN
p.s.

in attachment compare SINGLE (IEEE-754) versus REAL (Q24.8 fixed-point)

 

p.s. #2

function iSqrt(number: Single): Single;
//----------------------------------------------------------------------------------------------
// Fast inverse square root
// https://en.wikipedia.org/wiki/Fast_inverse_square_root
//----------------------------------------------------------------------------------------------
var sp: ^single;
    c: cardinal;
    f0, f1: single;
const
    threehalfs: single = 1.5;
begin
	sp:=@c;

	f0 := number * 0.5;
	c  := cardinal(number);		// evil floating point bit level hacking
	c  := $5f3759df - (c shr 1);	// what the fuck?
        f1 := f0 * sp^ * sp^;
	Result := sp^ * ( 1.5 - f1 );	// 1st iteration
end;

single_real.zip

post-4486-0-78244400-1501421017.png

Edited by tebe
  • Like 6
Link to comment
https://forums.atariage.com/topic/240919-mad-pascal/page/10/#findComment-3816759
Share on other sites

	c  := cardinal(number);		// evil floating point bit level hacking
	c  := $5f3759df - (c shr 1);	// what the fuck?

 

The final proof that source code comments are a must - best thing is that it's really from Wikipedia ;-).

 

In two weeks I'll a Fujiama, trying out MP for the first time. Englisg Google translation of the docs looks very good. Thanks tebe!

  • Like 2
Link to comment
https://forums.atariage.com/topic/240919-mad-pascal/page/10/#findComment-3817846
Share on other sites

That's just the magic number used in fast square root implementations.
It's simply a constant someone figured out to simplify the formula.
I think I ran across the math used to derive it when I was looking at how to implement a fast square root on the MC-10.
I also think there was a faster implementation than that.

  • Like 1
Link to comment
https://forums.atariage.com/topic/240919-mad-pascal/page/10/#findComment-3817914
Share on other sites

fast SQRT (IEEE-754 SINGLE)

function fsqrt(number: single): single;
var sp: ^single;
    c: cardinal;
begin
 
if number < single(0) then exit;
 
sp:=@c;
 
c := cardinal(number) - $3f800000;
c := c shr 1;
c := c + $3f800000;
 
Result := sp^;
 
Result:=(Result+number/Result) * 0.5;  // mul is faster than div
Result:=(Result+number/Result) * 0.5;
 
end;

original (Hero's algorithm)

function Sqrt(x: Single): Single; overload;
//----------------------------------------------------------------------------------------------
// Sqrt returns the square root of its argument X, which must be positive
//----------------------------------------------------------------------------------------------
var Divisor: Single;
begin
{ Hero's algorithm }
 
if x < single(0) then exit;
 
Result  := x;
Divisor := 1;
 
while Abs(Result - Divisor) > single(0.0001) do
  begin
  Divisor := (Result + Divisor) / 2;
  Result := x / Divisor;
  end;
end;
Edited by tebe
  • Like 2
Link to comment
https://forums.atariage.com/topic/240919-mad-pascal/page/10/#findComment-3818101
Share on other sites

 

fast SQRT (IEEE-754 SINGLE)

function fsqrt(number: single): single;
var sp: ^single;
    c: cardinal;
begin
 
if number < single(0) then exit;
 
sp:=@c;
 
c := cardinal(number) - $3f800000;
c := c shr 1;
c := c + $3f800000;
 
Result := sp^;
 
Result:=(Result+number/Result) * 0.5;  // mul is faster than div
Result:=(Result+number/Result) * 0.5;
 
end;

...

Yeah, that looks more like what I was using.

 

FWIW, Microsoft separates out the sign bit from normal IEEE-754 numbers in their 6803 math library..

They probably did the same thing on other CPUs but I haven't looked.

So if any of you ever want to speed up their square root, you need to adjust the magic constant to match.

 

Here is the explanation of the fast SQRT and the magic constant for any of you that care to check it out:

http://h14s.p5r.org/2012/09/0x5f3759df.html

 

Just for the record... it's really nice to see a compiler support floating point.

I've ported a few BASIC programs to C, and going from floats to int is always a pain in the neck.

 

Edited by JamesD
  • Like 1
Link to comment
https://forums.atariage.com/topic/240919-mad-pascal/page/10/#findComment-3818140
Share on other sites

Hi!

 

http://mads.atari8.info

 

Mad Pascal 1.5.0

 

- LONGWORD, DWORD, UINT32, LONGINT
- ShortReal (fixed point Q8., Real (fixed point Q24., Single (32bit IEEE-754)
- unit SYSTEM (const SINGLE): NaN, Infinity, NegInfinity
- unit SYSTEM (type SINGLE): SIN, COS, ABS, SQRT, ISQRT, ROUND, TRUNC
- unit MATH (type SINGLE): LOG2, LOG10, LOGN, IsNaN

 

This is great!

 

I looked at your math functions, I think that there are various optimizations possible. For now, this is a sine/cosine routines that are shorter and faster than the current ones, using a polynomial approximation to the full [0,pi/2] range.

function fsincos(x: single; sc: boolean): single;
var
    i: byte;
begin
    { Normalize argument, divide by (pi/2) }
    x := x * 0.63661977236758134308;
    { Get's integer part, should be }
    i := trunc(x);
    { Fixes negative part, needed to calculate "fractional" part }
    if cardinal(x) >= $80000000 then { this is shorter than "x < 0" }
        dec(i);
    { And finally get's fractional part }
    x := x - single(shortint(i));
    { If we need cosine, adds pi/2 }
    if sc then
        inc(i);

    { Test quadrant, odd values are reflected }
    if (i and 1) = 0 then
        x := single(1) - x;

    { Calculate cosine(x) with optimal polynomial approximation }
    x := x * x;
    Result := (((0.019940292 - x * 0.00084688153) * x - 0.23369547) * x + 1) * (1-x);

    { Test quadrant to return negative values }
    if (i and 2) = 2 then
        Result := -Result;
end;

function fsin(x: single): single;
begin
    Result := fsincos(x, false);
end;

function fcos(x: single): single;
begin
    Result := fsincos(x, true);
end;
The first function calculates sine or cosine depending on the value of "sc", true for cosine, false for sine. The functions bellow calls the main one with the correct argument. With the given polynomial the functions have a maximal relative error of 3.77777e-07, so the real limit is the normalization by (pi/2) at the start, as the division is not as accurate with large arguments.

 

Note that if you add one term to the polynomial, the function can be made accurate to the full IEEE754 precision, but of course will be slower and bigger.

 

 

 

Finally one reasonable FP libs on our 8-bitter - no screwing with this wicked 6 byte BCD craze. moving to 4 bytes alone is a gain. They should have stuck to MS Basic I say :]

I agree, but i recognize that for a lot of people BCD math was the correct choice, as very few understand why "0.1" is not an exact FP number, and why "FOR I=0 to 3 STEP 0.01" does not end with I=3.

 

 

Yeah, that looks more like what I was using.

 

FWIW, Microsoft separates out the sign bit from normal IEEE-754 numbers in their 6803 math library..

They probably did the same thing on other CPUs but I haven't looked.

So if any of you ever want to speed up their square root, you need to adjust the magic constant to match.

 

Here is the explanation of the fast SQRT and the magic constant for any of you that care to check it out:

http://h14s.p5r.org/2012/09/0x5f3759df.html

 

Just for the record... it's really nice to see a compiler support floating point.

I've ported a few BASIC programs to C, and going from floats to int is always a pain in the neck.

Yes, in 8bit implementations it's normal to modify the IEEE754 format to remove the need to pack/unpack the numbers on each operation, see http://ww1.microchip.com/downloads/en/AppNotes/00575.pdffor a modern FP library in an 8bit micro, this uses the trick to exchange the position of the sign bit. Also of interest are the accompanying functions at http://ww1.microchip.com/downloads/en/AppNotes/00660.pdf , porting some of the functions to 6502 assembly is not that difficult.

  • Like 2
Link to comment
https://forums.atariage.com/topic/240919-mad-pascal/page/10/#findComment-3818764
Share on other sites

  • 3 weeks later...

I am trying to convert an ACTION! program to MP. In ACTION you can decare variables like labels in assembler, i.e. you define the name, type and memory location.

This way you can have

BYTE ROWCRS=$54

 

...

ROWCRS = 0

 

becomes

LDA #0:STA $54.

 

How would I translate this to MP?

 

;OS ADDRESSES: PAGE 0
BYTE ROWCRS=$54
BYTE COLCRS=$55
CARD SAVMSC=$58
BYTE RAMTOP=$6A

;OS ADDRESSES: PAGE 2
BYTE SDMCTL=$22F
BYTE SDLSTL=$230
BYTE TXTROW=$290
CARD TXTCOL=$291
BYTE COLOR1=709
BYTE COLOR2=710
BYTE CURINH=755
BYTE CHBAS=756
BYTE CH=764

; GTIA REGISTERS
BYTE CONSOL=53279

; ACTION VARIABLES
CARD STANDARD_ERROR
CARD BLOAD_ERROR
BYTE BLOAD_DONE

PROC CIOV2=$E456(BYTE AREG,XREG)

Link to comment
https://forums.atariage.com/topic/240919-mad-pascal/page/10/#findComment-3829768
Share on other sites

I really want to move onto using Mad Pascal for future games I intend to market on cartridge. It will be much easier than trying to do huge programs all in assembly. I probably limit it to games that fit inside 16K for starters as doing any type of bank switching will add another problem to deal with. From what I done so far, it looks like it has a lot of potential.

Link to comment
https://forums.atariage.com/topic/240919-mad-pascal/page/10/#findComment-3833255
Share on other sites

I am just wondering what's the deal with using memory address at a000 (left slot cartridge ROM, Atari BASIC area) in Mad Pascal. Are there any conflicts in using this area, I mean, filling this area directly with some data and not interfering with any of routines in Mad Pascal library?

 

Good examples of using this area are nuts.pas, plasma.pas and music players. We know that we gain 16K of additional memory this way, not used in traditional way. So I wonder if I have to set any additional routines before using this area?

I didn't find code for switching off Atari BASIC in these examples. What am I missing?

Edited by Gury
Link to comment
https://forums.atariage.com/topic/240919-mad-pascal/page/10/#findComment-3834978
Share on other sites

I think there is no problem using memory above A000.

You can take a look into sources of PacMad,

I'm switching off OS (procedure SystemOff), taking over vblank, and using all memory above A000 (except D000-D800).

 

In MadPascal examples, system is also switched off in 'pasintro'.

Link to comment
https://forums.atariage.com/topic/240919-mad-pascal/page/10/#findComment-3835054
Share on other sites

Now I'm stuck for the first time:

 

type tile = record ts,tr,tx,ty,tz: byte end;
var tile_map: array[0..0] of byte absolute $414; // TODO Actual size?

 

procedure init_tiles;

var shape_list: array[0..6] of byte = (1, 1, 2, 3, 3, 4, 5);
var t: ^tile;
var i: byte;

t:=tile_map; // Yields: Syntax error, ':' expected but ':=' found

 

t:=@tile_map[0]; // Yields: Syntax error, ':' expected but ':=' found

 

Any ideas?

 

EDIT: Found it. The BEGIN was missing after the VAR block.

  • Like 1
Link to comment
https://forums.atariage.com/topic/240919-mad-pascal/page/10/#findComment-3835720
Share on other sites

Next: I have an array of records in memory.

 

// 8 tiles
type tile = record ts,tr,tx,ty,tz: byte end;
const tile_count = 8;
const tile_size = SizeOf(tile);
const tile_map_size = tile_count*tile_size;

var tile_map array[0..tile_count-1] of tile absolute $414;

 

Yields: Error: Multidimensional arrays are not supported

Does it mean arrays of recording not (yet) supported?

 

When I try to use pointers instead, I get:

 

var tile_map: ^tile;

 

procedure test;
var tile_map2: ^tile;
begin
tile_map2 := tile_map; // Incompatible types: got "RECORD" expected "POINTER"
end;

 

Why? Both sides are ^tile?

Link to comment
https://forums.atariage.com/topic/240919-mad-pascal/page/10/#findComment-3835762
Share on other sites

Thanks, I see arrays of records are not supported and I'll use arrays of pointers to records. That is fine. Maybe you can make the error message a litte more explicit.

 

But the 2nd problem I don't unterstand. What is wrong with the assignment of two variables of the same type (here ^tile)?

 

Addition:

 

var tile_map: array[0..tile_count-1] of pointer; // accepted

 

type tile = record ts,tr,tx,ty,tz: byte end;
type ptile = ^tile;

var tile_map: array[0..tile_count-1] of ptile; // Error: Multidimensional arrays are not supported

 

So no typed arrays of pointer?

Link to comment
https://forums.atariage.com/topic/240919-mad-pascal/page/10/#findComment-3836845
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...