diff --git a/compiler/res/prog8lib/math.asm b/compiler/res/prog8lib/math.asm index d33933785..d1117dfaf 100644 --- a/compiler/res/prog8lib/math.asm +++ b/compiler/res/prog8lib/math.asm @@ -86,8 +86,40 @@ result .byte 0,0,0,0 .pend +divmod_b_asm .proc + ; signed byte division: make everything positive and fix sign afterwards + sta P8ZP_SCRATCH_B1 + tya + eor P8ZP_SCRATCH_B1 + php ; save sign + lda P8ZP_SCRATCH_B1 + bpl + + eor #$ff + sec + adc #0 ; make it positive ++ pha + tya + bpl + + eor #$ff + sec + adc #0 ; make it positive + tay ++ pla + jsr divmod_ub_asm + sta _remainder + plp + bpl + + tya + eor #$ff + sec + adc #0 ; negate result + tay ++ rts +_remainder .byte 0 + .pend + + divmod_ub_asm .proc - ; TODO divmod_ub_asm doesn't work correctly. (remainder = ok, quotient = FAULTY) ; -- divide A by Y, result quotient in Y, remainder in A (unsigned) ; division by zero will result in quotient = 255 and remainder = original number sty P8ZP_SCRATCH_REG @@ -109,6 +141,49 @@ divmod_ub_asm .proc rts .pend +divmod_w_asm .proc + ; signed word division: make everything positive and fix sign afterwards + sta P8ZP_SCRATCH_W2 + sty P8ZP_SCRATCH_W2+1 + lda P8ZP_SCRATCH_W1+1 + eor P8ZP_SCRATCH_W2+1 + php ; save sign + lda P8ZP_SCRATCH_W1+1 + bpl + + lda #0 + sec + sbc P8ZP_SCRATCH_W1 + sta P8ZP_SCRATCH_W1 + lda #0 + sbc P8ZP_SCRATCH_W1+1 + sta P8ZP_SCRATCH_W1+1 ++ lda P8ZP_SCRATCH_W2+1 + bpl + + lda #0 + sec + sbc P8ZP_SCRATCH_W2 + sta P8ZP_SCRATCH_W2 + lda #0 + sbc P8ZP_SCRATCH_W2+1 + sta P8ZP_SCRATCH_W2+1 ++ tay + lda P8ZP_SCRATCH_W2 + jsr divmod_uw_asm + plp ; restore sign + bpl + + sta P8ZP_SCRATCH_W2 + sty P8ZP_SCRATCH_W2+1 + lda #0 + sec + sbc P8ZP_SCRATCH_W2 + pha + lda #0 + sbc P8ZP_SCRATCH_W2+1 + tay + pla ++ rts + .pend + divmod_uw_asm .proc ; -- divide two unsigned words (16 bit each) into 16 bit results ; input: P8ZP_SCRATCH_W1 in ZP: 16 bit number, A/Y: 16 bit divisor diff --git a/compiler/src/prog8/compiler/target/c64/codegen/assignment/AugmentableAssignmentAsmGen.kt b/compiler/src/prog8/compiler/target/c64/codegen/assignment/AugmentableAssignmentAsmGen.kt index 28a42b7a7..6a74eda4a 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/assignment/AugmentableAssignmentAsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/assignment/AugmentableAssignmentAsmGen.kt @@ -251,16 +251,16 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, else asmgen.out(" sta (P8ZP_SCRATCH_W1),y") } - "*" -> TODO("mul")// asmgen.out(" jsr prog8_lib.mul_byte") // the optimized routines should have been checked earlier - "/" -> TODO("div")// asmgen.out(if(types==DataType.UBYTE) " jsr prog8_lib.idiv_ub" else " jsr prog8_lib.idiv_b") + "*" -> TODO("mul mem byte")// asmgen.out(" jsr prog8_lib.mul_byte") // the optimized routines should have been checked earlier + "/" -> TODO("div mem byte")// asmgen.out(if(types==DataType.UBYTE) " jsr prog8_lib.idiv_ub" else " jsr prog8_lib.idiv_b") "%" -> { - TODO("byte remainder") + TODO("mem byte remainder") // if(types==DataType.BYTE) // throw AssemblyError("remainder of signed integers is not properly defined/implemented, use unsigned instead") // asmgen.out(" jsr prog8_lib.remainder_ub") } - "<<" -> TODO("ubyte asl") - ">>" -> TODO("ubyte lsr") + "<<" -> TODO("mem ubyte asl") + ">>" -> TODO("mem ubyte lsr") "&" -> { val (ptrOnZp, sourceName) = asmgen.loadByteFromPointerIntoA(pointervar) asmgen.out(" and P8ESTACK_LO+1,x") @@ -310,16 +310,16 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, else asmgen.out(" sta (P8ZP_SCRATCH_W1),y") } - "*" -> TODO("mul")// asmgen.out(" jsr prog8_lib.mul_byte") // the optimized routines should have been checked earlier - "/" -> TODO("div")// asmgen.out(if(types==DataType.UBYTE) " jsr prog8_lib.idiv_ub" else " jsr prog8_lib.idiv_b") + "*" -> TODO("mem mul")// asmgen.out(" jsr prog8_lib.mul_byte") // the optimized routines should have been checked earlier + "/" -> TODO("mem div")// asmgen.out(if(types==DataType.UBYTE) " jsr prog8_lib.idiv_ub" else " jsr prog8_lib.idiv_b") "%" -> { - TODO("byte remainder") + TODO("mem byte remainder") // if(types==DataType.BYTE) // throw AssemblyError("remainder of signed integers is not properly defined/implemented, use unsigned instead") // asmgen.out(" jsr prog8_lib.remainder_ub") } - "<<" -> TODO("ubyte asl") - ">>" -> TODO("ubyte lsr") + "<<" -> TODO("mem ubyte asl") + ">>" -> TODO("mem ubyte lsr") "&" -> { val (ptrOnZp, sourceName) = asmgen.loadByteFromPointerIntoA(pointervar) asmgen.out(" and $otherName") @@ -368,19 +368,19 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, asmgen.out(" sta (P8ZP_SCRATCH_W1),y") } "*" -> { - TODO("mul byte litval") + TODO("mem mul byte litval") // asmgen.out(" jsr prog8_lib.mul_byte") // the optimized routines should have been checked earlier } "/" -> { if(value==0) throw AssemblyError("division by zero") - TODO("div byte litval") + TODO("mem div byte litval") // asmgen.out(if(types==DataType.UBYTE) " jsr prog8_lib.idiv_ub" else " jsr prog8_lib.idiv_b") } "%" -> { if(value==0) throw AssemblyError("division by zero") - TODO("byte remainder litval") + TODO("mem byte remainder litval") // if(types==DataType.BYTE) // throw AssemblyError("remainder of signed integers is not properly defined/implemented, use unsigned instead") // asmgen.out(" jsr prog8_lib.remainder_ub") @@ -443,14 +443,14 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, "+" -> asmgen.out(" lda $name | clc | adc P8ESTACK_LO+1,x | sta $name") "-" -> asmgen.out(" lda $name | sec | sbc P8ESTACK_LO+1,x | sta $name") "*" -> { - TODO("mul byte expr") + TODO("var mul byte expr") // asmgen.out(" jsr prog8_lib.mul_byte") // the optimized routines should have been checked earlier } "/" -> { - TODO("div byte expr")// asmgen.out(if(types==DataType.UBYTE) " jsr prog8_lib.idiv_ub" else " jsr prog8_lib.idiv_b") + TODO("var div byte expr")// asmgen.out(if(types==DataType.UBYTE) " jsr prog8_lib.idiv_ub" else " jsr prog8_lib.idiv_b") } "%" -> { - TODO("byte remainder expr") + TODO("var byte remainder expr") // if(types==DataType.BYTE) // throw AssemblyError("remainder of signed integers is not properly defined/implemented, use unsigned instead") // asmgen.out(" jsr prog8_lib.remainder_ub") @@ -507,7 +507,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, "*" -> asmgen.out(" lda $name | ldy $otherName | jsr math.multiply_bytes | sta $name") "/" -> { if(dt==DataType.BYTE) { - TODO("signed byte divide see prog8lib.idiv_b") + asmgen.out(" lda $name | ldy $otherName | jsr math.divmod_b_asm | sty $name") } else { asmgen.out(" lda $name | ldy $otherName | jsr math.divmod_ub_asm | sty $name") @@ -574,7 +574,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, "-" -> asmgen.out(" lda $name | sec | sbc #$value | sta $name") "*" -> { // TODO what about the optimized mul_5 etc routines? - TODO("byte mul litval") + TODO("var byte mul litval") // asmgen.out(" jsr prog8_lib.mul_byte") // the optimized routines should have been checked earlier } "/" -> { @@ -586,7 +586,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, sty $name """) } else { - TODO("BYTE div litval") + TODO("var BYTE div litval") } } "%" -> { @@ -688,7 +688,17 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, if(value==0) throw AssemblyError("division by zero") if(dt==DataType.WORD) { - TODO("signed word divide see prog8lib.idiv_w") + asmgen.out(""" + lda $name + ldy $name+1 + sta P8ZP_SCRATCH_W1 + sty P8ZP_SCRATCH_W1+1 + lda #<$value + ldy #>$value + jsr math.divmod_w_asm + sta $name + sty $name+1 + """) } else { asmgen.out(""" @@ -863,7 +873,17 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, } "/" -> { if(dt==DataType.WORD) { - TODO("signed word divide see prog8lib.idiv_w") + asmgen.out(""" + lda $name + ldy $name+1 + sta P8ZP_SCRATCH_W1 + sty P8ZP_SCRATCH_W1+1 + lda $otherName + ldy $otherName+1 + jsr math.divmod_w_asm + sta $name + sty $name+1 + """) } else { asmgen.out(""" @@ -1007,7 +1027,17 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, } "/" -> { if (dt == DataType.WORD) { - TODO("signed word divide see prog8lib.idiv_w") + asmgen.out(""" + lda $name + ldy $name+1 + sta P8ZP_SCRATCH_W1 + sty P8ZP_SCRATCH_W1+1 + lda P8ESTACK_LO+1,x + ldy P8ESTACK_HI+1,x + jsr math.divmod_w_asm + sta $name + sty $name+1 + """) } else { asmgen.out(""" lda $name diff --git a/compiler/src/prog8/compiler/target/cx16/CX16MachineDefinition.kt b/compiler/src/prog8/compiler/target/cx16/CX16MachineDefinition.kt index 705bbb26b..472fc76af 100644 --- a/compiler/src/prog8/compiler/target/cx16/CX16MachineDefinition.kt +++ b/compiler/src/prog8/compiler/target/cx16/CX16MachineDefinition.kt @@ -30,7 +30,7 @@ internal object CX16MachineDefinition: IMachineDefinition { override fun getFloat(num: Number) = C64MachineDefinition.Mflpt5.fromNumber(num) - override fun getFloatRomConst(number: Double): String? = null // TODO Does Cx16 have ROM float locations? + override fun getFloatRomConst(number: Double): String? = null // Cx16 has no pulblic ROM float locations override fun importLibs(compilerOptions: CompilationOptions, importer: ModuleImporter, program: Program) { if (compilerOptions.launcher == LauncherType.BASIC || compilerOptions.output == OutputType.PRG) importer.importLibraryModule(program, "cx16lib") @@ -58,16 +58,17 @@ internal object CX16MachineDefinition: IMachineDefinition { } // 6502 opcodes (including aliases and illegal opcodes), these cannot be used as variable or label names - // TODO add 65C02 opcodes - override val opcodeNames = setOf("adc", "ahx", "alr", "anc", "and", "ane", "arr", "asl", "asr", "axs", "bcc", "bcs", + override val opcodeNames = setOf("adc", "and", "asl", "bcc", "bcs", "beq", "bge", "bit", "blt", "bmi", "bne", "bpl", "brk", "bvc", "bvs", "clc", - "cld", "cli", "clv", "cmp", "cpx", "cpy", "dcm", "dcp", "dec", "dex", "dey", + "cld", "cli", "clv", "cmp", "cpx", "cpy", "dec", "dex", "dey", "eor", "gcc", "gcs", "geq", "gge", "glt", "gmi", "gne", "gpl", "gvc", "gvs", - "inc", "ins", "inx", "iny", "isb", "isc", "jam", "jmp", "jsr", "lae", "las", - "lax", "lda", "lds", "ldx", "ldy", "lsr", "lxa", "nop", "ora", "pha", "php", - "pla", "plp", "rla", "rol", "ror", "rra", "rti", "rts", "sax", "sbc", "sbx", - "sec", "sed", "sei", "sha", "shl", "shr", "shs", "shx", "shy", "slo", "sre", - "sta", "stx", "sty", "tas", "tax", "tay", "tsx", "txa", "txs", "tya", "xaa") + "inc", "inx", "iny", "jmp", "jsr", + "lda", "ldx", "ldy", "lsr", "nop", "ora", "pha", "php", + "pla", "plp", "rol", "ror", "rti", "rts", "sbc", + "sec", "sed", "sei", + "sta", "stx", "sty", "tax", "tay", "tsx", "txa", "txs", "tya", + "bra", "phx", "phy", "plx", "ply", "stz", "trb", "tsb", "bbr", "bbs", + "rmb", "smb", "stp", "wai") internal class CX16Zeropage(options: CompilationOptions) : Zeropage(options) { diff --git a/examples/arithmetic/div.p8 b/examples/arithmetic/div.p8 index b1ea60ccd..ef8fcd7d2 100644 --- a/examples/arithmetic/div.p8 +++ b/examples/arithmetic/div.p8 @@ -2,8 +2,6 @@ %import c64textio %zeropage basicsafe -; TODO implement signed byte/word DIV asm generation, fix unsigned DIV asm generation (for in-place) - main { sub start() { @@ -11,17 +9,17 @@ main { div_ubyte(100, 6, 16) div_ubyte(255, 2, 127) - ;div_byte(0, 1, 0) ; TODO implement - ;div_byte(100, -6, -16) ; TODO implement - ;div_byte(127, -2, -63) ; TODO implement + div_byte(0, 1, 0) + div_byte(100, -6, -16) + div_byte(127, -2, -63) div_uword(0,1,0) div_uword(40000,500,80) div_uword(43211,2,21605) - ;div_word(0,1,0) ; TODO implement - ;div_word(-20000,500,-40) ; TODO implement - ;div_word(-2222,2,-1111) ; TODO implement + div_word(0,1,0) + div_word(-20000,500,-40) + div_word(-2222,2,-1111) div_float(0,1,0) div_float(999.9,111.0,9.008108108108107) diff --git a/examples/test.p8 b/examples/test.p8 index a286fa242..b946f351b 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -3,16 +3,116 @@ main { sub start() { - ubyte b1 = 2 - ubyte b2 = 13 - ubyte b3 = 100 + byte b1 + byte b2 + byte b3 - uword w1 = 2222 - uword w2 = 11 - uword w3 = 33 + word w1 + word w2 + word w3 - w1 %= (w2+w3) - txt.print_uw(w1) + + b2 = 13 + b3 = 100 + b1 = b3 / b2 + txt.print_b(b1) + c64.CHROUT('\n') + + b2 = -13 + b3 = 100 + b1 = b3 / b2 + txt.print_b(b1) + c64.CHROUT('\n') + + b2 = 13 + b3 = -100 + b1 = b3 / b2 + txt.print_b(b1) + c64.CHROUT('\n') + + b2 = -13 + b3 = -100 + b1 = b3 / b2 + txt.print_b(b1) + c64.CHROUT('\n') + + + b2 = 13 + b3 = 100 + b3 /= b2 + txt.print_b(b3) + c64.CHROUT('\n') + + b2 = -13 + b3 = 100 + b3 /= b2 + txt.print_b(b3) + c64.CHROUT('\n') + + b2 = 13 + b3 = -100 + b3 /= b2 + txt.print_b(b3) + c64.CHROUT('\n') + + b2 = -13 + b3 = -100 + b3 /= b2 + txt.print_b(b3) + c64.CHROUT('\n') + c64.CHROUT('\n') + + + + + + w2 = 133 + w3 = 20000 + w1 = w3 / w2 + txt.print_w(w1) + c64.CHROUT('\n') + + w2 = -133 + w3 = 20000 + w1 = w3 / w2 + txt.print_w(w1) + c64.CHROUT('\n') + + w2 = 133 + w3 = -20000 + w1 = w3 / w2 + txt.print_w(w1) + c64.CHROUT('\n') + + w2 = -133 + w3 = -20000 + w1 = w3 / w2 + txt.print_w(w1) + c64.CHROUT('\n') + + + w2 = 133 + w3 = 20000 + w3 /= w2 + txt.print_w(w3) + c64.CHROUT('\n') + + w2 = -133 + w3 = 20000 + w3 /= w2 + txt.print_w(w3) + c64.CHROUT('\n') + + w2 = 133 + w3 = -20000 + w3 /= w2 + txt.print_w(w3) + c64.CHROUT('\n') + + w2 = -133 + w3 = -20000 + w3 /= w2 + txt.print_w(w3) c64.CHROUT('\n') } }