diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt index 547299c7b..26154c310 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt @@ -2092,20 +2092,20 @@ internal class AssignmentAsmGen(private val program: PtProgram, } } - if(valueDt==DataType.UBYTE || valueDt==DataType.BOOL) { + if(valueDt in ByteDatatypes) { when(target.register) { RegisterOrPair.A, RegisterOrPair.X, RegisterOrPair.Y -> { // 'cast' an ubyte value to a byte register; no cast needed at all - return assignExpressionToRegister(value, target.register, false) + return assignExpressionToRegister(value, target.register, valueDt in SignedDatatypes) } RegisterOrPair.AX, RegisterOrPair.AY, RegisterOrPair.XY, in Cx16VirtualRegisters -> { assignExpressionToRegister(value, RegisterOrPair.A, false) - assignRegisterByte(target, CpuRegister.A, false, true) + assignRegisterByte(target, CpuRegister.A, valueDt in SignedDatatypes, true) return } else -> {} @@ -2124,7 +2124,7 @@ internal class AssignmentAsmGen(private val program: PtProgram, RegisterOrPair.XY, in Cx16VirtualRegisters -> { // 'cast' uword into a 16 bits register, just assign it - return assignExpressionToRegister(value, target.register!!, false) + return assignExpressionToRegister(value, target.register!!, targetDt in SignedDatatypes) } else -> {} } diff --git a/codeOptimizers/src/prog8/optimizer/ExpressionSimplifier.kt b/codeOptimizers/src/prog8/optimizer/ExpressionSimplifier.kt index b4f450c00..aa17b713f 100644 --- a/codeOptimizers/src/prog8/optimizer/ExpressionSimplifier.kt +++ b/codeOptimizers/src/prog8/optimizer/ExpressionSimplifier.kt @@ -626,10 +626,25 @@ class ExpressionSimplifier(private val program: Program, return expr.left } } + 256.0 -> { + when(leftDt) { + DataType.UBYTE -> return NumericLiteral(DataType.UBYTE, 0.0, expr.position) + DataType.BYTE -> return null // is either 0 or -1 we cannot tell here + DataType.UWORD, DataType.WORD -> { + // just use: msb(value) as type + val msb = BuiltinFunctionCall(IdentifierReference(listOf("msb"), expr.position), mutableListOf(expr.left), expr.position) + return if(leftDt==DataType.WORD) + TypecastExpression(msb, DataType.BYTE, true, expr.position) + else + TypecastExpression(msb, DataType.UWORD, true, expr.position) + } + else -> return null + } + } in powersOfTwo -> { if (leftDt==DataType.UBYTE || leftDt==DataType.UWORD) { // Unsigned number divided by a power of two => shift right - // Signed number can't simply be bitshifted in this case (due to rounding issues for negative values), + // Signed number can't simply be bitshifted in this case (due to rounding issues for negative values), TODO is this correct??? // so we leave that as is and let the code generator deal with it. val numshifts = log2(cv).toInt() return BinaryExpression(expr.left, ">>", NumericLiteral.optimalInteger(numshifts, expr.position), expr.position) @@ -791,8 +806,8 @@ class ExpressionSimplifier(private val program: Program, } DataType.UWORD -> { if (amount >= 16) { - errors.warn("shift always results in 0", expr.position) - return NumericLiteral.optimalInteger(0, expr.position) + errors.err("useless to shift by more than 15 bits", expr.position) + return null } else if(amount==8) { // shift right by 8 bits is just a byte operation: msb(X) as uword @@ -806,11 +821,20 @@ class ExpressionSimplifier(private val program: Program, } } DataType.WORD -> { - // bit-shifting a signed value shouldn't be allowed by the compiler but here we go... - if (amount > 16) { - expr.right = NumericLiteral.optimalInteger(16, expr.right.position) + if (amount >= 16) { + errors.err("useless to shift by more than 15 bits", expr.position) return null } + else if(amount == 8) { + // shift right by 8 bits is just a byte operation: msb(X) as byte + val msb = FunctionCallExpression(IdentifierReference(listOf("msb"), expr.position), mutableListOf(expr.left), expr.position) + return TypecastExpression(msb, DataType.BYTE, true, expr.position) + } + else if(amount > 8) { + // same as above but with residual shifts. + val msb = FunctionCallExpression(IdentifierReference(listOf("msb"), expr.position), mutableListOf(expr.left), expr.position) + return TypecastExpression(BinaryExpression(msb, ">>", NumericLiteral.optimalInteger(amount - 8, expr.position), expr.position), DataType.BYTE, true, expr.position) + } } else -> { } diff --git a/compiler/test/TestTypecasts.kt b/compiler/test/TestTypecasts.kt index 8eb4970c0..62de9b67e 100644 --- a/compiler/test/TestTypecasts.kt +++ b/compiler/test/TestTypecasts.kt @@ -679,6 +679,29 @@ main { stmts.size shouldBe 3 } + test("ubyte to word casts") { + var src=""" +main { + sub start() { + ubyte @shared bb = 255 + cx16.r0s = (bb as byte) as word ; should result in -1 word value + cx16.r1s = (bb as word) ; should result in 255 word value + } +}""" + + val result = compileText(C64Target(), true, src, writeAssembly = false)!! + val stmts = result.compilerAst.entrypoint.statements + stmts.size shouldBe 4 + val assign1tc = (stmts[2] as Assignment).value as TypecastExpression + val assign2tc = (stmts[3] as Assignment).value as TypecastExpression + assign1tc.type shouldBe DataType.WORD + assign2tc.type shouldBe DataType.WORD + assign2tc.expression shouldBe instanceOf() + val assign1subtc = (assign1tc.expression as TypecastExpression) + assign1subtc.type shouldBe DataType.BYTE + assign1subtc.expression shouldBe instanceOf() + } + test("add missing & to function arguments") { val text=""" main { diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 99f5b6a0b..9833cfe70 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -1,6 +1,7 @@ TODO ==== + ... diff --git a/examples/cx16/cobramk3-gfx.p8 b/examples/cx16/cobramk3-gfx.p8 index e83c244d9..a3afd8ed0 100644 --- a/examples/cx16/cobramk3-gfx.p8 +++ b/examples/cx16/cobramk3-gfx.p8 @@ -1,3 +1,4 @@ +%import textio %import syslib %import test_stack %import conv @@ -29,7 +30,7 @@ main { draw_lines_hiddenremoval() ; draw_lines() - anglex += 217 + anglex += 317 angley -= 505 anglez += 452 @@ -58,25 +59,10 @@ main { cx16.GRAPH_put_next_char(c) } - asmsub print_number_gfx(ubyte num @ A) clobbers(A,X,Y) { - %asm {{ - jsr conv.ubyte2decimal - phx - pha - cpy #'0' - beq + - tya - jsr cx16.GRAPH_put_char - pla - jsr cx16.GRAPH_put_char - bra _ones -+ pla - cmp #'0' - beq _ones - jsr cx16.GRAPH_put_char -_ones pla - jmp cx16.GRAPH_put_char - }} + sub print_number_gfx(ubyte num) { + conv.str_ub(num) + for cx16.r9L in conv.string_out + cx16.GRAPH_put_next_char(cx16.r9L) } const uword screen_width = 320 diff --git a/examples/test.p8 b/examples/test.p8 index 5ab398303..f138daffb 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,42 +1,56 @@ %import textio -%import string +%import math %zeropage basicsafe %option no_sysinit main { sub start() { - uword @shared uw = $3f2f - if uw & $0800 - txt.print("ok1\n") + ubyte @shared bb = 255 + txt.print_w((bb as byte) as word) ; should print -1 ! + txt.nl() + txt.print_w((bb as word)) ; should print 255 ! + txt.nl() + txt.nl() - if uw & 8 - txt.print("ok2\n") + bb= 30 + word @shared offset=1000 + cx16.r2s = (math.sin8u(bb) as word) + offset ; 1213 + txt.print_w(cx16.r2s) + txt.nl() + txt.nl() - if uw & $0800 ==0 - txt.print("fail1\n") + ; expected results: + ; -96 + ; -96 + ; 947 + ; 947 - if uw & $0800 !=0 - txt.print("ok3\n") + word @shared wcosa = 1111 + word @shared wsinb = -22 - if uw & 8 ==0 - txt.print("fail2\n") + txt.print_w(wcosa*wsinb / 256) + txt.nl() + txt.print_w((wcosa*wsinb) >>8) + txt.nl() - if uw & 8 !=0 - txt.print("ok4\n") + word[] rotatedz = [-11111,-12222,-13333,-14444,-15555] + + word @shared persp1 = 1000 + rotatedz[2]/256 + txt.print_w(persp1) + txt.nl() + persp1 = 1000 + (rotatedz[2]>>8) + txt.print_w(persp1) + txt.nl() +; ubyte[3] cycle_reverseflags +; +; ubyte @shared flags=2 +; bool @shared b1 +; bool @shared b2 +; +; cycle_reverseflags[1]= b1 and b2 ; flags & 2 != 0 as bool - if uw & $ff00 == $3f00 - txt.print("ok5\n") - - if uw & $ff00 != $3f00 - txt.print("fail5\n") - - if uw & $00ff == $002f - txt.print("ok6\n") - - if uw & $00ff != $002f - txt.print("fail6\n") } }