From 48bd51e1a5e3034ff0a3b266735f62bd87a07154 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Sun, 3 Sep 2023 03:06:59 +0200 Subject: [PATCH] c64 float problem --- .../cpu6502/assignment/AnyExprAsmGen.kt | 29 ++-- docs/source/todo.rst | 4 +- floatproblem64-small.asm | 80 ++++++++++ floatproblem64.asm | 144 ------------------ 4 files changed, 96 insertions(+), 161 deletions(-) create mode 100644 floatproblem64-small.asm delete mode 100644 floatproblem64.asm diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AnyExprAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AnyExprAsmGen.kt index 5bdbc606e..cd0fae209 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AnyExprAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AnyExprAsmGen.kt @@ -1,6 +1,7 @@ package prog8.codegen.cpu6502.assignment import prog8.code.ast.PtBinaryExpression +import prog8.code.ast.PtExpression import prog8.code.core.* import prog8.codegen.cpu6502.AsmGen6502Internal @@ -180,37 +181,25 @@ internal class AnyExprAsmGen( private fun assignFloatBinExpr(expr: PtBinaryExpression, assign: AsmAssignment): Boolean { when(expr.operator) { "+" -> { - asmgen.assignExpressionToRegister(expr.left, RegisterOrPair.FAC1, true) - if(!expr.right.isSimple()) asmgen.pushFAC1() - asmgen.assignExpressionToRegister(expr.right, RegisterOrPair.FAC2, true) - if(!expr.right.isSimple()) asmgen.popFAC1() + assignFloatOperandsToFACandARG(expr.left, expr.right) asmgen.out(" jsr floats.FADDT") asmgen.assignRegister(RegisterOrPair.FAC1, assign.target) return true } "-" -> { - asmgen.assignExpressionToRegister(expr.right, RegisterOrPair.FAC1, true) - if(!expr.left.isSimple()) asmgen.pushFAC1() - asmgen.assignExpressionToRegister(expr.left, RegisterOrPair.FAC2, true) - if(!expr.left.isSimple()) asmgen.popFAC1() + assignFloatOperandsToFACandARG(expr.right, expr.left) asmgen.out(" jsr floats.FSUBT") asmgen.assignRegister(RegisterOrPair.FAC1, assign.target) return true } "*" -> { - asmgen.assignExpressionToRegister(expr.left, RegisterOrPair.FAC1, true) - if(!expr.right.isSimple()) asmgen.pushFAC1() - asmgen.assignExpressionToRegister(expr.right, RegisterOrPair.FAC2, true) - if(!expr.right.isSimple()) asmgen.popFAC1() + assignFloatOperandsToFACandARG(expr.left, expr.right) asmgen.out(" jsr floats.FMULTT") asmgen.assignRegister(RegisterOrPair.FAC1, assign.target) return true } "/" -> { - asmgen.assignExpressionToRegister(expr.right, RegisterOrPair.FAC1, true) - if(!expr.left.isSimple()) asmgen.pushFAC1() - asmgen.assignExpressionToRegister(expr.left, RegisterOrPair.FAC2, true) - if(!expr.left.isSimple()) asmgen.popFAC1() + assignFloatOperandsToFACandARG(expr.right, expr.left) asmgen.out(" jsr floats.FDIVT") asmgen.assignRegister(RegisterOrPair.FAC1, assign.target) return true @@ -255,6 +244,14 @@ internal class AnyExprAsmGen( } } + private fun assignFloatOperandsToFACandARG(left: PtExpression, right: PtExpression) { + asmgen.assignExpressionToRegister(left, RegisterOrPair.FAC1, true) + if(!right.isSimple()) asmgen.pushFAC1() + asmgen.assignExpressionToRegister(right, RegisterOrPair.FAC2, true) + if(!right.isSimple()) asmgen.popFAC1() + // TODO: always make sure FAC2 is loaded last (done using CONUPK) otherwise the result will be corrupt on C64 + } + private fun setupFloatComparisonFAC1vsVarAY(expr: PtBinaryExpression) { asmgen.assignExpressionToRegister(expr.left, RegisterOrPair.FAC1, true) if(!expr.right.isSimple()) asmgen.pushFAC1() diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 4d759f123..35114c226 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -1,7 +1,9 @@ TODO ==== - fix on c64 target: examples/cube3d-float (broken since 9.3 with the evalstack removal) it works on x16 target, oddly enough. - More detailed and simpler code for this problem in floatproblem64.p8 / floatproblem64.asm (the minified version) + More detailed and simpler code for this problem in floatproblem.p8 / floatproblem64-small.asm (the minified version) + Seems like MOVFM (loading FAC) corrupts the sign of ARG, so CONUPK (loading ARG) needs to be done AFTER MOVFM (loading FAC)...? + See assignFloatOperandsToFACandARG() - prefix prog8 subroutines with p8s_ instead of p8_ to not let them clash with variables in the asm? - allow 'chained' array indexing for expressions: value = ptrarray[0][0] diff --git a/floatproblem64-small.asm b/floatproblem64-small.asm new file mode 100644 index 000000000..74c5ffb4a --- /dev/null +++ b/floatproblem64-small.asm @@ -0,0 +1,80 @@ + +.cpu '6502' + +CHROUT = $FFD2 + +; C64 addresses for float routines: +MOVFM = $bba2 +CONUPK = $ba8c +MOVAF = $bc0c +MOVEF = $bc0f +MOVMF = $bbd4 +FOUT = $bddd +FADDT = $b86a +FMULTT = $ba2b +; CX16 addresses for float routines: +;MOVFM = $fe63 +;CONUPK = $fe5a +;MOVAF = $fe6c +;MOVEF = $fe81 +;MOVMF = $fe66 +;FOUT = $fe06 +;FADDT = $fe1b +;FMULTT = $fe21 + +* = $0801 + +; 10 SYS 2062 + .word (+), 10 + .null $9e, " 2062" ++ .word 0 + +; program starts here at address 2062 + lda #$8d + jsr CHROUT + + ldx #0 + stx $6f + lda #prog8_float_const_1 + jsr CONUPK ; ARG = 0.3 + lda #prog8_float_const_0 + jsr MOVFM ; FAC1 = -0.8 ; On C64 this also seems to corrupt the value in ARG!!! (or at least, the sign of that) + jsr FADDT ; FAC1 = -0.8 + 0.3 = -0.5 + ; ... result in FAC1 will be wrong on C64 (1.1 instead of -0.5).... + ; Seems like MOVFM (loading FAC) corrupts the sign of ARG, so CONUPK (loading ARG) needs to be done AFTER MOVFM (loading FAC)...? + + ; print FAC1 + jsr FOUT ; fac1 to string in A/Y + sta _mod+1 + sty _mod+2 + ldy #0 +_mod lda $ffff,y ; modified + beq + + jsr CHROUT + iny + bne _mod ++ lda #$8d + jsr CHROUT + + ; print expected + ldy #0 +- lda string_1,y + beq + + jsr CHROUT + iny + bne - ++ + +loop jmp loop + + +string_1 + .text "-.5 was expected",$8d,0 + + +; global float constants +prog8_float_const_0 .byte $80, $cc, $cc, $cc, $cc ; float -0.8 +prog8_float_const_1 .byte $7f, $19, $99, $99, $99 ; float 0.3 +float_const_one .byte $81, $00, $00, $00, $00 ; float 1.0 diff --git a/floatproblem64.asm b/floatproblem64.asm deleted file mode 100644 index b0b3d2a2e..000000000 --- a/floatproblem64.asm +++ /dev/null @@ -1,144 +0,0 @@ - -.cpu '6502' - -CHROUT = $FFD2 - -; C64 addresses for float routines: -;MOVFM = $bba2 -;CONUPK = $ba8c -;MOVAF = $bc0c -;MOVMF = $bbd4 -;FOUT = $bddd -;FADDT = $b86a -;FMULTT = $ba2b -; CX16 addresses for float routines: -MOVFM = $fe63 -CONUPK = $fe5a -MOVAF = $fe6c -MOVMF = $fe66 -FOUT = $fe06 -FADDT = $fe1b -FMULTT = $fe21 - -* = $0801 - -; 10 SYS 2062 - .word (+), 10 - .null $9e, " 2062" -+ .word 0 - -; program starts here at address 2062 - lda #$8d - jsr CHROUT - - ; calculate: value1*one + value2*one - ; (yes the multiplications with one do nothing value-wise, but they influence the routines being called...) - lda #prog8_float_const_0 - jsr MOVFM ; FAC1 = -0.8 - lda #float_const_one - jsr CONUPK ; ARG = 1.0 - jsr FMULTT ; FAC1 = -0.8*1.0 = -0.8 - jsr pushFAC1 ; save value... - lda #prog8_float_const_1 - jsr MOVFM ; FAC1 = 0.3 - lda #float_const_one - jsr CONUPK ; ARG = 1.0 - jsr FMULTT ; FAC1 = 0.3*1.0 = 0.3 - jsr MOVAF ; ARG = FAC1 = 0.3 - jsr popFAC1 ; restore value... (-0.8) - jsr FADDT ; FAC1 = -0.8 + 0.3 = -0.5 - ; ... result in FAC1 will be wrong on C64 (1.1 instead of -0.5).... - - ; print FAC1 - jsr FOUT ; fac1 to string in A/Y - sta _mod+1 - sty _mod+2 - ldy #0 -_mod lda $ffff,y ; modified - beq + - jsr CHROUT - iny - bne _mod -+ lda #$8d - jsr CHROUT - - ; print expected - ldy #0 -- lda string_1,y - beq + - jsr CHROUT - iny - bne - -+ rts - -string_1 - .text "-.5 was expected",$8d,0 - - -floats_temp_var .byte 0,0,0,0,0 ; temporary storage for a float - -pushFAC1 - ;-- push floating point in FAC onto the cpu stack - ; save return address - pla - sta returnaddr - pla - sta returnaddr+1 - ldx #floats_temp_var - jsr MOVMF - lda floats_temp_var - pha - lda floats_temp_var+1 - pha - lda floats_temp_var+2 - pha - lda floats_temp_var+3 - pha - lda floats_temp_var+4 - pha - ; re-push return address - lda returnaddr+1 - pha - lda returnaddr - pha - rts - -returnaddr .word 0 - -popFAC1 - ; -- pop floating point value from cpu stack into FAC1 - ; save return address - pla - sta returnaddr - pla - sta returnaddr+1 - pla - sta floats_temp_var+4 - pla - sta floats_temp_var+3 - pla - sta floats_temp_var+2 - pla - sta floats_temp_var+1 - pla - sta floats_temp_var - lda #floats_temp_var - jsr MOVFM - ; re-push return address - lda returnaddr+1 - pha - lda returnaddr - pha - rts - - -; global float constants -prog8_float_const_0 .byte $80, $cc, $cc, $cc, $cc ; float -0.8 -prog8_float_const_1 .byte $7f, $19, $99, $99, $99 ; float 0.3 -float_const_one .byte $81, $00, $00, $00, $00 ; float 1.0