got floating points working in commanderx16

This commit is contained in:
Irmen de Jong 2020-08-29 23:55:26 +02:00
parent c50ecf6055
commit 88a9e09918
11 changed files with 357 additions and 55 deletions

View File

@ -8,7 +8,8 @@ ub2float .proc
sta P8ZP_SCRATCH_W2
sty P8ZP_SCRATCH_W2+1
ldy P8ZP_SCRATCH_B1
jsr FREADUY
lda #0
jsr GIVAYF
_fac_to_mem ldx P8ZP_SCRATCH_W2
ldy P8ZP_SCRATCH_W2+1
jsr MOVMF
@ -74,7 +75,8 @@ stack_ub2float .proc
lda P8ESTACK_LO,x
stx P8ZP_SCRATCH_REG_X
tay
jsr FREADUY
lda #0
jsr GIVAYF
jmp push_fac1_as_result
.pend
@ -663,8 +665,8 @@ _largest_pos_float .byte 255,127,255,255,255 ; largest positive float
.pend
func_sum_f .proc
lda #<FL_ZERO
ldy #>FL_ZERO
lda #<ZERO
ldy #>ZERO
jsr MOVFM
jsr prog8_lib.pop_array_and_lengthmin1Y
stx P8ZP_SCRATCH_REG_X

View File

@ -6,12 +6,12 @@
%option enable_floats
c64flt {
; ---- this block contains C-64 floating point related functions ----
const float PI = 3.141592653589793
const float TWOPI = 6.283185307179586
const float ZERO = 0.0
; ---- C64 basic and kernal ROM float constants and functions ----
@ -35,13 +35,11 @@ c64flt {
&float FL_TWOPI = $e2e5 ; 2 * PI
&float FL_FR4 = $e2ea ; .25
; oddly enough, 0.0 isn't available in the kernel.
float FL_ZERO = 0.0 ; oddly enough 0.0 isn't available in the kernel
; note: fac1/2 might get clobbered even if not mentioned in the function's name.
; note: for subtraction and division, the left operand is in fac2, the right operand in fac1.
; checked functions below:
romsub $bba2 = MOVFM(uword mflpt @ AY) clobbers(A,Y) ; load mflpt value from memory in A/Y into fac1
romsub $bba6 = FREADMEM() clobbers(A,Y) ; load mflpt value from memory in $22/$23 into fac1
romsub $ba8c = CONUPK(uword mflpt @ AY) clobbers(A,Y) ; load mflpt value from memory in A/Y into fac2
@ -91,6 +89,7 @@ romsub $bb12 = FDIVT() clobbers(A,X,Y) ; fac1 = fac2/fac1
romsub $bb0f = FDIV(uword mflpt @ AY) clobbers(A,X,Y) ; fac1 = mflpt in A/Y / fac1 (remainder in fac2)
romsub $bf7b = FPWRT() clobbers(A,X,Y) ; fac1 = fac2 ** fac1
romsub $bf78 = FPWR(uword mflpt @ AY) clobbers(A,X,Y) ; fac1 = fac2 ** mflpt from A/Y
romsub $bd7e = FINLOG(byte value @A) clobbers (A, X, Y) ; fac1 += signed byte in A
romsub $aed4 = NOTOP() clobbers(A,X,Y) ; fac1 = NOT(fac1)
romsub $bccc = INT() clobbers(A,X,Y) ; INT() truncates, use FADDH first to round instead of trunc
@ -193,33 +192,26 @@ asmsub GETADRAY () clobbers(X) -> uword @ AY {
}
sub print_f (float value) {
; ---- prints the floating point value (without a newline) using basic rom routines.
; ---- prints the floating point value (without a newline).
%asm {{
stx P8ZP_SCRATCH_REG_X
lda #<value
ldy #>value
jsr MOVFM ; load float into fac1
jsr FOUT ; fac1 to string in A/Y
jsr c64.STROUT ; print string in A/Y
sta P8ZP_SCRATCH_B1
sty P8ZP_SCRATCH_REG
ldy #0
- lda (P8ZP_SCRATCH_B1),y
beq +
jsr c64.CHROUT
iny
bne -
ldx P8ZP_SCRATCH_REG_X
rts
+ rts
}}
}
sub print_fln (float value) {
; ---- prints the floating point value (with a newline at the end) using basic rom routines
%asm {{
stx P8ZP_SCRATCH_REG_X
lda #<value
ldy #>value
jsr MOVFM ; load float into fac1
jsr FPRINTLN ; print fac1 with newline
ldx P8ZP_SCRATCH_REG_X
rts
}}
}
%asminclude "library:c64floats.asm", ""
} ; ------ end of block c64flt
}

