implemented signed byte and word division

This commit is contained in:
Irmen de Jong 2020-08-28 23:28:21 +02:00
parent 9154d8bd37
commit e112dfd910
5 changed files with 252 additions and 48 deletions

View File

@ -86,8 +86,40 @@ result .byte 0,0,0,0
.pend .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 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) ; -- divide A by Y, result quotient in Y, remainder in A (unsigned)
; division by zero will result in quotient = 255 and remainder = original number ; division by zero will result in quotient = 255 and remainder = original number
sty P8ZP_SCRATCH_REG sty P8ZP_SCRATCH_REG
@ -109,6 +141,49 @@ divmod_ub_asm .proc
rts rts
.pend .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 divmod_uw_asm .proc
; -- divide two unsigned words (16 bit each) into 16 bit results ; -- 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 ; input: P8ZP_SCRATCH_W1 in ZP: 16 bit number, A/Y: 16 bit divisor

View File

@ -251,16 +251,16 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
else else
asmgen.out(" sta (P8ZP_SCRATCH_W1),y") 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("mul mem byte")// 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("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) // if(types==DataType.BYTE)
// throw AssemblyError("remainder of signed integers is not properly defined/implemented, use unsigned instead") // throw AssemblyError("remainder of signed integers is not properly defined/implemented, use unsigned instead")
// asmgen.out(" jsr prog8_lib.remainder_ub") // asmgen.out(" jsr prog8_lib.remainder_ub")
} }
"<<" -> TODO("ubyte asl") "<<" -> TODO("mem ubyte asl")
">>" -> TODO("ubyte lsr") ">>" -> TODO("mem ubyte lsr")
"&" -> { "&" -> {
val (ptrOnZp, sourceName) = asmgen.loadByteFromPointerIntoA(pointervar) val (ptrOnZp, sourceName) = asmgen.loadByteFromPointerIntoA(pointervar)
asmgen.out(" and P8ESTACK_LO+1,x") asmgen.out(" and P8ESTACK_LO+1,x")
@ -310,16 +310,16 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
else else
asmgen.out(" sta (P8ZP_SCRATCH_W1),y") 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("mem 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 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) // if(types==DataType.BYTE)
// throw AssemblyError("remainder of signed integers is not properly defined/implemented, use unsigned instead") // throw AssemblyError("remainder of signed integers is not properly defined/implemented, use unsigned instead")
// asmgen.out(" jsr prog8_lib.remainder_ub") // asmgen.out(" jsr prog8_lib.remainder_ub")
} }
"<<" -> TODO("ubyte asl") "<<" -> TODO("mem ubyte asl")
">>" -> TODO("ubyte lsr") ">>" -> TODO("mem ubyte lsr")
"&" -> { "&" -> {
val (ptrOnZp, sourceName) = asmgen.loadByteFromPointerIntoA(pointervar) val (ptrOnZp, sourceName) = asmgen.loadByteFromPointerIntoA(pointervar)
asmgen.out(" and $otherName") asmgen.out(" and $otherName")
@ -368,19 +368,19 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
asmgen.out(" sta (P8ZP_SCRATCH_W1),y") 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 // asmgen.out(" jsr prog8_lib.mul_byte") // the optimized routines should have been checked earlier
} }
"/" -> { "/" -> {
if(value==0) if(value==0)
throw AssemblyError("division by zero") 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") // asmgen.out(if(types==DataType.UBYTE) " jsr prog8_lib.idiv_ub" else " jsr prog8_lib.idiv_b")
} }
"%" -> { "%" -> {
if(value==0) if(value==0)
throw AssemblyError("division by zero") throw AssemblyError("division by zero")
TODO("byte remainder litval") TODO("mem byte remainder litval")
// if(types==DataType.BYTE) // if(types==DataType.BYTE)
// throw AssemblyError("remainder of signed integers is not properly defined/implemented, use unsigned instead") // throw AssemblyError("remainder of signed integers is not properly defined/implemented, use unsigned instead")
// asmgen.out(" jsr prog8_lib.remainder_ub") // 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 | clc | adc P8ESTACK_LO+1,x | sta $name")
"-" -> asmgen.out(" lda $name | sec | sbc 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 // 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) // if(types==DataType.BYTE)
// throw AssemblyError("remainder of signed integers is not properly defined/implemented, use unsigned instead") // throw AssemblyError("remainder of signed integers is not properly defined/implemented, use unsigned instead")
// asmgen.out(" jsr prog8_lib.remainder_ub") // 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") "*" -> asmgen.out(" lda $name | ldy $otherName | jsr math.multiply_bytes | sta $name")
"/" -> { "/" -> {
if(dt==DataType.BYTE) { 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 { else {
asmgen.out(" lda $name | ldy $otherName | jsr math.divmod_ub_asm | sty $name") 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") "-" -> asmgen.out(" lda $name | sec | sbc #$value | sta $name")
"*" -> { "*" -> {
// TODO what about the optimized mul_5 etc routines? // 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 // 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 sty $name
""") """)
} else { } else {
TODO("BYTE div litval") TODO("var BYTE div litval")
} }
} }
"%" -> { "%" -> {
@ -688,7 +688,17 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
if(value==0) if(value==0)
throw AssemblyError("division by zero") throw AssemblyError("division by zero")
if(dt==DataType.WORD) { 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 { else {
asmgen.out(""" asmgen.out("""
@ -863,7 +873,17 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
} }
"/" -> { "/" -> {
if(dt==DataType.WORD) { 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 { else {
asmgen.out(""" asmgen.out("""
@ -1007,7 +1027,17 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
} }
"/" -> { "/" -> {
if (dt == DataType.WORD) { 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 { } else {
asmgen.out(""" asmgen.out("""
lda $name lda $name

View File

@ -30,7 +30,7 @@ internal object CX16MachineDefinition: IMachineDefinition {
override fun getFloat(num: Number) = C64MachineDefinition.Mflpt5.fromNumber(num) 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) { override fun importLibs(compilerOptions: CompilationOptions, importer: ModuleImporter, program: Program) {
if (compilerOptions.launcher == LauncherType.BASIC || compilerOptions.output == OutputType.PRG) if (compilerOptions.launcher == LauncherType.BASIC || compilerOptions.output == OutputType.PRG)
importer.importLibraryModule(program, "cx16lib") 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 // 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", "and", "asl", "bcc", "bcs",
override val opcodeNames = setOf("adc", "ahx", "alr", "anc", "and", "ane", "arr", "asl", "asr", "axs", "bcc", "bcs",
"beq", "bge", "bit", "blt", "bmi", "bne", "bpl", "brk", "bvc", "bvs", "clc", "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", "eor", "gcc", "gcs", "geq", "gge", "glt", "gmi", "gne", "gpl", "gvc", "gvs",
"inc", "ins", "inx", "iny", "isb", "isc", "jam", "jmp", "jsr", "lae", "las", "inc", "inx", "iny", "jmp", "jsr",
"lax", "lda", "lds", "ldx", "ldy", "lsr", "lxa", "nop", "ora", "pha", "php", "lda", "ldx", "ldy", "lsr", "nop", "ora", "pha", "php",
"pla", "plp", "rla", "rol", "ror", "rra", "rti", "rts", "sax", "sbc", "sbx", "pla", "plp", "rol", "ror", "rti", "rts", "sbc",
"sec", "sed", "sei", "sha", "shl", "shr", "shs", "shx", "shy", "slo", "sre", "sec", "sed", "sei",
"sta", "stx", "sty", "tas", "tax", "tay", "tsx", "txa", "txs", "tya", "xaa") "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) { internal class CX16Zeropage(options: CompilationOptions) : Zeropage(options) {

View File

@ -2,8 +2,6 @@
%import c64textio %import c64textio
%zeropage basicsafe %zeropage basicsafe
; TODO implement signed byte/word DIV asm generation, fix unsigned DIV asm generation (for in-place)
main { main {
sub start() { sub start() {
@ -11,17 +9,17 @@ main {
div_ubyte(100, 6, 16) div_ubyte(100, 6, 16)
div_ubyte(255, 2, 127) div_ubyte(255, 2, 127)
;div_byte(0, 1, 0) ; TODO implement div_byte(0, 1, 0)
;div_byte(100, -6, -16) ; TODO implement div_byte(100, -6, -16)
;div_byte(127, -2, -63) ; TODO implement div_byte(127, -2, -63)
div_uword(0,1,0) div_uword(0,1,0)
div_uword(40000,500,80) div_uword(40000,500,80)
div_uword(43211,2,21605) div_uword(43211,2,21605)
;div_word(0,1,0) ; TODO implement div_word(0,1,0)
;div_word(-20000,500,-40) ; TODO implement div_word(-20000,500,-40)
;div_word(-2222,2,-1111) ; TODO implement div_word(-2222,2,-1111)
div_float(0,1,0) div_float(0,1,0)
div_float(999.9,111.0,9.008108108108107) div_float(999.9,111.0,9.008108108108107)

View File

@ -3,16 +3,116 @@
main { main {
sub start() { sub start() {
ubyte b1 = 2 byte b1
ubyte b2 = 13 byte b2
ubyte b3 = 100 byte b3
uword w1 = 2222 word w1
uword w2 = 11 word w2
uword w3 = 33 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') c64.CHROUT('\n')
} }
} }