implement 6502 codegen for casting long to float

This commit is contained in:
Irmen de Jong
2025-11-18 22:56:50 +01:00
parent 6a6e18773e
commit c275aacd38
5 changed files with 199 additions and 58 deletions

View File

@@ -3077,7 +3077,14 @@ $endLabel""")
BaseDataType.BYTE -> asmgen.out(" jsr floats.cast_as_w_into_ay | sta $targetAsmVarName")
BaseDataType.UWORD -> asmgen.out(" jsr floats.cast_as_uw_into_ya | sty $targetAsmVarName | sta $targetAsmVarName+1")
BaseDataType.WORD -> asmgen.out(" jsr floats.cast_as_w_into_ay | sta $targetAsmVarName | sty $targetAsmVarName+1")
BaseDataType.LONG -> TODO("cast float to long")
BaseDataType.LONG -> {
asmgen.out("""
sta cx16.r0L
sty cx16.r0H
lda #<$targetAsmVarName
ldy #>$targetAsmVarName
jsr floats.internal_cast_as_long""")
}
else -> throw AssemblyError("weird type")
}
}
@@ -3087,6 +3094,15 @@ $endLabel""")
asmgen.out(" lda $sourceAsmVarName | sta $targetAsmVarName")
} else if(targetDt.isWord || targetDt.isPointer) {
asmgen.out(" lda $sourceAsmVarName | sta $targetAsmVarName | lda $sourceAsmVarName+1 | sta $targetAsmVarName+1")
} else if(targetDt.isFloat) {
asmgen.out("""
lda #<$targetAsmVarName
ldy #>$targetAsmVarName
sta cx16.r0L
sty cx16.r0H
lda #<$sourceAsmVarName
ldy #>$sourceAsmVarName
jsr floats.internal_cast_from_long""")
} else
throw AssemblyError("weird type")
}

View File

@@ -302,4 +302,58 @@ sub interpolate(float v, float inputMin, float inputMax, float outputMin, float
return v * (outputMax - outputMin) + outputMin
}
asmsub internal_cast_from_long(^^long lptr_src @AY, ^^float fptr_target @R0) {
%asm {{
; convert long pointed to by AY into a float pointed to by R0
; algorithm: (msw(l) as word) as float * 65536.0 + (lsw(l) as float)
; TODO optimize this by manipuliating the float memory bits directly
sta P8ZP_SCRATCH_W1
sty P8ZP_SCRATCH_W1+1
ldy #3
lda (P8ZP_SCRATCH_W1),y
sta P8ZP_SCRATCH_REG
dey
lda (P8ZP_SCRATCH_W1),y
ldy P8ZP_SCRATCH_REG
jsr GIVAYFAY
lda #<FL_65536_const
ldy #>FL_65536_const
jsr CONUPK
jsr FMULTT
jsr pushFAC1
ldy #1
lda (P8ZP_SCRATCH_W1),y
sta P8ZP_SCRATCH_REG
dey
lda (P8ZP_SCRATCH_W1),y
ldy P8ZP_SCRATCH_REG
jsr GIVUAYFAY
jsr MOVEF
clc
jsr popFAC
jsr FADDT
ldx cx16.r0L
ldy cx16.r0H
jmp MOVMF
FL_65536_const .byte $91, $00, $00, $00, $00 ; 65536.0
; !notreached!
}}
}
asmsub internal_cast_as_long(^^float fptr_src @R0, ^^long lptr_target @AY) {
%asm {{
; TODO actually implement this
sta P8ZP_SCRATCH_W1
sty P8ZP_SCRATCH_W1+1
lda #0
ldy #3
- sta (P8ZP_SCRATCH_W1),y
dey
bpl -
rts
}}
}
}

View File

