diff --git a/.gitignore b/.gitignore index cecc3d8f4..0c5cc029c 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,5 @@ __pycache__/ parser.out parsetab.py .pytest_cache/ +compiler/src/prog8_kotlin.jar +compiler/src/compiled_java diff --git a/compiler/examples/test.p8 b/compiler/examples/test.p8 index c0ce3c0aa..03a61a619 100644 --- a/compiler/examples/test.p8 +++ b/compiler/examples/test.p8 @@ -7,10 +7,10 @@ sub start() { - ubyte pixely = 255 - ubyte ub = 0 byte b = 99 byte b2 = 100 + ubyte ub = 255 + ubyte ub2 = 0 word w = 999 word w2 = 3 uword uw = 40000 @@ -33,7 +33,6 @@ sub start() { ubyte[2,3] ubmatrix1 ubyte[2,3] ubmatrix2 - memory byte mbyte = $c000 memory byte mbyte2 = $d000 memory ubyte mubyte = $c001 @@ -44,156 +43,138 @@ sub start() { memory uword muword2 = $d004 memory float mfloat = $c006 memory float mfloat2 = $d006 + memory byte[3] mbarr1 = $e000 + memory ubyte[3] mubarr1 = $e100 + memory word[3] mwarr1 = $e100 + memory uword[3] muwarr1 = $e100 -;label: + str string = "hello" + str_p stringp = "hello" + + +; all possible assignments to a BYTE VARIABLE (not array) + +byte_assignment_to_register: + A = 42 + A = X + A = ub + A = mubyte + A = AY[4] + A = ubarr1[2] + A = string[4] + A = string[X] + A = string[b] + A = string[ub] + A = ubarr1[X] + A = ubarr1[b] + A = ubarr1[ub] + A = AY[Y] + A = AY[b] + A = AY[ub] + A = ubmatrix1[1,2] + ;A = ubmatrix1[1,Y] ; todo via evaluation + A = ubmatrix1[X,2] ; todo via evaluation TODO fix error constant y dimension of index should have been const-folded with x into one value + ;A = ubmatrix1[X,Y] ; todo via evaluation + ;A = ubmatrix1[1,b2] ; todo via evaluation + ;A = ubmatrix1[X,b2] ; todo via evaluation + A = ubmatrix1[b2,2] ; todo FIX ERROR constant y dimension of index should have been const-folded with x into one value + ;A = ubmatrix1[b2,X] ; todo via evaluation + ;A = ubmatrix1[b,b2] ; todo via evaluation + ;A = ubmatrix1[ub,ub2] ; todo via evaluation + +;byte_assignment_to_bytevar: +; b = 42 +; b = b2 +; b = mbyte +; b = barr1[2] +; b = bmatrix1[1,2] ; -; while A>99 { -; X=22 -; } +; ub = 42 +; ub = X +; ub = ub2 +; ub = mubyte +; ub = ubarr1[2] +; ub = ubmatrix1[1,2] +; ub = string[4] +; ub = AY[4] ; -; repeat { -; X=22 -; } until A>99 ; -; for X in 0 to 99 { -; Y=33 -; } +;; all possible assignments to a WORD VARIABLE (not array) ; -; for ubyte derp in 2 to 44 { -; X=44 -; } +;word_assignment_to_registerpair: +; AY = 42 +; AY = 42.w +; AY = 42555 +; AY = X +; AY = XY +; AY = ub +; AY = mubyte +; AY = ubarr1[2] +; AY = ubmatrix1[1,2] +; AY = string[4] +; AY = uw +; AY = muword +; AY = uwarr1[2] +; AY = string[4] +; AY = XY[4] ; -; if A<22 goto label +;;word_assignment_to_wordvar: +; w = -42 +; w = -42.w +; w = -12345 +; w = X +; w = b2 +; w = ub2 +; w = w2 +; w = mbyte +; w = mubyte +; w = mword +; w = barr1[2] +; w = ubarr1[2] +; w = warr1[2] +; w = bmatrix1[1,2] +; w = ubmatrix1[1,2] +; w = string[4] +; w = AY[4] ; -; if X<22 { -; A=99 -; } else { -; Y=42 -; } - - Y=42 - AY=42 - AY=42555 - Y = ub - AY= ub - AY= uw - - Y = mubyte - AY = mubyte - AY = muword - - Y = ubarr1[2] - AY = ubarr1[2] - AY = uwarr1[2] - - barr1[2]=42 - ubarr1[2]=42 - warr1[2]=12555 - uwarr1[2]=42555 - farr1[2]=42.5678 - - ubarr1[2]=X - uwarr1[2]=XY - ; farr1[2]=XY ; @todo - - barr1[2] = b - ubarr1[2] = ub - warr1[2] = w - uwarr1[2] = uw - farr1[2] = fl1 - - barr1[2] = mbyte - ubarr1[2] = mubyte - warr1[2] = mword - uwarr1[2] = muword - farr1[2] = mfloat - - b= barr1[2] - ub = ubarr1[2] - w = warr1[2] - uw = uwarr1[2] - ; fl1 = farr1[2] ; @todo - - mbyte= barr1[2] - mubyte = ubarr1[2] - mword = warr1[2] - muword = uwarr1[2] - ; mfloat = farr1[2] ; @todo - - barr1[2] = barr2[3] - ubarr1[2] = ubarr2[3] - warr1[2] = warr2[3] - uwarr1[2] = uwarr2[3] - ; farr1[2] = farr2[3] ; @todo - - - XY[2]=42 - XY[2] = ub - XY[2] = mubyte - ub = XY[2] - uw = XY[2] - ;fl1 = XY[2] ; @todo - mubyte = XY[2] - muword = XY[2] - ;mfloat = XY[2] ; @todo - XY[2] = AY[3] ; @todo wat is de output hiervan??? - - - - b = 1 - ub = 1 - w = 1 - uw = 1 - fl1 = 2.345 - - b = b2 - ub = pixely - w = b2 - w = w2 - w = ub - uw = ub - uw = uw2 - ;fl1 = ub ; @todo - ;fl1 = b2 ; @todo - ;fl1 = uw2 ; @todo - ;fl1 = w2 ; @todo - fl1 = fl2 - - b = mbyte - ub = mubyte - w = mword - w = mbyte - w = mubyte - uw = mubyte - uw = muword - fl1 = mfloat - ;fl1 = mbyte ; @todo - ;fl1 = mword ; @todo - ;fl1 = mubyte ; @todo - ;fl1 = muword ; @todo - - mbyte = 1 - mubyte = 1 - mword = 1 - muword = 1 - mfloat = 3.456 - - %breakpoint - - mbyte = b - mubyte = ub - mword = w - muword = uw - mfloat = fl2 - - %breakpoint - - mbyte = mbyte2 - mubyte = mubyte2 - mword = mword2 - muword = muword2 - mfloat = mfloat2 - +; uw = 42 +; uw = 42.w +; uw = 42555 +; uw = X +; uw = AY +; uw = ub2 +; uw = uw2 +; uw = mubyte +; uw = muword +; uw = ubarr1[2] +; uw = uwarr1[2] +; uw = ubmatrix1[1,2] +; uw = string[4] +; uw = AY[4] +; +; +;; all possible assignments to a FLOAT VARIABLE +;float_assignment_to_floatvar: +; fl1 = 34 +; fl1 = 34555.w +; fl1 = 3.33e22 +; fl1 = X +; fl1 = AY +; fl1 = b2 +; fl1 = ub2 +; fl1 = w2 +; fl1 = uw2 +; fl1 = mbyte +; fl1 = mubyte +; fl1 = mword +; fl1 = muword +; fl1 = barr1[2] +; fl1 = ubarr1[2] +; fl1 = warr1[2] +; fl1 = uwarr1[2] +; fl1 = bmatrix1[1,2] +; fl1 = ubmatrix1[1,2] +; fl1 = string[4] return } diff --git a/compiler/src/build_the_compiler.cmd b/compiler/src/build_the_compiler.cmd index 1906af2bb..c427774af 100644 --- a/compiler/src/build_the_compiler.cmd +++ b/compiler/src/build_the_compiler.cmd @@ -1,6 +1,6 @@ mkdir compiled_java -java -jar ../antlr/lib/antlr-4.7.1-complete.jar -o ./prog8/parser -no-listener -no-visitor -package prog8.parser ../antlr/prog8.g4 +java -jar ../antlr/lib/antlr-4.7.1-complete.jar -o ./prog8/parser -Xexact-output-dir -no-listener -no-visitor -package prog8.parser ../antlr/prog8.g4 @dir /b /S src *.java > sources.txt javac -verbose -d compiled_java -cp ../antlr/lib/antlr-runtime-4.7.1.jar @sources.txt diff --git a/compiler/src/build_the_compiler.sh b/compiler/src/build_the_compiler.sh index 481d74c30..824bcd9f3 100755 --- a/compiler/src/build_the_compiler.sh +++ b/compiler/src/build_the_compiler.sh @@ -1,5 +1,7 @@ #!/usr/bin/env bash +java -jar ../antlr/lib/antlr-4.7.1-complete.jar -o ./prog8/parser -Xexact-output-dir -no-listener -no-visitor -package prog8.parser ../antlr/prog8.g4 + find prog8 -name \*.java > javasources.txt mkdir -p compiled_java javac -verbose -d compiled_java -cp ../antlr/lib/antlr-runtime-4.7.1.jar @javasources.txt diff --git a/compiler/src/prog8/ast/AST.kt b/compiler/src/prog8/ast/AST.kt index a90ce8a22..45d621fd1 100644 --- a/compiler/src/prog8/ast/AST.kt +++ b/compiler/src/prog8/ast/AST.kt @@ -67,7 +67,7 @@ enum class BranchCondition { } val IterableDatatypes = setOf( - DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS, + DataType.STR, DataType.STR_S, // note: the STR_P/STR_PS types aren't iterable because they store their length as the first byte DataType.ARRAY_UB, DataType.ARRAY_B, DataType.ARRAY_UW, DataType.ARRAY_W, DataType.ARRAY_F, DataType.MATRIX_UB, DataType.MATRIX_B) @@ -231,7 +231,7 @@ interface IAstProcessor { fun process(arrayIndexedExpression: ArrayIndexedExpression): IExpression { arrayIndexedExpression.identifier?.process(this) - arrayIndexedExpression.array.process(this) + arrayIndexedExpression.arrayspec.process(this) return arrayIndexedExpression } @@ -622,7 +622,7 @@ class VarDecl(val type: VarDeclType, DataType.WORD -> DataType.ARRAY_W DataType.FLOAT -> DataType.ARRAY_F else -> { - datatypeErrors.add(SyntaxError("array can only contain bytes/words/floats", position)) + datatypeErrors.add(SyntaxError("arrayspec can only contain bytes/words/floats", position)) DataType.UBYTE } } @@ -898,13 +898,13 @@ class BinaryExpression(var left: IExpression, var operator: String, var right: I class ArrayIndexedExpression(val identifier: IdentifierReference?, val register: Register?, - var array: ArraySpec, + var arrayspec: ArraySpec, override val position: Position) : IExpression { override lateinit var parent: Node override fun linkParents(parent: Node) { this.parent = parent identifier?.linkParents(this) - array.linkParents(this) + arrayspec.linkParents(this) } override fun isIterable(namespace: INameScope, heap: HeapValues) = false @@ -930,6 +930,10 @@ class ArrayIndexedExpression(val identifier: IdentifierReference?, } throw FatalAstException("cannot get indexed element on $target") } + + override fun toString(): String { + return "ArrayIndexed(ident=$identifier, reg=$register, arrayspec=$arrayspec; pos=$position)" + } } @@ -1046,8 +1050,8 @@ class LiteralValue(val type: DataType, else "str:$strvalue" } DataType.ARRAY_UB, DataType.ARRAY_B, DataType.ARRAY_UW, DataType.ARRAY_W, DataType.ARRAY_F -> { - if(heapId!=null) "array:#$heapId" - else "array:$arrayvalue" + if(heapId!=null) "arrayspec:#$heapId" + else "arrayspec:$arrayvalue" } DataType.MATRIX_UB, DataType.MATRIX_B -> { if(heapId!=null) "matrix:#$heapId" @@ -1936,7 +1940,7 @@ private fun prog8Parser.ExpressionContext.toAst() : IExpression { litval.charliteral()!=null -> LiteralValue(DataType.UBYTE, bytevalue = Petscii.encodePetscii(litval.charliteral().text.unescape(), true)[0], position = litval.toPosition()) litval.arrayliteral()!=null -> { val array = litval.arrayliteral()?.toAst() - // the actual type of the array can not yet be determined here (missing namespace & heap) + // the actual type of the arrayspec can not yet be determined here (missing namespace & heap) // the ConstantFolder takes care of that and converts the type if needed. LiteralValue(DataType.ARRAY_UB, arrayvalue = array, position = litval.toPosition()) } diff --git a/compiler/src/prog8/ast/AstChecker.kt b/compiler/src/prog8/ast/AstChecker.kt index e139cd718..8f049151d 100644 --- a/compiler/src/prog8/ast/AstChecker.kt +++ b/compiler/src/prog8/ast/AstChecker.kt @@ -247,7 +247,7 @@ class AstChecker(private val namespace: INameScope, if(param.second.register==Register.AX || param.second.register==Register.AY || param.second.register==Register.XY) { if(param.first.type!=DataType.UWORD && param.first.type !in StringDatatypes && param.first.type !in ArrayDatatypes) - err("parameter '${param.first.name}' should be uword/str/array") + err("parameter '${param.first.name}' should be uword/str/arrayspec") } } for(ret in subroutine.returntypes.withIndex().zip(subroutine.asmReturnvaluesRegisters)) { @@ -260,7 +260,7 @@ class AstChecker(private val namespace: INameScope, ret.second.register==Register.XY) { if(ret.first.value!=DataType.UWORD && ret.first.value != DataType.UBYTE && ret.first.value !in StringDatatypes && ret.first.value !in ArrayDatatypes) - err("return value #${ret.first.index+1} should be uword/ubyte/string/array") + err("return value #${ret.first.index+1} should be uword/ubyte/string/arrayspec") } } @@ -330,11 +330,17 @@ class AstChecker(private val namespace: INameScope, return super.process(assignment) } } + } else if(assignment.target.arrayindexed!=null) { + if(assignment.target.arrayindexed!!.register!=null) { + val value = assignment.value + if (value is ArrayIndexedExpression && value.register in setOf(Register.AX, Register.AY, Register.XY)) + checkResult.add(SyntaxError("reading AND writing from registerpair arrays not supported due to register overlap", assignment.position)) + } } - // it is not possible to assign a new array to something. + // it is not possible to assign a new arrayspec to something. if(assignment.value.resultingDatatype(namespace, heap) in ArrayDatatypes) - checkResult.add(SyntaxError("it's not possible to assign an array literal value to something, use it as a variable decl initializer instead", assignment.position)) + checkResult.add(SyntaxError("it's not possible to assign an arrayspec literal value to something, use it as a variable decl initializer instead", assignment.position)) if(assignment.aug_op!=null) { // check augmented assignment: @@ -440,6 +446,25 @@ class AstChecker(private val namespace: INameScope, } } VarDeclType.MEMORY -> { + if(decl.arrayspec!=null) { + val arraySize = decl.arrayspec.size() ?: 1 + when(decl.datatype) { + DataType.ARRAY_B, DataType.ARRAY_UB -> + if(arraySize > 256) + err("byte arrayspec length must be 1-256") + DataType.ARRAY_W, DataType.ARRAY_UW -> + if(arraySize > 128) + err("word arrayspec length must be 1-128") + DataType.ARRAY_F -> + if(arraySize > 51) + err("float arrayspec length must be 1-51") + DataType.MATRIX_B, DataType.MATRIX_UB -> + if(arraySize > 32768) + err("invalid matrix size, must be 1-32768") + else -> {} + } + } + if(decl.value !is LiteralValue) { err("value of memory var decl is not a literal (it is a ${decl.value!!::class.simpleName}).", decl.value?.position) } else { @@ -545,7 +570,7 @@ class AstChecker(private val namespace: INameScope, } in ArrayDatatypes -> { if(lv.heapId==null) - throw FatalAstException("array/matrix should have been moved to heap at ${lv.position}") + throw FatalAstException("arrayspec/matrix should have been moved to heap at ${lv.position}") } else -> {} } @@ -677,7 +702,7 @@ class AstChecker(private val namespace: INameScope, val indexedRegister = postIncrDecr.target.arrayindexed?.register if(indexedRegister!=null) { if(indexedRegister==Register.A || indexedRegister==Register.X || indexedRegister==Register.Y) - checkResult.add(SyntaxError("array indexing on registers requires register pair variable", postIncrDecr.position)) + checkResult.add(SyntaxError("indexing on registers requires register pair variable", postIncrDecr.position)) } else { val target = postIncrDecr.target.arrayindexed?.identifier?.targetStatement(namespace) if(target==null) { @@ -699,25 +724,45 @@ class AstChecker(private val namespace: INameScope, val target = arrayIndexedExpression.identifier!!.targetStatement(namespace) if(target is VarDecl) { if(target.datatype !in IterableDatatypes) - checkResult.add(SyntaxError("array indexing requires an iterable variable", arrayIndexedExpression.position)) + checkResult.add(SyntaxError("indexing requires an iterable variable", arrayIndexedExpression.position)) val arraysize = target.arrayspec?.size() if(arraysize!=null) { // check out of bounds - if((arrayIndexedExpression.array.y as? LiteralValue)?.asIntegerValue != null) { - throw FatalAstException("constant y dimension of index should have been const-folded with x into one value") + if((arrayIndexedExpression.arrayspec.y as? LiteralValue)?.asIntegerValue != null) { + throw FatalAstException("constant y dimension of index should have been const-folded with x into one value ${arrayIndexedExpression.arrayspec.position}") } - val index = (arrayIndexedExpression.array.x as? LiteralValue)?.asIntegerValue + val index = (arrayIndexedExpression.arrayspec.x as? LiteralValue)?.asIntegerValue if(index!=null && (index<0 || index>=arraysize)) - checkResult.add(ExpressionError("array index out of bounds", arrayIndexedExpression.array.position)) + checkResult.add(ExpressionError("arrayspec index out of bounds", arrayIndexedExpression.arrayspec.position)) + } else if(target.datatype in StringDatatypes) { + // check string lengths + (arrayIndexedExpression.arrayspec.y as? LiteralValue)?.asIntegerValue + val heapId = (target.value as LiteralValue).heapId!! + val stringLen = heap.get(heapId).str!!.length + val index = (arrayIndexedExpression.arrayspec.x as? LiteralValue)?.asIntegerValue + if(index!=null && (index<0 || index>=stringLen)) + checkResult.add(ExpressionError("index out of bounds", arrayIndexedExpression.arrayspec.position)) } } else - checkResult.add(SyntaxError("array indexing requires a variable to act upon", arrayIndexedExpression.position)) + checkResult.add(SyntaxError("indexing requires a variable to act upon", arrayIndexedExpression.position)) } else if(reg==Register.A || reg==Register.X || reg==Register.Y) { - checkResult.add(SyntaxError("array indexing on registers requires register pair variable", arrayIndexedExpression.position)) - } else if(arrayIndexedExpression.array.y!=null) { - checkResult.add(SyntaxError("array indexing on registers can only use one index dimension", arrayIndexedExpression.position)) + checkResult.add(SyntaxError("indexing on registers requires register pair variable", arrayIndexedExpression.position)) + } else if(arrayIndexedExpression.arrayspec.y!=null) { + checkResult.add(SyntaxError("indexing on registers can only use one index dimension", arrayIndexedExpression.position)) } + // check index value 0..255 + val regx = (arrayIndexedExpression.arrayspec.x as? RegisterExpr)?.register + val regy = (arrayIndexedExpression.arrayspec.y as? RegisterExpr)?.register + if((regx in setOf(Register.AX, Register.AY, Register.XY)) || + (regy in setOf(Register.AX, Register.AY, Register.XY))) { + checkResult.add(SyntaxError("array indexing is limited to byte size 0..255", arrayIndexedExpression.position)) + } + val dtx = arrayIndexedExpression.arrayspec.x.resultingDatatype(namespace, heap) + val dty = arrayIndexedExpression.arrayspec.y?.resultingDatatype(namespace, heap) + if(dtx!=DataType.UBYTE && dtx!=DataType.BYTE || (dty!=null && dty != DataType.UBYTE && dty != DataType.BYTE)) + checkResult.add(SyntaxError("array indexing is limited to byte size 0..255", arrayIndexedExpression.position)) + return super.process(arrayIndexedExpression) } @@ -760,7 +805,7 @@ class AstChecker(private val namespace: INameScope, val expectedSize = arrayspec!!.size() val rangeSize=range.size() if(rangeSize!=null && rangeSize != expectedSize) { - checkResult.add(ExpressionError("range size doesn't match array/matrix size, expected $expectedSize found $rangeSize", range.position)) + checkResult.add(ExpressionError("range size doesn't match arrayspec/matrix size, expected $expectedSize found $rangeSize", range.position)) return false } return true @@ -825,61 +870,61 @@ class AstChecker(private val namespace: INameScope, return err("string length must be 0-255") } DataType.ARRAY_UB, DataType.ARRAY_B -> { - // value may be either a single byte, or a byte array (of all constant values) + // value may be either a single byte, or a byte arrayspec (of all constant values) if(value.type==targetDt) { val arraySpecSize = arrayspec.size() val arraySize = value.arrayvalue?.size ?: heap.get(value.heapId!!).arraysize if(arraySpecSize!=null && arraySpecSize>0) { if(arraySpecSize<1 || arraySpecSize>256) - return err("byte array length must be 1-256") + return err("byte arrayspec length must be 1-256") val constX = arrayspec.x.constValue(namespace, heap) if(constX?.asIntegerValue==null) - return err("array size specifier must be constant integer value") + return err("arrayspec size specifier must be constant integer value") val expectedSize = constX.asIntegerValue if (arraySize != expectedSize) - return err("initializer array size mismatch (expecting $expectedSize, got $arraySize)") + return err("initializer arrayspec size mismatch (expecting $expectedSize, got $arraySize)") return true } - return err("invalid byte array size, must be 1-256") + return err("invalid byte arrayspec size, must be 1-256") } - return err("invalid byte array initialization value ${value.type}, expected $targetDt") + return err("invalid byte arrayspec initialization value ${value.type}, expected $targetDt") } DataType.ARRAY_UW, DataType.ARRAY_W -> { - // value may be either a single word, or a word array + // value may be either a single word, or a word arrayspec if(value.type==targetDt) { val arraySpecSize = arrayspec.size() val arraySize = value.arrayvalue?.size ?: heap.get(value.heapId!!).arraysize if(arraySpecSize!=null && arraySpecSize>0) { if(arraySpecSize<1 || arraySpecSize>128) - return err("word array length must be 1-128") + return err("word arrayspec length must be 1-128") val constX = arrayspec.x.constValue(namespace, heap) if(constX?.asIntegerValue==null) - return err("array size specifier must be constant integer value") + return err("arrayspec size specifier must be constant integer value") val expectedSize = constX.asIntegerValue if (arraySize != expectedSize) - return err("initializer array size mismatch (expecting $expectedSize, got $arraySize)") + return err("initializer arrayspec size mismatch (expecting $expectedSize, got $arraySize)") return true } - return err("invalid word array size, must be 1-128") + return err("invalid word arrayspec size, must be 1-128") } - return err("invalid word array initialization value ${value.type}, expected $targetDt") + return err("invalid word arrayspec initialization value ${value.type}, expected $targetDt") } DataType.ARRAY_F -> { - // value may be either a single float, or a float array + // value may be either a single float, or a float arrayspec if(value.type==targetDt) { val arraySize = value.arrayvalue?.size ?: heap.get(value.heapId!!).doubleArray!!.size val arraySpecSize = arrayspec.size() if(arraySpecSize!=null && arraySpecSize>0) { if(arraySpecSize < 1 || arraySpecSize>51) - return err("float array length must be 1-51") + return err("float arrayspec length must be 1-51") val constX = arrayspec.x.constValue(namespace, heap) if(constX?.asIntegerValue==null) - return err("array size specifier must be constant integer value") + return err("arrayspec size specifier must be constant integer value") val expectedSize = constX.asIntegerValue if (arraySize != expectedSize) - return err("initializer array size mismatch (expecting $expectedSize, got $arraySize)") + return err("initializer arrayspec size mismatch (expecting $expectedSize, got $arraySize)") } else - return err("invalid float array size, must be 1-51") + return err("invalid float arrayspec size, must be 1-51") // check if the floating point values are all within range val doubles = if(value.arrayvalue!=null) @@ -890,17 +935,17 @@ class AstChecker(private val namespace: INameScope, return err("floating point value overflow") return true } - return err("invalid float array initialization value ${value.type}, expected $targetDt") + return err("invalid float arrayspec initialization value ${value.type}, expected $targetDt") } DataType.MATRIX_UB, DataType.MATRIX_B -> { - // value can only be a single byte, or a byte array (which represents the matrix) + // value can only be a single byte, or a byte arrayspec (which represents the matrix) if(value.type==targetDt || (targetDt==DataType.MATRIX_UB && value.type==DataType.ARRAY_UB) || (targetDt==DataType.MATRIX_B && value.type==DataType.ARRAY_B)) { val arraySpecSize = arrayspec.size() if(arraySpecSize!=null && arraySpecSize>0) { - if(arraySpecSize<1 || arraySpecSize>256) - return err("invalid matrix size, must be 1-256") + if(arraySpecSize<1 || arraySpecSize>32768) + return err("invalid matrix size, must be 1-32768") val constX = arrayspec.x.constValue(namespace, heap) val constY = arrayspec.y?.constValue(namespace, heap) if (constX?.asIntegerValue == null || (constY!=null && constY.asIntegerValue == null)) @@ -912,9 +957,9 @@ class AstChecker(private val namespace: INameScope, return err("initializer matrix size mismatch (expecting $expectedSize, got ${matrix.size} elements)") return true } - return err("invalid matrix size, must be 1-256") + return err("invalid matrix size, must be 1-32768") } - return err("invalid matrix initialization value of type ${value.type} - expecting byte array") + return err("invalid matrix initialization value of type ${value.type} - expecting byte arrayspec") } } return true diff --git a/compiler/src/prog8/ast/AstIdentifiersChecker.kt b/compiler/src/prog8/ast/AstIdentifiersChecker.kt index f48107438..09a4c7ea7 100644 --- a/compiler/src/prog8/ast/AstIdentifiersChecker.kt +++ b/compiler/src/prog8/ast/AstIdentifiersChecker.kt @@ -126,7 +126,7 @@ class AstIdentifiersChecker : IAstProcessor { if(forLoop.decltype!=null) checkResult.add(SyntaxError("register loop variables cannot be explicitly declared with a datatype", forLoop.position)) if(forLoop.loopRegister == Register.X || forLoop.loopRegister==Register.XY || forLoop.loopRegister==Register.AX) - checkResult.add(SyntaxError("it's not possible to write to the X register because it's used as an internal pointer", forLoop.position)) + printWarning("possible problem writing to the X register, because it's used as an internal pointer", forLoop.position) } else if(forLoop.loopVar!=null) { val varName = forLoop.loopVar.nameInSource.last() when (forLoop.decltype) { @@ -148,7 +148,7 @@ class AstIdentifiersChecker : IAstProcessor { override fun process(assignTarget: AssignTarget): AssignTarget { if(assignTarget.register==Register.X || assignTarget.register==Register.AX || assignTarget.register==Register.XY) - checkResult.add(SyntaxError("it's not possible to write to the X register because it's used as an internal pointer", assignTarget.position)) + printWarning("possible problem writing to the X register, because it's used as an internal pointer", assignTarget.position) return super.process(assignTarget) } } diff --git a/compiler/src/prog8/compiler/Compiler.kt b/compiler/src/prog8/compiler/Compiler.kt index 65b45f82f..c3e029c93 100644 --- a/compiler/src/prog8/compiler/Compiler.kt +++ b/compiler/src/prog8/compiler/Compiler.kt @@ -312,7 +312,9 @@ private class StatementTranslator(private val prog: IntermediateProgram, DataType.ARRAY_UW, DataType.ARRAY_W -> Opcode.READ_INDEXED_VAR_WORD DataType.ARRAY_F -> Opcode.READ_INDEXED_VAR_FLOAT DataType.MATRIX_UB, DataType.MATRIX_B -> Opcode.READ_INDEXED_VAR_BYTE - else -> throw CompilerException("invalid dt for indexed $dt") + DataType.STR, DataType.STR_S -> Opcode.READ_INDEXED_VAR_BYTE + DataType.STR_P, DataType.STR_PS -> throw CompilerException("cannot access pascal-string type $dt with index") + else -> throw CompilerException("invalid dt for indexed access $dt") } } @@ -322,7 +324,9 @@ private class StatementTranslator(private val prog: IntermediateProgram, DataType.ARRAY_UW, DataType.ARRAY_W -> Opcode.WRITE_INDEXED_VAR_WORD DataType.ARRAY_F -> Opcode.WRITE_INDEXED_VAR_FLOAT DataType.MATRIX_UB, DataType.MATRIX_B -> Opcode.WRITE_INDEXED_VAR_BYTE - else -> throw CompilerException("invalid dt for indexed $dt") + DataType.STR, DataType.STR_S -> Opcode.WRITE_INDEXED_VAR_BYTE + DataType.STR_P, DataType.STR_PS -> throw CompilerException("cannot access pascal-string type $dt with index") + else -> throw CompilerException("invalid dt for indexed access $dt") } } @@ -350,14 +354,12 @@ private class StatementTranslator(private val prog: IntermediateProgram, private fun opcodePopmem(dt: DataType): Opcode { return when (dt) { - DataType.UBYTE -> Opcode.POP_MEM_UB - DataType.BYTE -> Opcode.POP_MEM_B - DataType.UWORD -> Opcode.POP_MEM_UW - DataType.WORD -> Opcode.POP_MEM_W + DataType.UBYTE, DataType.BYTE -> Opcode.POP_MEM_BYTE + DataType.UWORD, DataType.WORD -> Opcode.POP_MEM_WORD DataType.FLOAT -> Opcode.POP_MEM_FLOAT DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS, DataType.ARRAY_UB, DataType.ARRAY_UW, DataType.ARRAY_F, DataType.MATRIX_UB, - DataType.ARRAY_B, DataType.ARRAY_W, DataType.MATRIX_B -> Opcode.POP_MEM_UW + DataType.ARRAY_B, DataType.ARRAY_W, DataType.MATRIX_B -> Opcode.POP_MEM_WORD } } @@ -628,7 +630,7 @@ private class StatementTranslator(private val prog: IntermediateProgram, DataType.ARRAY_UB, DataType.ARRAY_UW, DataType.ARRAY_F, DataType.MATRIX_UB, DataType.ARRAY_B, DataType.ARRAY_W, DataType.MATRIX_B -> { if(lv.heapId==null) - throw CompilerException("array/matrix should have been moved into heap ${lv.position}") + throw CompilerException("arrayspec/matrix should have been moved into heap ${lv.position}") prog.instr(Opcode.PUSH_WORD, Value(lv.type, lv.heapId)) } } @@ -1046,14 +1048,14 @@ private class StatementTranslator(private val prog: IntermediateProgram, val reg=arrayindexed.register if(reg==Register.A || reg==Register.X || reg==Register.Y) throw CompilerException("requires register pair") - if(arrayindexed.array.y!=null) + if(arrayindexed.arrayspec.y!=null) throw CompilerException("when using an address, can only use one index dimension") reg.toString() } else { variable!!.scopedname } - translate(arrayindexed.array.x) - val y = arrayindexed.array.y + translate(arrayindexed.arrayspec.x) + val y = arrayindexed.arrayspec.y if(y!=null) { // calc matrix index i=y*columns+x // (the const-folding will have removed this for us when both x and y are constants) @@ -1167,12 +1169,12 @@ private class StatementTranslator(private val prog: IntermediateProgram, when (valueDt) { DataType.UBYTE -> prog.instr(Opcode.UB2FLOAT) DataType.BYTE -> prog.instr(Opcode.B2FLOAT) - DataType.UWORD -> prog.instr(Opcode.W2FLOAT) - DataType.WORD -> prog.instr(Opcode.UW2FLOAT) + DataType.UWORD -> prog.instr(Opcode.UW2FLOAT) + DataType.WORD -> prog.instr(Opcode.W2FLOAT) else -> throw CompilerException("incompatible data types valueDt=$valueDt targetDt=$targetDt at $stmt") } } - // todo: maybe if you assign byte or word to array/matrix, clear it with that value? + // todo: maybe if you assign byte or word to arrayspec/matrix, clear it with that value? DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> throw CompilerException("incompatible data types valueDt=$valueDt targetDt=$targetDt at $stmt") DataType.ARRAY_UB, DataType.ARRAY_B, DataType.ARRAY_UW, DataType.ARRAY_W, DataType.ARRAY_F, DataType.MATRIX_UB, DataType.MATRIX_B -> throw CompilerException("incompatible data types valueDt=$valueDt targetDt=$targetDt at $stmt") diff --git a/compiler/src/prog8/compiler/Zeropage.kt b/compiler/src/prog8/compiler/Zeropage.kt index 9235df486..3c6db607f 100644 --- a/compiler/src/prog8/compiler/Zeropage.kt +++ b/compiler/src/prog8/compiler/Zeropage.kt @@ -16,15 +16,15 @@ abstract class Zeropage(private val options: CompilationOptions) { val size = if(vardecl.arrayspec!=null) { - printWarning("allocating a large value (array) in zeropage", vardecl.position) + printWarning("allocating a large value (arrayspec) in zeropage", vardecl.position) val y = (vardecl.arrayspec.y as? LiteralValue)?.asIntegerValue if(y==null) { - // 1 dimensional array + // 1 dimensional arrayspec when(vardecl.datatype) { DataType.UBYTE -> (vardecl.arrayspec.x as LiteralValue).asIntegerValue!! DataType.UWORD -> (vardecl.arrayspec.x as LiteralValue).asIntegerValue!! * 2 DataType.FLOAT -> (vardecl.arrayspec.x as LiteralValue).asIntegerValue!! * 5 - else -> throw CompilerException("array can only be of byte, word, float") + else -> throw CompilerException("arrayspec can only be of byte, word, float") } } else { // 2 dimensional matrix (only bytes for now) diff --git a/compiler/src/prog8/compiler/intermediate/Instruction.kt b/compiler/src/prog8/compiler/intermediate/Instruction.kt index 269393c11..ac9a48dfb 100644 --- a/compiler/src/prog8/compiler/intermediate/Instruction.kt +++ b/compiler/src/prog8/compiler/intermediate/Instruction.kt @@ -25,10 +25,6 @@ open class Instruction(val opcode: Opcode, // opcodes that manipulate a variable "${opcode.toString().toLowerCase()} ${callLabel?:""} ${callLabel2?:""}".trimEnd() } - opcode in setOf(Opcode.COPY_MEM_BYTE, Opcode.COPY_MEM_WORD, Opcode.COPY_MEM_FLOAT) -> { - // opcodes with two (address) args - "${opcode.toString().toLowerCase()} $arg $arg2" - } callLabel==null -> "${opcode.toString().toLowerCase()} $argStr" else -> "${opcode.toString().toLowerCase()} $callLabel $argStr" } diff --git a/compiler/src/prog8/compiler/intermediate/IntermediateProgram.kt b/compiler/src/prog8/compiler/intermediate/IntermediateProgram.kt index 5471449a1..db6eee886 100644 --- a/compiler/src/prog8/compiler/intermediate/IntermediateProgram.kt +++ b/compiler/src/prog8/compiler/intermediate/IntermediateProgram.kt @@ -79,54 +79,47 @@ class IntermediateProgram(val name: String, var loadAddress: Int, val heap: Heap when (it[0].value.opcode) { Opcode.PUSH_VAR_BYTE -> if (it[1].value.opcode == Opcode.POP_VAR_BYTE) { - if (it[0].value.callLabel != it[1].value.callLabel) - instructionsToReplace[it[0].index] = Instruction(Opcode.COPY_VAR_BYTE, null, null, it[0].value.callLabel, it[1].value.callLabel) - else + if (it[0].value.callLabel == it[1].value.callLabel) { instructionsToReplace[it[0].index] = Instruction(Opcode.NOP) - instructionsToReplace[it[1].index] = Instruction(Opcode.NOP) + instructionsToReplace[it[1].index] = Instruction(Opcode.NOP) + } } Opcode.PUSH_VAR_WORD -> if (it[1].value.opcode == Opcode.POP_VAR_WORD) { - if (it[0].value.callLabel != it[1].value.callLabel) - instructionsToReplace[it[0].index] = Instruction(Opcode.COPY_VAR_WORD, null, null, it[0].value.callLabel, it[1].value.callLabel) - else + if (it[0].value.callLabel == it[1].value.callLabel) { instructionsToReplace[it[0].index] = Instruction(Opcode.NOP) - instructionsToReplace[it[1].index] = Instruction(Opcode.NOP) + instructionsToReplace[it[1].index] = Instruction(Opcode.NOP) + } } Opcode.PUSH_VAR_FLOAT -> if (it[1].value.opcode == Opcode.POP_VAR_FLOAT) { - if (it[0].value.callLabel != it[1].value.callLabel) - instructionsToReplace[it[0].index] = Instruction(Opcode.COPY_VAR_FLOAT, null, null, it[0].value.callLabel, it[1].value.callLabel) - else + if (it[0].value.callLabel == it[1].value.callLabel) { instructionsToReplace[it[0].index] = Instruction(Opcode.NOP) - instructionsToReplace[it[1].index] = Instruction(Opcode.NOP) + instructionsToReplace[it[1].index] = Instruction(Opcode.NOP) + } } Opcode.PUSH_MEM_B, Opcode.PUSH_MEM_UB -> - if(it[1].value.opcode == Opcode.POP_MEM_B || it[1].value.opcode == Opcode.POP_MEM_UB) { - if(it[0].value.arg != it[1].value.arg) - instructionsToReplace[it[0].index] = Instruction(Opcode.COPY_MEM_BYTE, it[0].value.arg, it[1].value.arg) - else + if(it[1].value.opcode == Opcode.POP_MEM_BYTE) { + if(it[0].value.arg == it[1].value.arg) { instructionsToReplace[it[0].index] = Instruction(Opcode.NOP) - instructionsToReplace[it[1].index] = Instruction(Opcode.NOP) + instructionsToReplace[it[1].index] = Instruction(Opcode.NOP) + } } Opcode.PUSH_MEM_W, Opcode.PUSH_MEM_UW -> - if(it[1].value.opcode == Opcode.POP_MEM_W || it[1].value.opcode == Opcode.POP_MEM_UW) { - if(it[0].value.arg != it[1].value.arg) - instructionsToReplace[it[0].index] = Instruction(Opcode.COPY_MEM_WORD, it[0].value.arg, it[1].value.arg) - else + if(it[1].value.opcode == Opcode.POP_MEM_WORD) { + if(it[0].value.arg == it[1].value.arg) { instructionsToReplace[it[0].index] = Instruction(Opcode.NOP) - instructionsToReplace[it[1].index] = Instruction(Opcode.NOP) + instructionsToReplace[it[1].index] = Instruction(Opcode.NOP) + } } Opcode.PUSH_MEM_FLOAT -> if(it[1].value.opcode == Opcode.POP_MEM_FLOAT) { - if(it[0].value.arg != it[1].value.arg) - instructionsToReplace[it[0].index] = Instruction(Opcode.COPY_MEM_FLOAT, it[0].value.arg, it[1].value.arg) - else + if(it[0].value.arg == it[1].value.arg) { instructionsToReplace[it[0].index] = Instruction(Opcode.NOP) - instructionsToReplace[it[1].index] = Instruction(Opcode.NOP) + instructionsToReplace[it[1].index] = Instruction(Opcode.NOP) + } } - else -> { - } + else -> {} } } @@ -289,7 +282,7 @@ class IntermediateProgram(val name: String, var loadAddress: Int, val heap: Heap DataType.ARRAY_UB, DataType.ARRAY_UW, DataType.ARRAY_F -> { val litval = (decl.value as LiteralValue) if(litval.heapId==null) - throw CompilerException("array/matrix should already be in the heap") + throw CompilerException("arrayspec/matrix should already be in the heap") Value(decl.datatype, litval.heapId) } } diff --git a/compiler/src/prog8/compiler/intermediate/Opcode.kt b/compiler/src/prog8/compiler/intermediate/Opcode.kt index f9ab137fb..cc7c1bf23 100644 --- a/compiler/src/prog8/compiler/intermediate/Opcode.kt +++ b/compiler/src/prog8/compiler/intermediate/Opcode.kt @@ -4,7 +4,7 @@ enum class Opcode { // pushing values on the (evaluation) stack PUSH_BYTE, // push byte value - PUSH_WORD, // push word value (or 'address' of string / array / matrix) + PUSH_WORD, // push word value (or 'address' of string / arrayspec / matrix) PUSH_FLOAT, // push float value PUSH_MEM_B, // push byte value from memory to stack PUSH_MEM_UB, // push unsigned byte value from memory to stack @@ -19,23 +19,13 @@ enum class Opcode { DISCARD_BYTE, // discard top byte value DISCARD_WORD, // discard top word value DISCARD_FLOAT, // discard top float value - POP_MEM_B, // pop byte value into destination memory address - POP_MEM_UB, // pop byte value into destination memory address - POP_MEM_W, // pop word value into destination memory address - POP_MEM_UW, // pop word value into destination memory address + POP_MEM_BYTE, // pop (u)byte value into destination memory address + POP_MEM_WORD, // pop (u)word value into destination memory address POP_MEM_FLOAT, // pop float value into destination memory address - POP_VAR_BYTE, // pop byte value into variable (byte, ubyte) - POP_VAR_WORD, // pop word value into variable (word, uword) + POP_VAR_BYTE, // pop (u)byte value into variable + POP_VAR_WORD, // pop (u)word value into variable POP_VAR_FLOAT, // pop float value into variable - // optimized copying of one var to another (replaces push+pop) - COPY_VAR_BYTE, - COPY_VAR_WORD, - COPY_VAR_FLOAT, - COPY_MEM_BYTE, - COPY_MEM_WORD, - COPY_MEM_FLOAT, - // numeric arithmetic ADD_UB, ADD_B, @@ -187,7 +177,7 @@ enum class Opcode { NOTEQUAL_WORD, NOTEQUAL_F, - // array access + // arrayspec access READ_INDEXED_VAR_BYTE, READ_INDEXED_VAR_WORD, READ_INDEXED_VAR_FLOAT, @@ -233,32 +223,6 @@ val opcodesWithVarArgument = setOf( Opcode.ROL2_VAR_BYTE, Opcode.ROL2_VAR_WORD, Opcode.ROR2_VAR_BYTE, Opcode.ROR2_VAR_WORD, Opcode.POP_VAR_BYTE, Opcode.POP_VAR_WORD, Opcode.POP_VAR_FLOAT, Opcode.PUSH_VAR_BYTE, Opcode.PUSH_VAR_WORD, Opcode.PUSH_VAR_FLOAT, - Opcode.COPY_VAR_BYTE, Opcode.COPY_VAR_WORD, Opcode.COPY_VAR_FLOAT, Opcode.READ_INDEXED_VAR_BYTE, Opcode.READ_INDEXED_VAR_WORD, Opcode.READ_INDEXED_VAR_FLOAT, Opcode.WRITE_INDEXED_VAR_BYTE, Opcode.WRITE_INDEXED_VAR_WORD, Opcode.WRITE_INDEXED_VAR_FLOAT ) - -val pushOpcodes = setOf( - Opcode.PUSH_BYTE, - Opcode.PUSH_WORD, - Opcode.PUSH_FLOAT, - Opcode.PUSH_MEM_B, - Opcode.PUSH_MEM_UB, - Opcode.PUSH_MEM_W, - Opcode.PUSH_MEM_UW, - Opcode.PUSH_MEM_FLOAT, - Opcode.PUSH_VAR_BYTE, - Opcode.PUSH_VAR_WORD, - Opcode.PUSH_VAR_FLOAT -) - -val popOpcodes = setOf( - Opcode.POP_MEM_B, - Opcode.POP_MEM_UB, - Opcode.POP_MEM_W, - Opcode.POP_MEM_UW, - Opcode.POP_MEM_FLOAT, - Opcode.POP_VAR_BYTE, - Opcode.POP_VAR_WORD, - Opcode.POP_VAR_FLOAT -) \ No newline at end of file diff --git a/compiler/src/prog8/compiler/target/c64/AsmGen.kt b/compiler/src/prog8/compiler/target/c64/AsmGen.kt index eb9ccf55f..b95e449e6 100644 --- a/compiler/src/prog8/compiler/target/c64/AsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/AsmGen.kt @@ -173,7 +173,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, out("* = ${block.address?.toHex()}") } out("${block.shortname}\t.proc\n") - out("\n; constants/memdefs/kernel subroutines") + out("\n; memdefs and kernel subroutines") memdefs2asm(block) out("\n; variables") vardecls2asm(block) @@ -218,7 +218,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, out("\t.byte " + chunk.joinToString()) } DataType.ARRAY_UB, DataType.MATRIX_UB -> { - // unsigned integer byte array + // unsigned integer byte arrayspec val data = makeArrayFillDataUnsigned(v.second) if (data.size <= 16) out("${v.first}\t.byte ${data.joinToString()}") @@ -229,7 +229,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, } } DataType.ARRAY_B, DataType.MATRIX_B -> { - // signed integer byte array + // signed integer byte arrayspec val data = makeArrayFillDataSigned(v.second) if (data.size <= 16) out("${v.first}\t.char ${data.joinToString()}") @@ -240,7 +240,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, } } DataType.ARRAY_UW -> { - // unsigned word array + // unsigned word arrayspec val data = makeArrayFillDataUnsigned(v.second) if (data.size <= 16) out("${v.first}\t.word ${data.joinToString()}") @@ -251,7 +251,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, } } DataType.ARRAY_W -> { - // signed word array + // signed word arrayspec val data = makeArrayFillDataSigned(v.second) if (data.size <= 16) out("${v.first}\t.sint ${data.joinToString()}") @@ -262,7 +262,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, } } DataType.ARRAY_F -> { - // float array + // float arrayspec val array = heap.get(v.second.heapId).doubleArray!! val floatFills = array.map { makeFloatFill(Mflpt5.fromNumber(it)) } out(v.first) @@ -302,7 +302,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, return if (value.type == DataType.ARRAY_UB || value.type == DataType.ARRAY_UW || value.type == DataType.MATRIX_UB) array.map { "$"+it.toString(16).padStart(2, '0') } else - throw AssemblyError("invalid array type") + throw AssemblyError("invalid arrayspec type") } private fun makeArrayFillDataSigned(value: Value): List { @@ -315,7 +315,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, "-$"+abs(it).toString(16).padStart(2, '0') } } - else throw AssemblyError("invalid array type") + else throw AssemblyError("invalid arrayspec type") } private fun instr2asm(ins: List): Int { @@ -445,14 +445,14 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, // """ // } - Opcode.POP_MEM_B, Opcode.POP_MEM_UB -> { + Opcode.POP_MEM_BYTE -> { """ inx lda ${ESTACK_LO.toHex()},x sta ${ins.arg!!.integerValue().toHex()} """ } - Opcode.POP_MEM_W, Opcode.POP_MEM_UW -> { + Opcode.POP_MEM_WORD -> { """ inx lda ${ESTACK_LO.toHex()},x @@ -481,106 +481,6 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, " lda #<${ins.callLabel} | ldy #>${ins.callLabel} | jsr prog8_lib.pop_var_float" } - Opcode.COPY_VAR_BYTE -> { - when { - ins.callLabel2 in registerStrings -> { - val reg2 = ins.callLabel2!!.toLowerCase() - if (ins.callLabel in registerStrings) { - val reg1 = ins.callLabel!!.toLowerCase() - // register -> register - return when { - reg1 == "a" -> " ta$reg2" - reg2 == "a" -> " t${reg1}a" - else -> " t${reg1}a | ta$reg2" // 6502 doesn't have tyx/txy - } - } - // var -> reg - return " ld${ins.callLabel2.toLowerCase()} ${ins.callLabel}" - } - ins.callLabel in registerStrings -> - // reg -> var - return " st${ins.callLabel!!.toLowerCase()} ${ins.callLabel2}" - else -> - // var -> var - return " lda ${ins.callLabel} | sta ${ins.callLabel2}" - } - } - Opcode.COPY_VAR_WORD -> { - when { - ins.callLabel2 in registerStrings -> { - if (ins.callLabel in registerStrings) { - // copying registerpair -> registerpair - when { - ins.callLabel == "AX" -> return when (ins.callLabel2) { - "AY" -> " txy" - "XY" -> " stx ${C64Zeropage.SCRATCH_B1.toHex()} | tax | ldy ${C64Zeropage.SCRATCH_B1.toHex()}" - else -> "" - } - ins.callLabel == "AY" -> return when (ins.callLabel2) { - "AX" -> " sty ${C64Zeropage.SCRATCH_B1.toHex()} | ldx ${C64Zeropage.SCRATCH_B1.toHex()}" - "XY" -> " tax" - else -> "" - } - else /* XY */ -> return when (ins.callLabel2) { - "AX" -> " txa | sty ${C64Zeropage.SCRATCH_B1.toHex()} | ldx ${C64Zeropage.SCRATCH_B1.toHex()}" - "AY" -> " txa" - else -> "" - } - } - } - // wvar -> regpair - val regpair = ins.callLabel2!!.toLowerCase() - return " ld${regpair[0]} ${ins.callLabel} | ld${regpair[1]} ${ins.callLabel}+1" - } - ins.callLabel in registerStrings -> { - // regpair->wvar - val regpair = ins.callLabel!!.toLowerCase() - return " st${regpair[0]} ${ins.callLabel2} | st${regpair[1]} ${ins.callLabel2}+1" - } - else -> { - // wvar->wvar - return " lda ${ins.callLabel} | sta ${ins.callLabel2} | " + - " lda ${ins.callLabel}+1 | sta ${ins.callLabel2}+1" - } - } - } - Opcode.COPY_VAR_FLOAT -> { - """ - lda #<${ins.callLabel} - ldy #>${ins.callLabel} - sta ${C64Zeropage.SCRATCH_W1} - sty ${C64Zeropage.SCRATCH_W1+1} - lda #<${ins.callLabel2} - ldy #>${ins.callLabel2} - sta ${C64Zeropage.SCRATCH_W2} - sty ${C64Zeropage.SCRATCH_W2+1} - jsr prog8_lib.copy_float - """ - } - - Opcode.COPY_MEM_BYTE -> " lda ${ins.arg!!.integerValue().toHex()} | sta ${ins.arg2!!.integerValue().toHex()}" - Opcode.COPY_MEM_WORD -> { - """ - lda ${ins.arg!!.integerValue().toHex()} - sta ${ins.arg2!!.integerValue().toHex()} - lda ${(ins.arg.integerValue()+1).toHex()} - sta ${(ins.arg2.integerValue()+1).toHex()} - """ - } - Opcode.COPY_MEM_FLOAT -> { - """ - lda #<${ins.arg!!.integerValue().toHex()} - ldy #>${ins.arg.integerValue().toHex()} - sta ${C64Zeropage.SCRATCH_W1} - sty ${C64Zeropage.SCRATCH_W1+1} - lda #<${ins.arg2!!.integerValue().toHex()} - ldy #>${ins.arg2.integerValue().toHex()} - sta ${C64Zeropage.SCRATCH_W2} - sty ${C64Zeropage.SCRATCH_W2+1} - jsr prog8_lib.copy_float - """ - } - Opcode.INC_VAR_UB, Opcode.INC_VAR_B -> { when (ins.callLabel) { "A" -> " clc | adc #1" @@ -713,11 +613,11 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, """ } Opcode.ADD_F -> " jsr prog8_lib.add_f" - Opcode.ADD_W -> " jsr prog8_lib.add_w" // todo or inline rather - Opcode.ADD_UW -> " jsr prog8_lib.add_uw" // todo or inline rather + Opcode.ADD_W -> " jsr prog8_lib.add_w" // todo or inline? + Opcode.ADD_UW -> " jsr prog8_lib.add_uw" // todo or inline? Opcode.SUB_F -> " jsr prog8_lib.sub_f" - Opcode.SUB_W -> " jsr prog8_lib.sub_w" // todo or inline rather - Opcode.SUB_UW -> " jsr prog8_lib.sub_uw" // todo or inline rather + Opcode.SUB_W -> " jsr prog8_lib.sub_w" // todo or inline? + Opcode.SUB_UW -> " jsr prog8_lib.sub_uw" // todo or inline? Opcode.MUL_F -> " jsr prog8_lib.mul_f" Opcode.MUL_B -> " jsr prog8_lib.mul_b" Opcode.MUL_UB -> " jsr prog8_lib.mul_ub" @@ -754,22 +654,6 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, val opcodes = segment.map { it.opcode } val result = mutableListOf() - // check for direct var assignments that should have been converted into COPY_VAR_XXX opcodes - if((opcodes[0]==Opcode.PUSH_VAR_BYTE && opcodes[1]==Opcode.POP_VAR_BYTE) || - (opcodes[0]==Opcode.PUSH_VAR_WORD && opcodes[1]==Opcode.POP_VAR_WORD) || - (opcodes[0]==Opcode.PUSH_VAR_FLOAT && opcodes[1]==Opcode.POP_VAR_FLOAT) || - (opcodes[0]==Opcode.PUSH_MEM_B && opcodes[1]==Opcode.POP_MEM_B) || - (opcodes[0]==Opcode.PUSH_MEM_B && opcodes[1]==Opcode.POP_MEM_UB) || - (opcodes[0]==Opcode.PUSH_MEM_UB && opcodes[1]==Opcode.POP_MEM_B) || - (opcodes[0]==Opcode.PUSH_MEM_UB && opcodes[1]==Opcode.POP_MEM_UB) || - (opcodes[0]==Opcode.PUSH_MEM_W && opcodes[1]==Opcode.POP_MEM_W) || - (opcodes[0]==Opcode.PUSH_MEM_W && opcodes[1]==Opcode.POP_MEM_UW) || - (opcodes[0]==Opcode.PUSH_MEM_UW && opcodes[1]==Opcode.POP_MEM_W) || - (opcodes[0]==Opcode.PUSH_MEM_UW && opcodes[1]==Opcode.POP_MEM_UW) || - (opcodes[0]==Opcode.PUSH_MEM_FLOAT && opcodes[1]==Opcode.POP_MEM_FLOAT)) { - throw AssemblyError("push+pop var/mem should have been changed into COPY_VAR_XXX opcode") - } - // check for operations that modify a single value, by putting it on the stack (and popping it afterwards) if((opcodes[0]==Opcode.PUSH_VAR_BYTE && opcodes[2]==Opcode.POP_VAR_BYTE) || (opcodes[0]==Opcode.PUSH_VAR_WORD && opcodes[2]==Opcode.POP_VAR_WORD) || @@ -782,10 +666,10 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, } } } - else if((opcodes[0]==Opcode.PUSH_MEM_UB && opcodes[2]==Opcode.POP_MEM_UB) || - (opcodes[0]==Opcode.PUSH_MEM_B && opcodes[2]==Opcode.POP_MEM_B) || - (opcodes[0]==Opcode.PUSH_MEM_UW && opcodes[2]==Opcode.POP_MEM_UW) || - (opcodes[0]==Opcode.PUSH_MEM_W && opcodes[2]==Opcode.POP_MEM_W) || + else if((opcodes[0]==Opcode.PUSH_MEM_UB && opcodes[2]==Opcode.POP_MEM_BYTE) || + (opcodes[0]==Opcode.PUSH_MEM_B && opcodes[2]==Opcode.POP_MEM_BYTE) || + (opcodes[0]==Opcode.PUSH_MEM_UW && opcodes[2]==Opcode.POP_MEM_WORD) || + (opcodes[0]==Opcode.PUSH_MEM_W && opcodes[2]==Opcode.POP_MEM_WORD) || (opcodes[0]==Opcode.PUSH_MEM_FLOAT && opcodes[2]==Opcode.POP_MEM_FLOAT)) { if(segment[0].arg==segment[2].arg) { val fragment = sameMemOperation(segment[0].arg!!.integerValue(), segment[1]) @@ -820,8 +704,13 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, } } - for(pattern in patterns.filter { it.sequence.size <= segment.size}) { - if(pattern.sequence == opcodes.subList(0, pattern.sequence.size)) { + for(pattern in patterns.filter { it.sequence.size <= segment.size || (it.altSequence != null && it.altSequence.size <= segment.size)}) { + val opcodesList = opcodes.subList(0, pattern.sequence.size) + if(pattern.sequence == opcodesList) { + val asm = pattern.asm(segment) + if(asm!=null) + result.add(AsmFragment(asm, pattern.sequence.size)) + } else if(pattern.altSequence == opcodesList) { val asm = pattern.asm(segment) if(asm!=null) result.add(AsmFragment(asm, pattern.sequence.size)) @@ -835,16 +724,16 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, return when(ins.opcode) { Opcode.SHL_BYTE -> AsmFragment(" asl $variable+$index", 8) Opcode.SHR_BYTE -> AsmFragment(" lsr $variable+$index", 8) - Opcode.SHL_WORD -> AsmFragment(" asl $variable+$index | rol $variable+$index+1", 8) - Opcode.SHR_WORD -> AsmFragment(" lsr $variable+$index+1,x | ror $variable+$index", 8) + Opcode.SHL_WORD -> AsmFragment(" asl $variable+$index | rol $variable+${index+1}", 8) + Opcode.SHR_WORD -> AsmFragment(" lsr $variable+${index+1},x | ror $variable+$index", 8) Opcode.ROL_BYTE -> AsmFragment(" rol $variable+$index", 8) Opcode.ROR_BYTE -> AsmFragment(" ror $variable+$index", 8) - Opcode.ROL_WORD -> AsmFragment(" rol $variable+$index | rol $variable+$index+1", 8) - Opcode.ROR_WORD -> AsmFragment(" ror $variable+$index+1 | ror $variable+$index", 8) + Opcode.ROL_WORD -> AsmFragment(" rol $variable+$index | rol $variable+${index+1}", 8) + Opcode.ROR_WORD -> AsmFragment(" ror $variable+${index+1} | ror $variable+$index", 8) Opcode.ROL2_BYTE -> AsmFragment(" lda $variable+$index | cmp #\$80 | rol $variable+$index", 8) Opcode.ROR2_BYTE -> AsmFragment(" lda $variable+$index | lsr a | bcc + | ora #\$80 |+ | sta $variable+$index", 10) - Opcode.ROL2_WORD -> AsmFragment(" asl $variable+$index | rol $variable+$index+1 | bcc + | inc $variable+$index |+",20) - Opcode.ROR2_WORD -> AsmFragment(" lsr $variable+$index+1 | ror $variable+$index | bcc + | lda $variable+$index+1 | ora #\$80 | sta $variable+$index+1 |+", 30) + Opcode.ROL2_WORD -> AsmFragment(" asl $variable+$index | rol $variable+${index+1} | bcc + | inc $variable+$index |+",20) + Opcode.ROR2_WORD -> AsmFragment(" lsr $variable+${index+1} | ror $variable+$index | bcc + | lda $variable+${index+1} | ora #\$80 | sta $variable+${index+1} |+", 30) else -> null } } @@ -1009,7 +898,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, "AX" -> AsmFragment(" sta ${C64Zeropage.SCRATCH_W1} | stx ${C64Zeropage.SCRATCH_W1+1} | jsr prog8_lib.ror2_word | lda ${C64Zeropage.SCRATCH_W1} | ldx ${C64Zeropage.SCRATCH_W1+1}", 20) "AY" -> AsmFragment(" sta ${C64Zeropage.SCRATCH_W1} | sty ${C64Zeropage.SCRATCH_W1+1} | jsr prog8_lib.ror2_word | lda ${C64Zeropage.SCRATCH_W1} | ldy ${C64Zeropage.SCRATCH_W1+1}", 20) "XY" -> AsmFragment(" stx ${C64Zeropage.SCRATCH_W1} | sty ${C64Zeropage.SCRATCH_W1+1} | jsr prog8_lib.ror2_word | ldx ${C64Zeropage.SCRATCH_W1} | ldy ${C64Zeropage.SCRATCH_W1+1}", 20) - else -> AsmFragment(" lda $variable | sta ${C64Zeropage.SCRATCH_W1} | lda $variable+1 | sta ${C64Zeropage.SCRATCH_W1+1} | jsr prog8_lib.ror2_word | lda ${C64Zeropage.SCRATCH_W1} | sta $variable | lda ${C64Zeropage.SCRATCH_W1+1} | sta $variable+1", 30) + else -> AsmFragment(" lda $variable | sta ${C64Zeropage.SCRATCH_W1} | lda $variable+1 | sta ${C64Zeropage.SCRATCH_W1+1} | jsr prog8_lib.ror2_word | lda ${C64Zeropage.SCRATCH_W1} | sta $variable | lda ${C64Zeropage.SCRATCH_W1+1} | sta $variable+1", 30) } } // Opcode.SYSCALL -> { @@ -1021,11 +910,12 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, class AsmFragment(val asm: String, var segmentSize: Int=0) - class AsmPattern(val sequence: List, val asm: (List)->String?) + class AsmPattern(val sequence: List, val altSequence: List?=null, val asm: (List)->String?) private val patterns = listOf( - // assignment: var = byte + // ----------- assignment to BYTE VARIABLE ---------------- + // var = bytevalue AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.POP_VAR_BYTE)) { segment -> when (segment[1].callLabel) { "A", "X", "Y" -> @@ -1034,45 +924,178 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, " lda #${segment[0].arg!!.integerValue().toHex()} | sta ${segment[1].callLabel}" } }, - - // assignment: mem = bytevar/ubytevar - AsmPattern(listOf(Opcode.PUSH_VAR_BYTE, Opcode.POP_MEM_B)) { segment -> - when(segment[0].callLabel) { - "A", "X", "Y" -> TODO("$segment") - else -> " lda ${segment[0].callLabel} | sta ${segment[1].arg!!.integerValue().toHex()}" + // var = other var + AsmPattern(listOf(Opcode.PUSH_VAR_BYTE, Opcode.POP_VAR_BYTE)) { segment -> + when(segment[1].callLabel) { + "A" -> + when(segment[0].callLabel) { + "A" -> null + "X" -> " txa" + "Y" -> " tya" + else -> " lda ${segment[0].callLabel}" + } + "X" -> + when(segment[0].callLabel) { + "A" -> " tax" + "X" -> null + "Y" -> " tya | tax" + else -> " ldx ${segment[0].callLabel}" + } + "Y" -> + when(segment[0].callLabel) { + "A" -> " tay" + "X" -> " txa | tay" + "Y" -> null + else -> " ldy ${segment[0].callLabel}" + } + else -> + when(segment[0].callLabel) { + "A" -> " sta ${segment[1].callLabel}" + "X" -> " stx ${segment[1].callLabel}" + "Y" -> " sty ${segment[1].callLabel}" + else -> " lda ${segment[0].callLabel} | sta ${segment[1].callLabel}" + } } }, - AsmPattern(listOf(Opcode.PUSH_VAR_BYTE, Opcode.POP_MEM_UB)) { segment -> - when(segment[0].callLabel) { - "A", "X", "Y" -> TODO("$segment") - else -> " lda ${segment[0].callLabel} | sta ${segment[1].arg!!.integerValue().toHex()}" - } - }, - - // assignment: mem = byte/ubyte - AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.POP_MEM_B)) { segment -> - " lda #${segment[0].arg!!.integerValue().toHex()} | sta ${segment[1].arg!!.integerValue().toHex()}" - }, - AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.POP_MEM_UB)) { segment -> - " lda #${segment[0].arg!!.integerValue().toHex()} | sta ${segment[1].arg!!.integerValue().toHex()}" - }, - - // assignment: (u)bytevar = membyte - AsmPattern(listOf(Opcode.PUSH_MEM_B, Opcode.POP_VAR_BYTE)) { segment -> + // var = mem (u)byte + AsmPattern( + listOf(Opcode.PUSH_MEM_B, Opcode.POP_VAR_BYTE), + listOf(Opcode.PUSH_MEM_UB, Opcode.POP_VAR_BYTE)) { segment -> when(segment[1].callLabel) { "A", "X", "Y" -> " ld${segment[1].callLabel!!.toLowerCase()} ${segment[0].arg!!.integerValue().toHex()}" else -> " lda ${segment[0].arg!!.integerValue().toHex()} | sta ${segment[1].callLabel}" } }, - AsmPattern(listOf(Opcode.PUSH_MEM_UB, Opcode.POP_VAR_BYTE)) { segment -> + // var = bytearray[index] + AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.READ_INDEXED_VAR_BYTE, Opcode.POP_VAR_BYTE)) { segment -> + val index = segment[0].arg!!.integerValue() when(segment[1].callLabel) { - "A", "X", "Y" -> " ld${segment[1].callLabel!!.toLowerCase()} ${segment[0].arg!!.integerValue().toHex()}" - else -> " lda ${segment[0].arg!!.integerValue().toHex()} | sta ${segment[1].callLabel}" + "AX" -> when(segment[2].callLabel) { + "A" -> " sta ${C64Zeropage.SCRATCH_W1} | stx ${C64Zeropage.SCRATCH_W1+1} | ldy #$index | lda (${C64Zeropage.SCRATCH_W1}),y" + "X" -> " sta ${C64Zeropage.SCRATCH_W1} | stx ${C64Zeropage.SCRATCH_W1+1} | ldy #$index | lda (${C64Zeropage.SCRATCH_W1}),y | tax" + "Y" -> " sta ${C64Zeropage.SCRATCH_W1} | stx ${C64Zeropage.SCRATCH_W1+1} | ldy #$index | lda (${C64Zeropage.SCRATCH_W1}),y | tay" + else -> " sta ${C64Zeropage.SCRATCH_W1} | stx ${C64Zeropage.SCRATCH_W1+1} | ldy #$index | lda (${C64Zeropage.SCRATCH_W1}),y | sta ${segment[2].callLabel}" + } + "AY" -> when(segment[2].callLabel) { + "A" -> " sta ${C64Zeropage.SCRATCH_W1} | sty ${C64Zeropage.SCRATCH_W1+1} | ldy #$index | lda (${C64Zeropage.SCRATCH_W1}),y" + "X" -> " sta ${C64Zeropage.SCRATCH_W1} | sty ${C64Zeropage.SCRATCH_W1+1} | ldy #$index | lda (${C64Zeropage.SCRATCH_W1}),y | tax" + "Y" -> " sta ${C64Zeropage.SCRATCH_W1} | sty ${C64Zeropage.SCRATCH_W1+1} | ldy #$index | lda (${C64Zeropage.SCRATCH_W1}),y | tay" + else -> " sta ${C64Zeropage.SCRATCH_W1} | sty ${C64Zeropage.SCRATCH_W1+1} | ldy #$index | lda (${C64Zeropage.SCRATCH_W1}),y | sta ${segment[2].callLabel}" + } + "XY" -> when(segment[2].callLabel) { + "A" -> " stx ${C64Zeropage.SCRATCH_W1} | sty ${C64Zeropage.SCRATCH_W1+1} | ldy #$index | lda (${C64Zeropage.SCRATCH_W1}),y" + "X" -> " stx ${C64Zeropage.SCRATCH_W1} | sty ${C64Zeropage.SCRATCH_W1+1} | ldy #$index | lda (${C64Zeropage.SCRATCH_W1}),y | tax" + "Y" -> " stx ${C64Zeropage.SCRATCH_W1} | sty ${C64Zeropage.SCRATCH_W1+1} | ldy #$index | lda (${C64Zeropage.SCRATCH_W1}),y | tay" + else -> " stx ${C64Zeropage.SCRATCH_W1} | sty ${C64Zeropage.SCRATCH_W1+1} | ldy #$index | lda (${C64Zeropage.SCRATCH_W1}),y | sta ${segment[2].callLabel}" + } + else -> + when (segment[2].callLabel) { + "A", "X", "Y" -> + " ld${segment[2].callLabel!!.toLowerCase()} ${segment[1].callLabel}+$index" + else -> + " lda ${segment[1].callLabel}+$index | sta ${segment[2].callLabel}" + } + } + }, + // var = bytearray[indexvar] + AsmPattern(listOf(Opcode.PUSH_VAR_BYTE, Opcode.READ_INDEXED_VAR_BYTE, Opcode.POP_VAR_BYTE)) { segment -> + // TODO reuse: load byte in A + val setupPtr: String + val loadByte: String + when(segment[1].callLabel) { + "AX" -> { + setupPtr = "sta ${C64Zeropage.SCRATCH_W1} | stx ${C64Zeropage.SCRATCH_W1 + 1} " + loadByte = when (segment[0].callLabel) { + "A" -> "tay | lda (${C64Zeropage.SCRATCH_W1}),y" + "X" -> "txa | tay | lda (${C64Zeropage.SCRATCH_W1}),y" + "Y" -> "lda (${C64Zeropage.SCRATCH_W1}),y" + else -> "ldy ${segment[0].callLabel} | lda (${C64Zeropage.SCRATCH_W1}),y" + } + } + "AY" -> { + setupPtr = " sta ${C64Zeropage.SCRATCH_W1} | sty ${C64Zeropage.SCRATCH_W1 + 1} " + loadByte = when (segment[0].callLabel) { + "A" -> "tay | lda (${C64Zeropage.SCRATCH_W1}),y" + "X" -> "txa | tay | lda (${C64Zeropage.SCRATCH_W1}),y" + "Y" -> "lda (${C64Zeropage.SCRATCH_W1}),y" + else -> "ldy ${segment[0].callLabel} | lda (${C64Zeropage.SCRATCH_W1}),y" + } + } + "XY" -> { + setupPtr = " stx ${C64Zeropage.SCRATCH_W1} | sty ${C64Zeropage.SCRATCH_W1 + 1} " + loadByte = when (segment[0].callLabel) { + "A" -> "tay | lda (${C64Zeropage.SCRATCH_W1}),y" + "X" -> "txa | tay | lda (${C64Zeropage.SCRATCH_W1}),y" + "Y" -> "lda (${C64Zeropage.SCRATCH_W1}),y" + else -> "ldy ${segment[0].callLabel} | lda (${C64Zeropage.SCRATCH_W1}),y" + } + } + else -> { + when (segment[0].callLabel) { + "A" -> { + setupPtr = "" + loadByte = "tay | lda ${segment[1].callLabel},y" + } + "X" -> { + setupPtr = "" + loadByte = "txa | tay | lda ${segment[1].callLabel},y" + } + "Y" -> { + setupPtr = "" + loadByte = "lda ${segment[1].callLabel},y" + } + else -> { + setupPtr = "" + loadByte = "ldy ${segment[0].callLabel} | lda ${segment[1].callLabel},y" + } + } + } + } + + // store A in target + val storeByte = when(segment[2].callLabel) { + "A" -> "" + "X" -> " tax" + "Y" -> " tya" + else -> " sta ${segment[2].callLabel}" + } + + " $setupPtr | $loadByte | $storeByte" + }, + + + // ----------- assignment to MEMORY BYTE ---------------- + // @todo mem=mem + // mem = (u)byte value + AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.POP_MEM_BYTE)) { segment -> + " lda #${segment[0].arg!!.integerValue().toHex()} | sta ${segment[1].arg!!.integerValue().toHex()}" + }, + // mem = (u)bytevar + AsmPattern(listOf(Opcode.PUSH_VAR_BYTE, Opcode.POP_MEM_BYTE)) { segment -> + when(segment[0].callLabel) { + "A" -> " sta ${segment[1].arg!!.integerValue().toHex()}" + "X" -> " stx ${segment[1].arg!!.integerValue().toHex()}" + "Y" -> " sty ${segment[1].arg!!.integerValue().toHex()}" + else -> " lda ${segment[0].callLabel} | sta ${segment[1].arg!!.integerValue().toHex()}" + } + }, + // mem = (u)bytearray[indexvalue] + AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.READ_INDEXED_VAR_BYTE, Opcode.POP_MEM_BYTE)) { segment -> + val address = segment[2].arg!!.integerValue().toHex() + val index = segment[0].arg!!.integerValue() + when(segment[1].callLabel) { + "AX" -> " sta ${C64Zeropage.SCRATCH_W1} | stx ${C64Zeropage.SCRATCH_W1+1} | ldy #$index | lda (${C64Zeropage.SCRATCH_W1}),y | sta $address" + "AY" -> " sta ${C64Zeropage.SCRATCH_W1} | sty ${C64Zeropage.SCRATCH_W1+1} | ldy #$index | lda (${C64Zeropage.SCRATCH_W1}),y | sta $address" + "XY" -> " stx ${C64Zeropage.SCRATCH_W1} | sty ${C64Zeropage.SCRATCH_W1+1} | ldy #$index | lda (${C64Zeropage.SCRATCH_W1}),y | sta $address" + else -> " lda ${segment[1].callLabel}+$index | sta $address" } }, - // assignment: var = word + + // ----------- assignment to WORD VARIABLE ---------------- + // @todo var=var + // var = wordvalue AsmPattern(listOf(Opcode.PUSH_WORD, Opcode.POP_VAR_WORD)) { segment -> val number = segment[0].arg!!.integerValue().toHex() when (segment[1].callLabel) { @@ -1088,57 +1111,49 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, """ } }, - - // assignment: mem = wordvar/uwordvar - AsmPattern(listOf(Opcode.PUSH_VAR_WORD, Opcode.POP_MEM_W)) { segment -> - when(segment[0].callLabel) { - "AX" -> TODO("$segment") - "AY" -> TODO("$segment") - "XY" -> TODO("$segment") + // var = other var + AsmPattern(listOf(Opcode.PUSH_VAR_WORD, Opcode.POP_VAR_WORD)) { segment -> + when(segment[1].callLabel) { + "AX" -> + when(segment[0].callLabel) { + "AX" -> null + "AY" -> " stx ${C64Zeropage.SCRATCH_B1} | ldy ${C64Zeropage.SCRATCH_B1}" + "XY" -> " stx ${C64Zeropage.SCRATCH_B1} | tax | ldy ${C64Zeropage.SCRATCH_B1}" + else -> " lda ${segment[0].callLabel} | ldx ${segment[0].callLabel}+1" + } + "AY" -> + when(segment[0].callLabel) { + "AX" -> " sty ${C64Zeropage.SCRATCH_B1} | ldx ${C64Zeropage.SCRATCH_B1}" + "AY" -> null + "XY" -> " tax" + else -> " lda ${segment[0].callLabel} | ldy ${segment[0].callLabel}+1" + } + "XY" -> + when(segment[0].callLabel) { + "AX" -> " txa | sty ${C64Zeropage.SCRATCH_B1} | ldx ${C64Zeropage.SCRATCH_B1}" + "AY" -> " txa" + "XY" -> null + else -> " ldx ${segment[0].callLabel} | ldy ${segment[0].callLabel}+1" + } else -> - """ - lda ${segment[0].callLabel} - sta ${segment[1].arg!!.integerValue().toHex()} - lda ${segment[0].callLabel}+1 - sta ${(segment[1].arg!!.integerValue()+1).toHex()} - """ + when(segment[0].callLabel) { + "AX" -> " sta ${segment[1].callLabel} | stx ${segment[1].callLabel}+1" + "AY" -> " sta ${segment[1].callLabel} | sty ${segment[1].callLabel}+1" + "XY" -> " stx ${segment[1].callLabel} | sty ${segment[1].callLabel}+1" + else -> + """ + lda ${segment[0].callLabel} + ldy ${segment[0].callLabel}+1 + sta ${segment[1].callLabel} + sty ${segment[1].callLabel}+1 + """ + } } }, - AsmPattern(listOf(Opcode.PUSH_VAR_WORD, Opcode.POP_MEM_UW)) { segment -> - when(segment[0].callLabel) { - "AX" -> TODO("$segment") - "AY" -> TODO("$segment") - "XY" -> TODO("$segment") - else -> - """ - lda ${segment[0].callLabel} - sta ${segment[1].arg!!.integerValue().toHex()} - lda ${segment[0].callLabel}+1 - sta ${(segment[1].arg!!.integerValue()+1).toHex()} - """ - } - }, - - // assignment: mem = word/uword - AsmPattern(listOf(Opcode.PUSH_WORD, Opcode.POP_MEM_W)) { segment -> - """ - lda #<${segment[0].arg!!.integerValue().toHex()} - sta ${segment[1].arg!!.integerValue().toHex()} - lda #>${segment[0].arg!!.integerValue().toHex()} - sta ${(segment[1].arg!!.integerValue()+1).toHex()} - """ - }, - AsmPattern(listOf(Opcode.PUSH_WORD, Opcode.POP_MEM_UW)) { segment -> - """ - lda #<${segment[0].arg!!.integerValue().toHex()} - sta ${segment[1].arg!!.integerValue().toHex()} - lda #>${segment[0].arg!!.integerValue().toHex()} - sta ${(segment[1].arg!!.integerValue()+1).toHex()} - """ - }, - - // assignment: (u)wordvar = memword - AsmPattern(listOf(Opcode.PUSH_MEM_W, Opcode.POP_VAR_WORD)) { segment -> + // var = mem (u)word + AsmPattern( + listOf(Opcode.PUSH_MEM_W, Opcode.POP_VAR_WORD), + listOf(Opcode.PUSH_MEM_UW, Opcode.POP_VAR_WORD)) { segment -> when(segment[1].callLabel) { "AX" -> " lda ${segment[0].arg!!.integerValue().toHex()} | ldx ${(segment[0].arg!!.integerValue()+1).toHex()}" "AY" -> " lda ${segment[0].arg!!.integerValue().toHex()} | ldy ${(segment[0].arg!!.integerValue()+1).toHex()}" @@ -1152,87 +1167,27 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, """ } }, - AsmPattern(listOf(Opcode.PUSH_MEM_UW, Opcode.POP_VAR_WORD)) { segment -> - when(segment[1].callLabel) { - "AX" -> " lda ${segment[0].arg!!.integerValue().toHex()} | ldx ${(segment[0].arg!!.integerValue()+1).toHex()}" - "AY" -> " lda ${segment[0].arg!!.integerValue().toHex()} | ldy ${(segment[0].arg!!.integerValue()+1).toHex()}" - "XY" -> " ldx ${segment[0].arg!!.integerValue().toHex()} | ldy ${(segment[0].arg!!.integerValue()+1).toHex()}" - else -> - """ - lda ${segment[0].arg!!.integerValue().toHex()} - sta ${segment[1].callLabel} - lda ${(segment[0].arg!!.integerValue()+1).toHex()} - sta ${segment[1].callLabel}+1 - """ - } - }, - - // assignment: var = float - AsmPattern(listOf(Opcode.PUSH_FLOAT, Opcode.POP_VAR_FLOAT)) { segment -> - val floatConst = getFloatConst(segment[0].arg!!) - """ - lda #<$floatConst - ldy #>$floatConst - sta ${C64Zeropage.SCRATCH_W1} - sty ${C64Zeropage.SCRATCH_W1+1} - lda #<${segment[1].callLabel} - ldy #>${segment[1].callLabel} - sta ${C64Zeropage.SCRATCH_W2} - sty ${C64Zeropage.SCRATCH_W2+1} - jsr prog8_lib.copy_float - """ - }, - - // assignment: var = memfloat - AsmPattern(listOf(Opcode.PUSH_MEM_FLOAT, Opcode.POP_VAR_FLOAT)) { segment -> - """ - lda #<${segment[0].arg!!.integerValue().toHex()} - ldy #>${segment[0].arg!!.integerValue().toHex()} - sta ${C64Zeropage.SCRATCH_W1} - sty ${C64Zeropage.SCRATCH_W1+1} - lda #<${segment[1].callLabel} - ldy #>${segment[1].callLabel} - sta ${C64Zeropage.SCRATCH_W2} - sty ${C64Zeropage.SCRATCH_W2+1} - jsr prog8_lib.copy_float - """ - }, - - // assignment: mem = float - AsmPattern(listOf(Opcode.PUSH_FLOAT, Opcode.POP_MEM_FLOAT)) { segment -> - val floatConst = getFloatConst(segment[0].arg!!) - """ - lda #<$floatConst - ldy #>$floatConst - sta ${C64Zeropage.SCRATCH_W1} - sty ${C64Zeropage.SCRATCH_W1+1} - lda #<${segment[1].arg!!.integerValue().toHex()} - ldy #>${segment[1].arg!!.integerValue().toHex()} - sta ${C64Zeropage.SCRATCH_W2} - sty ${C64Zeropage.SCRATCH_W2+1} - jsr prog8_lib.copy_float - """ - }, - - // assignment: mem = floatvar - AsmPattern(listOf(Opcode.PUSH_VAR_FLOAT, Opcode.POP_MEM_FLOAT)) { segment -> - """ - lda #<${segment[0].callLabel} - ldy #>${segment[0].callLabel} - sta ${C64Zeropage.SCRATCH_W1} - sty ${C64Zeropage.SCRATCH_W1+1} - lda #<${segment[1].arg!!.integerValue().toHex()} - ldy #>${segment[1].arg!!.integerValue().toHex()} - sta ${C64Zeropage.SCRATCH_W2} - sty ${C64Zeropage.SCRATCH_W2+1} - jsr prog8_lib.copy_float - """ - }, - - // assignment: uwordvar = ubytevar + // var = ubytevar AsmPattern(listOf(Opcode.PUSH_VAR_BYTE, Opcode.UB2UWORD, Opcode.POP_VAR_WORD)) { segment -> when(segment[0].callLabel) { - "A", "X", "Y" -> TODO("$segment") + "A" -> when(segment[2].callLabel) { + "AX" -> " ldx #0" + "AY" -> " ldy #0" + "XY" -> " tax | ldy #0" + else -> " sta ${segment[2].callLabel} | lda #0 | sta ${segment[2].callLabel}+1" + } + "X" -> when(segment[2].callLabel) { + "AX" -> " txa | ldx #0" + "AY" -> " txa | ldy #0" + "XY" -> " ldy #0" + else -> " stx ${segment[2].callLabel} | lda #0 | sta ${segment[2].callLabel}+1" + } + "Y" -> when(segment[2].callLabel) { + "AX" -> " tya | ldx #0" + "AY" -> " tya | ldy #0" + "XY" -> " tya | tax | ldy #0" + else -> " sty ${segment[2].callLabel} | lda #0 | sta ${segment[2].callLabel}+1" + } else -> when(segment[2].callLabel) { "AX" -> " lda ${segment[0].callLabel} | ldx #0" @@ -1242,45 +1197,29 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, } } }, - // assignment: wordvar = bytevar (sign extended) + // var = bytevar (sign extended) AsmPattern(listOf(Opcode.PUSH_VAR_BYTE, Opcode.B2WORD, Opcode.POP_VAR_WORD)) { segment -> - when(segment[0].callLabel) { - "A", "X", "Y" -> TODO("$segment") - else -> - when(segment[2].callLabel) { - "AX" -> TODO(" $segment") - "AY" -> TODO(" $segment") - "XY" -> TODO(" $segment") - else -> - """ - lda ${segment[0].callLabel} - sta ${segment[2].callLabel} - ora #$7f - bmi + - lda #0 -+ sta ${segment[2].callLabel}+1 """ - } - } + lda ${segment[0].callLabel} + sta ${segment[2].callLabel} + ora #$7f + bmi + + lda #0 ++ sta ${segment[2].callLabel}+1 + """ }, - // assignment: wordvar = membyte (sign extended) + // var = membyte (sign extended) AsmPattern(listOf(Opcode.PUSH_MEM_B, Opcode.B2WORD, Opcode.POP_VAR_WORD)) { segment -> - when(segment[2].callLabel) { - "AX" -> TODO("$segment") - "AY" -> TODO("$segment") - "XY" -> TODO("$segment") - else -> - """ - lda ${segment[0].arg!!.integerValue().toHex()} - sta ${segment[2].callLabel} - ora #$7f - bmi + - lda #0 -+ sta ${segment[2].callLabel}+1 - """ - } + """ + lda ${segment[0].arg!!.integerValue().toHex()} + sta ${segment[2].callLabel} + ora #$7f + bmi + + lda #0 ++ sta ${segment[2].callLabel}+1 + """ }, - // assignment: uwordvar = mem ubyte + // var = mem ubyte AsmPattern(listOf(Opcode.PUSH_MEM_UB, Opcode.UB2UWORD, Opcode.POP_VAR_WORD)) { segment -> when(segment[2].callLabel) { "AX" -> " lda ${segment[0].arg!!.integerValue().toHex()} | ldx #0" @@ -1289,13 +1228,13 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, else -> " lda ${segment[0].arg!!.integerValue().toHex()} | sta ${segment[2].callLabel} | lda #0 | sta ${segment[2].callLabel}+1" } }, - // assignment: uwordvar = ubytearray[index_byte] + // var = ubytearray[index_byte] AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.READ_INDEXED_VAR_BYTE, Opcode.UB2UWORD, Opcode.POP_VAR_WORD)) { segment -> val index = segment[0].arg!!.integerValue().toHex() when(segment[1].callLabel) { - "AX" -> TODO("$segment") - "AY" -> TODO("$segment") - "XY" -> TODO("$segment") + "AX" -> " sta ${C64Zeropage.SCRATCH_W1} | stx ${C64Zeropage.SCRATCH_W1+1} | ldy #$index | lda (${C64Zeropage.SCRATCH_W1}),y | sta ${segment[3].callLabel} | lda #0 | sta ${segment[3].callLabel}+1" + "AY" -> " sta ${C64Zeropage.SCRATCH_W1} | sty ${C64Zeropage.SCRATCH_W1+1} | ldy #$index | lda (${C64Zeropage.SCRATCH_W1}),y | sta ${segment[3].callLabel} | lda #0 | sta ${segment[3].callLabel}+1" + "XY" -> " stx ${C64Zeropage.SCRATCH_W1} | sty ${C64Zeropage.SCRATCH_W1+1} | ldy #$index | lda (${C64Zeropage.SCRATCH_W1}),y | sta ${segment[3].callLabel} | lda #0 | sta ${segment[3].callLabel}+1" else -> when(segment[3].callLabel) { "AX" -> " lda ${segment[1].callLabel}+$index | ldx #0" @@ -1305,32 +1244,302 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, } } }, - // assignment: mem uword = ubytearray[index_byte] - AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.READ_INDEXED_VAR_BYTE, Opcode.UB2UWORD, Opcode.POP_MEM_UW)) { segment -> + // var = bytearray[index_byte] (sign extended) + AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.READ_INDEXED_VAR_BYTE, Opcode.B2WORD, Opcode.POP_VAR_WORD)) { segment -> val index = segment[0].arg!!.integerValue().toHex() - """ - lda ${segment[1].callLabel}+$index - ldy ${segment[1].callLabel}+$index+1 - sta ${segment[3].arg!!.integerValue().toHex()} - sty ${(segment[3].arg!!.integerValue()+1).toHex()} - """ + TODO("$segment (sign extended)") }, - // assignment: (u)wordvar = (u)wordarray[index_byte] + // var = (u)wordarray[index_byte] AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.READ_INDEXED_VAR_WORD, Opcode.POP_VAR_WORD)) { segment -> val index = segment[0].arg!!.integerValue()*2 - when(segment[1].callLabel) { - "AX" -> TODO("$segment") - "AY" -> TODO("$segment") - "XY" -> TODO("$segment") - else -> - when(segment[2].callLabel) { - "AX" -> " lda ${segment[1].callLabel}+$index | ldx ${segment[1].callLabel}+$index+1" - "AY" -> " lda ${segment[1].callLabel}+$index | ldy ${segment[1].callLabel}+$index+1" - "XY" -> " ldx ${segment[1].callLabel}+$index | ldy ${segment[1].callLabel}+$index+1" - else -> " lda ${segment[1].callLabel}+$index | sta ${segment[2].callLabel} | lda ${segment[1].callLabel}+$index+1,x | sta ${segment[2].callLabel}+1" - } + when(segment[2].callLabel) { + "AX" -> " lda ${segment[1].callLabel}+$index | ldx ${segment[1].callLabel}+${index+1}" + "AY" -> " lda ${segment[1].callLabel}+$index | ldy ${segment[1].callLabel}+${index+1}" + "XY" -> " ldx ${segment[1].callLabel}+$index | ldy ${segment[1].callLabel}+${index+1}" + else -> " lda ${segment[1].callLabel}+$index | sta ${segment[2].callLabel} | lda ${segment[1].callLabel}+${index+1} | sta ${segment[2].callLabel}+1" } }, + // var = bytearray[indexvar] (sign extended) VIA REGULAR STACK EVALUATION: Opcode.PUSH_VAR_BYTE, Opcode.READ_INDEXED_VAR_BYTE, Opcode.UB2UWORD, Opcode.POP_VAR_WORD + // TODO: UB2UWORD + POP_VAR_WORD special pattern? + // var = (u)wordarray[indexvar] VIA REGULAR STACK EVALUATION: Opcode.PUSH_VAR_BYTE, Opcode.READ_INDEXED_VAR_WORD, Opcode.POP_VAR_WORD + + + // ----------- assignment to MEMORY WORD ---------------- + // @todo mem=mem + // mem = (u)word value + AsmPattern(listOf(Opcode.PUSH_WORD, Opcode.POP_MEM_WORD)) { segment -> + """ + lda #<${segment[0].arg!!.integerValue().toHex()} + sta ${segment[1].arg!!.integerValue().toHex()} + lda #>${segment[0].arg!!.integerValue().toHex()} + sta ${(segment[1].arg!!.integerValue()+1).toHex()} + """ + }, + // mem = (u)word var + AsmPattern(listOf(Opcode.PUSH_VAR_WORD, Opcode.POP_MEM_WORD)) { segment -> + when(segment[0].callLabel) { + "AX" -> " sta ${segment[1].arg!!.integerValue().toHex()} | stx ${(segment[1].arg!!.integerValue()+1).toHex()}" + "AY" -> " sta ${segment[1].arg!!.integerValue().toHex()} | sty ${(segment[1].arg!!.integerValue()+1).toHex()}" + "XY" -> " stx ${segment[1].arg!!.integerValue().toHex()} | sty ${(segment[1].arg!!.integerValue()+1).toHex()}" + else -> + """ + lda ${segment[0].callLabel} + sta ${segment[1].arg!!.integerValue().toHex()} + lda ${segment[0].callLabel}+1 + sta ${(segment[1].arg!!.integerValue()+1).toHex()} + """ + } + }, + // mem = (u)wordarray[indexvalue] + AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.READ_INDEXED_VAR_WORD, Opcode.POP_MEM_WORD)) { segment -> + val index = segment[0].arg!!.integerValue()*2 + """ + lda ${segment[1].callLabel}+$index + ldy ${segment[1].callLabel}+1+$index + sta ${segment[2].arg!!.integerValue().toHex()} + sty ${(segment[2].arg!!.integerValue()+1).toHex()} + """ + }, + // assignment: mem uword = ubytearray[index_byte] + AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.READ_INDEXED_VAR_BYTE, Opcode.UB2UWORD, Opcode.POP_MEM_WORD)) { segment -> + val index = segment[0].arg!!.integerValue() + when(segment[1].callLabel) { + "AX" -> " sta ${C64Zeropage.SCRATCH_W1} | stx ${C64Zeropage.SCRATCH_W1+1} | ldy #$index | lda (${C64Zeropage.SCRATCH_W1}),y | sta ${segment[3].arg!!.integerValue().toHex()} | lda #0 | sta ${(segment[3].arg!!.integerValue()+1).toHex()}" + "AY" -> " sta ${C64Zeropage.SCRATCH_W1} | sty ${C64Zeropage.SCRATCH_W1+1} | ldy #$index | lda (${C64Zeropage.SCRATCH_W1}),y | sta ${segment[3].arg!!.integerValue().toHex()} | lda #0 | sta ${(segment[3].arg!!.integerValue()+1).toHex()}" + "XY" -> " stx ${C64Zeropage.SCRATCH_W1} | sty ${C64Zeropage.SCRATCH_W1+1} | ldy #$index | lda (${C64Zeropage.SCRATCH_W1}),y | sta ${segment[3].arg!!.integerValue().toHex()} | lda #0 | sta ${(segment[3].arg!!.integerValue()+1).toHex()}" + else -> + """ + lda ${segment[1].callLabel}+$index + ldy ${segment[1].callLabel}+${index+1} + sta ${segment[3].arg!!.integerValue().toHex()} + sty ${(segment[3].arg!!.integerValue()+1).toHex()} + """ + } + }, + + + + // ----------- assignment to FLOAT VARIABLE ---------------- + // floatvar = float value + AsmPattern(listOf(Opcode.PUSH_FLOAT, Opcode.POP_VAR_FLOAT)) { segment -> + val floatConst = getFloatConst(segment[0].arg!!) + """ + lda #<$floatConst + ldy #>$floatConst + sta ${C64Zeropage.SCRATCH_W1} + sty ${C64Zeropage.SCRATCH_W1+1} + lda #<${segment[1].callLabel} + ldy #>${segment[1].callLabel} + jsr prog8_lib.copy_float + """ + }, + // floatvar = mem float + AsmPattern(listOf(Opcode.PUSH_MEM_FLOAT, Opcode.POP_VAR_FLOAT)) { segment -> + """ + lda #<${segment[0].arg!!.integerValue().toHex()} + ldy #>${segment[0].arg!!.integerValue().toHex()} + sta ${C64Zeropage.SCRATCH_W1} + sty ${C64Zeropage.SCRATCH_W1+1} + lda #<${segment[1].callLabel} + ldy #>${segment[1].callLabel} + jsr prog8_lib.copy_float + """ + }, + // floatvar = ubytevar + AsmPattern(listOf(Opcode.PUSH_VAR_BYTE, Opcode.UB2FLOAT, Opcode.POP_VAR_FLOAT)) { segment-> + val loadByteA = when(segment[0].callLabel) { + "A" -> "" + "X" -> "txa" + "Y" -> "tya" + else -> "lda ${segment[0].callLabel}" + } + """ + $loadByteA + sta ${C64Zeropage.SCRATCH_B1} + lda #<${segment[2].callLabel} + ldy #>${segment[2].callLabel} + jsr prog8_lib.ub2float + """ + }, + // floatvar = bytevar + AsmPattern(listOf(Opcode.PUSH_VAR_BYTE, Opcode.B2FLOAT, Opcode.POP_VAR_FLOAT)) { segment-> + val loadByteA = when(segment[0].callLabel) { + "A" -> "" + "X" -> "txa" + "Y" -> "tya" + else -> "lda ${segment[0].callLabel}" + } + """ + $loadByteA + sta ${C64Zeropage.SCRATCH_B1} + lda #<${segment[2].callLabel} + ldy #>${segment[2].callLabel} + jsr prog8_lib.b2float + """ + }, + // floatvar = uwordvar + AsmPattern(listOf(Opcode.PUSH_VAR_WORD, Opcode.UW2FLOAT, Opcode.POP_VAR_FLOAT)) { segment-> + when (segment[0].callLabel) { + "AX" -> + """ + sta ${C64Zeropage.SCRATCH_W1} + stx ${C64Zeropage.SCRATCH_W1+1} + lda #<${segment[2].callLabel} + ldy #>${segment[2].callLabel} + jsr prog8_lib.uw2float + """ + "AY" -> + """ + sta ${C64Zeropage.SCRATCH_W1} + sty ${C64Zeropage.SCRATCH_W1+1} + lda #<${segment[2].callLabel} + ldy #>${segment[2].callLabel} + jsr prog8_lib.uw2float + """ + "XY" -> + """ + stx ${C64Zeropage.SCRATCH_W1} + sty ${C64Zeropage.SCRATCH_W1+1} + lda #<${segment[2].callLabel} + ldy #>${segment[2].callLabel} + jsr prog8_lib.uw2float + """ + else -> + """ + lda ${segment[0].callLabel} + sta ${C64Zeropage.SCRATCH_W1} + lda ${segment[0].callLabel}+1 + sta ${C64Zeropage.SCRATCH_W1+1} + lda #<${segment[2].callLabel} + ldy #>${segment[2].callLabel} + jsr prog8_lib.uw2float + """ + } + }, + // floatvar = wordvar + AsmPattern(listOf(Opcode.PUSH_VAR_WORD, Opcode.W2FLOAT, Opcode.POP_VAR_FLOAT)) { segment -> + when (segment[0].callLabel) { + "AX" -> + """ + sta ${C64Zeropage.SCRATCH_W1} + stx ${C64Zeropage.SCRATCH_W1+1} + lda #<${segment[2].callLabel} + ldy #>${segment[2].callLabel} + jsr prog8_lib.w2float + """ + "AY" -> + """ + sta ${C64Zeropage.SCRATCH_W1} + sty ${C64Zeropage.SCRATCH_W1+1} + lda #<${segment[2].callLabel} + ldy #>${segment[2].callLabel} + jsr prog8_lib.w2float + """ + "XY" -> + """ + stx ${C64Zeropage.SCRATCH_W1} + sty ${C64Zeropage.SCRATCH_W1+1} + lda #<${segment[2].callLabel} + ldy #>${segment[2].callLabel} + jsr prog8_lib.w2float + """ + else -> + """ + lda ${segment[0].callLabel} + sta ${C64Zeropage.SCRATCH_W1} + lda ${segment[0].callLabel}+1 + sta ${C64Zeropage.SCRATCH_W1+1} + lda #<${segment[2].callLabel} + ldy #>${segment[2].callLabel} + jsr prog8_lib.w2float + """ + } + }, + // floatvar = mem byte + AsmPattern(listOf(Opcode.PUSH_MEM_B, Opcode.B2FLOAT, Opcode.POP_VAR_FLOAT)) { segment-> + """ + lda ${segment[0].arg!!.integerValue().toHex()} + sta ${C64Zeropage.SCRATCH_B1} + lda #<${segment[2].callLabel} + ldy #>${segment[2].callLabel} + jsr prog8_lib.b2float + """ + }, + // floatvar = mem ubyte + AsmPattern(listOf(Opcode.PUSH_MEM_UB, Opcode.UB2FLOAT, Opcode.POP_VAR_FLOAT)) { segment-> + """ + lda ${segment[0].arg!!.integerValue().toHex()} + sta ${C64Zeropage.SCRATCH_B1} + lda #<${segment[2].callLabel} + ldy #>${segment[2].callLabel} + jsr prog8_lib.ub2float + """ + }, + // floatvar = mem word + AsmPattern(listOf(Opcode.PUSH_MEM_W, Opcode.W2FLOAT, Opcode.POP_VAR_FLOAT)) { segment -> + """ + lda ${segment[0].arg!!.integerValue().toHex()} + sta ${C64Zeropage.SCRATCH_W1} + lda ${(segment[0].arg!!.integerValue()+1).toHex()} + sta ${C64Zeropage.SCRATCH_W1+1} + lda #<${segment[2].callLabel} + ldy #>${segment[2].callLabel} + jsr prog8_lib.w2float + """ + }, + // floatvar = mem uword + AsmPattern(listOf(Opcode.PUSH_MEM_UW, Opcode.UW2FLOAT, Opcode.POP_VAR_FLOAT)) { segment -> + """ + lda ${segment[0].arg!!.integerValue().toHex()} + sta ${C64Zeropage.SCRATCH_W1} + lda ${(segment[0].arg!!.integerValue()+1).toHex()} + sta ${C64Zeropage.SCRATCH_W1+1} + lda #<${segment[2].callLabel} + ldy #>${segment[2].callLabel} + jsr prog8_lib.uw2float + """ + }, + // floatvar = floatarray[index] + AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.READ_INDEXED_VAR_FLOAT, Opcode.POP_VAR_FLOAT)) { segment -> + TODO("$segment") + }, + // floatvar = floatarray[indexvar] VIA REGULAR STACK EVALUATION FOR NOW: Opcode.PUSH_VAR_BYTE, Opcode.READ_INDEXED_VAR_FLOAT, Opcode.POP_VAR_FLOAT) TODO Optimize this in special pattern? + // floatvar = floatarray[mem index (u)byte] VIA REGULAR STACK EVALUATION FOR NOW: Opcode.PUSH_MEM_[U]B, Opcode.READ_INDEXED_VAR_FLOAT, Opcode.POP_VAR_FLOAT TODO Optimize this in special pattern? + + + + // ----------- assignment to MEMORY FLOAT ---------------- + // mem = floatvalue + AsmPattern(listOf(Opcode.PUSH_FLOAT, Opcode.POP_MEM_FLOAT)) { segment -> + val floatConst = getFloatConst(segment[0].arg!!) + """ + lda #<$floatConst + ldy #>$floatConst + sta ${C64Zeropage.SCRATCH_W1} + sty ${C64Zeropage.SCRATCH_W1+1} + lda #<${segment[1].arg!!.integerValue().toHex()} + ldy #>${segment[1].arg!!.integerValue().toHex()} + jsr prog8_lib.copy_float + """ + }, + // mem = floatvar + AsmPattern(listOf(Opcode.PUSH_VAR_FLOAT, Opcode.POP_MEM_FLOAT)) { segment -> + """ + lda #<${segment[0].callLabel} + ldy #>${segment[0].callLabel} + sta ${C64Zeropage.SCRATCH_W1} + sty ${C64Zeropage.SCRATCH_W1+1} + lda #<${segment[1].arg!!.integerValue().toHex()} + ldy #>${segment[1].arg!!.integerValue().toHex()} + jsr prog8_lib.copy_float + """ + }, + + + + // ---- @todo assignment to arrays follow below ---------- + + // assignment: bytearray[idxbyte] = byte AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.PUSH_BYTE, Opcode.WRITE_INDEXED_VAR_BYTE)) { segment -> @@ -1373,19 +1582,35 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, else -> " $loadValue | sta ${segment[2].callLabel}+$index" } }, + + // assignment: bytearray[memory (u)byte] = byte + AsmPattern( + listOf(Opcode.PUSH_BYTE, Opcode.PUSH_MEM_B, Opcode.WRITE_INDEXED_VAR_BYTE), + listOf(Opcode.PUSH_BYTE, Opcode.PUSH_MEM_UB, Opcode.WRITE_INDEXED_VAR_BYTE)) { segment -> + TODO("$segment") + }, + + // assignment: bytearray[idxvar] = byte + AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.PUSH_VAR_BYTE, Opcode.WRITE_INDEXED_VAR_BYTE)) { segment -> + TODO("$segment") + }, + // assignment: bytearray[idxvar] = bytevar + AsmPattern(listOf(Opcode.PUSH_VAR_BYTE, Opcode.PUSH_VAR_BYTE, Opcode.WRITE_INDEXED_VAR_BYTE)) { segment -> + TODO("$segment") + }, + + // assignment: bytearray[mem (u)byte] = bytevar + AsmPattern( + listOf(Opcode.PUSH_VAR_BYTE, Opcode.PUSH_MEM_B, Opcode.WRITE_INDEXED_VAR_BYTE), + listOf(Opcode.PUSH_VAR_BYTE, Opcode.PUSH_MEM_UB, Opcode.WRITE_INDEXED_VAR_BYTE)) { segment -> + TODO("$segment") + }, + // assignment: bytearray[idxbyte] = membyte AsmPattern(listOf(Opcode.PUSH_MEM_B, Opcode.PUSH_BYTE, Opcode.WRITE_INDEXED_VAR_BYTE)) { segment -> val index = segment[1].arg!!.integerValue() - when(segment[2].callLabel) { - "AX" -> TODO("$segment") - "AY" -> TODO("$segment") - "XY" -> TODO("$segment") - else -> - """ - lda ${segment[0].arg!!.integerValue().toHex()} - sta ${segment[2].callLabel}+$index - """ - } + TODO("registerpair array") // same as below??? + " lda ${segment[0].arg!!.integerValue().toHex()} | sta ${segment[2].callLabel}+$index " }, // assignment: bytearray[idxbyte] = memubyte AsmPattern(listOf(Opcode.PUSH_MEM_UB, Opcode.PUSH_BYTE, Opcode.WRITE_INDEXED_VAR_BYTE)) { segment -> @@ -1400,193 +1625,97 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, // assignment: wordarray[idxbyte] = word AsmPattern(listOf(Opcode.PUSH_WORD, Opcode.PUSH_BYTE, Opcode.WRITE_INDEXED_VAR_WORD)) { segment -> val index = segment[1].arg!!.integerValue()*2 - when(segment[2].callLabel) { - "AX" -> TODO("$segment") - "AY" -> TODO("$segment") - "XY" -> TODO("$segment") - else -> - """ - lda #<${segment[0].arg!!.integerValue().toHex()} - ldy #>${segment[0].arg!!.integerValue().toHex()} - sta ${segment[2].callLabel}+$index - sty ${segment[2].callLabel}+$index+1 - """ - } + """ + lda #<${segment[0].arg!!.integerValue().toHex()} + ldy #>${segment[0].arg!!.integerValue().toHex()} + sta ${segment[2].callLabel}+$index + sty ${segment[2].callLabel}+${index+1} + """ + }, + + // assignment: wordarray[memory (u)byte] = word + AsmPattern( + listOf(Opcode.PUSH_WORD, Opcode.PUSH_MEM_B, Opcode.WRITE_INDEXED_VAR_WORD), + listOf(Opcode.PUSH_WORD, Opcode.PUSH_MEM_UB, Opcode.WRITE_INDEXED_VAR_WORD)) { segment -> + TODO("$segment") + }, + + // assignment: wordarray[indexvar] = word + AsmPattern(listOf(Opcode.PUSH_WORD, Opcode.PUSH_VAR_BYTE, Opcode.WRITE_INDEXED_VAR_WORD)) { segment -> + TODO("$segment") }, // assignment: wordarray[idxbyte] = wordvar AsmPattern(listOf(Opcode.PUSH_VAR_WORD, Opcode.PUSH_BYTE, Opcode.WRITE_INDEXED_VAR_WORD)) { segment -> val index = segment[1].arg!!.integerValue()*2 when(segment[0].callLabel) { - "AX" -> " sta ${segment[2].callLabel}+$index | stx ${segment[2].callLabel}+$index+1" - "AY" -> " sta ${segment[2].callLabel}+$index | sty ${segment[2].callLabel}+$index+1" - "XY" -> " stx ${segment[2].callLabel}+$index | sty ${segment[2].callLabel}+$index+1" + "AX" -> " sta ${segment[2].callLabel}+$index | stx ${segment[2].callLabel}+${index+1}" + "AY" -> " sta ${segment[2].callLabel}+$index | sty ${segment[2].callLabel}+${index+1}" + "XY" -> " stx ${segment[2].callLabel}+$index | sty ${segment[2].callLabel}+${index+1}" else -> """ lda ${segment[0].callLabel} ldy ${segment[0].callLabel}+1 sta ${segment[2].callLabel}+$index - sty ${segment[2].callLabel}+$index+1 + sty ${segment[2].callLabel}+${index+1} """ } }, - // assignment: wordarray[idxbyte] = memword - AsmPattern(listOf(Opcode.PUSH_MEM_W, Opcode.PUSH_BYTE, Opcode.WRITE_INDEXED_VAR_WORD)) { segment -> + // assignment: wordarray[indexvar] = wordvar + AsmPattern(listOf(Opcode.PUSH_VAR_WORD, Opcode.PUSH_VAR_BYTE, Opcode.WRITE_INDEXED_VAR_WORD)) { segment -> + TODO("$segment") + }, + // assignment: wordarray[idxbyte] = mem(u)word + AsmPattern( + listOf(Opcode.PUSH_MEM_W, Opcode.PUSH_BYTE, Opcode.WRITE_INDEXED_VAR_WORD), + listOf(Opcode.PUSH_MEM_UW, Opcode.PUSH_BYTE, Opcode.WRITE_INDEXED_VAR_WORD)) { segment -> val index = segment[1].arg!!.integerValue()*2 - when(segment[2].callLabel) { - "AX" -> TODO("$segment") - "AY" -> TODO("$segment") - "XY" -> TODO("$segment") - else -> - """ - lda ${segment[0].arg!!.integerValue().toHex()} - ldy ${segment[0].arg!!.integerValue().toHex()}+1 - sta ${segment[2].callLabel}+$index - sty ${segment[2].callLabel}+$index+1 - """ - } - }, - // assignment: wordarray[idxbyte] = memuword (=same as above) - AsmPattern(listOf(Opcode.PUSH_MEM_UW, Opcode.PUSH_BYTE, Opcode.WRITE_INDEXED_VAR_WORD)) { segment -> - val index = segment[1].arg!!.integerValue()*2 - when(segment[2].callLabel) { - "AX" -> TODO("$segment") - "AY" -> TODO("$segment") - "XY" -> TODO("$segment") - else -> - """ - lda ${segment[0].arg!!.integerValue().toHex()} - ldy ${segment[0].arg!!.integerValue().toHex()}+1 - sta ${segment[2].callLabel}+$index - sty ${segment[2].callLabel}+$index+1 - """ - } - }, - // assignment: floatarray[idxbyte] = float - AsmPattern(listOf(Opcode.PUSH_FLOAT, Opcode.PUSH_BYTE, Opcode.WRITE_INDEXED_VAR_FLOAT)) { segment -> - val floatConst = getFloatConst(segment[0].arg!!) - val index = segment[1].arg!!.integerValue() * Mflpt5.MemorySize """ - lda #<$floatConst - ldy #>$floatConst - sta ${C64Zeropage.SCRATCH_W1} - sty ${C64Zeropage.SCRATCH_W1+1} - lda #<(${segment[2].callLabel}+$index) - ldy #>(${segment[2].callLabel}+$index+1) - sta ${C64Zeropage.SCRATCH_W2} - sty ${C64Zeropage.SCRATCH_W2+1} - jsr prog8_lib.copy_float - """ - }, - // assignment: floatarray[idxbyte] = floatvar - AsmPattern(listOf(Opcode.PUSH_VAR_FLOAT, Opcode.PUSH_BYTE, Opcode.WRITE_INDEXED_VAR_FLOAT)) { segment -> - val index = segment[1].arg!!.integerValue() * Mflpt5.MemorySize - """ - lda #<${segment[0].callLabel} - ldy #>${segment[0].callLabel} - sta ${C64Zeropage.SCRATCH_W1} - sty ${C64Zeropage.SCRATCH_W1+1} - lda #<(${segment[2].callLabel}+$index) - ldy #>(${segment[2].callLabel}+$index+1) - sta ${C64Zeropage.SCRATCH_W2} - sty ${C64Zeropage.SCRATCH_W2+1} - jsr prog8_lib.copy_float - """ - }, - // assignment: floatarray[idxbyte] = memfloat - AsmPattern(listOf(Opcode.PUSH_MEM_FLOAT, Opcode.PUSH_BYTE, Opcode.WRITE_INDEXED_VAR_FLOAT)) { segment -> - val index = segment[1].arg!!.integerValue() * Mflpt5.MemorySize - """ - lda #<${segment[0].arg!!.integerValue().toHex()} - ldy #>${segment[0].arg!!.integerValue().toHex()} - sta ${C64Zeropage.SCRATCH_W1} - sty ${C64Zeropage.SCRATCH_W1+1} - lda #<(${segment[2].callLabel}+$index) - ldy #>(${segment[2].callLabel}+$index+1) - sta ${C64Zeropage.SCRATCH_W2} - sty ${C64Zeropage.SCRATCH_W2+1} - jsr prog8_lib.copy_float + lda ${segment[0].arg!!.integerValue().toHex()} + ldy ${(segment[0].arg!!.integerValue()+1).toHex()} + sta ${segment[2].callLabel}+$index + sty ${segment[2].callLabel}+${index+1} """ }, - // assignment: var = bytearray[index] - AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.READ_INDEXED_VAR_BYTE, Opcode.POP_VAR_BYTE)) { segment -> - val index = segment[0].arg!!.integerValue() - when(segment[1].callLabel) { - "AX" -> TODO("$segment") - "AY" -> TODO("$segment") - "XY" -> TODO("$segment") - else -> - when (segment[2].callLabel) { - "A", "X", "Y" -> - " ld${segment[2].callLabel!!.toLowerCase()} ${segment[1].callLabel}+$index" - else -> - " lda ${segment[1].callLabel}+$index | sta ${segment[2].callLabel}" - } - } - }, - - // assignment: mem(u)byte = (u)bytearray[index] - AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.READ_INDEXED_VAR_BYTE, Opcode.POP_MEM_B)) { segment -> - val address = segment[2].arg!!.integerValue().toHex() - val index = segment[0].arg!!.integerValue() - when(segment[1].callLabel) { - "AX" -> " sta ${C64Zeropage.SCRATCH_W1} | stx ${C64Zeropage.SCRATCH_W1+1} | ldy #$index | lda (${C64Zeropage.SCRATCH_W1}),y | sta $address" - "AY" -> " sta ${C64Zeropage.SCRATCH_W1} | sty ${C64Zeropage.SCRATCH_W1+1} | ldy #$index | lda (${C64Zeropage.SCRATCH_W1}),y | sta $address" - "XY" -> " stx ${C64Zeropage.SCRATCH_W1} | sty ${C64Zeropage.SCRATCH_W1+1} | ldy #$index | lda (${C64Zeropage.SCRATCH_W1}),y | sta $address" - else -> " lda ${segment[1].callLabel}+$index | sta $address" - } - }, - AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.READ_INDEXED_VAR_BYTE, Opcode.POP_MEM_UB)) { segment -> - val address = segment[2].arg!!.integerValue().toHex() - val index = segment[0].arg!!.integerValue() - when(segment[1].callLabel) { - "AX" -> " sta ${C64Zeropage.SCRATCH_W1} | stx ${C64Zeropage.SCRATCH_W1+1} | ldy #$index | lda (${C64Zeropage.SCRATCH_W1}),y | sta $address" - "AY" -> " sta ${C64Zeropage.SCRATCH_W1} | sty ${C64Zeropage.SCRATCH_W1+1} | ldy #$index | lda (${C64Zeropage.SCRATCH_W1}),y | sta $address" - "XY" -> " stx ${C64Zeropage.SCRATCH_W1} | sty ${C64Zeropage.SCRATCH_W1+1} | ldy #$index | lda (${C64Zeropage.SCRATCH_W1}),y | sta $address" - else -> " lda ${segment[1].callLabel}+$index | sta $address" - } - }, - - // assignment: mem(u)word = (u)wordarray[index] - AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.READ_INDEXED_VAR_WORD, Opcode.POP_MEM_W)) { segment -> - val index = segment[0].arg!!.integerValue()*2 - when(segment[1].callLabel) { - "AX" -> TODO("$segment") - "AY" -> TODO("$segment") - "XY" -> TODO("$segment") - else -> - """ - lda ${segment[1].callLabel}+$index - ldy ${segment[1].callLabel}+1+$index - sta ${segment[2].arg!!.integerValue().toHex()} - sty ${(segment[2].arg!!.integerValue()+1).toHex()} - """ - } - }, - AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.READ_INDEXED_VAR_WORD, Opcode.POP_MEM_UW)) { segment -> - val index = segment[0].arg!!.integerValue()*2 - when(segment[1].callLabel) { - "AX" -> TODO("$segment") - "AY" -> TODO("$segment") - "XY" -> TODO("$segment") - else -> - """ - lda ${segment[1].callLabel}+$index - ldy ${segment[1].callLabel}+1+$index - sta ${segment[2].arg!!.integerValue().toHex()} - sty ${(segment[2].arg!!.integerValue()+1).toHex()} - """ - } - }, // assignment: bytearray2[index2] = bytearray1[index1] AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.READ_INDEXED_VAR_BYTE, Opcode.PUSH_BYTE, Opcode.WRITE_INDEXED_VAR_BYTE)) { segment-> val index1 = segment[0].arg!!.integerValue() val index2 = segment[2].arg!!.integerValue() when(segment[1].callLabel) { - "AX" -> TODO("$segment") - "AY" -> TODO("$segment") - "XY" -> TODO("$segment") + "AX" -> when(segment[3].callLabel) { + "AX", "AY", "XY" -> throw AssemblyError("reading AND writing from registerpair arrays not supported due to register overlap") + else -> + """ + sta ${C64Zeropage.SCRATCH_W1} + stx ${C64Zeropage.SCRATCH_W1+1} + ldy #$index1 + lda (${C64Zeropage.SCRATCH_W1}),y + sta ${segment[3].callLabel}+$index2 + """ + } + "AY" -> when(segment[3].callLabel) { + "AX", "AY", "XY" -> throw AssemblyError("reading AND writing from registerpair arrays not supported due to register overlap") + else -> + """ + sta ${C64Zeropage.SCRATCH_W1} + sty ${C64Zeropage.SCRATCH_W1+1} + ldy #$index1 + lda (${C64Zeropage.SCRATCH_W1}),y + sta ${segment[3].callLabel}+$index2 + """ + } + "XY" -> when(segment[3].callLabel) { + "AX", "AY", "XY" -> throw AssemblyError("reading AND writing from registerpair arrays not supported due to register overlap") + else -> + """ + stx ${C64Zeropage.SCRATCH_W1} + sty ${C64Zeropage.SCRATCH_W1+1} + ldy #$index1 + lda (${C64Zeropage.SCRATCH_W1}),y + sta ${segment[3].callLabel}+$index2 + """ + } else -> when(segment[3].callLabel) { "AX" -> " sta ${C64Zeropage.SCRATCH_W1} | stx ${C64Zeropage.SCRATCH_W1+1} | lda ${segment[1].callLabel}+$index1 | ldy #$index2 | sta (${C64Zeropage.SCRATCH_W1}),y" @@ -1600,24 +1729,53 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.READ_INDEXED_VAR_WORD, Opcode.PUSH_BYTE, Opcode.WRITE_INDEXED_VAR_WORD)) { segment-> val index1 = segment[0].arg!!.integerValue()*2 val index2 = segment[2].arg!!.integerValue()*2 - when(segment[1].callLabel) { - "AX" -> TODO("$segment") - "AY" -> TODO("$segment") - "XY" -> TODO("$segment") - else -> - when(segment[3].callLabel) { - "AX" -> TODO("$segment") - "AY" -> TODO("$segment") - "XY" -> TODO("$segment") - else -> - """ - lda ${segment[1].callLabel}+$index1 - ldy ${segment[1].callLabel}+$index1+1 - sta ${segment[3].callLabel}+$index2 - sty ${segment[3].callLabel}+$index2+1 - """ - } - } + """ + lda ${segment[1].callLabel}+$index1 + ldy ${segment[1].callLabel}+${index1+1} + sta ${segment[3].callLabel}+$index2 + sty ${segment[3].callLabel}+${index2+1} + """ + }, + + // assignment: floatarray[idxbyte] = float + AsmPattern(listOf(Opcode.PUSH_FLOAT, Opcode.PUSH_BYTE, Opcode.WRITE_INDEXED_VAR_FLOAT)) { segment -> + val floatConst = getFloatConst(segment[0].arg!!) + val index = segment[1].arg!!.integerValue() * Mflpt5.MemorySize + """ + lda #<$floatConst + ldy #>$floatConst + sta ${C64Zeropage.SCRATCH_W1} + sty ${C64Zeropage.SCRATCH_W1+1} + lda #<(${segment[2].callLabel}+$index) + ldy #>(${segment[2].callLabel}+$index) + jsr prog8_lib.copy_float + """ + }, + // assignment: floatarray[idxbyte] = floatvar + AsmPattern(listOf(Opcode.PUSH_VAR_FLOAT, Opcode.PUSH_BYTE, Opcode.WRITE_INDEXED_VAR_FLOAT)) { segment -> + val index = segment[1].arg!!.integerValue() * Mflpt5.MemorySize + """ + lda #<${segment[0].callLabel} + ldy #>${segment[0].callLabel} + sta ${C64Zeropage.SCRATCH_W1} + sty ${C64Zeropage.SCRATCH_W1+1} + lda #<(${segment[2].callLabel}+$index) + ldy #>(${segment[2].callLabel}+$index) + jsr prog8_lib.copy_float + """ + }, + // assignment: floatarray[idxbyte] = memfloat + AsmPattern(listOf(Opcode.PUSH_MEM_FLOAT, Opcode.PUSH_BYTE, Opcode.WRITE_INDEXED_VAR_FLOAT)) { segment -> + val index = segment[1].arg!!.integerValue() * Mflpt5.MemorySize + """ + lda #<${segment[0].arg!!.integerValue().toHex()} + ldy #>${segment[0].arg!!.integerValue().toHex()} + sta ${C64Zeropage.SCRATCH_W1} + sty ${C64Zeropage.SCRATCH_W1+1} + lda #<(${segment[2].callLabel}+$index) + ldy #>(${segment[2].callLabel}+$index) + jsr prog8_lib.copy_float + """ } ) diff --git a/compiler/src/prog8/functions/BuiltinFunctions.kt b/compiler/src/prog8/functions/BuiltinFunctions.kt index 4daf452dc..8cf8323bb 100644 --- a/compiler/src/prog8/functions/BuiltinFunctions.kt +++ b/compiler/src/prog8/functions/BuiltinFunctions.kt @@ -100,7 +100,7 @@ fun builtinFunctionReturnType(function: String, args: List, namespa if(arglist.type==DataType.ARRAY_UB || arglist.type==DataType.ARRAY_UW || arglist.type==DataType.ARRAY_F || arglist.type==DataType.MATRIX_UB) { val dt = arglist.arrayvalue!!.map {it.resultingDatatype(namespace, heap)} if(dt.any { it!=DataType.UBYTE && it!=DataType.UWORD && it!=DataType.FLOAT}) { - throw FatalAstException("fuction $function only accepts array of numeric values") + throw FatalAstException("fuction $function only accepts arrayspec of numeric values") } if(dt.any { it==DataType.FLOAT }) return DataType.FLOAT if(dt.any { it==DataType.UWORD }) return DataType.UWORD @@ -119,10 +119,10 @@ fun builtinFunctionReturnType(function: String, args: List, namespa DataType.ARRAY_F -> DataType.FLOAT DataType.MATRIX_UB -> DataType.UBYTE DataType.MATRIX_B -> DataType.BYTE - null -> throw FatalAstException("function requires one argument which is an array $function") + null -> throw FatalAstException("function requires one argument which is an arrayspec $function") } } - throw FatalAstException("function requires one argument which is an array $function") + throw FatalAstException("function requires one argument which is an arrayspec $function") } val func = BuiltinFunctions[function]!! @@ -237,7 +237,7 @@ private fun collectionArgOutputBoolean(args: List, position: Positi throw NotConstArgumentException() function(constants.map { it!!.toDouble() }) } else { - val array = heap.get(iterable.heapId!!).array ?: throw SyntaxError("function requires array/matrix argument", position) + val array = heap.get(iterable.heapId!!).array ?: throw SyntaxError("function requires arrayspec/matrix argument", position) function(array.map { it.toDouble() }) } return LiteralValue.fromBoolean(result, position) @@ -313,7 +313,7 @@ private fun builtinAbs(args: List, position: Position, namespace:IN private fun builtinAvg(args: List, position: Position, namespace:INameScope, heap: HeapValues): LiteralValue { if(args.size!=1) - throw SyntaxError("avg requires array/matrix argument", position) + throw SyntaxError("avg requires arrayspec/matrix argument", position) val iterable = args[0].constValue(namespace, heap) ?: throw NotConstArgumentException() val result = if(iterable.arrayvalue!=null) { @@ -323,7 +323,7 @@ private fun builtinAvg(args: List, position: Position, namespace:IN (constants.map { it!!.toDouble() }).average() } else { - val array = heap.get(iterable.heapId!!).array ?: throw SyntaxError("avg requires array/matrix argument", position) + val array = heap.get(iterable.heapId!!).array ?: throw SyntaxError("avg requires arrayspec/matrix argument", position) array.average() } return numericLiteral(result, args[0].position) diff --git a/compiler/src/prog8/optimizing/ConstantFolding.kt b/compiler/src/prog8/optimizing/ConstantFolding.kt index 2a98c16f6..1b44f8dc9 100644 --- a/compiler/src/prog8/optimizing/ConstantFolding.kt +++ b/compiler/src/prog8/optimizing/ConstantFolding.kt @@ -56,10 +56,10 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV DataType.ARRAY_UB, DataType.ARRAY_B, DataType.ARRAY_UW, DataType.ARRAY_W, DataType.MATRIX_UB, DataType.MATRIX_B -> { val litval = decl.value as? LiteralValue if(litval?.type==DataType.FLOAT) - errors.add(ExpressionError("array requires only integers here", litval.position)) + errors.add(ExpressionError("arrayspec requires only integers here", litval.position)) val size = decl.arrayspec!!.size() if(litval!=null && litval.isArray) { - // array initializer value is an array already, keep as-is (or convert to WORDs if needed) + // arrayspec initializer value is an arrayspec already, keep as-is (or convert to WORDs if needed) if(litval.heapId!=null) { if (decl.datatype == DataType.MATRIX_UB && litval.type != DataType.MATRIX_UB) { val array = heap.get(litval.heapId).copy(type = DataType.MATRIX_UB) @@ -79,7 +79,7 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV } } } else if (size != null) { - // array initializer is empty or a single int, and we know the size; create the array. + // arrayspec initializer is empty or a single int, and we know the size; create the arrayspec. val fillvalue = if (litval == null) 0 else litval.asIntegerValue ?: 0 when(decl.datatype){ DataType.ARRAY_UB, DataType.MATRIX_UB -> { @@ -109,7 +109,7 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV val litval = decl.value as? LiteralValue val size = decl.arrayspec!!.size() if(litval!=null && litval.isArray) { - // array initializer value is an array already, make sure to convert to floats + // arrayspec initializer value is an arrayspec already, make sure to convert to floats if(litval.heapId!=null) { val array = heap.get(litval.heapId) if (array.doubleArray == null) { @@ -119,7 +119,7 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV } } } else if (size != null) { - // array initializer is empty or a single int, and we know the size; create the array. + // arrayspec initializer is empty or a single int, and we know the size; create the arrayspec. val fillvalue = if (litval == null) 0.0 else litval.asNumericValue?.toDouble() ?: 0.0 if(fillvalue< FLOAT_MAX_NEGATIVE || fillvalue> FLOAT_MAX_POSITIVE) errors.add(ExpressionError("float value overflow", litval?.position ?: decl.position)) @@ -492,7 +492,7 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV val array: Array = arraylit.arrayvalue!!.map { it.process(this) }.toTypedArray() val allElementsAreConstant = array.fold(true) { c, expr-> c and (expr is LiteralValue)} if(!allElementsAreConstant) { - addError(ExpressionError("array/matrix literal can contain only constant values", arraylit.position)) + addError(ExpressionError("arrayspec/matrix literal can contain only constant values", arraylit.position)) return arraylit } else { val valuesInArray = array.map { it.constValue(namespace, heap)!!.asNumericValue!! } @@ -533,24 +533,24 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV DataType.MATRIX_UB, DataType.MATRIX_B -> heap.add(arrayDt, integerArray) DataType.ARRAY_F -> heap.add(arrayDt, doubleArray) - else -> throw CompilerException("invalid array type") + else -> throw CompilerException("invalid arrayspec type") } return LiteralValue(arrayDt, heapId = heapId, position = arraylit.position) } } override fun process(arrayIndexedExpression: ArrayIndexedExpression): IExpression { - if(arrayIndexedExpression.array.y!=null) { - if(arrayIndexedExpression.array.size()!=null) { + if(arrayIndexedExpression.arrayspec.y!=null) { + if(arrayIndexedExpression.arrayspec.size()!=null) { // both x and y are known // calculate the 2-dimension index i = y*columns + x if(arrayIndexedExpression.identifier!=null) { - val x = (arrayIndexedExpression.array.x as LiteralValue).asIntegerValue!! - val y = (arrayIndexedExpression.array.y as LiteralValue).asIntegerValue!! + val x = (arrayIndexedExpression.arrayspec.x as LiteralValue).asIntegerValue!! + val y = (arrayIndexedExpression.arrayspec.y as LiteralValue).asIntegerValue!! val variable = arrayIndexedExpression.identifier.targetStatement(namespace) as? VarDecl if(variable!=null) { val index = x + y * (variable.arrayspec!!.x as LiteralValue).asIntegerValue!! - arrayIndexedExpression.array = ArraySpec(LiteralValue.optimalInteger(index, arrayIndexedExpression.array.position), null, arrayIndexedExpression.array.position) + arrayIndexedExpression.arrayspec = ArraySpec(LiteralValue.optimalInteger(index, arrayIndexedExpression.arrayspec.position), null, arrayIndexedExpression.arrayspec.position) } } } diff --git a/compiler/src/prog8/stackvm/Program.kt b/compiler/src/prog8/stackvm/Program.kt index f042f1892..615cc9b44 100644 --- a/compiler/src/prog8/stackvm/Program.kt +++ b/compiler/src/prog8/stackvm/Program.kt @@ -124,16 +124,6 @@ class Program (val name: String, val args = if(parts.size==2) parts[1] else null val instruction = when(opcode) { Opcode.LINE -> Instruction(opcode, null, callLabel = args) - Opcode.COPY_VAR_BYTE, Opcode.COPY_VAR_WORD, Opcode.COPY_VAR_FLOAT -> { - val (v1, v2) = args!!.split(splitpattern, limit = 2) - Instruction(opcode, null, null, v1, v2) - } - Opcode.COPY_MEM_BYTE, Opcode.COPY_MEM_WORD, Opcode.COPY_MEM_FLOAT -> { - val (v1, v2) = args!!.split(splitpattern, limit = 2) - val address1 = getArgValue(v1, heap) - val address2 = getArgValue(v2, heap) - Instruction(opcode, address1, address2) - } Opcode.JUMP, Opcode.CALL, Opcode.BNEG, Opcode.BPOS, Opcode.BZ, Opcode.BNZ, Opcode.BCS, Opcode.BCC -> { if(args!!.startsWith('$')) { @@ -222,7 +212,7 @@ class Program (val name: String, DataType.MATRIX_UB, DataType.MATRIX_B -> { if(!valueStr.startsWith("heap:")) - throw VmExecutionException("invalid array/matrix value, should be a heap reference") + throw VmExecutionException("invalid arrayspec/matrix value, should be a heap reference") else { val heapId = valueStr.substring(5).toInt() Value(type, heapId) @@ -303,4 +293,4 @@ class Program (val name: String, } } } -} \ No newline at end of file +} diff --git a/compiler/src/prog8/stackvm/StackVm.kt b/compiler/src/prog8/stackvm/StackVm.kt index 1204ea948..ceb0f8c2d 100644 --- a/compiler/src/prog8/stackvm/StackVm.kt +++ b/compiler/src/prog8/stackvm/StackVm.kt @@ -218,30 +218,24 @@ class StackVm(private var traceOutputFile: String?) { } } - private fun checkDt(value: Value?, expected: DataType) { - if(value==null) - throw VmExecutionException("expected value") - if(value.type!=expected) - throw VmExecutionException("expected $expected value, found ${value.type}") - } - - private fun checkDt(value: Value?, expected: Set) { + private fun checkDt(value: Value?, vararg expected: DataType) { if(value==null) throw VmExecutionException("expected value") if(value.type !in expected) - throw VmExecutionException("incompatible type found ${value.type}") + throw VmExecutionException("incompatible type ${value.type}") } + private fun dispatch(ins: Instruction) : Instruction { traceOutput?.println("\n$ins") when (ins.opcode) { Opcode.NOP -> {} Opcode.PUSH_BYTE -> { - checkDt(ins.arg, setOf(DataType.UBYTE, DataType.BYTE)) + checkDt(ins.arg, DataType.UBYTE, DataType.BYTE) evalstack.push(ins.arg) } Opcode.PUSH_WORD -> { - checkDt(ins.arg, setOf(DataType.UWORD, DataType.WORD) + IterableDatatypes) + checkDt(ins.arg, *(setOf(DataType.UWORD, DataType.WORD) + IterableDatatypes).toTypedArray()) evalstack.push(ins.arg) } Opcode.PUSH_FLOAT -> { @@ -280,29 +274,23 @@ class StackVm(private var traceOutputFile: String?) { val value = evalstack.pop() checkDt(value, DataType.FLOAT) } - Opcode.POP_MEM_UB -> { + Opcode.POP_MEM_BYTE -> { val value = evalstack.pop() - checkDt(value, DataType.UBYTE) + checkDt(value, DataType.BYTE, DataType.UBYTE) val address = ins.arg!!.integerValue() - mem.setUByte(address, value.integerValue().toShort()) + if(value.type==DataType.BYTE) + mem.setSByte(address, value.integerValue().toShort()) + else + mem.setUByte(address, value.integerValue().toShort()) } - Opcode.POP_MEM_B -> { + Opcode.POP_MEM_WORD -> { val value = evalstack.pop() - checkDt(value, DataType.BYTE) + checkDt(value, DataType.WORD, DataType.UWORD) val address = ins.arg!!.integerValue() - mem.setSByte(address, value.integerValue().toShort()) - } - Opcode.POP_MEM_UW -> { - val value = evalstack.pop() - checkDt(value, DataType.UWORD) - val address = ins.arg!!.integerValue() - mem.setUWord(address, value.integerValue()) - } - Opcode.POP_MEM_W -> { - val value = evalstack.pop() - checkDt(value, DataType.WORD) - val address = ins.arg!!.integerValue() - mem.setSWord(address, value.integerValue()) + if(value.type==DataType.WORD) + mem.setSWord(address, value.integerValue()) + else + mem.setUWord(address, value.integerValue()) } Opcode.POP_MEM_FLOAT -> { val value = evalstack.pop() @@ -765,12 +753,12 @@ class StackVm(private var traceOutputFile: String?) { } Opcode.PUSH_VAR_BYTE -> { val value = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") - checkDt(value, setOf(DataType.UBYTE, DataType.BYTE)) + checkDt(value, DataType.UBYTE, DataType.BYTE) evalstack.push(value) } Opcode.PUSH_VAR_WORD -> { val value = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") - checkDt(value, setOf(DataType.UWORD, DataType.WORD, DataType.ARRAY_UB, DataType.ARRAY_UW, DataType.ARRAY_F, DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS, DataType.MATRIX_UB)) + checkDt(value, *(setOf(DataType.UWORD, DataType.WORD) + IterableDatatypes).toTypedArray()) evalstack.push(value) } Opcode.PUSH_VAR_FLOAT -> { @@ -780,62 +768,22 @@ class StackVm(private var traceOutputFile: String?) { } Opcode.POP_VAR_BYTE -> { val value = evalstack.pop() - checkDt(value, setOf(DataType.UBYTE, DataType.BYTE)) + checkDt(value, DataType.UBYTE, DataType.BYTE) val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") - checkDt(variable, setOf(DataType.UBYTE, DataType.BYTE)) + checkDt(variable, DataType.UBYTE, DataType.BYTE) if(value.type!=variable.type) throw VmExecutionException("datatype mismatch") variables[ins.callLabel!!] = value } Opcode.POP_VAR_WORD -> { val value = evalstack.pop() - checkDt(value, setOf(DataType.UWORD, DataType.WORD, DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS)) + checkDt(value, DataType.UWORD, DataType.WORD, DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS) val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") - checkDt(variable, setOf(DataType.UWORD, DataType.WORD, DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS)) + checkDt(variable, DataType.UWORD, DataType.WORD, DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS) if(value.type!=variable.type) throw VmExecutionException("datatype mismatch") variables[ins.callLabel!!] = value } - Opcode.COPY_VAR_BYTE -> { - val source = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") - val dest = variables[ins.callLabel2] ?: throw VmExecutionException("unknown variable: ${ins.callLabel2}") - checkDt(source, setOf(DataType.UBYTE, DataType.BYTE)) - checkDt(dest, setOf(DataType.UBYTE, DataType.BYTE)) - if(dest.type!=source.type) - throw VmExecutionException("datatype mismatch") - variables[ins.callLabel2!!] = source - } - Opcode.COPY_VAR_WORD -> { - val source = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") - val dest = variables[ins.callLabel2] ?: throw VmExecutionException("unknown variable: ${ins.callLabel2}") - checkDt(source, setOf(DataType.UWORD, DataType.WORD, DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS)) - checkDt(dest, setOf(DataType.UWORD, DataType.WORD, DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS)) - if(dest.type!=source.type) - throw VmExecutionException("datatype mismatch") - variables[ins.callLabel2!!] = source - } - Opcode.COPY_VAR_FLOAT -> { - val source = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") - val dest = variables[ins.callLabel2] ?: throw VmExecutionException("unknown variable: ${ins.callLabel2}") - checkDt(source, DataType.FLOAT) - checkDt(dest, DataType.FLOAT) - variables[ins.callLabel2!!] = source - } - Opcode.COPY_MEM_BYTE -> { - val sourceAddr = ins.arg!!.integerValue() - val destAddr = ins.arg2!!.integerValue() - mem.setUByte(destAddr, mem.getUByte(sourceAddr)) - } - Opcode.COPY_MEM_WORD -> { - val sourceAddr = ins.arg!!.integerValue() - val destAddr = ins.arg2!!.integerValue() - mem.setUWord(destAddr, mem.getUWord(sourceAddr)) - } - Opcode.COPY_MEM_FLOAT -> { - val sourceAddr = ins.arg!!.integerValue() - val destAddr = ins.arg2!!.integerValue() - mem.setFloat(destAddr, mem.getFloat(sourceAddr)) - } Opcode.POP_VAR_FLOAT -> { val value = evalstack.pop() checkDt(value, DataType.FLOAT) @@ -1229,13 +1177,13 @@ class StackVm(private var traceOutputFile: String?) { // assume the variable is a pointer (address) and get the ubyte value from that memory location evalstack.push(Value(DataType.UBYTE, mem.getUByte(variable.integerValue()))) } else { - // get indexed byte element from the array + // get indexed byte element from the arrayspec val array = heap.get(variable.heapId) when(array.type) { DataType.ARRAY_UB, DataType.MATRIX_UB -> evalstack.push(Value(DataType.UBYTE, array.array!![index])) DataType.ARRAY_B, DataType.MATRIX_B -> evalstack.push(Value(DataType.BYTE, array.array!![index])) DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> evalstack.push(Value(DataType.UBYTE, Petscii.encodePetscii(array.str!![index].toString(), true)[0])) - else -> throw VmExecutionException("not a proper array/matrix/string variable with byte elements") + else -> throw VmExecutionException("not a proper arrayspec/matrix/string variable with byte elements") } } } @@ -1247,12 +1195,12 @@ class StackVm(private var traceOutputFile: String?) { // assume the variable is a pointer (address) and get the word value from that memory location evalstack.push(Value(DataType.UWORD, mem.getUWord(variable.integerValue()))) } else { - // get indexed word element from the array + // get indexed word element from the arrayspec val array = heap.get(variable.heapId) when(array.type){ DataType.ARRAY_UW -> evalstack.push(Value(DataType.UWORD, array.array!![index])) DataType.ARRAY_W -> evalstack.push(Value(DataType.WORD, array.array!![index])) - else -> throw VmExecutionException("not a proper array var with word elements") + else -> throw VmExecutionException("not a proper arrayspec var with word elements") } } } @@ -1264,10 +1212,10 @@ class StackVm(private var traceOutputFile: String?) { // assume the variable is a pointer (address) and get the float value from that memory location evalstack.push(Value(DataType.UWORD, mem.getFloat(variable.integerValue()))) } else { - // get indexed float element from the array + // get indexed float element from the arrayspec val array = heap.get(variable.heapId) if(array.type!=DataType.ARRAY_F) - throw VmExecutionException("not a proper array var with float elements") + throw VmExecutionException("not a proper arrayspec var with float elements") evalstack.push(Value(DataType.FLOAT, array.doubleArray!![index])) } } @@ -1275,13 +1223,13 @@ class StackVm(private var traceOutputFile: String?) { // store byte value on the stack in variable[index] (index is on the stack as well) val index = evalstack.pop().integerValue() val value = evalstack.pop() - checkDt(value, setOf(DataType.UBYTE, DataType.BYTE)) + checkDt(value, DataType.UBYTE, DataType.BYTE) val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") if(variable.type==DataType.UWORD) { // assume the variable is a pointer (address) and write the byte value to that memory location mem.setUByte(variable.integerValue(), value.integerValue().toShort()) } else { - // set indexed byte element in the array + // set indexed byte element in the arrayspec val array = heap.get(variable.heapId) when(array.type) { DataType.ARRAY_UB, DataType.MATRIX_UB -> array.array!![index] = value.integerValue() @@ -1294,7 +1242,7 @@ class StackVm(private var traceOutputFile: String?) { chars[index] = Petscii.decodePetscii(listOf(value.integerValue().toShort()), true)[0] heap.update(variable.heapId, chars.joinToString("")) } - else -> throw VmExecutionException("not a proper array/matrix/string var with byte elements") + else -> throw VmExecutionException("not a proper arrayspec/matrix/string var with byte elements") } } } @@ -1302,18 +1250,18 @@ class StackVm(private var traceOutputFile: String?) { // store word value on the stack in variable[index] (index is on the stack as well) val index = evalstack.pop().integerValue() val value = evalstack.pop() - checkDt(value, setOf(DataType.UWORD, DataType.WORD)) + checkDt(value, DataType.UWORD, DataType.WORD) val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") if(variable.type==DataType.UWORD) { // assume the variable is a pointer (address) and write the word value to that memory location mem.setUWord(variable.integerValue(), value.integerValue()) } else { - // set indexed word element in the array + // set indexed word element in the arrayspec val array = heap.get(variable.heapId) when(array.type) { DataType.ARRAY_UW -> array.array!![index] = value.integerValue() DataType.ARRAY_W -> array.array!![index] = value.integerValue() - else -> throw VmExecutionException("not a proper array var with word elements") + else -> throw VmExecutionException("not a proper arrayspec var with word elements") } } @@ -1328,10 +1276,10 @@ class StackVm(private var traceOutputFile: String?) { // assume the variable is a pointer (address) and write the float value to that memory location mem.setFloat(variable.integerValue(), value.numericValue().toDouble()) } else { - // set indexed float element in the array + // set indexed float element in the arrayspec val array = heap.get(variable.heapId) if(array.type!=DataType.ARRAY_F) - throw VmExecutionException("not a proper array var with float elements") + throw VmExecutionException("not a proper arrayspec var with float elements") array.doubleArray!![index] = value.numericValue().toDouble() } } @@ -1570,7 +1518,7 @@ class StackVm(private var traceOutputFile: String?) { } Syscall.FUNC_WRD -> { val value = evalstack.pop() - checkDt(value, setOf(DataType.UBYTE, DataType.BYTE, DataType.UWORD)) + checkDt(value, DataType.UBYTE, DataType.BYTE, DataType.UWORD) when(value.type) { DataType.UBYTE, DataType.BYTE -> evalstack.push(Value(DataType.WORD, value.integerValue())) DataType.UWORD -> { @@ -1587,7 +1535,7 @@ class StackVm(private var traceOutputFile: String?) { } Syscall.FUNC_UWRD -> { val value = evalstack.pop() - checkDt(value, setOf(DataType.UBYTE, DataType.BYTE, DataType.WORD)) + checkDt(value, DataType.UBYTE, DataType.BYTE, DataType.WORD) when(value.type) { DataType.UBYTE -> evalstack.push(Value(DataType.UWORD, value.integerValue())) DataType.UWORD -> evalstack.push(value) diff --git a/compiler/test/StackVMOpcodeTests.kt b/compiler/test/StackVMOpcodeTests.kt index e67a20102..c9e5c4bb3 100644 --- a/compiler/test/StackVMOpcodeTests.kt +++ b/compiler/test/StackVMOpcodeTests.kt @@ -222,10 +222,10 @@ class TestStackVmOpcodes { Instruction(Opcode.PUSH_WORD, Value(DataType.WORD, -23456)), Instruction(Opcode.PUSH_BYTE, Value(DataType.UBYTE, 177)), Instruction(Opcode.PUSH_BYTE, Value(DataType.BYTE, -55)), - Instruction(Opcode.POP_MEM_B, Value(DataType.UWORD, 0x2000)), - Instruction(Opcode.POP_MEM_UB, Value(DataType.UWORD, 0x2001)), - Instruction(Opcode.POP_MEM_W, Value(DataType.UWORD, 0x3000)), - Instruction(Opcode.POP_MEM_UW, Value(DataType.UWORD, 0x3002)), + Instruction(Opcode.POP_MEM_BYTE, Value(DataType.UWORD, 0x2000)), + Instruction(Opcode.POP_MEM_BYTE, Value(DataType.UWORD, 0x2001)), + Instruction(Opcode.POP_MEM_WORD, Value(DataType.UWORD, 0x3000)), + Instruction(Opcode.POP_MEM_WORD, Value(DataType.UWORD, 0x3002)), Instruction(Opcode.POP_MEM_FLOAT, Value(DataType.UWORD, 0x4000))) vm.load(makeProg(ins), null) assertEquals(0, vm.mem.getUWord(0x2000)) @@ -281,51 +281,6 @@ class TestStackVmOpcodes { } } - @Test - fun testCopyVar() { - val ins = mutableListOf( - Instruction(Opcode.COPY_VAR_BYTE, null, null, "bvar1", "bvar2"), - Instruction(Opcode.COPY_VAR_WORD, null, null, "wvar1", "wvar2"), - Instruction(Opcode.COPY_VAR_FLOAT, null, null, "fvar1", "fvar2"), - Instruction(Opcode.COPY_VAR_WORD, null, null, "wvar1", "bvar2")) - val vars = mapOf( - "bvar1" to Value(DataType.UBYTE, 1), - "bvar2" to Value(DataType.UBYTE, 2), - "wvar1" to Value(DataType.UWORD, 1111), - "wvar2" to Value(DataType.UWORD, 2222), - "fvar1" to Value(DataType.FLOAT, 11.11), - "fvar2" to Value(DataType.FLOAT, 22.22) - ) - vm.load(makeProg(ins, vars), null) - assertEquals(12, vm.variables.size) - vm.step(3) - assertEquals(Value(DataType.UBYTE, 1), vm.variables["bvar2"]) - assertEquals(Value(DataType.UWORD, 1111), vm.variables["wvar2"]) - assertEquals(Value(DataType.FLOAT, 11.11), vm.variables["fvar2"]) - assertFailsWith { - vm.step(1) - } - } - - @Test - fun testCopyMem() { - val ins = mutableListOf( - Instruction(Opcode.COPY_MEM_BYTE, Value(DataType.UWORD, 0xc000), Value(DataType.UWORD, 0xc001)), - Instruction(Opcode.COPY_MEM_WORD, Value(DataType.UWORD, 0xc100), Value(DataType.UWORD, 0xc102)), - Instruction(Opcode.COPY_MEM_FLOAT, Value(DataType.UWORD, 0xc200), Value(DataType.UWORD, 0xc300))) - val mem=mapOf(0xc000 to listOf(Value(DataType.UBYTE, 0x45)), - 0xc100 to listOf(Value(DataType.UWORD, 0xc2ca)), - 0xc200 to listOf(Value(DataType.FLOAT, 42.25))) - vm.load(makeProg(ins, mem=mem), null) - assertEquals(0, vm.mem.getUByte(0xc001)) - assertEquals(0, vm.mem.getUWord(0xc102)) - assertEquals(0.0, vm.mem.getFloat(0xc300)) - vm.step(3) - assertEquals(0x45, vm.mem.getUByte(0xc001)) - assertEquals(0xc2ca, vm.mem.getUWord(0xc102)) - assertEquals(42.25, vm.mem.getFloat(0xc300)) - } - @Test fun testAdd() { testBinaryOperator(Value(DataType.UBYTE, 140), Opcode.ADD_UB, Value(DataType.UBYTE, 222), Value(DataType.UBYTE, 106)) diff --git a/docs/source/programming.rst b/docs/source/programming.rst index 69cf5c6e0..6e69a3b12 100644 --- a/docs/source/programming.rst +++ b/docs/source/programming.rst @@ -200,17 +200,19 @@ Arrays can be made of bytes, words and floats. Matrixes can oly be made of bytes byte[4] array = [1, 2, 3, 4] ; initialize the array byte[99] array = 255 ; initialize array with all 255's [255, 255, 255, 255, ...] byte[100] array = 100 to 199 ; initialize array with [100, 101, ..., 198, 199] - byte[2,3] matrix = 1 ; a matrix of 2*3=6 bytes all with value 1 byte[2,3] matrix = [1,2,3,4,5,6] ; a 2*3 matrix with value |(1,2) (3,4) (5,6)| + ubyte[2,3] matrix = 255 ; a matrix of 2*3=6 unsigned bytes all with value 255 value = array[3] ; the fourth value in the array (index is 0-based) value = matrix[4,2] ; the byte at the 5th column and 3rd row in the matrix char = string[4] ; the fifth character (=byte) in the string .. note:: - Right now, the array and matrix size should be small enough to be indexable by a single byte index. - This means byte arrays and matrixes should be <= 256 elements, word arrays <= 128 elements, and float - arrays <= 51 elements. This limit may be lifted in a future version. + Right now, the array should be small enough to be indexable by a single byte index. + This means byte arrays should be <= 256 elements, word arrays <= 128 elements, and float + arrays <= 51 elements. This limit may or may not be lifted in a future version. + Matrixes can be indexed in each dimension only by a byte as well, this also means + their maximum size is 65536 elements (bytes). Note that the various keywords for the data type and variable type (``byte``, ``word``, ``const``, etc.) diff --git a/prog8lib/prog8lib.p8 b/prog8lib/prog8lib.p8 index c20460865..884d2bea3 100644 --- a/prog8lib/prog8lib.p8 +++ b/prog8lib/prog8lib.p8 @@ -34,9 +34,15 @@ ror2_word ub2float rts +b2float + rts + uw2float rts +w2float + rts + push_float rts