diff --git a/codeCore/src/prog8/code/core/Enumerations.kt b/codeCore/src/prog8/code/core/Enumerations.kt index 1cda51515..58b5740cb 100644 --- a/codeCore/src/prog8/code/core/Enumerations.kt +++ b/codeCore/src/prog8/code/core/Enumerations.kt @@ -11,7 +11,9 @@ enum class DataType { ARRAY_UB, // pass by reference ARRAY_B, // pass by reference ARRAY_UW, // pass by reference + ARRAY_UW_SPLIT, // pass by reference, lo/hi byte split ARRAY_W, // pass by reference + ARRAY_W_SPLIT, // pass by reference, lo/hi byte split ARRAY_F, // pass by reference ARRAY_BOOL, // pass by reference UNDEFINED; @@ -119,12 +121,13 @@ val IntegerDatatypesNoBool = arrayOf(DataType.UBYTE, DataType.BYTE, DataType.UWO val NumericDatatypes = arrayOf(DataType.UBYTE, DataType.BYTE, DataType.UWORD, DataType.WORD, DataType.FLOAT, DataType.BOOL) val NumericDatatypesNoBool = arrayOf(DataType.UBYTE, DataType.BYTE, DataType.UWORD, DataType.WORD, DataType.FLOAT) val SignedDatatypes = arrayOf(DataType.BYTE, DataType.WORD, DataType.FLOAT) -val ArrayDatatypes = arrayOf(DataType.ARRAY_UB, DataType.ARRAY_B, DataType.ARRAY_UW, DataType.ARRAY_W, DataType.ARRAY_F, DataType.ARRAY_BOOL) +val ArrayDatatypes = arrayOf(DataType.ARRAY_UB, DataType.ARRAY_B, DataType.ARRAY_UW, DataType.ARRAY_UW_SPLIT, DataType.ARRAY_W, DataType.ARRAY_W_SPLIT, DataType.ARRAY_F, DataType.ARRAY_BOOL) val StringlyDatatypes = arrayOf(DataType.STR, DataType.ARRAY_UB, DataType.ARRAY_B, DataType.UWORD) val IterableDatatypes = arrayOf( DataType.STR, DataType.ARRAY_UB, DataType.ARRAY_B, DataType.ARRAY_UW, DataType.ARRAY_W, + DataType.ARRAY_UW_SPLIT, DataType.ARRAY_W_SPLIT, DataType.ARRAY_F, DataType.ARRAY_BOOL ) val PassByValueDatatypes = NumericDatatypes @@ -135,6 +138,8 @@ val ArrayToElementTypes = mapOf( DataType.ARRAY_UB to DataType.UBYTE, DataType.ARRAY_W to DataType.WORD, DataType.ARRAY_UW to DataType.UWORD, + DataType.ARRAY_W_SPLIT to DataType.WORD, + DataType.ARRAY_UW_SPLIT to DataType.UWORD, DataType.ARRAY_F to DataType.FLOAT, DataType.ARRAY_BOOL to DataType.BOOL ) diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/ForLoopsAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/ForLoopsAsmGen.kt index 24d92b175..8d5c9ccdd 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/ForLoopsAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/ForLoopsAsmGen.kt @@ -449,6 +449,14 @@ $loopLabel sty $indexVar } asmgen.out(endLabel) } + DataType.ARRAY_UW_SPLIT -> { + asmgen.out("; TODO iterate over split uword array") + // TODO("iterate over split uword array") + } + DataType.ARRAY_W_SPLIT -> { + asmgen.out("; TODO iterate over split word array") + // TODO("iterate over split word array") + } DataType.ARRAY_F -> { throw AssemblyError("for loop with floating point variables is not supported") } diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt index eaa5e9b44..04502e95f 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt @@ -627,6 +627,14 @@ internal class ProgramAndVarsGen( asmgen.out(" .sint " + chunk.joinToString()) } } + DataType.ARRAY_UW_SPLIT -> { + val data = makeArrayFillDataUnsigned(dt, value, orNumberOfZeros) + // TODO("gen split uword array $data") + } + DataType.ARRAY_W_SPLIT -> { + val data = makeArrayFillDataSigned(dt, value, orNumberOfZeros) + // TODO("gen split word array $data") + } DataType.ARRAY_F -> { val array = value ?: zeroFilledArray(orNumberOfZeros!!) val floatFills = array.map { @@ -686,7 +694,7 @@ internal class ProgramAndVarsGen( val number = it.number!!.toInt() "$"+number.toString(16).padStart(2, '0') } - DataType.ARRAY_UW -> array.map { + DataType.ARRAY_UW, DataType.ARRAY_UW_SPLIT -> array.map { if(it.number!=null) { "$" + it.number!!.toInt().toString(16).padStart(4, '0') } @@ -718,11 +726,11 @@ internal class ProgramAndVarsGen( else "-$$hexnum" } - DataType.ARRAY_UW -> array.map { + DataType.ARRAY_UW, DataType.ARRAY_UW_SPLIT -> array.map { val number = it.number!!.toInt() "$" + number.toString(16).padStart(4, '0') } - DataType.ARRAY_W -> array.map { + DataType.ARRAY_W, DataType.ARRAY_W_SPLIT -> array.map { val number = it.number!!.toInt() val hexnum = number.absoluteValue.toString(16).padStart(4, '0') if(number>=0) diff --git a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt index 511b0ceab..f64a39112 100644 --- a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt +++ b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt @@ -165,7 +165,8 @@ internal class AstChecker(private val program: Program, } DataType.UWORD -> { if(iterableDt!= DataType.UBYTE && iterableDt!= DataType.UWORD && iterableDt != DataType.STR && - iterableDt != DataType.ARRAY_UB && iterableDt!= DataType.ARRAY_UW) + iterableDt != DataType.ARRAY_UB && iterableDt != DataType.ARRAY_UW && + iterableDt != DataType.ARRAY_UW_SPLIT) errors.err("uword loop variable can only loop over unsigned bytes, words or strings", forLoop.position) checkUnsignedLoopDownto0(forLoop.iterable as? RangeExpression) @@ -176,7 +177,8 @@ internal class AstChecker(private val program: Program, } DataType.WORD -> { if(iterableDt!= DataType.BYTE && iterableDt!= DataType.WORD && - iterableDt != DataType.ARRAY_B && iterableDt!= DataType.ARRAY_W) + iterableDt != DataType.ARRAY_B && iterableDt!= DataType.ARRAY_W && + iterableDt != DataType.ARRAY_W_SPLIT) errors.err("word loop variable can only loop over bytes or words", forLoop.position) } DataType.FLOAT -> { @@ -629,6 +631,9 @@ internal class AstChecker(private val program: Program, DataType.ARRAY_W, DataType.ARRAY_UW -> if(arraySize > 128) err("word array length must be 1-128") + DataType.ARRAY_W_SPLIT, DataType.ARRAY_UW_SPLIT -> + if(arraySize > 256) + err("split word array length must be 1-256") DataType.ARRAY_F -> if(arraySize > 51) err("float array length must be 1-51") @@ -1443,6 +1448,10 @@ internal class AstChecker(private val program: Program, } return err("invalid word array initialization value ${value.type}, expected $targetDt") } + DataType.ARRAY_UW_SPLIT, DataType.ARRAY_W_SPLIT -> { + return true + TODO("check split array type") + } DataType.ARRAY_F -> { // value may be either a single float, or a float arraysize if(value.type istype targetDt) { diff --git a/compiler/src/prog8/compiler/astprocessing/BoolRemover.kt b/compiler/src/prog8/compiler/astprocessing/BoolRemover.kt index 0adb4ab7f..b3deb03d6 100644 --- a/compiler/src/prog8/compiler/astprocessing/BoolRemover.kt +++ b/compiler/src/prog8/compiler/astprocessing/BoolRemover.kt @@ -30,7 +30,7 @@ internal class BoolRemover(val program: Program) : AstWalker() { newvalue = NumericLiteral(DataType.UBYTE, 1.0, newvalue.position) } val ubyteDecl = VarDecl(decl.type, decl.origin, DataType.UBYTE, decl.zeropage, decl.arraysize, decl.name, - newvalue, decl.isArray, decl.sharedWithAsm, decl.position) + newvalue, decl.isArray, decl.sharedWithAsm, decl.splitArray, decl.position) return listOf(IAstModification.ReplaceNode(decl, ubyteDecl, parent)) } @@ -47,7 +47,7 @@ internal class BoolRemover(val program: Program) : AstWalker() { newarray = ArrayLiteral(InferredTypes.InferredType.known(DataType.ARRAY_UB), convertedArray, decl.position) } val ubyteArrayDecl = VarDecl(decl.type, decl.origin, DataType.ARRAY_UB, decl.zeropage, decl.arraysize, decl.name, - newarray, true, decl.sharedWithAsm, decl.position) + newarray, true, decl.sharedWithAsm, decl.splitArray, decl.position) return listOf(IAstModification.ReplaceNode(decl, ubyteArrayDecl, parent)) } diff --git a/compiler/src/prog8/compiler/astprocessing/StatementReorderer.kt b/compiler/src/prog8/compiler/astprocessing/StatementReorderer.kt index bd3396df6..d8359bab9 100644 --- a/compiler/src/prog8/compiler/astprocessing/StatementReorderer.kt +++ b/compiler/src/prog8/compiler/astprocessing/StatementReorderer.kt @@ -162,6 +162,7 @@ internal class StatementReorderer(val program: Program, null, false, it.sharedWithAsm, + it.splitArray, it.position ) IAstModification.ReplaceNode(it, newvar, subroutine) diff --git a/compilerAst/src/prog8/ast/Extensions.kt b/compilerAst/src/prog8/ast/Extensions.kt index 050433bac..7025c1f02 100644 --- a/compilerAst/src/prog8/ast/Extensions.kt +++ b/compilerAst/src/prog8/ast/Extensions.kt @@ -40,7 +40,7 @@ fun Program.getTempVar(dt: DataType, altNames: Boolean=false): Pair // add new temp variable to the ast directly (we can do this here because we're not iterating inside those container blocks) val decl = VarDecl( VarDeclType.VAR, VarDeclOrigin.AUTOGENERATED, dt, ZeropageWish.DONTCARE, - null, tmpvarName[1], null, isArray = false, sharedWithAsm = false, position = Position.DUMMY + null, tmpvarName[1], null, isArray = false, sharedWithAsm = false, splitArray = false, position = Position.DUMMY ) block.statements.add(decl) decl.linkParents(block) diff --git a/compilerAst/src/prog8/ast/Program.kt b/compilerAst/src/prog8/ast/Program.kt index ef460d398..7fbb014fe 100644 --- a/compilerAst/src/prog8/ast/Program.kt +++ b/compilerAst/src/prog8/ast/Program.kt @@ -85,7 +85,7 @@ class Program(val name: String, val varName = "string_${internedStringsBlock.statements.size}" val decl = VarDecl( VarDeclType.VAR, VarDeclOrigin.STRINGLITERAL, DataType.STR, ZeropageWish.NOT_IN_ZEROPAGE, null, varName, string, - isArray = false, sharedWithAsm = false, position = string.position + isArray = false, sharedWithAsm = false, splitArray = false, position = string.position ) internedStringsBlock.statements.add(decl) decl.linkParents(internedStringsBlock) diff --git a/compilerAst/src/prog8/ast/antlr/Antlr2Kotlin.kt b/compilerAst/src/prog8/ast/antlr/Antlr2Kotlin.kt index 5bc84ac1b..dbc1e3e04 100644 --- a/compilerAst/src/prog8/ast/antlr/Antlr2Kotlin.kt +++ b/compilerAst/src/prog8/ast/antlr/Antlr2Kotlin.kt @@ -615,7 +615,6 @@ private fun Prog8ANTLRParser.VardeclContext.toAst(type: VarDeclType, value: Expr options.ZEROPAGE().isNotEmpty() -> ZeropageWish.PREFER_ZEROPAGE else -> ZeropageWish.DONTCARE } - val shared = options.SHARED().isNotEmpty() return VarDecl( type, VarDeclOrigin.USERCODE, datatype()?.toAst() ?: DataType.UNDEFINED, @@ -624,7 +623,8 @@ private fun Prog8ANTLRParser.VardeclContext.toAst(type: VarDeclType, value: Expr varname.text, value, ARRAYSIG() != null || arrayindex() != null, - shared, + options.SHARED().isNotEmpty(), + options.SPLIT().isNotEmpty(), toPosition() ) } diff --git a/compilerAst/src/prog8/ast/expressions/InferredTypes.kt b/compilerAst/src/prog8/ast/expressions/InferredTypes.kt index 3762a6624..2451a74c4 100644 --- a/compilerAst/src/prog8/ast/expressions/InferredTypes.kt +++ b/compilerAst/src/prog8/ast/expressions/InferredTypes.kt @@ -73,7 +73,9 @@ object InferredTypes { DataType.ARRAY_UB to InferredType.known(DataType.ARRAY_UB), DataType.ARRAY_B to InferredType.known(DataType.ARRAY_B), DataType.ARRAY_UW to InferredType.known(DataType.ARRAY_UW), + DataType.ARRAY_UW_SPLIT to InferredType.known(DataType.ARRAY_UW_SPLIT), DataType.ARRAY_W to InferredType.known(DataType.ARRAY_W), + DataType.ARRAY_W_SPLIT to InferredType.known(DataType.ARRAY_W_SPLIT), DataType.ARRAY_F to InferredType.known(DataType.ARRAY_F), DataType.ARRAY_BOOL to InferredType.known(DataType.ARRAY_BOOL) ) diff --git a/compilerAst/src/prog8/ast/statements/AstStatements.kt b/compilerAst/src/prog8/ast/statements/AstStatements.kt index 331d0134c..6cd314254 100644 --- a/compilerAst/src/prog8/ast/statements/AstStatements.kt +++ b/compilerAst/src/prog8/ast/statements/AstStatements.kt @@ -197,6 +197,7 @@ class VarDecl(val type: VarDeclType, var value: Expression?, val isArray: Boolean, val sharedWithAsm: Boolean, + val splitArray: Boolean, override val position: Position) : Statement(), INamedStatement { override lateinit var parent: Node var allowInitializeWithZero = true @@ -210,6 +211,7 @@ class VarDecl(val type: VarDeclType, return VarDecl(VarDeclType.VAR, VarDeclOrigin.SUBROUTINEPARAM, param.type, ZeropageWish.DONTCARE, null, param.name, null, isArray = false, sharedWithAsm = false, + splitArray = false, position = param.position ) } @@ -220,12 +222,15 @@ class VarDecl(val type: VarDeclType, val declaredType = ArrayToElementTypes.getValue(arrayDt) val arraysize = ArrayIndex.forArray(array) return VarDecl(VarDeclType.VAR, VarDeclOrigin.ARRAYLITERAL, declaredType, ZeropageWish.NOT_IN_ZEROPAGE, arraysize, autoVarName, array, - isArray = true, sharedWithAsm = false, position = array.position) + isArray = true, sharedWithAsm = false, splitArray = false, position = array.position) } } val datatypeErrors = mutableListOf() // don't crash at init time, report them in the AstChecker - val datatype = + val datatype: DataType + + init { + val dt = if (!isArray) declaredDatatype else when (declaredDatatype) { DataType.UBYTE -> DataType.ARRAY_UB @@ -241,6 +246,18 @@ class VarDecl(val type: VarDeclType, } } + datatype = if(splitArray) { + when(dt) { + DataType.ARRAY_UW -> DataType.ARRAY_UW_SPLIT + DataType.ARRAY_W -> DataType.ARRAY_W_SPLIT + else -> { + datatypeErrors.add(SyntaxError("split can only be used on word arrays", position)) + DataType.UNDEFINED + } + } + } else dt + } + override fun linkParents(parent: Node) { this.parent = parent arraysize?.linkParents(this) @@ -267,14 +284,14 @@ class VarDecl(val type: VarDeclType, override fun copy(): VarDecl { val copy = VarDecl(type, origin, declaredDatatype, zeropage, arraysize?.copy(), name, value?.copy(), - isArray, sharedWithAsm, position) + isArray, sharedWithAsm, splitArray, position) copy.allowInitializeWithZero = this.allowInitializeWithZero return copy } fun renamed(newName: String): VarDecl { val copy = VarDecl(type, origin, declaredDatatype, zeropage, arraysize, newName, value, - isArray, sharedWithAsm, position) + isArray, sharedWithAsm, splitArray, position) copy.allowInitializeWithZero = this.allowInitializeWithZero return copy } diff --git a/examples/test.p8 b/examples/test.p8 index c1ae9a19f..42993fafb 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -5,12 +5,47 @@ main { sub start() { - ubyte[] array = [ $00, $11, $22, $33, $44, $55, $66, $77, $88, $99, $aa, $bb] + uword[] @split split_uwords = [12345, 60000, 4096] + word[] @split split_words = [-12345, -2222, 22222] + uword[256] @split @shared split2 + word[256] @split @shared split3 - ubyte x = 2 - ubyte y = 3 - txt.print_uwhex(mkword(array[9], array[8]), true) - txt.print_uwhex(mkword(array[x*y+y], array[y*x+x]), true) + + print_arrays() + + sub print_arrays() { + for cx16.r0 in split_uwords { + txt.print_uw(cx16.r0) + txt.spc() + } + txt.nl() + + for cx16.r0s in split_words { + txt.print_w(cx16.r0s) + txt.spc() + } + txt.nl() + } + + ubyte idx + for idx in 0 to 2 { + cx16.r0 = split_uwords[idx] + cx16.r1s = split_words[idx] + txt.print_uw(cx16.r0) + txt.spc() + txt.print_w(cx16.r1s) + txt.nl() + } + + split_uwords[1] = 9999 + split_words[1] = -9999 + + print_arrays() + + split_uwords[1]++ + split_words[1]-- + + print_arrays() } } diff --git a/intermediate/src/prog8/intermediate/IRFileReader.kt b/intermediate/src/prog8/intermediate/IRFileReader.kt index 814722dcd..bc4736fe1 100644 --- a/intermediate/src/prog8/intermediate/IRFileReader.kt +++ b/intermediate/src/prog8/intermediate/IRFileReader.kt @@ -488,6 +488,8 @@ class IRFileReader { "uword" -> DataType.ARRAY_UW "float" -> DataType.ARRAY_F "bool" -> DataType.ARRAY_B + "uword_split" -> DataType.ARRAY_UW_SPLIT + "word_split" -> DataType.ARRAY_W_SPLIT else -> throw IRParseException("invalid dt $type") } } else { diff --git a/intermediate/src/prog8/intermediate/Utils.kt b/intermediate/src/prog8/intermediate/Utils.kt index 9107b95d2..2dbce8a8a 100644 --- a/intermediate/src/prog8/intermediate/Utils.kt +++ b/intermediate/src/prog8/intermediate/Utils.kt @@ -10,10 +10,13 @@ fun getTypeString(dt : DataType): String = when(dt) { DataType.UWORD -> "uword" DataType.WORD -> "word" DataType.FLOAT -> "float" + DataType.BOOL, DataType.ARRAY_BOOL -> throw InternalCompilerException("bool should have been converted to ubyte") DataType.ARRAY_UB, DataType.STR -> "ubyte[]" DataType.ARRAY_B -> "byte[]" DataType.ARRAY_UW -> "uword[]" + DataType.ARRAY_UW_SPLIT -> "uword_split[]" DataType.ARRAY_W -> "word[]" + DataType.ARRAY_W_SPLIT -> "word_split[]" DataType.ARRAY_F -> "float[]" else -> throw InternalCompilerException("weird dt") } @@ -24,10 +27,13 @@ fun getTypeString(memvar: StMemVar): String = when(memvar.dt) { DataType.UWORD -> "uword" DataType.WORD -> "word" DataType.FLOAT -> "float" + DataType.BOOL, DataType.ARRAY_BOOL -> throw InternalCompilerException("bool should have been converted to ubyte") DataType.ARRAY_UB, DataType.STR -> "ubyte[${memvar.length}]" DataType.ARRAY_B -> "byte[${memvar.length}]" DataType.ARRAY_UW -> "uword[${memvar.length}]" + DataType.ARRAY_UW_SPLIT -> "uword_split[${memvar.length}]" DataType.ARRAY_W -> "word[${memvar.length}]" + DataType.ARRAY_W_SPLIT -> "word_split[${memvar.length}]" DataType.ARRAY_F -> "float[${memvar.length}]" else -> throw InternalCompilerException("weird dt") } @@ -38,10 +44,13 @@ fun getTypeString(variable : StStaticVariable): String = when(variable.dt) { DataType.UWORD -> "uword" DataType.WORD -> "word" DataType.FLOAT -> "float" + DataType.BOOL, DataType.ARRAY_BOOL -> throw InternalCompilerException("bool should have been converted to ubyte") DataType.ARRAY_UB, DataType.STR -> "ubyte[${variable.length}]" DataType.ARRAY_B -> "byte[${variable.length}]" DataType.ARRAY_UW -> "uword[${variable.length}]" + DataType.ARRAY_UW_SPLIT -> "uword_split[${variable.length}]" DataType.ARRAY_W -> "word[${variable.length}]" + DataType.ARRAY_W_SPLIT -> "word_split[${variable.length}]" DataType.ARRAY_F -> "float[${variable.length}]" else -> throw InternalCompilerException("weird dt") } diff --git a/parser/antlr/Prog8ANTLR.g4 b/parser/antlr/Prog8ANTLR.g4 index 0e9b29eb1..f8e4b9973 100644 --- a/parser/antlr/Prog8ANTLR.g4 +++ b/parser/antlr/Prog8ANTLR.g4 @@ -53,6 +53,8 @@ ZEROPAGEREQUIRE : '@requirezp' ; SHARED : '@shared' ; +SPLIT: '@split' ; + ARRAYSIG : '[]' ; @@ -130,7 +132,7 @@ directivearg : stringliteral | identifier | integerliteral ; vardecl: datatype (arrayindex | ARRAYSIG)? decloptions varname=identifier ; -decloptions: (SHARED | ZEROPAGE | ZEROPAGEREQUIRE)* ; +decloptions: (SHARED | ZEROPAGE | ZEROPAGEREQUIRE | SPLIT)* ; varinitializer : vardecl '=' expression ; diff --git a/virtualmachine/src/prog8/vm/VmProgramLoader.kt b/virtualmachine/src/prog8/vm/VmProgramLoader.kt index 74eb28f8f..23736334c 100644 --- a/virtualmachine/src/prog8/vm/VmProgramLoader.kt +++ b/virtualmachine/src/prog8/vm/VmProgramLoader.kt @@ -223,6 +223,12 @@ class VmProgramLoader { memory.setFloat(addr, 0.0f) addr += program.options.compTarget.machine.FLOAT_MEM_SIZE } + DataType.ARRAY_UW_SPLIT, DataType.ARRAY_W_SPLIT -> { + // lo bytes come after the hi bytes + memory.setUB(addr, 0u) + memory.setUB(addr+variable.length!!, 0u) + addr++ + } else -> throw IRParseException("invalid dt") } } @@ -274,6 +280,12 @@ class VmProgramLoader { addr+=2 } } + DataType.ARRAY_UW_SPLIT -> { + TODO("$it") + } + DataType.ARRAY_W_SPLIT -> { + TODO("$it") + } DataType.ARRAY_F -> { repeat(variable.length!!) { memory.setFloat(addr, value.toFloat()) @@ -315,6 +327,12 @@ class VmProgramLoader { addr+=2 } } + DataType.ARRAY_UW_SPLIT -> { + TODO("$it") + } + DataType.ARRAY_W_SPLIT -> { + TODO("$it") + } DataType.ARRAY_F -> { for(elt in it) { memory.setFloat(addr, elt.number!!.toFloat())