diff --git a/compiler/examples/cube3d-c64.p8 b/compiler/examples/cube3d-c64.p8 index 0039660a9..d24d69487 100644 --- a/compiler/examples/cube3d-c64.p8 +++ b/compiler/examples/cube3d-c64.p8 @@ -8,14 +8,14 @@ const float height_f = height ; vertices - byte[8] xcoor = [ -50, -50, -50, -50, 50, 50, 50, 50 ] - byte[8] ycoor = [ -50, -50, 50, 50, -50, -50, 50, 50 ] - byte[8] zcoor = [ -50, 50, -50, 50, -50, 50, -50, 50 ] + byte[8] xcoor = [ -40, -40, -40, -40, 40, 40, 40, 40 ] + byte[8] ycoor = [ -40, -40, 40, 40, -40, -40, 40, 40 ] + byte[8] zcoor = [ -40, 40, -40, 40, -40, 40, -40, 40 ] ; storage for rotated coordinates - word[len(xcoor)] rotatedx=0 - word[len(ycoor)] rotatedy=0 - word[len(zcoor)] rotatedz=-1 + word[len(xcoor)] rotatedx + word[len(ycoor)] rotatedy + word[len(zcoor)] rotatedz sub start() { uword anglex @@ -23,11 +23,11 @@ uword anglez while(true) { rotate_vertices(msb(anglex), msb(angley), msb(anglez)) - c64.CLEARSCR() + c64scr.clear_screen(32,1) draw_edges() anglex+=1000 - angley+=333 - anglez+=807 + angley+=433 + anglez+=907 } } @@ -59,33 +59,21 @@ lsr(wsina_sinb) lsr(wsina_sinb) ; / 128 - float cosa_sinb = wcosa_sinb as float / 128.0 - float sina_sinb = wsina_sinb as float / 128.0 - float Axx = wcosa*wcosb as float / 16384.0 - float Axy = cosa_sinb*(wsinc as float / 128.0) - (wsina*wcosc as float / 16384.0) - float Axz = cosa_sinb*(wcosc as float / 128.0) + (wsina*wsinc as float / 16384.0) - float Ayx = wsina*wcosb as float / 16384.0 - float Ayy = sina_sinb*(wsinc as float / 128.0) + (wcosa*wcosc as float / 16384.0) - float Ayz = sina_sinb*(wcosc as float / 128.0) - (wcosa*wsinc as float / 16384.0) - float Azx = -wsinb as float / 128.0 - float Azy = wcosb*wsinc as float / 16384.0 - float Azz = wcosb*wcosc as float / 16384.0 - - word wAxx = Axx * 128.0 as word - word wAxy = Axy * 128.0 as word - word wAxz = Axz * 128.0 as word - word wAyx = Ayx * 128.0 as word - word wAyy = Ayy * 128.0 as word - word wAyz = Ayz * 128.0 as word - word wAzx = Azx * 128.0 as word - word wAzy = Azy * 128.0 as word - word wAzz = Azz * 128.0 as word + word Axx = (wcosa*wcosb as float / 128.0) as word + word Axy = ((wcosa_sinb*wsinc - wsina*wcosc) as float / 128.0) as word + word Axz = ((wcosa_sinb*wcosc + wsina*wsinc) as float / 128.0) as word + word Ayx = (wsina*wcosb as float / 128.0) as word + word Ayy = ((wsina_sinb*wsinc + wcosa*wcosc) as float / 128.0) as word + word Ayz = ((wsina_sinb*wcosc - wcosa*wsinc) as float / 128.0) as word + word Azx = -wsinb + word Azy = (wcosb*wsinc as float / 128.0) as word + word Azz = (wcosb*wcosc as float / 128.0) as word for ubyte i in 0 to len(xcoor)-1 { word xc = xcoor[i] as word word yc = ycoor[i] as word word zc = zcoor[i] as word - word zz = wAxx*xc + wAxy*yc + wAxz*zc + word zz = Axx*xc + Axy*yc + Axz*zc lsr(zz) lsr(zz) lsr(zz) @@ -94,7 +82,7 @@ lsr(zz) lsr(zz) ; /128 rotatedx[i] = zz - zz=wAyx*xc + wAyy*yc + wAyz*zc + zz=Ayx*xc + Ayy*yc + Ayz*zc lsr(zz) lsr(zz) lsr(zz) @@ -103,7 +91,7 @@ lsr(zz) lsr(zz) ; /128 rotatedy[i] = zz - zz = wAzx*xc + wAzy*yc + wAzz*zc + zz = Azx*xc + Azy*yc + Azz*zc lsr(zz) lsr(zz) lsr(zz) @@ -123,7 +111,7 @@ for ubyte i in 0 to len(xcoor)-1 { word rz = rotatedz[i] if rz >= 10 { - float persp = (rz as float + 250.0)/height_f + float persp = (rz as float + 180.0)/height_f byte sx = rotatedx[i] as float / persp as byte + width//2 byte sy = rotatedy[i] as float / persp as byte + height//2 c64scr.setchrclr(sx as ubyte, sy as ubyte, 46, i+2) @@ -133,7 +121,7 @@ for ubyte i in 0 to len(xcoor)-1 { word rz = rotatedz[i] if rz < 10 { - float persp = (rz as float + 250.0)/height_f + float persp = (rz as float + 180.0)/height_f byte sx = rotatedx[i] as float / persp as byte + width//2 byte sy = rotatedy[i] as float / persp as byte + height//2 c64scr.setchrclr(sx as ubyte, sy as ubyte, 81, i+2) diff --git a/compiler/examples/test.p8 b/compiler/examples/test.p8 index 1bc251535..e83fb3c2c 100644 --- a/compiler/examples/test.p8 +++ b/compiler/examples/test.p8 @@ -1,148 +1,52 @@ %import c64utils -%import c64flt ~ main { - const uword width = 40 - const uword height = 25 - - ; vertices - byte[8] xcoor = [ -50, -50, -50, -50, 50, 50, 50, 50 ] - byte[8] ycoor = [ -50, -50, 50, 50, -50, -50, 50, 50 ] - byte[8] zcoor = [ -50, 50, -50, 50, -50, 50, -50, 50 ] - - ; storage for rotated coordinates - word[len(xcoor)] rotatedx=0 - word[len(ycoor)] rotatedy=0 - word[len(zcoor)] rotatedz=-1 - sub start() { - uword anglex - uword angley - uword anglez - while(true) { - rotate_vertices(msb(anglex), msb(angley), msb(anglez)) - c64.CLEARSCR() - draw_edges() - anglex+=1000 - angley+=333 - anglez+=807 - } + + ubyte a=200 + ubyte b=33 + ubyte c + + byte ab=100 + byte bb=-6 + byte cb + + uword wa=50000 + uword wb=999 + uword wc + word wab=30000 + word wbb=-99 + word wcb + + c=a//b + c64scr.print_ub(c) + c64.CHROUT('\n') + a=155 + b=11 + c=a//b + c64scr.print_ub(c) + c64.CHROUT('\n') + cb=ab//bb + c64scr.print_b(cb) + c64.CHROUT('\n') + ab=-100 + bb=6 + cb=ab//bb + c64scr.print_b(cb) + c64.CHROUT('\n') + ab=-100 + bb=-6 + cb=ab//bb + c64scr.print_b(cb) + c64.CHROUT('\n') + ab=100 + bb=6 + cb=ab//bb + c64scr.print_b(cb) + c64.CHROUT('\n') + c64scr.print_ub(X) + c64.CHROUT('\n') } - sub rotate_vertices(ubyte ax, ubyte ay, ubyte az) { - ; rotate around origin (0,0,0) - - ; set up the 3d rotation matrix values - word wcosa = cos8(ax) as word - word wsina = sin8(ax) as word - word wcosb = cos8(ay) as word - word wsinb = sin8(ay) as word - word wcosc = cos8(az) as word - word wsinc = sin8(az) as word - - word wcosa_sinb = wcosa*wsinb - lsr(wcosa_sinb) - lsr(wcosa_sinb) - lsr(wcosa_sinb) - lsr(wcosa_sinb) - lsr(wcosa_sinb) - lsr(wcosa_sinb) - lsr(wcosa_sinb) ; / 128 - word wsina_sinb = wsina*wsinb - lsr(wsina_sinb) - lsr(wsina_sinb) - lsr(wsina_sinb) - lsr(wsina_sinb) - lsr(wsina_sinb) - lsr(wsina_sinb) - lsr(wsina_sinb) ; / 128 - - float cosa_sinb = wcosa_sinb as float / 128.0 - float sina_sinb = wsina_sinb as float / 128.0 - float Axx = wcosa*wcosb as float / 16384.0 - float Axy = cosa_sinb*(wsinc as float / 128.0) - (wsina*wcosc as float / 16384.0) - float Axz = cosa_sinb*(wcosc as float / 128.0) + (wsina*wsinc as float / 16384.0) - float Ayx = wsina*wcosb as float / 16384.0 - float Ayy = sina_sinb*(wsinc as float / 128.0) + (wcosa*wcosc as float / 16384.0) - float Ayz = sina_sinb*(wcosc as float / 128.0) - (wcosa*wsinc as float / 16384.0) - float Azx = -wsinb as float / 128.0 - float Azy = wcosb*wsinc as float / 16384.0 - float Azz = wcosb*wcosc as float / 16384.0 - - word wAxx = Axx * 128.0 as word - word wAxy = Axy * 128.0 as word - word wAxz = Axz * 128.0 as word - word wAyx = Ayx * 128.0 as word - word wAyy = Ayy * 128.0 as word - word wAyz = Ayz * 128.0 as word - word wAzx = Azx * 128.0 as word - word wAzy = Azy * 128.0 as word - word wAzz = Azz * 128.0 as word - - for ubyte i in 0 to len(xcoor)-1 { - word xc = xcoor[i] as word - word yc = ycoor[i] as word - word zc = zcoor[i] as word - word zz = wAxx*xc + wAxy*yc + wAxz*zc - lsr(zz) - lsr(zz) - lsr(zz) - lsr(zz) - lsr(zz) - lsr(zz) - lsr(zz) ; /128 - rotatedx[i] = zz - zz=wAyx*xc + wAyy*yc + wAyz*zc - lsr(zz) - lsr(zz) - lsr(zz) - lsr(zz) - lsr(zz) - lsr(zz) - lsr(zz) ; /128 - rotatedy[i] = zz - zz = wAzx*xc + wAzy*yc + wAzz*zc - lsr(zz) - lsr(zz) - lsr(zz) - lsr(zz) - lsr(zz) - lsr(zz) - lsr(zz) ; /128 - rotatedz[i] = zz - } - } - - sub draw_edges() { - - sub toscreenx(float x, float z) -> byte { - return x/(250.0+z) * (height as float) as byte + width // 2 - } - - sub toscreeny(float y, float z) -> byte { - return y/(250.0+z) * (height as float) as byte + height // 2 - } - - ; plot the points of the 3d cube - ; first the points on the back, then the points on the front (painter algorithm) - - for ubyte i in 0 to len(xcoor)-1 { - word rz = rotatedz[i] - if rz >= 10 { - ubyte sx = toscreenx(rotatedx[i] as float, rz as float) as ubyte ; @todo crash when not using 'as float' for the param! - ubyte sy = toscreeny(rotatedy[i] as float, rz as float) as ubyte ; @todo crash when not using 'as float' for the param! - c64scr.setchrclr(sx, sy, 46, i+2) - } - } - - for ubyte i in 0 to len(xcoor)-1 { - word rz = rotatedz[i] - if rz < 10 { - ubyte sx = toscreenx(rotatedx[i] as float, rz as float) as ubyte ; @todo crash when not using 'as float' for the param! - ubyte sy = toscreeny(rotatedy[i] as float, rz as float) as ubyte ; @todo crash when not using 'as float' for the param! - c64scr.setchrclr(sx, sy, 81, i+2) - } - } - } } diff --git a/compiler/src/prog8/ast/AST.kt b/compiler/src/prog8/ast/AST.kt index a3fd436be..fe275e327 100644 --- a/compiler/src/prog8/ast/AST.kt +++ b/compiler/src/prog8/ast/AST.kt @@ -868,50 +868,7 @@ class BinaryExpression(var left: IExpression, var operator: String, var right: I "<", ">", "<=", ">=", "==", "!=" -> DataType.UBYTE - "/" -> { - val rightNum = right.constValue(namespace, heap)?.asNumericValue?.toDouble() - if(rightNum!=null) { - when(leftDt) { - DataType.UBYTE -> - when(rightDt) { - DataType.UBYTE -> DataType.UBYTE - DataType.BYTE -> DataType.BYTE - DataType.UWORD -> if(rightNum >= 256) DataType.UBYTE else DataType.UWORD - DataType.WORD -> { - if(rightNum < 0) - if(rightNum<-256) DataType.UBYTE else DataType.WORD - else - if(rightNum>256) DataType.UBYTE else DataType.UWORD - } - DataType.FLOAT -> if(rightNum <= -256 || rightNum >= 256) DataType.UBYTE else DataType.FLOAT - else -> throw FatalAstException("invalid rightDt $rightDt") - } - DataType.BYTE -> - when(rightDt) { - DataType.UBYTE, DataType.BYTE -> DataType.BYTE - DataType.UWORD, DataType.WORD -> if(rightNum <= -256 || rightNum >= 256) DataType.BYTE else DataType.WORD - DataType.FLOAT -> if(rightNum <= -256 || rightNum >= 256) DataType.BYTE else DataType.FLOAT - else -> throw FatalAstException("invalid rightDt $rightDt") - } - DataType.UWORD -> - when(rightDt) { - DataType.UBYTE, DataType.UWORD -> DataType.UWORD - DataType.BYTE, DataType.WORD -> DataType.WORD - DataType.FLOAT -> if(rightNum <= -65536 || rightNum >= 65536) DataType.UWORD else DataType.FLOAT - else -> throw FatalAstException("invalid rightDt $rightDt") - } - DataType.WORD -> - when(rightDt) { - DataType.UBYTE, DataType.UWORD, DataType.BYTE, DataType.WORD -> DataType.WORD - DataType.FLOAT -> if(rightNum <= -65536 || rightNum >= 65536) DataType.WORD else DataType.FLOAT - else -> throw FatalAstException("invalid rightDt $rightDt") - } - DataType.FLOAT -> DataType.FLOAT - null -> DataType.FLOAT - else -> throw FatalAstException("invalid leftDt $leftDt") - } - } else if(leftDt==null || rightDt==null) null else arithmeticOpDt(leftDt, rightDt) - } + "/" -> DataType.FLOAT // use integer division '//' if you don't want floats else -> throw FatalAstException("resulting datatype check for invalid operator $operator") } } diff --git a/compiler/src/prog8/compiler/Compiler.kt b/compiler/src/prog8/compiler/Compiler.kt index eeb3760f9..968e6efb9 100644 --- a/compiler/src/prog8/compiler/Compiler.kt +++ b/compiler/src/prog8/compiler/Compiler.kt @@ -552,7 +552,11 @@ private class StatementTranslator(private val prog: IntermediateProgram, is BinaryExpression -> { val leftDt = expr.left.resultingDatatype(namespace, heap)!! val rightDt = expr.right.resultingDatatype(namespace, heap)!! - val commonDt = commonDatatype(leftDt, rightDt, expr.left.position, expr.right.position) + val commonDt = + if(expr.operator=="/") + DataType.FLOAT // result of division is always float + else + commonDatatype(leftDt, rightDt, expr.left.position, expr.right.position) translate(expr.left) if(leftDt!=commonDt) convertType(leftDt, commonDt) @@ -1039,21 +1043,15 @@ private class StatementTranslator(private val prog: IntermediateProgram, } } "/" -> { - when(dt) { - DataType.UBYTE -> Opcode.DIV_UB - DataType.BYTE -> Opcode.DIV_B - DataType.UWORD -> Opcode.DIV_UW - DataType.WORD -> Opcode.DIV_W - DataType.FLOAT -> Opcode.DIV_F - else -> throw CompilerException("only byte/word/float possible") - } + if(dt!=DataType.FLOAT) throw CompilerException("normal division only possible between floats") + else Opcode.DIV_F } "//" -> { when(dt) { - DataType.UBYTE -> Opcode.DIV_UB - DataType.BYTE -> Opcode.DIV_B - DataType.UWORD -> Opcode.DIV_UW - DataType.WORD -> Opcode.DIV_W + DataType.UBYTE -> Opcode.IDIV_UB + DataType.BYTE -> Opcode.IDIV_B + DataType.UWORD -> Opcode.IDIV_UW + DataType.WORD -> Opcode.IDIV_W DataType.FLOAT -> Opcode.FLOORDIV else -> throw CompilerException("only byte/word/float possible") } @@ -1538,18 +1536,13 @@ private class StatementTranslator(private val prog: IntermediateProgram, else -> throw CompilerException("only byte/word/lfoat possible") } } - "/=" -> { - when (valueDt) { - DataType.UBYTE -> Opcode.DIV_UB - DataType.UWORD -> Opcode.DIV_UW - DataType.FLOAT -> Opcode.DIV_F - else -> throw CompilerException("only byte/word/lfoat possible") - } - } + "/=" -> TODO("/=") "//=" -> { when (valueDt) { - DataType.UBYTE -> Opcode.DIV_UB - DataType.UWORD -> Opcode.DIV_UW + DataType.UBYTE -> Opcode.IDIV_UB + DataType.BYTE -> Opcode.IDIV_B + DataType.UWORD -> Opcode.IDIV_UW + DataType.WORD -> Opcode.IDIV_W DataType.FLOAT -> Opcode.FLOORDIV else -> throw CompilerException("only byte/word/lfoat possible") } diff --git a/compiler/src/prog8/compiler/intermediate/Opcode.kt b/compiler/src/prog8/compiler/intermediate/Opcode.kt index 778e8946a..c542b0322 100644 --- a/compiler/src/prog8/compiler/intermediate/Opcode.kt +++ b/compiler/src/prog8/compiler/intermediate/Opcode.kt @@ -52,10 +52,10 @@ enum class Opcode { MUL_UW, MUL_W, MUL_F, - DIV_UB, - DIV_B, - DIV_UW, - DIV_W, + IDIV_UB, + IDIV_B, + IDIV_UW, + IDIV_W, DIV_F, FLOORDIV, // integer division but on floatint point argument(s) REMAINDER_UB, diff --git a/compiler/src/prog8/compiler/intermediate/Value.kt b/compiler/src/prog8/compiler/intermediate/Value.kt index 8ae3eb00f..fc711fa96 100644 --- a/compiler/src/prog8/compiler/intermediate/Value.kt +++ b/compiler/src/prog8/compiler/intermediate/Value.kt @@ -180,16 +180,20 @@ class Value(val type: DataType, numericvalueOrHeapId: Number) { val v1 = numericValue() val v2 = other.numericValue() if(v2.toDouble()==0.0) { - if (type == DataType.UBYTE) - return Value(DataType.UBYTE, 255) - else if(type == DataType.UWORD) - return Value(DataType.UWORD, 65535) + when (type) { + DataType.UBYTE -> return Value(DataType.UBYTE, 255) + DataType.BYTE -> return Value(DataType.BYTE, 127) + DataType.UWORD -> return Value(DataType.UWORD, 65535) + DataType.WORD -> return Value(DataType.WORD, 32767) + } } val result = v1.toDouble() / v2.toDouble() // NOTE: integer division returns integer result! return when(type) { DataType.UBYTE -> Value(DataType.UBYTE, result) + DataType.BYTE -> Value(DataType.BYTE, result) DataType.UWORD -> Value(DataType.UWORD, result) + DataType.WORD -> Value(DataType.WORD, result) DataType.FLOAT -> Value(DataType.FLOAT, result) else -> throw ValueException("div on non-numeric type") } @@ -203,7 +207,9 @@ class Value(val type: DataType, numericvalueOrHeapId: Number) { val result = floor(v1.toDouble() / v2.toDouble()) // NOTE: integer division returns integer result! return when(type) { + DataType.BYTE -> Value(DataType.BYTE, result) DataType.UBYTE -> Value(DataType.UBYTE, result) + DataType.WORD -> Value(DataType.WORD, result) DataType.UWORD -> Value(DataType.UWORD, result) DataType.FLOAT -> Value(DataType.FLOAT, result) else -> throw ValueException("div on non-numeric type") diff --git a/compiler/src/prog8/compiler/target/c64/AsmGen.kt b/compiler/src/prog8/compiler/target/c64/AsmGen.kt index d3c6169d0..8d39dd65e 100644 --- a/compiler/src/prog8/compiler/target/c64/AsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/AsmGen.kt @@ -758,7 +758,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, Opcode.CAST_F_TO_UW -> " jsr c64flt.stack_float2uw" Opcode.CAST_F_TO_W -> " jsr c64flt.stack_float2w" Opcode.CAST_UB_TO_UW, Opcode.CAST_UB_TO_W -> " lda #0 | sta ${(ESTACK_HI+1).toHex()},x" // clear the msb - Opcode.CAST_B_TO_UW, Opcode.CAST_B_TO_W -> " lda ${(ESTACK_LO+1)},x | ${signExtendA("${(ESTACK_HI+1).toHex()},x")}" // sign extend the lsb + Opcode.CAST_B_TO_UW, Opcode.CAST_B_TO_W -> " lda ${(ESTACK_LO+1).toHex()},x | ${signExtendA("${(ESTACK_HI+1).toHex()},x")}" // sign extend the lsb Opcode.MSB -> " lda ${(ESTACK_HI+1).toHex()},x | sta ${(ESTACK_LO+1).toHex()},x" Opcode.ADD_UB, Opcode.ADD_B -> { // TODO inline better? @@ -788,10 +788,10 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, Opcode.MUL_F -> " jsr c64flt.mul_f" Opcode.DIV_F -> " jsr c64flt.div_f" Opcode.FLOORDIV -> " jsr c64flt.floordiv_f" - Opcode.DIV_UB -> " jsr prog8_lib.div_ub" - Opcode.DIV_B -> " jsr prog8_lib.div_b" - Opcode.DIV_W -> " jsr prog8_lib.div_w" - Opcode.DIV_UW -> " jsr prog8_lib.div_uw" + Opcode.IDIV_UB -> " jsr prog8_lib.idiv_ub" + Opcode.IDIV_B -> " jsr prog8_lib.idiv_b" + Opcode.IDIV_W -> " jsr prog8_lib.idiv_w" + Opcode.IDIV_UW -> " jsr prog8_lib.idiv_uw" Opcode.AND_BYTE -> { """ diff --git a/compiler/src/prog8/stackvm/StackVm.kt b/compiler/src/prog8/stackvm/StackVm.kt index 454a1ac5d..eefff0fd5 100644 --- a/compiler/src/prog8/stackvm/StackVm.kt +++ b/compiler/src/prog8/stackvm/StackVm.kt @@ -434,25 +434,25 @@ class StackVm(private var traceOutputFile: String?) { checkDt(second, DataType.FLOAT) evalstack.push(second.mul(top)) } - Opcode.DIV_UB -> { + Opcode.IDIV_UB -> { val (top, second) = evalstack.pop2() checkDt(top, DataType.UBYTE) checkDt(second, DataType.UBYTE) evalstack.push(second.div(top)) } - Opcode.DIV_UW -> { + Opcode.IDIV_UW -> { val (top, second) = evalstack.pop2() checkDt(top, DataType.UWORD) checkDt(second, DataType.UWORD) evalstack.push(second.div(top)) } - Opcode.DIV_B -> { + Opcode.IDIV_B -> { val (top, second) = evalstack.pop2() checkDt(top, DataType.BYTE) checkDt(second, DataType.BYTE) evalstack.push(second.div(top)) } - Opcode.DIV_W -> { + Opcode.IDIV_W -> { val (top, second) = evalstack.pop2() checkDt(top, DataType.WORD) checkDt(second, DataType.WORD) diff --git a/compiler/test/StackVMOpcodeTests.kt b/compiler/test/StackVMOpcodeTests.kt index ccf216294..1dc768eb5 100644 --- a/compiler/test/StackVMOpcodeTests.kt +++ b/compiler/test/StackVMOpcodeTests.kt @@ -315,11 +315,13 @@ class TestStackVmOpcodes { @Test fun testDiv() { - testBinaryOperator(Value(DataType.UBYTE, 250), Opcode.DIV_UB, Value(DataType.UBYTE, 12), Value(DataType.UBYTE, 20)) - testBinaryOperator(Value(DataType.UWORD, 3999), Opcode.DIV_UW, Value(DataType.UWORD, 40), Value(DataType.UWORD, 99)) + testBinaryOperator(Value(DataType.UBYTE, 250), Opcode.IDIV_UB, Value(DataType.UBYTE, 12), Value(DataType.UBYTE, 20)) + testBinaryOperator(Value(DataType.BYTE, 120), Opcode.IDIV_B, Value(DataType.BYTE, -9), Value(DataType.BYTE, -13)) + testBinaryOperator(Value(DataType.UWORD, 3999), Opcode.IDIV_UW, Value(DataType.UWORD, 40), Value(DataType.UWORD, 99)) + testBinaryOperator(Value(DataType.WORD, 3999), Opcode.IDIV_W, Value(DataType.WORD, -40), Value(DataType.WORD, -99)) testBinaryOperator(Value(DataType.FLOAT, 42.25), Opcode.DIV_F, Value(DataType.FLOAT, 99.0), Value(DataType.FLOAT, 42.25 / 99.0)) assertFailsWith { - testBinaryOperator(Value(DataType.UWORD, 3333), Opcode.DIV_UW, Value(DataType.FLOAT, 2.22), Value(DataType.FLOAT, 3333 / 2.22)) + testBinaryOperator(Value(DataType.UWORD, 3333), Opcode.IDIV_UW, Value(DataType.FLOAT, 2.22), Value(DataType.FLOAT, 3333 / 2.22)) } } diff --git a/docs/source/syntaxreference.rst b/docs/source/syntaxreference.rst index f4bc6e534..b2c4e38ec 100644 --- a/docs/source/syntaxreference.rst +++ b/docs/source/syntaxreference.rst @@ -362,7 +362,8 @@ Operators arithmetic: ``+`` ``-`` ``*`` ``/`` ``//`` ``**`` ``%`` ``+``, ``-``, ``*``, ``/`` are the familiar arithmetic operations. - ``//`` is the floor-divide, the division resulting in a whole number rounded towards minus infinity. + ``/`` is floating-point division (will always result in a floating point result) + ``//`` is the integer divison (can divide integers into integer result of the same type), or floor-division on floating points (the division resulting in a whole number rounded towards minus infinity). ``**`` is the power operator: ``3 ** 5`` is equal to 3*3*3*3*3 and is 243. ``%`` is the remainder operator: ``25 % 7`` is 4. Be careful: without a space, %10 will be parsed as the binary number 2 Remainder is only supported on integer operands (not floats). diff --git a/prog8lib/prog8lib.p8 b/prog8lib/prog8lib.p8 index d97345f6b..69ce4d278 100644 --- a/prog8lib/prog8lib.p8 +++ b/prog8lib/prog8lib.p8 @@ -163,54 +163,58 @@ mul_word .proc rts .pend -div_b .proc +idiv_b .proc + ; signed division: use unsigned division and fix sign of result afterwards + lda c64.ESTACK_LO+1,x + eor c64.ESTACK_LO+2,x + php ; save sign of result inx - lda #42 - sta c64.ESTACK_LO+1,x - lda #0 - sta c64.ESTACK_HI+1,x + lda c64.ESTACK_LO,x + bpl + + eor #$ff + sec + adc #0 ; make num1 positive ++ tay + inx + lda c64.ESTACK_LO,x + bpl + + eor #$ff + sec + adc #0 ; make num2 positive ++ jsr math.divmod_ubytes + tya + plp ; get sign of result + bpl + + eor #$ff + sec + adc #0 ; negate result ++ sta c64.ESTACK_LO,x + dex rts - .warn "div_b not implemented" .pend -div_ub .proc +idiv_ub .proc inx - lda #42 - sta c64.ESTACK_LO+1,x - lda #0 - sta c64.ESTACK_HI+1,x + ldy c64.ESTACK_LO,x + inx + lda c64.ESTACK_LO,x + jsr math.divmod_ubytes + tya + sta c64.ESTACK_LO,x + dex rts - .warn "div_ub not implemented" .pend -div_w .proc - inx - lda #42 - sta c64.ESTACK_LO+1,x - lda #0 - sta c64.ESTACK_HI+1,x - rts - .warn "div_w not implemented" +idiv_w .proc + .error "idiv_w not yet implemented" .pend -div_uw .proc - inx - lda #42 - sta c64.ESTACK_LO+1,x - lda #0 - sta c64.ESTACK_HI+1,x - rts - .warn "div_uw not implemented" +idiv_uw .proc + .error "idiv_uw not implemented" .pend remainder_b .proc - inx - lda #42 - sta c64.ESTACK_LO+1,x - lda #0 - sta c64.ESTACK_HI+1,x - rts - .warn "remainder_b via div_b?" + .error "remainder_b not yet implemented, via div_b?" .pend remainder_ub .proc @@ -227,23 +231,11 @@ remainder_ub .proc .pend remainder_w .proc - inx - lda #42 - sta c64.ESTACK_LO+1,x - lda #0 - sta c64.ESTACK_HI+1,x - rts - .warn "remainder_w not implemented - via div_w" + .error "remainder_w not implemented - via div_w" .pend remainder_uw .proc - inx - lda #42 - sta c64.ESTACK_LO+1,x - lda #0 - sta c64.ESTACK_HI+1,x - rts - .warn "remainder_uw not implemented - via div_uw" + .error "remainder_uw not implemented - via div_uw" .pend equal_w .proc @@ -1029,12 +1021,13 @@ multiply_words_result .byte 0,0,0,0 }} } -asmsub divmod_bytes (ubyte number @ X, ubyte divisor @ Y) -> clobbers() -> (ubyte @ X, ubyte @ A) { - ; ---- divide X by Y, result quotient in X, remainder in A (unsigned) +asmsub divmod_ubytes (ubyte number @ A, ubyte divisor @ Y) -> clobbers() -> (ubyte @ Y, ubyte @ A) { + ; ---- divide A by Y, result quotient in Y, remainder in A (unsigned) ; division by zero will result in quotient = 255 and remainder = original number %asm {{ - stx c64.SCRATCH_ZPB1 sty c64.SCRATCH_ZPREG + sta c64.SCRATCH_ZPB1 + stx c64.SCRATCH_ZPREGX lda #0 ldx #8 @@ -1047,7 +1040,8 @@ asmsub divmod_bytes (ubyte number @ X, ubyte divisor @ Y) -> clobbers() -> (ub dex bne - - ldx c64.SCRATCH_ZPB1 + ldy c64.SCRATCH_ZPB1 + ldx c64.SCRATCH_ZPREGX rts }} }