View File

@ -0,0 +1,140 @@
; Prog8 definitions for floating point handling on the CommanderX16
;
; Written by Irmen de Jong (irmen@razorvine.net) - license: GNU GPL 3.0
;
; indent format: TABS, size=8
%option enable_floats
c64flt {
; ---- this block contains C-64 floating point related functions ----
const float PI = 3.141592653589793
const float TWOPI = 6.283185307179586
const float ZERO = 0.0
; ---- ROM float functions ----
; note: the fac1 and fac2 are working registers and take 6 bytes each,
; floats in memory (and rom) are stored in 5-byte MFLPT packed format.
; note: fac1/2 might get clobbered even if not mentioned in the function's name.
; note: for subtraction and division, the left operand is in fac2, the right operand in fac1.
romsub $fe00 = AYINT() clobbers(A,X,Y) ; fac1-> signed word in 100-101 ($64-$65) MSB FIRST. (might throw ILLEGAL QUANTITY)
; GIVAYF: signed word in Y/A (note different lsb/msb order) -> float in fac1
; there is also c64flt.GIVUAYFAY - unsigned word in A/Y (lo/hi) to fac1
; (tip: use GIVAYFAY to use A/Y input; lo/hi switched to normal order)
romsub $fe03 = GIVAYF(ubyte lo @ Y, ubyte hi @ A) clobbers(A,X,Y)
; fac1 -> unsigned word in Y/A (might throw ILLEGAL QUANTITY) (result also in $14/15)
; (tip: use GETADRAY to get A/Y output; lo/hi switched to normal little endian order)
romsub $fe06 = GETADR() clobbers(X) -> ubyte @ Y, ubyte @ A
romsub $fe09 = FADDH() clobbers(A,X,Y) ; fac1 += 0.5, for rounding- call this before INT
romsub $fe0c = FSUB(uword mflpt @ AY) clobbers(A,X,Y) ; fac1 = mflpt from A/Y - fac1
romsub $fe0f = FSUBT() clobbers(A,X,Y) ; fac1 = fac2-fac1 mind the order of the operands
romsub $fe12 = FADD(uword mflpt @ AY) clobbers(A,X,Y) ; fac1 += mflpt value from A/Y
romsub $fe15 = FADDT() clobbers(A,X,Y) ; fac1 += fac2
romsub $fe1b = ZEROFC() clobbers(A,X,Y) ; fac1 = 0
romsub $fe1e = NORMAL() clobbers(A,X,Y) ; normalize fac1 (?)
romsub $fe24 = LOG() clobbers(A,X,Y) ; fac1 = LN(fac1) (natural log)
romsub $fe27 = FMULT(uword mflpt @ AY) clobbers(A,X,Y) ; fac1 *= mflpt value from A/Y
romsub $fe2a = FMULTT() clobbers(A,X,Y) ; fac1 *= fac2
romsub $fe33 = CONUPK(uword mflpt @ AY) clobbers(A,Y) ; load mflpt value from memory in A/Y into fac2
romsub $fe36 = MUL10() clobbers(A,X,Y) ; fac1 *= 10
romsub $fe3c = DIV10() clobbers(A,X,Y) ; fac1 /= 10 , CAUTION: result is always positive!
romsub $fe3f = FDIV(uword mflpt @ AY) clobbers(A,X,Y) ; fac1 = mflpt in A/Y / fac1 (remainder in fac2)
romsub $fe42 = FDIVT() clobbers(A,X,Y) ; fac1 = fac2/fac1 (remainder in fac2) mind the order of the operands
romsub $fe48 = MOVFM(uword mflpt @ AY) clobbers(A,Y) ; load mflpt value from memory in A/Y into fac1
romsub $fe4b = MOVMF(uword mflpt @ XY) clobbers(A,Y) ; store fac1 to memory X/Y as 5-byte mflpt
romsub $fe4e = MOVFA() clobbers(A,X) ; copy fac2 to fac1
romsub $fe51 = MOVAF() clobbers(A,X) ; copy fac1 to fac2 (rounded)
romsub $fe54 = MOVEF() clobbers(A,X) ; copy fac1 to fac2
romsub $fe5a = SIGN() -> ubyte @ A ; SIGN(fac1) to A, $ff, $0, $1 for negative, zero, positive
romsub $fe5d = SGN() clobbers(A,X,Y) ; fac1 = SGN(fac1), result of SIGN (-1, 0 or 1)
romsub $fe60 = FREADSA(byte value @ A) clobbers(A,X,Y) ; 8 bit signed A -> float in fac1
romsub $fe6c = ABS() ; fac1 = ABS(fac1)
romsub $fe6f = FCOMP(uword mflpt @ AY) clobbers(X,Y) -> ubyte @ A ; A = compare fac1 to mflpt in A/Y, 0=equal 1=fac1 is greater, 255=fac1 is less than
romsub $fe78 = INT() clobbers(A,X,Y) ; INT() truncates, use FADDH first to round instead of trunc
romsub $fe7e = FINLOG(byte value @A) clobbers (A, X, Y) ; fac1 += signed byte in A
romsub $fe81 = FOUT() clobbers(X) -> uword @ AY ; fac1 -> string, address returned in AY ($0100)
romsub $fe8a = SQR() clobbers(A,X,Y) ; fac1 = SQRT(fac1)
romsub $fe8d = FPWRT() clobbers(A,X,Y) ; fac1 = fac2 ** fac1
romsub $fe93 = NEGOP() clobbers(A) ; switch the sign of fac1
romsub $fe96 = EXP() clobbers(A,X,Y) ; fac1 = EXP(fac1) (e ** fac1)
romsub $fe9f = RND2(byte value @A) clobbers(A,X,Y) ; fac1 = RND(A) float random number generator
romsub $fea2 = RND() clobbers(A,X,Y) ; fac1 = RND(fac1) float random number generator
romsub $fea5 = COS() clobbers(A,X,Y) ; fac1 = COS(fac1)
romsub $fea8 = SIN() clobbers(A,X,Y) ; fac1 = SIN(fac1)
romsub $feab = TAN() clobbers(A,X,Y) ; fac1 = TAN(fac1)
romsub $feae = ATN() clobbers(A,X,Y) ; fac1 = ATN(fac1)
asmsub GIVUAYFAY (uword value @ AY) clobbers(A,X,Y) {
; ---- unsigned 16 bit word in A/Y (lo/hi) to fac1
%asm {{
jmp GIVAYFAY ; TODO make this work for unsigned!!
}}
}
asmsub GIVAYFAY (uword value @ AY) clobbers(A,X,Y) {
; ---- signed 16 bit word in A/Y (lo/hi) to float in fac1
%asm {{
sta P8ZP_SCRATCH_REG
tya
ldy P8ZP_SCRATCH_REG
jmp GIVAYF ; this uses the inverse order, Y/A
}}
}
asmsub FTOSWRDAY () clobbers(X) -> uword @ AY {
; ---- fac1 to signed word in A/Y
%asm {{
jsr FTOSWORDYA ; note the inverse Y/A order
sta P8ZP_SCRATCH_REG
tya
ldy P8ZP_SCRATCH_REG
rts
}}
}
asmsub GETADRAY () clobbers(X) -> uword @ AY {
; ---- fac1 to unsigned word in A/Y
%asm {{
jsr GETADR ; this uses the inverse order, Y/A
sta P8ZP_SCRATCH_B1
tya
ldy P8ZP_SCRATCH_B1
rts
}}
}
sub print_f (float value) {
; ---- prints the floating point value (without a newline).
%asm {{
stx P8ZP_SCRATCH_REG_X
lda #<value
ldy #>value
jsr MOVFM ; load float into fac1
jsr FOUT ; fac1 to string in A/Y
sta P8ZP_SCRATCH_B1
sty P8ZP_SCRATCH_REG
ldy #0
- lda (P8ZP_SCRATCH_B1),y
beq +
jsr c64.CHROUT
iny
bne -
ldx P8ZP_SCRATCH_REG_X
+ rts
}}
}
%asminclude "library:c64floats.asm", ""
}