@@ -497,8 +497,8 @@ internal class AstChecker(private val program: Program,
errors.err("parameter '${param.first.name}' should be (u)byte or bool", param.first.position)
}
else if(param.second.registerOrPair in arrayOf(RegisterOrPair.AX, RegisterOrPair.AY, RegisterOrPair.XY)) {
if (!param.first.type.isWord && !param.first.type.isString && !param.first.type.isArray && param.first.type!=DataType.pointer(BaseDataType.UBYTE)) {
err("parameter '${param.first.name}' should be (u)word, str or ^^ubyte")
if (!param.first.type.isWord && !param.first.type.isString && !param.first.type.isArray && !param.first.type.isPointer) {
err("parameter '${param.first.name}' should be (u)word, str or a pointer")
}
}
else if(param.second.statusflag!=null) {

View File

@@ -1,14 +1,16 @@
TODO
====
- implement float to long casting and vice versa (6502)
- IR BUG: bool negative = sgn(f)<0 register type error
- 6502 codegen: lptr_target^^ = -lptr_target^^ then put that into internal_cast_as_long()
- before final release: test all examples and programs again with final version of the compiler!
Future Things and Ideas
^^^^^^^^^^^^^^^^^^^^^^^
- implement float to long casting and vice versa (6502)
- make $8000000 a valid long integer (-2147483648) this is more involved than you think. To make this work: long \|= $80000000
- add cx16.r0r1sL, r2r3sL, ... etc to map signed longs on the virtual registers?
- implement rest of long comparisons in IfElseAsmGen compareLongValues(): expressions operands that might clobber the R14-R15 registers...
- struct/ptr: implement the remaining TODOs in PointerAssignmentsGen.
- struct/ptr: optimize deref in PointerAssignmentsGen: optimize 'forceTemporary' to only use a temporary when the offset is >0
@@ -117,6 +119,7 @@ Optimizations
- change float<0, float==0, float>0 to use sgn(float) instead? (also see IR)
- optimize inplaceLongShiftRight() for byte aligned cases
- optimize floats.internal_cast_from_long and floats.internal_cast_as_long
- more optimized operator handling of different types, for example uword a ^ byte b now does a type cast of b to word first
- optimize longEqualsValue() for const and variable operands to not assign needlessly to R0-R3.
- optimize optimizedBitwiseExpr() for const and variable operands to not assign needlessly to R0-R3.

View File

@@ -1,63 +1,131 @@
%import floats
%import textio
%zeropage basicsafe
main {
sub start() {
repeat test()
manual()
casts()
}
sub test() {
txt.cls()
txt.plot(10, 10)
txt.print("enter four digit access code:")
txt.plot(20, 12)
txt.print("╭──────╮")
txt.plot(20, 13)
txt.print("│ │")
txt.plot(20, 14)
txt.print("╰──────╯")
txt.plot(22, 13)
cx16.blink_enable(true)
str code = "????"
ubyte numbers = 0
repeat {
ubyte char = txt.waitkey()
when char {
'0' to '9' -> {
if numbers<4 {
cx16.blink_enable(false)
txt.chrout(char)
cx16.blink_enable(true)
code[numbers] = char
numbers++
}
}
'\r' -> {
if numbers==4 {
cx16.blink_enable(false)
break
}
}
20, 25 -> {
if numbers>0 {
cx16.blink_enable(false)
txt.chrout(157) ; cursor left
txt.spc() ; clear digit
txt.chrout(157) ; cursor left
cx16.blink_enable(true)
numbers--
}
}
}
}
txt.print("\n\n\ncode entered: ")
txt.print(code)
sys.wait(120)
sub manual() {
txt.print("\nwith conversion function:\n")
long lv
float f
lv = 123456789
txt.print_l(lv)
txt.spc()
floats.internal_cast_from_long(&lv, &f)
txt.print_f(f)
txt.spc()
internal_cast_as_long(&f, &lv)
txt.print_l(lv)
txt.nl()
lv = -987654321
txt.print_l(lv)
txt.spc()
floats.internal_cast_from_long(&lv, &f)
txt.print_f(f)
txt.spc()
internal_cast_as_long(&f, &lv)
txt.print_l(lv)
txt.nl()
lv = -$111101
txt.print_l(lv)
txt.spc()
txt.print_ulhex(lv, true)
txt.spc()
floats.internal_cast_from_long(&lv, &f)
txt.print_f(f)
txt.spc()
internal_cast_as_long(&f, &lv)
txt.print_l(lv)
txt.nl()
}
sub casts() {
txt.print("\nwith casting:\n")
long lv
float f
lv = 123456789
txt.print_l(lv)
txt.spc()
f = lv as float
txt.print_f(f)
txt.spc()
txt.print_l(f as long)
txt.nl()
lv = -987654321
txt.print_l(lv)
txt.spc()
f = lv as float
txt.print_f(f)
txt.spc()
txt.print_l(f as long)
txt.nl()
lv = -$111101
txt.print_l(lv)
txt.spc()
txt.print_ulhex(lv, true)
txt.spc()
f = lv as float
txt.print_f(f)
txt.spc()
txt.print_l(f as long)
txt.nl()
}
sub internal_cast_as_long(^^float fptr_src, ^^long lptr_target) {
; clobbers R0-R3
float @nozp f = fptr_src^^
alias sign = cx16.r3sL
sign = sgn(f)
if sign<0
f = abs(f)
cx16.r2 = (f / 65536.0) as uword
&long result = &cx16.r0
result = mklong2(cx16.r2, (f - 65536.0 * (cx16.r2 as float)) as uword)
if sign<0
result = -result
lptr_target^^ = result
}
/*
sub start2() {
uword uw
word sw
long lv
float fl
uw = 44555
fl = uw as float
txt.print_f(fl)
txt.nl()
fl /= 2
uw = fl as uword
txt.print_uw(uw)
txt.nl()
sw = -8888
fl = sw as float
txt.print_f(fl)
txt.nl()
fl /= 2
sw = fl as word
txt.print_w(sw)
txt.nl()
lv = -99886666
fl = lv as float
txt.print_f(fl)
txt.nl()
fl /= 2
lv = fl as long
txt.print_l(lv)
txt.nl()
}
*/
}