From c275aacd383722faecdad85df164ed53594299c7 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Tue, 18 Nov 2025 22:56:50 +0100 Subject: [PATCH] implement 6502 codegen for casting long to float --- .../cpu6502/assignment/AssignmentAsmGen.kt | 18 +- .../res/prog8lib/shared_floats_functions.p8 | 54 ++++++ .../compiler/astprocessing/AstChecker.kt | 4 +- docs/source/todo.rst | 5 +- examples/test.p8 | 176 ++++++++++++------ 5 files changed, 199 insertions(+), 58 deletions(-) diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt index ca0326bf0..27613168f 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt @@ -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") } diff --git a/compiler/res/prog8lib/shared_floats_functions.p8 b/compiler/res/prog8lib/shared_floats_functions.p8 index 3a8312a71..73a6503a5 100644 --- a/compiler/res/prog8lib/shared_floats_functions.p8 +++ b/compiler/res/prog8lib/shared_floats_functions.p8 @@ -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 + 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 + }} +} + } diff --git a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt index 8a8bb470b..dea28fd44 100644 --- a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt +++ b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt @@ -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) { diff --git a/docs/source/todo.rst b/docs/source/todo.rst index ddfece70f..73329c9fa 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -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. diff --git a/examples/test.p8 b/examples/test.p8 index 6e98d9071..aa238a82b 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -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() + + } +*/ }