View File

@ -11,7 +11,7 @@
txt {
asmsub clear_screen (ubyte char @ A, ubyte color @ Y) clobbers(A) {
asmsub clear_screen (ubyte char @ A, ubyte txtcolor @ Y) clobbers(A) {
; ---- clear the character screen with the given fill character and character color.
%asm {{
@ -224,6 +224,32 @@ asmsub print_w (word value @ AY) clobbers(A,Y) {
}}
}
ubyte[16] color_to_charcode = [$90,$05,$1c,$9f,$9c,$1e,$1f,$9e,$81,$95,$96,$97,$98,$99,$9a,$9b]
sub color (ubyte txtcol) {
c64.CHROUT(color_to_charcode[txtcol & 15])
}
sub color2 (ubyte txtcol, ubyte bgcol) {
c64.CHROUT(color_to_charcode[bgcol & 15])
c64.CHROUT(1) ; switch fg and bg colors
c64.CHROUT(color_to_charcode[txtcol & 15])
}
sub setc (ubyte column, ubyte row, ubyte char) {
; ---- set char at the given position on the screen
%asm {{
phx
ldy column
ldx row
clc
jsr c64.PLOT
plx
lda char
jmp c64.CHROUT
}}
}
asmsub plot (ubyte col @ Y, ubyte row @ A) clobbers(A) {
; ---- safe wrapper around PLOT kernel routine, to save the X register.
%asm {{

View File

@ -151,7 +151,8 @@ private fun optimizeSameAssignments(linesByFourteen: List<List<IndexedValue<Stri
}
if(first.startsWith("lda") && second.startsWith("ldy") && third.startsWith("sta") && fourth.startsWith("sty") &&
fifth.startsWith("lda") && sixth.startsWith("ldy") && seventh.startsWith("jsr c64flt.copy_float")) {
fifth.startsWith("lda") && sixth.startsWith("ldy") &&
(seventh.startsWith("jsr c64flt.copy_float") || seventh.startsWith("jsr cx16flt.copy_float"))) {
val nineth = pair[8].value.trimStart()
val tenth = pair[9].value.trimStart()
@ -161,7 +162,8 @@ private fun optimizeSameAssignments(linesByFourteen: List<List<IndexedValue<Stri
val fourteenth = pair[13].value.trimStart()
if(eighth.startsWith("lda") && nineth.startsWith("ldy") && tenth.startsWith("sta") && eleventh.startsWith("sty") &&
twelveth.startsWith("lda") && thirteenth.startsWith("ldy") && fourteenth.startsWith("jsr c64flt.copy_float")) {
twelveth.startsWith("lda") && thirteenth.startsWith("ldy") &&
(fourteenth.startsWith("jsr c64flt.copy_float") || fourteenth.startsWith("jsr cx16flt.copy_float"))) {
if(first.substring(4) == eighth.substring(4) && second.substring(4)==nineth.substring(4)) {
// identical float init

23
examples/cx16/floats.p8 Normal file
View File

@ -0,0 +1,23 @@
; CommanderX16 floating point example!
; make sure to compile with the cx16 compiler target.
%import cx16textio
%import cx16flt
%zeropage basicsafe
main {
sub start() {
float f1 = 5.55
float f2 = 33.3
float f3 = f1 * f2
c64flt.print_f(f1)
c64.CHROUT('*')
c64flt.print_f(f2)
c64.CHROUT('=')
c64flt.print_f(f3)
c64.CHROUT('\n')
}
}

View File

@ -7,7 +7,7 @@ main {
sub start() {
cx16.screen_set_mode($80)
void cx16.screen_set_mode($80)
cx16.r0=0
cx16.FB_init()
@ -17,24 +17,23 @@ main {
uword xx
ubyte yy
for yy in 199 downto 0 {
for xx in 319 downto 0 { ; TODO fix compiler hang -- should be error message when range is too large
for xx in 319 downto 0 {
cx16.FB_set_pixel( yy+lsb(xx))
}
}
; uword xx
; for xx in 0 to 319 step 32 {
; cx16.GRAPH_clear()
; ubyte q
; for q in 0 to 31 {
; cx16.GRAPH_set_colors(q, 2, 0)
; cx16.r0 = xx+q
; cx16.r1=0
; cx16.r2=rnd()
; cx16.r3=199
; cx16.GRAPH_draw_line()
; }
; }
; cx16.GRAPH_init()
for xx in 0 to 319 step 32 {
ubyte q
for q in 0 to 31 {
cx16.GRAPH_set_colors(q, 2, 0)
cx16.r0 = xx+q
cx16.r1=0
cx16.r2=rnd()
cx16.r3=199
cx16.GRAPH_draw_line()
}
}
}
}

View File

@ -0,0 +1,45 @@
%import cx16flt
%zeropage basicsafe
main {
const uword width = 256
const uword height = 200
const ubyte max_iter = 16
sub start() {
void cx16.screen_set_mode($80)
cx16.r0=0
cx16.FB_init()
ubyte pixelx
ubyte pixely
for pixely in 0 to height-1 {
float yy = (pixely as float)/0.4/height - 1.0
cx16.r0 = 0
cx16.r1 = pixely
cx16.FB_cursor_position()
for pixelx in 0 to width-1 {
float xx = (pixelx as float)/0.3/width - 2.2
float xsquared = 0.0
float ysquared = 0.0
float x = 0.0
float y = 0.0
ubyte iter = 0
while iter<max_iter and xsquared+ysquared<4.0 {
y = x*y*2.0 + yy
x = xsquared - ysquared + xx
xsquared = x*x
ysquared = y*y
iter++
}
cx16.FB_set_pixel(max_iter-iter)
}
}
}
}

View File

@ -0,0 +1,42 @@
%import cx16textio
%import cx16flt
%zeropage basicsafe
main {
const uword width = 60
const uword height = 50
const ubyte max_iter = 16
sub start() {
txt.print("calculating mandelbrot fractal...\n\n")
ubyte pixelx
ubyte pixely
for pixely in 0 to height-1 {
float yy = (pixely as float)/0.4/height - 1.0
for pixelx in 0 to width-1 {
float xx = (pixelx as float)/0.3/width - 2.2
float xsquared = 0.0
float ysquared = 0.0
float x = 0.0
float y = 0.0
ubyte iter = 0
while iter<max_iter and xsquared+ysquared<4.0 {
y = x*y*2.0 + yy
x = xsquared - ysquared + xx
xsquared = x*x
ysquared = y*y
iter++
}
txt.color2(1, max_iter-iter)
c64.CHROUT(' ')
}
c64.CHROUT('\n')
}
}
}

View File

@ -4,8 +4,47 @@
main {
sub start() {
print_rom_floats_values()
c64.CHROUT('\n')
print_rom_floats()
c64.CHROUT('\n')
}
sub print_rom_floats() {
c64flt.FL_PIVAL=9.9999
c64flt.print_f(c64flt.FL_PIVAL)
c64.CHROUT('\n')
c64flt.print_f(c64flt.FL_N32768)
c64.CHROUT('\n')
c64flt.print_f(c64flt.FL_FONE)
c64.CHROUT('\n')
c64flt.print_f(c64flt.FL_SQRHLF)
c64.CHROUT('\n')
c64flt.print_f(c64flt.FL_SQRTWO)
c64.CHROUT('\n')
c64flt.print_f(c64flt.FL_NEGHLF)
c64.CHROUT('\n')
c64flt.print_f(c64flt.FL_LOG2)
c64.CHROUT('\n')
c64flt.print_f(c64flt.FL_TENC)
c64.CHROUT('\n')
c64flt.print_f(c64flt.FL_NZMIL)
c64.CHROUT('\n')
c64flt.print_f(c64flt.FL_FHALF)
c64.CHROUT('\n')
c64flt.print_f(c64flt.FL_LOGEB2)
c64.CHROUT('\n')
c64flt.print_f(c64flt.FL_PIHALF)
c64.CHROUT('\n')
c64flt.print_f(c64flt.FL_TWOPI)
c64.CHROUT('\n')
c64flt.print_f(c64flt.FL_FR4)
c64.CHROUT('\n')
}
sub print_rom_floats_values() {
; these are all floating point constants defined in the ROM so no allocation required
; the compiler recognises these and will substitute the ROM values automatically
c64flt.print_f(3.141592653589793)
c64.CHROUT('\n')

View File

@ -4,19 +4,11 @@
main {
sub start() {
uword xx
ubyte yy
for xx in 319 downto 0 {
; TODO also fix that the asm is invalid for word iterator variable.
}
for yy in 199 downto 0 {
for xx in 319 downto 0 {
; TODO also fix that the asm is invalid for word iterator variable.
}
}
;asmsub clear_screen (ubyte char @ A, ubyte color @ Y) clobbers(A) { ...}
; TODO dont cause name conflict if we define sub or sub with param 'color' or even a var 'color' later.
; sub color(...) {}
; sub other(ubyte color) {} ; TODO don't cause name conflict
byte b1