From e9c357a8856cc8f3e80f8ff3a9b9a2f699065b19 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Fri, 2 Aug 2019 01:26:28 +0200 Subject: [PATCH] fix range typing issues and function call param cleanup bug for asmsub --- .../prog8/ast/expressions/AstExpressions.kt | 10 +-- .../src/prog8/ast/processing/AstChecker.kt | 8 ++- .../compiler/target/c64/codegen2/AsmGen2.kt | 71 +++++++++++++------ examples/test.p8 | 45 +++++++----- 4 files changed, 89 insertions(+), 45 deletions(-) diff --git a/compiler/src/prog8/ast/expressions/AstExpressions.kt b/compiler/src/prog8/ast/expressions/AstExpressions.kt index 3d491752b..0e33372c5 100644 --- a/compiler/src/prog8/ast/expressions/AstExpressions.kt +++ b/compiler/src/prog8/ast/expressions/AstExpressions.kt @@ -637,13 +637,13 @@ class RangeExpr(var from: Expression, val toDt=to.inferType(program) return when { fromDt==null || toDt==null -> null - fromDt== DataType.UBYTE && toDt== DataType.UBYTE -> DataType.UBYTE - fromDt== DataType.UWORD && toDt== DataType.UWORD -> DataType.UWORD + fromDt== DataType.UBYTE && toDt== DataType.UBYTE -> DataType.ARRAY_UB + fromDt== DataType.UWORD && toDt== DataType.UWORD -> DataType.ARRAY_UW fromDt== DataType.STR && toDt== DataType.STR -> DataType.STR fromDt== DataType.STR_S && toDt== DataType.STR_S -> DataType.STR_S - fromDt== DataType.WORD || toDt== DataType.WORD -> DataType.WORD - fromDt== DataType.BYTE || toDt== DataType.BYTE -> DataType.BYTE - else -> DataType.UBYTE + fromDt== DataType.WORD || toDt== DataType.WORD -> DataType.ARRAY_W + fromDt== DataType.BYTE || toDt== DataType.BYTE -> DataType.ARRAY_B + else -> DataType.ARRAY_UB } } override fun toString(): String { diff --git a/compiler/src/prog8/ast/processing/AstChecker.kt b/compiler/src/prog8/ast/processing/AstChecker.kt index 9d48748c6..720c876f6 100644 --- a/compiler/src/prog8/ast/processing/AstChecker.kt +++ b/compiler/src/prog8/ast/processing/AstChecker.kt @@ -120,7 +120,7 @@ internal class AstChecker(private val program: Program, } else { if (forLoop.loopRegister != null) { // loop register - if (iterableDt != DataType.UBYTE && iterableDt!= DataType.ARRAY_UB && iterableDt !in StringDatatypes) + if (iterableDt != DataType.ARRAY_UB && iterableDt != DataType.ARRAY_B && iterableDt !in StringDatatypes) checkResult.add(ExpressionError("register can only loop over bytes", forLoop.position)) if(forLoop.loopRegister!=Register.A) checkResult.add(ExpressionError("it's only possible to use A as a loop register", forLoop.position)) @@ -750,6 +750,12 @@ internal class AstChecker(private val program: Program, if(leftDt !in IntegerDatatypes || rightDt !in IntegerDatatypes) checkResult.add(ExpressionError("bitwise operator can only be used on integer operands", expr.right.position)) } + "<<", ">>" -> { + // for now, bit-shifts can only shift by a constant number + val constRight = expr.right.constValue(program) + if(constRight==null) + checkResult.add(ExpressionError("bit-shift can only be done by a constant number (for now)", expr.right.position)) + } } if(leftDt !in NumericDatatypes) diff --git a/compiler/src/prog8/compiler/target/c64/codegen2/AsmGen2.kt b/compiler/src/prog8/compiler/target/c64/codegen2/AsmGen2.kt index ac5b66999..14aeab464 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen2/AsmGen2.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen2/AsmGen2.kt @@ -599,10 +599,13 @@ internal class AsmGen2(val program: Program, } else { translateSubroutineCall(stmt) // discard any results from the stack: - val returns = stmt.target.targetSubroutine(program.namespace)!!.returntypes - for(t in returns) { - if (t in IntegerDatatypes || t in PassByReferenceDatatypes) out(" inx") - else if (t == DataType.FLOAT) out(" inx | inx | inx") + val sub = stmt.target.targetSubroutine(program.namespace)!! + val returns = sub.returntypes.zip(sub.asmReturnvaluesRegisters) + for((t, reg) in returns) { + if(reg.stack) { + if (t in IntegerDatatypes || t in PassByReferenceDatatypes) out(" inx") + else if (t == DataType.FLOAT) out(" inx | inx | inx") + } } } } @@ -1032,7 +1035,7 @@ $loopLabel lda ${65535.toHex()} ; modified $endLabel""") } DataType.ARRAY_UB, DataType.ARRAY_B -> { - val length = decl.arraysize!!.size() + val length = decl.arraysize!!.size()!! if(stmt.loopRegister!=null && stmt.loopRegister!=Register.A) throw AssemblyError("can only use A") val counterLabel = makeLabel("for_counter") @@ -1044,8 +1047,6 @@ $endLabel""") sty $modifiedLabel+2 ldy #0 $loopLabel sty $counterLabel - cpy #$length - beq $endLabel $modifiedLabel lda ${65535.toHex()},y ; modified""") if(stmt.loopVar!=null) out(" sta ${asmIdentifierName(stmt.loopVar!!)}") @@ -1053,6 +1054,8 @@ $modifiedLabel lda ${65535.toHex()},y ; modified""") out(""" ldy $counterLabel iny + cpy #${length and 255} + beq $endLabel jmp $loopLabel $counterLabel .byte 0 $endLabel""") @@ -1076,8 +1079,6 @@ $endLabel""") sty $modifiedLabel2+2 ldy #0 $loopLabel sty $counterLabel - cpy #$length - beq $endLabel $modifiedLabel lda ${65535.toHex()},y ; modified sta $loopvarName $modifiedLabel2 lda ${65535.toHex()},y ; modified @@ -1087,6 +1088,8 @@ $modifiedLabel2 lda ${65535.toHex()},y ; modified ldy $counterLabel iny iny + cpy #${length and 255} + beq $endLabel jmp $loopLabel $counterLabel .byte 0 $endLabel""") @@ -1102,7 +1105,7 @@ $endLabel""") val loopLabel = makeLabel("for_loop") val endLabel = makeLabel("for_end") when(iterableDt) { - in ByteDatatypes -> { + DataType.ARRAY_B, DataType.ARRAY_UB -> { if(stmt.loopRegister!=null) { // loop register over range @@ -1269,7 +1272,7 @@ $endLabel""") } } } - in WordDatatypes -> { + DataType.ARRAY_W, DataType.ARRAY_UW -> { // loop over word range via loopvar val counterLabel = makeLabel("for_counter") val varname = asmIdentifierName(stmt.loopVar!!) @@ -1745,17 +1748,42 @@ $endLabel""") } private fun translateExpression(expr: BinaryExpression) { - translateExpression(expr.left) - translateExpression(expr.right) val leftDt = expr.left.inferType(program)!! val rightDt = expr.right.inferType(program)!! - if(leftDt!=rightDt) - throw AssemblyError("binary operator ${expr.operator} left/right dt not identical") // is this strictly required always? - when (leftDt) { - in ByteDatatypes -> translateBinaryOperatorBytes(expr.operator, leftDt) - in WordDatatypes -> translateBinaryOperatorWords(expr.operator, leftDt) - DataType.FLOAT -> translateBinaryOperatorFloats(expr.operator) - else -> throw AssemblyError("non-numerical datatype") + when(expr.operator) { + ">>" -> { + // bit-shifts are always by a constant number (for now) + translateExpression(expr.left) + val amount = expr.right.constValue(program)!!.number.toInt() + when(leftDt) { + DataType.UBYTE -> repeat(amount) { out(" lsr $ESTACK_LO_PLUS1_HEX,x") } + DataType.BYTE -> repeat(amount) { out(" lda $ESTACK_LO_PLUS1_HEX,x | asl a | ror $ESTACK_LO_PLUS1_HEX,x") } + DataType.UWORD -> repeat(amount) { out(" lsr $ESTACK_HI_PLUS1_HEX,x | ror $ESTACK_LO_PLUS1_HEX,x") } + DataType.WORD -> repeat(amount) { out( " lda $ESTACK_HI_PLUS1_HEX,x | asl a | ror $ESTACK_HI_PLUS1_HEX,x | ror $ESTACK_LO_PLUS1_HEX,x") } + else -> throw AssemblyError("weird type") + } + } + "<<" -> { + // bit-shifts are always by a constant number (for now) + translateExpression(expr.left) + val amount = expr.right.constValue(program)!!.number.toInt() + if(leftDt in ByteDatatypes) + repeat(amount) { out(" asl $ESTACK_LO_PLUS1_HEX,x") } + else + repeat(amount) { out(" asl $ESTACK_LO_PLUS1_HEX,x | rol $ESTACK_HI_PLUS1_HEX,x") } + } + else -> { + translateExpression(expr.left) + translateExpression(expr.right) + if(leftDt!=rightDt) + throw AssemblyError("binary operator ${expr.operator} left/right dt not identical") // is this strictly required always? + when (leftDt) { + in ByteDatatypes -> translateBinaryOperatorBytes(expr.operator, leftDt) + in WordDatatypes -> translateBinaryOperatorWords(expr.operator, leftDt) + DataType.FLOAT -> translateBinaryOperatorFloats(expr.operator) + else -> throw AssemblyError("non-numerical datatype") + } + } } } @@ -1819,8 +1847,7 @@ $endLabel""") inx sta $ESTACK_LO_PLUS1_HEX,x """) - "<<" -> throw AssemblyError("<< should not operate via stack") - ">>" -> throw AssemblyError(">> should not operate via stack") + "<<", ">>" -> throw AssemblyError("bit-shifts not via stack") "<" -> out(if(types==DataType.UBYTE) " jsr prog8_lib.less_ub" else " jsr prog8_lib.less_b") ">" -> out(if(types==DataType.UBYTE) " jsr prog8_lib.greater_ub" else " jsr prog8_lib.greater_b") "<=" -> out(if(types==DataType.UBYTE) " jsr prog8_lib.lesseq_ub" else " jsr prog8_lib.lesseq_b") diff --git a/examples/test.p8 b/examples/test.p8 index 01af605b9..55b1d7396 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -3,23 +3,34 @@ main { sub start() { + c64.CHROUT('\n') + %asm {{ + stx $0410 + }} + c64.CHRIN() + %asm {{ + stx $0411 + }} + print_notes(80,35) + %asm {{ + stx $0412 + }} + return + } - byte bb=10 - - while bb<15 { - bb++ - c64scr.print_b(bb) - c64.CHROUT('\n') - } - - word ww=5 - - while ww > -5 { - ww-- - c64scr.print_w(ww) - c64.CHROUT('\n') - } - - + sub print_notes(ubyte n1, ubyte n2) { + c64scr.print_ub(n1/2) + c64.CHROUT('\n') + c64scr.print_ub(n1/3) + c64.CHROUT('\n') + c64scr.print_ub(n1/4) + c64.CHROUT('\n') + c64.CHROUT('\n') + c64scr.print_ub(n2/2) + c64.CHROUT('\n') + c64scr.print_ub(n2/3) + c64.CHROUT('\n') + c64scr.print_ub(n2/4) + c64.CHROUT('\n') } }