diff --git a/codeCore/src/prog8/code/core/Enumerations.kt b/codeCore/src/prog8/code/core/Enumerations.kt index ca5f198e5..6bfc22461 100644 --- a/codeCore/src/prog8/code/core/Enumerations.kt +++ b/codeCore/src/prog8/code/core/Enumerations.kt @@ -145,7 +145,7 @@ class DataType private constructor(val base: BaseDataType, val sub: BaseDataType return if(splitwordarray && actualElementDt.isWord) DataType(BaseDataType.ARRAY_SPLITW, actualElementDt, null) else { - if(actualElementDt.isNumericOrBool && actualElementDt != BaseDataType.LONG) + if(actualElementDt.isNumericOrBool) DataType(BaseDataType.ARRAY, actualElementDt, null) else throw NoSuchElementException("invalid basic element dt $elementDt") @@ -224,6 +224,7 @@ class DataType private constructor(val base: BaseDataType, val sub: BaseDataType BaseDataType.WORD -> "word[]" BaseDataType.UBYTE -> "ubyte[]" BaseDataType.UWORD -> "uword[]" + BaseDataType.LONG -> "long[]" else -> throw IllegalArgumentException("invalid sub type") } } @@ -286,6 +287,7 @@ class DataType private constructor(val base: BaseDataType, val sub: BaseDataType BaseDataType.BOOL -> "bool[" BaseDataType.BYTE -> "byte[" BaseDataType.WORD -> "@nosplit word[" + BaseDataType.LONG -> "long[" BaseDataType.FLOAT -> "float[" else -> throw IllegalArgumentException("invalid sub type") } @@ -365,6 +367,7 @@ class DataType private constructor(val base: BaseDataType, val sub: BaseDataType val isWordArray = base.isArray && !base.isPointerArray && (sub == BaseDataType.UWORD || sub == BaseDataType.WORD) val isUnsignedWordArray = base.isArray && !base.isPointerArray && sub == BaseDataType.UWORD val isSignedWordArray = base.isArray && !base.isPointerArray && sub == BaseDataType.WORD + val isLongArray = base.isArray && sub == BaseDataType.LONG val isFloatArray = base.isArray && !base.isPointerArray && sub == BaseDataType.FLOAT val isString = base == BaseDataType.STR val isBool = base == BaseDataType.BOOL diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/BuiltinFunctionsAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/BuiltinFunctionsAsmGen.kt index 90ea4fcf8..0fcc72bcc 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/BuiltinFunctionsAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/BuiltinFunctionsAsmGen.kt @@ -27,8 +27,8 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, val sscope = fcall.definingISub() when (fcall.name) { - "lsw" -> throw AssemblyError("lsw() should have been removed or replaced by a const value") - "msw" -> throw AssemblyError("msw() should have been removed or replaced by a const value") + "msw" -> funcMsw(fcall, resultRegister) + "lsw" -> funcLsw(fcall, resultRegister) "msb" -> funcMsb(fcall, resultRegister) "lsb" -> funcLsb(fcall, resultRegister) "mkword" -> funcMkword(fcall, resultRegister) @@ -1185,7 +1185,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, private fun funcMsb(fcall: PtBuiltinFunctionCall, resultRegister: RegisterOrPair?) { val arg = fcall.args.single() if (!arg.type.isWord) - throw AssemblyError("msb required word argument") + throw AssemblyError("msb requires word argument") if (arg is PtNumber) throw AssemblyError("msb(const) should have been const-folded away") if (arg is PtIdentifier) { @@ -1371,6 +1371,53 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, } } + private fun funcMsw(fcall: PtBuiltinFunctionCall, resultRegister: RegisterOrPair?) { + val arg = fcall.args.single() + if (!arg.type.isLong) + throw AssemblyError("msw requires long argument") + if (arg is PtNumber) + throw AssemblyError("msw(const) should have been const-folded away") + if (arg is PtIdentifier) { + val sourceName = asmgen.asmVariableName(arg) + when(resultRegister) { + RegisterOrPair.AX -> asmgen.out(" lda $sourceName+2 | ldx $sourceName+3") + null, RegisterOrPair.AY -> asmgen.out(" lda $sourceName+2 | ldy $sourceName+3") + RegisterOrPair.XY -> asmgen.out(" ldx $sourceName+2 | ldy $sourceName+3") + in Cx16VirtualRegisters -> { + val regname = resultRegister.name.lowercase() + asmgen.out(" lda $sourceName+2 | sta cx16.$regname | lda $sourceName+3 | sta cx16.$regname+1") + } + else -> throw AssemblyError("invalid reg") + } + } else { + TODO("msw(expression) ${fcall.position} - use a temporary variable for now") + } + } + + private fun funcLsw(fcall: PtBuiltinFunctionCall, resultRegister: RegisterOrPair?) { + val arg = fcall.args.single() + if (!arg.type.isLong) + throw AssemblyError("lsw requires long argument") + if (arg is PtNumber) + throw AssemblyError("lsw(const) should have been const-folded away") + if (arg is PtIdentifier) { + val sourceName = asmgen.asmVariableName(arg) + when(resultRegister) { + RegisterOrPair.AX -> asmgen.out(" lda $sourceName | ldx $sourceName+1") + null, RegisterOrPair.AY -> asmgen.out(" lda $sourceName | ldy $sourceName+1") + RegisterOrPair.XY -> asmgen.out(" ldx $sourceName | ldy $sourceName+1") + in Cx16VirtualRegisters -> { + val regname = resultRegister.name.lowercase() + asmgen.out(" lda $sourceName | sta cx16.$regname | lda $sourceName+1 | sta cx16.$regname+1") + } + else -> throw AssemblyError("invalid reg") + } + } else { + TODO("lsw(expression) ${fcall.position} - use a temporary variable for now") + } + + } + private fun translateArguments(call: PtBuiltinFunctionCall, scope: IPtSubroutine?) { val signature = BuiltinFunctions.getValue(call.name) val callConv = signature.callConvention(call.args.map { diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/ForLoopsAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/ForLoopsAsmGen.kt index 9e2f8952f..6dfa6006f 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/ForLoopsAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/ForLoopsAsmGen.kt @@ -505,137 +505,158 @@ $endLabel""") is StMemVar -> symbol.length!! else -> 0u } - when { - iterableDt.isString -> { - if(asmgen.options.romable) { - val indexVar = asmgen.createTempVarReused(BaseDataType.UBYTE, false, stmt) - asmgen.out(""" + + fun iterateStrings() { + if(asmgen.options.romable) { + val indexVar = asmgen.createTempVarReused(BaseDataType.UBYTE, false, stmt) + asmgen.out(""" ldy #0 sty $indexVar $loopLabel lda $iterableName,y beq $endLabel sta ${asmgen.asmVariableName(stmt.variable)}""") - asmgen.translate(stmt.statements) - asmgen.out(""" + asmgen.translate(stmt.statements) + asmgen.out(""" inc $indexVar ldy $indexVar bne $loopLabel $endLabel""") - } else { - val indexVar = asmgen.makeLabel("for_index") - asmgen.out(""" + } else { + val indexVar = asmgen.makeLabel("for_index") + asmgen.out(""" ldy #0 sty $indexVar $loopLabel lda $iterableName,y beq $endLabel sta ${asmgen.asmVariableName(stmt.variable)}""") - asmgen.translate(stmt.statements) - asmgen.out(""" + asmgen.translate(stmt.statements) + asmgen.out(""" inc $indexVar ldy $indexVar bne $loopLabel $indexVar .byte 0 $endLabel""") - } } - iterableDt.isByteArray || iterableDt.isBoolArray -> { - val indexVar = if(asmgen.options.romable) - asmgen.createTempVarReused(iterableDt.elementType().base, false, stmt) - else - asmgen.makeLabel("for_index") - asmgen.out(""" + } + + fun iterateBytes() { + val indexVar = if(asmgen.options.romable) + asmgen.createTempVarReused(iterableDt.elementType().base, false, stmt) + else + asmgen.makeLabel("for_index") + asmgen.out(""" ldy #0 $loopLabel sty $indexVar lda $iterableName,y sta ${asmgen.asmVariableName(stmt.variable)}""") - asmgen.translate(stmt.statements) - if(numElements<=255u) { - asmgen.out(""" + asmgen.translate(stmt.statements) + if(numElements<=255u) { + asmgen.out(""" ldy $indexVar iny cpy #$numElements beq $endLabel bne $loopLabel""") - } else { - // length is 256 - asmgen.out(""" + } else { + // length is 256 + asmgen.out(""" ldy $indexVar iny bne $loopLabel beq $endLabel""") - } - if(!asmgen.options.romable) { - if(numElements>=16u) { - // allocate index var on ZP if possible, otherwise inline - val result = zeropage.allocate(indexVar, DataType.UBYTE, null, stmt.position, asmgen.errors) - result.fold( - success = { (address, _, _)-> asmgen.out("""$indexVar = $address ; auto zp UBYTE""") }, - failure = { asmgen.out("$indexVar .byte 0") } - ) - } else { - asmgen.out("$indexVar .byte 0") - } - } - asmgen.out(endLabel) } - iterableDt.isSplitWordArray -> { - val indexVar = if(asmgen.options.romable) - asmgen.createTempVarReused(BaseDataType.UBYTE, false, stmt) - else - asmgen.makeLabel("for_index") - val loopvarName = asmgen.asmVariableName(stmt.variable) - asmgen.out(""" + if(!asmgen.options.romable) { + if(numElements>=16u) { + // allocate index var on ZP if possible, otherwise inline + val result = zeropage.allocate(indexVar, DataType.UBYTE, null, stmt.position, asmgen.errors) + result.fold( + success = { (address, _, _)-> asmgen.out("""$indexVar = $address ; auto zp UBYTE""") }, + failure = { asmgen.out("$indexVar .byte 0") } + ) + } else { + asmgen.out("$indexVar .byte 0") + } + } + asmgen.out(endLabel) + } + + fun iterateSplitWords() { + val indexVar = if(asmgen.options.romable) + asmgen.createTempVarReused(BaseDataType.UBYTE, false, stmt) + else + asmgen.makeLabel("for_index") + val loopvarName = asmgen.asmVariableName(stmt.variable) + asmgen.out(""" ldy #0 $loopLabel sty $indexVar lda ${iterableName}_lsb,y sta $loopvarName lda ${iterableName}_msb,y sta $loopvarName+1""") - asmgen.translate(stmt.statements) - if(numElements<=255u) { - asmgen.out(""" + asmgen.translate(stmt.statements) + if(numElements<=255u) { + asmgen.out(""" ldy $indexVar iny cpy #$numElements beq $endLabel bne $loopLabel""") - } else { - // length is 256 - asmgen.out(""" + } else { + // length is 256 + asmgen.out(""" ldy $indexVar iny bne $loopLabel beq $endLabel""") - } - if(!asmgen.options.romable) { - if(numElements>=16u) { - // allocate index var on ZP if possible, otherwise inline - val result = zeropage.allocate(indexVar, DataType.UBYTE, null, stmt.position, asmgen.errors) - result.fold( - success = { (address, _, _)-> asmgen.out("""$indexVar = $address ; auto zp UBYTE""") }, - failure = { asmgen.out("$indexVar .byte 0") } - ) - } else { - asmgen.out("$indexVar .byte 0") - } - } - asmgen.out(endLabel) } - iterableDt.isWordArray -> { - val indexVar = if(asmgen.options.romable) - asmgen.createTempVarReused(BaseDataType.UBYTE, false, stmt) - else - asmgen.makeLabel("for_index") - val loopvarName = asmgen.asmVariableName(stmt.variable) - asmgen.out(""" + if(!asmgen.options.romable) { + if(numElements>=16u) { + // allocate index var on ZP if possible, otherwise inline + val result = zeropage.allocate(indexVar, DataType.UBYTE, null, stmt.position, asmgen.errors) + result.fold( + success = { (address, _, _)-> asmgen.out("""$indexVar = $address ; auto zp UBYTE""") }, + failure = { asmgen.out("$indexVar .byte 0") } + ) + } else { + asmgen.out("$indexVar .byte 0") + } + } + asmgen.out(endLabel) + } + + fun iterateWords(actuallyLongs: Boolean = false) { + val indexVar = if(asmgen.options.romable) + asmgen.createTempVarReused(BaseDataType.UBYTE, false, stmt) + else + asmgen.makeLabel("for_index") + val loopvarName = asmgen.asmVariableName(stmt.variable) + asmgen.out(""" ldy #0 $loopLabel sty $indexVar lda $iterableName,y sta $loopvarName lda $iterableName+1,y sta $loopvarName+1""") - asmgen.translate(stmt.statements) - if(numElements<=127u) { + if(actuallyLongs) { + asmgen.out(""" + lda $iterableName+2,y + sta $loopvarName+2 + lda $iterableName+3,y + sta $loopvarName+3""") + } + asmgen.translate(stmt.statements) + if(numElements<=127u) { + if(actuallyLongs) { + asmgen.out(""" + ldy $indexVar + iny + iny + iny + iny + cpy #${numElements*4u} + beq $endLabel + bne $loopLabel""") + } else { asmgen.out(""" ldy $indexVar iny @@ -643,6 +664,19 @@ $loopLabel sty $indexVar cpy #${numElements*2u} beq $endLabel bne $loopLabel""") + } + } else { + if(actuallyLongs) { + // array size is 64 longs, 256 bytes + asmgen.out(""" + ldy $indexVar + iny + iny + iny + iny + bne $loopLabel + beq $endLabel""") + } else { // array size is 128 words, 256 bytes asmgen.out(""" @@ -652,23 +686,29 @@ $loopLabel sty $indexVar bne $loopLabel beq $endLabel""") } - if(!asmgen.options.romable) { - if(numElements>=16u) { - // allocate index var on ZP if possible, otherwise inline - val result = zeropage.allocate(indexVar, DataType.UBYTE, null, stmt.position, asmgen.errors) - result.fold( - success = { (address, _, _)-> asmgen.out("""$indexVar = $address ; auto zp UBYTE""") }, - failure = { asmgen.out("$indexVar .byte 0") } - ) - } else { - asmgen.out("$indexVar .byte 0") - } + } + if(!asmgen.options.romable) { + if(numElements>=16u) { + // allocate index var on ZP if possible, otherwise inline + val result = zeropage.allocate(indexVar, DataType.UBYTE, null, stmt.position, asmgen.errors) + result.fold( + success = { (address, _, _)-> asmgen.out("""$indexVar = $address ; auto zp UBYTE""") }, + failure = { asmgen.out("$indexVar .byte 0") } + ) + } else { + asmgen.out("$indexVar .byte 0") } - asmgen.out(endLabel) - } - iterableDt.isFloatArray -> { - throw AssemblyError("for loop with floating point variables is not supported") } + asmgen.out(endLabel) + } + + when { + iterableDt.isString -> iterateStrings() + iterableDt.isByteArray || iterableDt.isBoolArray -> iterateBytes() + iterableDt.isSplitWordArray -> iterateSplitWords() + iterableDt.isWordArray -> iterateWords() + iterableDt.isLongArray -> iterateWords(true) + iterableDt.isFloatArray -> throw AssemblyError("for loop with floating point variables is not supported") else -> throw AssemblyError("can't iterate over $iterableDt") } asmgen.loopEndLabels.removeLast() diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt index a792026c3..b93a69a70 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt @@ -901,6 +901,16 @@ internal class ProgramAndVarsGen( asmgen.out(" .sint " + chunk.joinToString()) } } + dt.isLongArray -> { + val data = makeArrayFillDataSigned(dt, value, orNumberOfZeros) + if (data.size <= 16) + asmgen.out("$varname\t.dint ${data.joinToString()}") + else { + asmgen.out(varname) + for (chunk in data.chunked(16)) + asmgen.out(" .dint " + chunk.joinToString()) + } + } dt.isFloatArray -> { val array = value ?: zeroFilledArray(orNumberOfZeros!!) val floatFills = array.map { @@ -1023,7 +1033,7 @@ internal class ProgramAndVarsGen( val number = it.number!!.toInt() "$" + number.toString(16).padStart(4, '0') } - dt.isArray && dt.elementType().isSignedWord -> array.map { + dt.isSignedWordArray -> array.map { val number = it.number!!.toInt() val hexnum = number.absoluteValue.toString(16).padStart(4, '0') if(number>=0) @@ -1031,6 +1041,14 @@ internal class ProgramAndVarsGen( else "-$$hexnum" } + dt.isLongArray -> array.map { + val number = it.number!!.toInt() + val hexnum = number.absoluteValue.toString(16).padStart(8, '0') + if(number>=0) + "$$hexnum" + else + "-$$hexnum" + } else -> throw AssemblyError("invalid dt") } } diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt index a15593f2d..3d237c889 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt @@ -3964,7 +3964,20 @@ $endLabel""") stz ${target.asmVarname}+2 stz ${target.asmVarname}+3""") } - TargetStorageKind.ARRAY -> TODO("assign long zero to array ${target.position}") + TargetStorageKind.ARRAY -> { + val deref = target.array!!.pointerderef + if(deref!=null) { + pointergen.assignLong(IndexedPtrTarget(target), 0) + return + } + asmgen.loadScaledArrayIndexIntoRegister(target.array, CpuRegister.Y) + asmgen.out(""" + lda #0 + sta ${target.asmVarname},y + sta ${target.asmVarname}+1,y + sta ${target.asmVarname}+2,y + sta ${target.asmVarname}+3,y""") + } TargetStorageKind.MEMORY -> throw AssemblyError("memory is bytes not long ${target.position}") TargetStorageKind.REGISTER -> TODO("32 bits register assign? (we have no 32 bits registers right now) ${target.position}") TargetStorageKind.POINTER -> throw AssemblyError("can't assign long to pointer, pointers are 16 bits ${target.position}") @@ -3988,7 +4001,24 @@ $endLabel""") store(hex.substring(2,4), 2) store(hex.substring(0,2), 3) } - TargetStorageKind.ARRAY -> TODO("assign long $long to array ${target.position}") + TargetStorageKind.ARRAY -> { + val deref = target.array!!.pointerderef + if(deref!=null) { + pointergen.assignWord(IndexedPtrTarget(target), long) + return + } + asmgen.loadScaledArrayIndexIntoRegister(target.array, CpuRegister.Y) + val hex = long.toUInt().toString(16).padStart(8, '0') + asmgen.out(""" + lda #$${hex.substring(6,8)} + sta ${target.asmVarname},y + lda #$${hex.substring(4, 6)} + sta ${target.asmVarname}+1,y + lda #$${hex.substring(2, 4)} + sta ${target.asmVarname}+2,y + lda #$${hex.take(2)} + sta ${target.asmVarname}+3,y""") + } TargetStorageKind.MEMORY -> throw AssemblyError("memory is bytes not long ${target.position}") TargetStorageKind.REGISTER -> TODO("32 bits register assign? (we have no 32 bits registers right now) ${target.position}") TargetStorageKind.POINTER -> throw AssemblyError("can't assign long to pointer, pointers are 16 bits ${target.position}") @@ -4009,7 +4039,7 @@ $endLabel""") TargetStorageKind.ARRAY -> { val deref = target.array!!.pointerderef if(deref!=null) { - pointergen.assignWord(IndexedPtrTarget(target), word) + pointergen.assignWord(IndexedPtrTarget(target), 0) return } asmgen.loadScaledArrayIndexIntoRegister(target.array, CpuRegister.Y) diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AugmentableAssignmentAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AugmentableAssignmentAsmGen.kt index 41e78d193..0e642dd70 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AugmentableAssignmentAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AugmentableAssignmentAsmGen.kt @@ -302,6 +302,25 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, } } + target.datatype.isLong -> { + when(value.kind) { + SourceStorageKind.LITERALBOOLEAN -> inplacemodificationLongWithLiteralval(targetVarName, operator, value.boolean!!.asInt()) + SourceStorageKind.LITERALNUMBER -> inplacemodificationLongWithLiteralval(targetVarName, operator, value.number!!.number.toInt()) + SourceStorageKind.VARIABLE -> inplacemodificationLongWithVariable(targetVarName, operator, value.asmVarname) + SourceStorageKind.REGISTER -> inplacemodificationLongWithVariable(targetVarName, operator, regName(value)) + SourceStorageKind.MEMORY -> TODO("inplace long modifiication ${target.position}") + SourceStorageKind.ARRAY -> TODO("inplace long modifiication ${target.position}") + SourceStorageKind.EXPRESSION -> { + if(value.expression is PtTypeCast) { + if (tryInplaceModifyWithRemovedRedundantCast(value.expression, target, operator)) return + TODO("inplace long modifiication ${target.position}") + } else { + TODO("inplace long modifiication ${target.position}") + } + } + } + } + target.datatype.isFloat -> { when(value.kind) { SourceStorageKind.LITERALBOOLEAN -> inplacemodificationFloatWithLiteralval(targetVarName, operator, value.boolean!!.asInt().toDouble()) diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/PointerAssignmentsGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/PointerAssignmentsGen.kt index 5ae58f6e3..200c15635 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/PointerAssignmentsGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/PointerAssignmentsGen.kt @@ -406,6 +406,10 @@ internal class PointerAssignmentsGen(private val asmgen: AsmGen6502Internal, pri TODO("array ptr assign const word ${target.position}") } + internal fun assignLong(target: IndexedPtrTarget, long: Int) { + TODO("array ptr assign const long ${target.position}") + } + internal fun assignFloat(target: IndexedPtrTarget, float: Double) { TODO("array ptr assign const float ${target.position}") } diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/BuiltinFuncGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/BuiltinFuncGen.kt index 797ac4925..efc247ac6 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/BuiltinFuncGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/BuiltinFuncGen.kt @@ -24,8 +24,8 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe "callfar" -> funcCallfar(call) "callfar2" -> funcCallfar2(call) "call" -> funcCall(call) - "lsw" -> throw AssemblyError("lsw() should have been removed or replaced by a const value") - "msw" -> throw AssemblyError("msw() should have been removed or replaced by a const value") + "msw" -> funcMsw(call) + "lsw" -> funcLsw(call) "msb" -> funcMsb(call) "lsb" -> funcLsb(call) "memory" -> funcMemory(call) @@ -525,6 +525,15 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe return ExpressionCodeResult(result, IRDataType.BYTE, resultReg, -1) } + private fun funcLsw(call: PtBuiltinFunctionCall): ExpressionCodeResult { + val result = mutableListOf() + val tr = exprGen.translateExpression(call.args.single()) + addToResult(result, tr, tr.resultReg, -1) + val resultReg = codeGen.registers.next(IRDataType.WORD) + addInstr(result, IRInstruction(Opcode.LSIG, IRDataType.WORD, reg1 = resultReg, reg2 = tr.resultReg), null) + return ExpressionCodeResult(result, IRDataType.WORD, resultReg, -1) + } + private fun funcMsb(call: PtBuiltinFunctionCall): ExpressionCodeResult { val result = mutableListOf() val tr = exprGen.translateExpression(call.args.single()) @@ -535,6 +544,15 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe return ExpressionCodeResult(result, IRDataType.BYTE, resultReg, -1) } + private fun funcMsw(call: PtBuiltinFunctionCall): ExpressionCodeResult { + val result = mutableListOf() + val tr = exprGen.translateExpression(call.args.single()) + addToResult(result, tr, tr.resultReg, -1) + val resultReg = codeGen.registers.next(IRDataType.WORD) + addInstr(result, IRInstruction(Opcode.MSIG, IRDataType.WORD, reg1 = resultReg, reg2 = tr.resultReg), null) + return ExpressionCodeResult(result, IRDataType.WORD, resultReg, -1) + } + private fun funcRolRor(call: PtBuiltinFunctionCall): ExpressionCodeResult { val result = mutableListOf() val arg = call.args[0] diff --git a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt index f4326c374..6d6cfed2d 100644 --- a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt +++ b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt @@ -240,6 +240,11 @@ internal class AstChecker(private val program: Program, errors.err("word loop variable can only loop over bytes or words", forLoop.position) } + BaseDataType.LONG -> { + if(!iterableDt.elementType().isInteger) + errors.err("long loop variable can only loop over integers", forLoop.position) + } + BaseDataType.FLOAT -> { // Looping over float variables is very inefficient because the loopvar is going to // get copied over with new values all the time. We don't support this for now. @@ -941,6 +946,9 @@ internal class AstChecker(private val program: Program, dt.isWordArray -> if(arraySize > 128) err("regular word array length must be 1-128, use split array to get to 256") + dt.isLongArray -> + if(arraySize > 64) + err("long array length must be 1-64") dt.isFloatArray -> if(arraySize > 51) err("float array length must be 1-51") @@ -1044,6 +1052,10 @@ internal class AstChecker(private val program: Program, if (length == 0 || length > 128) err("regular word array length must be 1-128, use split array to get to 256") } + decl.datatype.isLongArray -> { + if (length == 0 || length > 64) + err("long array length must be 1-64") + } decl.datatype.isFloatArray -> { if (length == 0 || length > 51) err("float array length must be 1-51") @@ -2478,7 +2490,6 @@ internal class AstChecker(private val program: Program, } override fun visit(onGoto: OnGoto) { - val t = onGoto.index.inferType(program) if(!onGoto.index.inferType(program).getOrUndef().isUnsignedByte) { errors.err("on..goto index must be an unsigned byte", onGoto.index.position) } diff --git a/compiler/test/TestMemory.kt b/compiler/test/TestMemory.kt index ecbfdac34..5a3125bd0 100644 --- a/compiler/test/TestMemory.kt +++ b/compiler/test/TestMemory.kt @@ -386,9 +386,6 @@ class TestMemory: FunSpec({ shouldThrow { target.memorySize(BaseDataType.UNDEFINED) } - shouldThrow { - target.memorySize(DataType.arrayFor(BaseDataType.LONG), 10) - } target.memorySize(BaseDataType.BOOL) shouldBe 1 target.memorySize(BaseDataType.BYTE) shouldBe 1 target.memorySize(BaseDataType.WORD) shouldBe 2 @@ -397,6 +394,7 @@ class TestMemory: FunSpec({ target.memorySize(DataType.BOOL, null) shouldBe 1 target.memorySize(DataType.WORD, null) shouldBe 2 + target.memorySize(DataType.LONG, null) shouldBe 4 target.memorySize(DataType.FLOAT, null) shouldBe target.FLOAT_MEM_SIZE target.memorySize(DataType.STR, null) shouldBe 2 @@ -409,6 +407,7 @@ class TestMemory: FunSpec({ target.memorySize(DataType.arrayFor(BaseDataType.BYTE), 10) shouldBe 10 target.memorySize(DataType.arrayFor(BaseDataType.WORD), 10) shouldBe 20 target.memorySize(DataType.arrayFor(BaseDataType.UWORD), 10) shouldBe 20 + target.memorySize(DataType.arrayFor(BaseDataType.LONG), 10) shouldBe 40 target.memorySize(DataType.arrayFor(BaseDataType.FLOAT), 10) shouldBe 10*target.FLOAT_MEM_SIZE target.memorySize(DataType.arrayFor(BaseDataType.WORD, true), 10) shouldBe 20 target.memorySize(DataType.arrayFor(BaseDataType.UWORD, true), 10) shouldBe 20 diff --git a/compiler/test/ast/TestVariousCompilerAst.kt b/compiler/test/ast/TestVariousCompilerAst.kt index aa5371601..c38647b8a 100644 --- a/compiler/test/ast/TestVariousCompilerAst.kt +++ b/compiler/test/ast/TestVariousCompilerAst.kt @@ -871,6 +871,7 @@ main { DataType.forDt(BaseDataType.FLOAT).isFloat shouldBe true DataType.arrayFor(BaseDataType.UBYTE, true).isUnsignedByteArray shouldBe true + DataType.arrayFor(BaseDataType.LONG).isLongArray shouldBe true DataType.arrayFor(BaseDataType.FLOAT).isFloatArray shouldBe true DataType.arrayFor(BaseDataType.UWORD).isUnsignedWordArray shouldBe true DataType.arrayFor(BaseDataType.UWORD).isArray shouldBe true @@ -886,9 +887,6 @@ main { shouldThrow { DataType.arrayFor(BaseDataType.ARRAY) } - shouldThrow { - DataType.arrayFor(BaseDataType.LONG) - } shouldThrow { DataType.arrayFor(BaseDataType.UNDEFINED) } diff --git a/examples/test.p8 b/examples/test.p8 index f51a01bb6..91eec9d99 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -14,6 +14,21 @@ main { ; } sub start() { + long[] array = [-1999888777, -999, 42, 0, 77, 123456, 999999999] + long xx + for xx in array { + txt.print_uw(msw(xx)) + txt.spc() + txt.print_uw(lsw(xx)) + txt.nl() + } + txt.nl() + array[2] = 0 + array[3] = 222222222 + array[4] = bignum + array[5]++ + array[6]-- + txt.print_l(-1999888777) txt.spc() txt.print_l(-999) diff --git a/intermediate/src/prog8/intermediate/Utils.kt b/intermediate/src/prog8/intermediate/Utils.kt index 6eefe8a6e..aafdc8b2d 100644 --- a/intermediate/src/prog8/intermediate/Utils.kt +++ b/intermediate/src/prog8/intermediate/Utils.kt @@ -32,6 +32,7 @@ fun DataType.irTypeString(length: UInt?): String { BaseDataType.UWORD -> "uword[$lengthStr]" BaseDataType.BYTE -> "byte[$lengthStr]" BaseDataType.WORD -> "word[$lengthStr]" + BaseDataType.LONG -> "long[$lengthStr]" BaseDataType.BOOL -> "bool[$lengthStr]" BaseDataType.FLOAT -> "float[$lengthStr]" else -> throw IllegalArgumentException("invalid sub type") diff --git a/virtualmachine/src/prog8/vm/VmProgramLoader.kt b/virtualmachine/src/prog8/vm/VmProgramLoader.kt index 15151db48..5738ff947 100644 --- a/virtualmachine/src/prog8/vm/VmProgramLoader.kt +++ b/virtualmachine/src/prog8/vm/VmProgramLoader.kt @@ -386,6 +386,17 @@ class VmProgramLoader { } } + variable.dt.isLongArray -> { + for (elt in iElts) { + val value = getInitializerValue(variable.dt, elt, symbolAddresses) + value.fold( + { memory.setSL(address, it.toInt()) }, + { throw IRParseException("didn't expect bool") } + ) + address += 4 + } + } + variable.dt.isFloatArray -> { for (elt in iElts) { val value = getInitializerValue(variable.dt, elt, symbolAddresses)