diff --git a/codeCore/src/prog8/code/ast/AstExpressions.kt b/codeCore/src/prog8/code/ast/AstExpressions.kt index 6578432e0..043ca8e4c 100644 --- a/codeCore/src/prog8/code/ast/AstExpressions.kt +++ b/codeCore/src/prog8/code/ast/AstExpressions.kt @@ -82,6 +82,7 @@ sealed class PtExpression(val type: DataType, position: Position) : PtNode(posit } fun asConstInteger(): Int? = (this as? PtNumber)?.number?.toInt() ?: (this as? PtBool)?.asInt() + fun asConstValue(): Double? = (this as? PtNumber)?.number ?: (this as? PtBool)?.asInt()?.toDouble() fun isSimple(): Boolean { return when(this) { @@ -378,7 +379,3 @@ class PtTypeCast(type: DataType, position: Position) : PtExpression(type, positi // special node that isn't created from compiling user code, but used internally in the Intermediate Code class PtIrRegister(val register: Int, type: DataType, position: Position) : PtExpression(type, position) - - -fun constValue(expr: PtExpression): Double? = if(expr is PtNumber) expr.number else if(expr is PtBool) expr.asInt().toDouble() else null -fun constIntValue(expr: PtExpression): Int? = if(expr is PtNumber) expr.number.toInt() else if(expr is PtBool) expr.asInt() else null diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt index 67f482349..516366c63 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt @@ -790,7 +790,7 @@ class AsmGen6502Internal ( when { iterations == 0 -> {} iterations == 1 -> translate(stmt.statements) - iterations<0 || iterations>65535 -> throw AssemblyError("invalid number of iterations") + iterations<0 || iterations>65536 -> throw AssemblyError("invalid number of iterations") iterations <= 256 -> repeatByteCount(iterations, stmt) else -> repeatWordCount(iterations, stmt) } @@ -830,10 +830,10 @@ class AsmGen6502Internal ( } private fun repeatWordCount(iterations: Int, stmt: PtRepeatLoop) { - require(iterations in 257..65535) { "invalid repeat count ${stmt.position}" } + require(iterations in 257..65536) { "invalid repeat count ${stmt.position}" } val repeatLabel = makeLabel("repeat") val counterVar = createRepeatCounterVar(DataType.UWORD, isTargetCpu(CpuType.CPU65c02), stmt) - val loopcount = if(iterations and 0x00ff == 0) iterations else iterations + 0x0100 // so that the loop can simply use a double-dec + val loopcount = if(iterations==65536) 0 else if(iterations and 0x00ff == 0) iterations else iterations + 0x0100 // so that the loop can simply use a double-dec out(""" ldy #>$loopcount lda #<$loopcount diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt index 7cae9125f..aaaf6437a 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt @@ -359,7 +359,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express val variable = targetArray.variable.name val itemsize = codeGen.program.memsizer.memorySize(targetArray.type) - val fixedIndex = constIntValue(targetArray.index) + val fixedIndex = targetArray.index.asConstInteger() val arrayLength = codeGen.symbolTable.getLength(targetArray.variable.name) if(zero) { if(fixedIndex!=null) { diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt index 6bff7ed4b..fc08f18b4 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt @@ -894,7 +894,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { if(binExpr.left.type==DataType.STR || binExpr.right.type==DataType.STR) { throw AssemblyError("str compares should have been replaced with builtin function call to do the compare") } else { - return if(constValue(binExpr.right)==0.0) { + return if(binExpr.right.asConstValue()==0.0) { val tr = translateExpression(binExpr.left) addToResult(result, tr, tr.resultReg, -1) val opcode = if (notEquals) Opcode.SNZ else Opcode.SZ diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt index b76bbe345..57da5431a 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt @@ -1589,7 +1589,7 @@ class IRCodeGen( } private fun translate(repeat: PtRepeatLoop): IRCodeChunks { - when (constIntValue(repeat.count)) { + when (repeat.count.asConstInteger()) { 0 -> return emptyList() 1 -> return translateGroup(repeat.children) 256 -> { @@ -1600,18 +1600,30 @@ class IRCodeGen( val repeatLabel = createLabelName() val skipRepeatLabel = createLabelName() - val irDt = irType(repeat.count.type) + val constRepeats = repeat.count.asConstInteger() val result = mutableListOf() - val countTr = expressionEval.translateExpression(repeat.count) - addToResult(result, countTr, countTr.resultReg, -1) - if(constIntValue(repeat.count)==null) { - // check if the counter is already zero - addInstr(result, IRInstruction(Opcode.BSTEQ, labelSymbol = skipRepeatLabel), null) - } - result += labelFirstChunk(translateNode(repeat.statements), repeatLabel) - result += IRCodeChunk(null, null).also { - it += IRInstruction(Opcode.DEC, irDt, reg1 = countTr.resultReg) // sets status bits - it += IRInstruction(Opcode.BSTNE, labelSymbol = repeatLabel) + if(constRepeats==65536) { + // make use of the word wrap around to count to 65536 + val resultRegister = registers.nextFree() + addInstr(result, IRInstruction(Opcode.LOAD, IRDataType.WORD, reg1=resultRegister, immediate = 0), null) + result += labelFirstChunk(translateNode(repeat.statements), repeatLabel) + result += IRCodeChunk(null, null).also { + it += IRInstruction(Opcode.DEC, IRDataType.WORD, reg1 = resultRegister) // sets status bits + it += IRInstruction(Opcode.BSTNE, labelSymbol = repeatLabel) + } + } else { + val irDt = irType(repeat.count.type) + val countTr = expressionEval.translateExpression(repeat.count) + addToResult(result, countTr, countTr.resultReg, -1) + if (repeat.count.asConstValue() == null) { + // check if the counter is already zero + addInstr(result, IRInstruction(Opcode.BSTEQ, labelSymbol = skipRepeatLabel), null) + } + result += labelFirstChunk(translateNode(repeat.statements), repeatLabel) + result += IRCodeChunk(null, null).also { + it += IRInstruction(Opcode.DEC, irDt, reg1 = countTr.resultReg) // sets status bits + it += IRInstruction(Opcode.BSTNE, labelSymbol = repeatLabel) + } } result += IRCodeChunk(skipRepeatLabel, null) return result diff --git a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt index 237eab252..869356ca3 100644 --- a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt +++ b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt @@ -547,7 +547,7 @@ internal class AstChecker(private val program: Program, val iterations = repeatLoop.iterations?.constValue(program) if (iterations != null) { require(floor(iterations.number)==iterations.number) - if (iterations.number.toInt() > 65535) errors.err("repeat cannot go over 65535 iterations", iterations.position) + if (iterations.number.toInt() > 65536) errors.err("repeat cannot exceed 65536 iterations", iterations.position) } val ident = repeatLoop.iterations as? IdentifierReference @@ -1700,8 +1700,10 @@ internal class AstChecker(private val program: Program, private fun checkLongType(expression: Expression) { if(expression.inferType(program).istype(DataType.LONG)) { - if(errors.noErrorForLine(expression.position)) - errors.err("integer overflow", expression.position) + if(expression.parent !is RepeatLoop) { + if (errors.noErrorForLine(expression.position)) + errors.err("integer overflow", expression.position) + } } } diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 6ae4c515d..6c758ce17 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -1,9 +1,7 @@ TODO ==== -make repeat support 65536 iterations - -scripts/cx16_images : add an option to keep the first palette entry black (there's already the option to retain the first 16 entries) +scripts/cx16_images : add an option to keep the first palette entry black (or any specific color) (there's already the option to retain the first 16 entries) support this usage of defer: diff --git a/examples/test.p8 b/examples/test.p8 index 4d8a5037d..807e8aa4e 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,12 +1,13 @@ %import textio %option no_sysinit %zeropage basicsafe -%address $f200 -%output raw -%launcher none main { sub start() { - txt.print_uwhex(cbm.MEMTOP(0, true), true) + cx16.r0=0 + repeat 65536 { + cx16.r0++ + } + txt.print_uw(cx16.r0) } }