Wow! It looks like I might have cracked this 'nut' wide open
It seems I can now convert Delphi Doubles to c64 5-byte (packed memory representation, used for variables, etc) and 6-byte (c64 FP register) floating point representations!!
I used the description found below to make the algorithms:
ftp://n2dvm.com/Commodore/Commie-CDs...e-base/197.htm
Here is the code if anyone is interested
Code:
PC64MemFloat = ^TC64MemFloat;
TC64MemFloat = packed record
Exponent: Byte;
Mantissa: array[0..3] of Byte;
end;
PC64RegFloat = ^TC64RegFloat;
TC64RegFloat = packed record
Exponent: Byte;
Mantissa: array[0..3] of Byte;
Sign: Byte;
end;
procedure FloatToC64Float(num: Double; out aC64Float: TC64MemFloat); overload;
procedure FloatToC64Float(num: Double; out aC64Float: TC64RegFloat); overload;
function C64FloatToStr(var aC64Float: TC64MemFloat): String; overload;
function C64FloatToStr(var aC64Float: TC64RegFloat): String; overload;
implementation
procedure FloatToC64Float(num: Double; out aC64Float: TC64MemFloat);
// converts a floating point number to 5-byte memory FP representation: exponent (1), mantissa (4)
//ftp://n2dvm.com/Commodore/Commie-CDs/Kazez%20FREE-CD/c64-knowledge-base/197.htm
var
ExpCount: Integer;
SignBit: Integer;
Index: Integer;
begin
Write(Format('%.10f = ',[num]));
// save sign bit
SignBit := 0;
if num < 0 then
begin
SignBit := 128;
num := -num;
end;
if Abs(num) < 0.000001 then
begin
aC64Float.Exponent := 0;
aC64Float.Mantissa[0] := 0;
aC64Float.Mantissa[1] := 0;
aC64Float.Mantissa[2] := 0;
aC64Float.Mantissa[3] := 0;
C64FloatToStr(aC64Float);
Exit;
end;
// calculate exponent byte
ExpCount := 0;
if num < 1 then
while num < 1 do
begin
Dec(ExpCount);
num := num * 2;
end
else
if num >= 2 then
while num >= 2 do
begin
Inc(ExpCount);
num := num / 2;
end;
aC64Float.Exponent := 129 + ExpCount;
num := Frac(num / 2); // 'un-normalize' it for forther processing (immediate mantissa)
// calculate mantissa digits
for Index := 0 to 3 do
begin
num := num * 256;
aC64Float.Mantissa[Index] := Trunc(num);
num := Frac(num);
end;
// round last mantissa digit when required
if num > 0.5 then Inc(aC64Float.Mantissa[3]);
// include sign bit in first mantissa digit
aC64Float.Mantissa[0] := (aC64Float.Mantissa[0] and $7F) or SignBit;
C64FloatToStr(aC64Float);
end;
procedure FloatToC64Float(num: Double; out aC64Float: TC64RegFloat);
// converts a floating point number to 6-byte register FP representation: exponent (1), mantissa (4), separate sign (1)
//ftp://n2dvm.com/Commodore/Commie-CDs/Kazez%20FREE-CD/c64-knowledge-base/197.htm
var
ExpCount: Integer;
SignBit: Integer;
Index: Integer;
begin
Write(Format('%.10f = ',[num]));
// save sign bit
SignBit := 0;
if num < 0 then
begin
SignBit := 128;
num := -num;
end;
if Abs(num) < 0.000001 then
begin
aC64Float.Exponent := 0;
aC64Float.Mantissa[0] := 0;
aC64Float.Mantissa[1] := 0;
aC64Float.Mantissa[2] := 0;
aC64Float.Mantissa[3] := 0;
aC64Float.Sign := 0;
C64FloatToStr(aC64Float);
Exit;
end;
// calculate exponent byte
ExpCount := 0;
if num < 1 then
while num < 1 do
begin
Dec(ExpCount);
num := num * 2;
end
else
if num >= 2 then
while num >= 2 do
begin
Inc(ExpCount);
num := num / 2;
end;
aC64Float.Exponent := 129 + ExpCount;
num := Frac(num / 2); // 'un-normalize' it for forther processing (immediate mantissa)
// calculate mantissa digits
for Index := 0 to 3 do
begin
num := num * 256;
aC64Float.Mantissa[Index] := Trunc(num);
num := Frac(num);
end;
// round last mantissa digit when required
if num > 0.5 then Inc(aC64Float.Mantissa[3]);
// include sign bit in sign part
aC64Float.Mantissa[4] := SignBit;
C64FloatToStr(aC64Float);
end;
function C64FloatToStr(var aC64Float: TC64MemFloat): String;
begin
//output C64 mem floating point as hex (Exponent, Mantissa)
WriteLn(Format('$%.2x $%.2x $%.2x $%.2x $%.2x (mem FP)',
[aC64Float.Exponent,
aC64Float.Mantissa[0],
aC64Float.Mantissa[1],
aC64Float.Mantissa[2],
aC64Float.Mantissa[3]]));
end;
function C64FloatToStr(var aC64Float: TC64RegFloat): String;
begin
//output C64 reg floating point as hex (Exponent, Mantissa, Sign)
WriteLn(Format('$%.2x $%.2x $%.2x $%.2x $%.2x $%.2x (reg FP)',
[aC64Float.Exponent,
aC64Float.Mantissa[0],
aC64Float.Mantissa[1],
aC64Float.Mantissa[2],
aC64Float.Mantissa[3],
aC64Float.Sign]));
end;
I can do this:
Code:
var
C64MemFLoat: TC64MemFloat;
C64RegFLoat: TC64RegFloat;
begin
FloatToC64Float(0,C64RegFLoat);
FloatToC64Float(1,C64RegFLoat);
FloatToC64Float(2,C64RegFLoat);
FloatToC64Float(3,C64RegFLoat);
FloatToC64Float(1/2,C64RegFLoat);
FloatToC64Float(1/4,C64RegFLoat);
FloatToC64Float(-67,C64RegFLoat);
FloatToC64Float(13,C64RegFLoat);
FloatToC64Float(0,C64MemFLoat);
FloatToC64Float(3.141592654,C64MemFLoat);
FloatToC64Float(+27,C64MemFLoat);
ReadLn;
end.
and get this output (seems to exactly match what examples I have seen online!)
Code:
0.0000000000 = $00 $00 $00 $00 $00 $00 (reg FP)
1.0000000000 = $81 $80 $00 $00 $00 $00 (reg FP)
2.0000000000 = $82 $80 $00 $00 $00 $00 (reg FP)
3.0000000000 = $82 $C0 $00 $00 $00 $00 (reg FP)
0.5000000000 = $80 $80 $00 $00 $00 $00 (reg FP)
0.2500000000 = $7F $80 $00 $00 $00 $00 (reg FP)
-67.0000000000 = $87 $86 $00 $00 $00 $80 (reg FP)
13.0000000000 = $84 $D0 $00 $00 $00 $00 (reg FP)
0.0000000000 = $00 $00 $00 $00 $00 (mem FP)
3.1415926540 = $82 $49 $0F $DA $A3 (mem FP)
27.0000000000 = $85 $58 $00 $00 $00 (mem FP)
Originally Posted by
Darthman
Great news! Still waiting release
LOL thanks! if I get much further, I might make an open source project (read-only for now) somewhere so people can follow using SVN, etc.
Oh, I am also going to see if I can make the reverse, following the instructions on that site so I can go from c64 FP to Delphi Double for debugging, etc.
cheers,
Paul
Bookmarks