From 7cb5702b3712979bb89701fa833068350bdd4ea4 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Sun, 28 Jul 2019 21:03:09 +0200 Subject: [PATCH] array asm --- compiler/src/prog8/ast/base/Base.kt | 2 + .../src/prog8/ast/processing/AstChecker.kt | 14 +- .../compiler/target/c64/codegen2/AsmGen2.kt | 442 +++++++++++++----- .../c64/codegen2/BuiltinFunctionsAsmGen.kt | 18 +- examples/test.p8 | 84 +++- examples/testarrays.p8 | 144 ++++++ 6 files changed, 562 insertions(+), 142 deletions(-) create mode 100644 examples/testarrays.p8 diff --git a/compiler/src/prog8/ast/base/Base.kt b/compiler/src/prog8/ast/base/Base.kt index c89d4664b..cc811df01 100644 --- a/compiler/src/prog8/ast/base/Base.kt +++ b/compiler/src/prog8/ast/base/Base.kt @@ -122,6 +122,8 @@ val IterableDatatypes = setOf( val PassByValueDatatypes = NumericDatatypes val PassByReferenceDatatypes = IterableDatatypes.plus(DataType.STRUCT) val ArrayElementTypes = mapOf( + DataType.STR to DataType.UBYTE, + DataType.STR_S to DataType.UBYTE, DataType.ARRAY_B to DataType.BYTE, DataType.ARRAY_UB to DataType.UBYTE, DataType.ARRAY_W to DataType.WORD, diff --git a/compiler/src/prog8/ast/processing/AstChecker.kt b/compiler/src/prog8/ast/processing/AstChecker.kt index 738f70486..b4188d6fb 100644 --- a/compiler/src/prog8/ast/processing/AstChecker.kt +++ b/compiler/src/prog8/ast/processing/AstChecker.kt @@ -913,12 +913,14 @@ internal class AstChecker(private val program: Program, if(index!=null && (index<0 || index>=arraysize)) checkResult.add(ExpressionError("array index out of bounds", arrayIndexedExpression.arrayspec.position)) } else if(target.datatype in StringDatatypes) { - // check string lengths - val heapId = (target.value as ReferenceLiteralValue).heapId!! - val stringLen = program.heap.get(heapId).str!!.length - val index = (arrayIndexedExpression.arrayspec.index as? NumericLiteralValue)?.number?.toInt() - if(index!=null && (index<0 || index>=stringLen)) - checkResult.add(ExpressionError("index out of bounds", arrayIndexedExpression.arrayspec.position)) + if(target.value is ReferenceLiteralValue) { + // check string lengths for non-memory mapped strings + val heapId = (target.value as ReferenceLiteralValue).heapId!! + val stringLen = program.heap.get(heapId).str!!.length + val index = (arrayIndexedExpression.arrayspec.index as? NumericLiteralValue)?.number?.toInt() + if (index != null && (index < 0 || index >= stringLen)) + checkResult.add(ExpressionError("index out of bounds", arrayIndexedExpression.arrayspec.position)) + } } } else checkResult.add(SyntaxError("indexing requires a variable to act upon", arrayIndexedExpression.position)) diff --git a/compiler/src/prog8/compiler/target/c64/codegen2/AsmGen2.kt b/compiler/src/prog8/compiler/target/c64/codegen2/AsmGen2.kt index ec7cd1e4a..0c1ffaafb 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen2/AsmGen2.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen2/AsmGen2.kt @@ -15,6 +15,7 @@ import prog8.compiler.target.c64.MachineDefinition.ESTACK_HI_HEX import prog8.compiler.target.c64.MachineDefinition.ESTACK_HI_PLUS1_HEX import prog8.compiler.target.c64.MachineDefinition.ESTACK_LO_HEX import prog8.compiler.target.c64.MachineDefinition.ESTACK_LO_PLUS1_HEX +import prog8.compiler.target.c64.MachineDefinition.ESTACK_LO_PLUS2_HEX import prog8.compiler.target.c64.Petscii import prog8.functions.BuiltinFunctions import java.io.File @@ -361,6 +362,13 @@ internal class AsmGen2(val program: Program, val array = (decl.value as ReferenceLiteralValue).array!! return when { decl.datatype == DataType.ARRAY_UB -> + // byte array can never contain pointer-to types, so treat values as all integers + array.map { + val number = (it as NumericLiteralValue).number.toInt() + val hexnum = number.toString(16).padStart(2, '0') + "$$hexnum" + } + decl.datatype == DataType.ARRAY_B -> // byte array can never contain pointer-to types, so treat values as all integers array.map { val number = (it as NumericLiteralValue).number.toInt() @@ -371,6 +379,11 @@ internal class AsmGen2(val program: Program, "-$$hexnum" } decl.datatype== DataType.ARRAY_UW -> array.map { + val number = (it as NumericLiteralValue).number.toInt() + val hexnum = number.toString(16).padStart(4, '0') + "$$hexnum" + } + decl.datatype== DataType.ARRAY_W -> array.map { val number = (it as NumericLiteralValue).number.toInt() val hexnum = number.absoluteValue.toString(16).padStart(4, '0') if(number>=0) @@ -378,7 +391,7 @@ internal class AsmGen2(val program: Program, else "-$$hexnum" } - else -> throw AssemblyError("invalid arraysize type") + else -> throw AssemblyError("invalid arraysize type ${decl.datatype}") } } @@ -481,6 +494,45 @@ internal class AsmGen2(val program: Program, return false } + private fun readAndPushArrayvalueWithIndexA(arrayDt: DataType, variablename: String) { + when (ArrayElementTypes.getValue(arrayDt).memorySize()) { + 1 -> {} + 2 -> out(" asl a") + 5 -> out(" sta ${C64Zeropage.SCRATCH_REG} | asl a | asl a | clc | adc ${C64Zeropage.SCRATCH_REG}") + else -> throw AssemblyError("invalid memory size") + } + when (arrayDt) { + DataType.STR, DataType.STR_S, DataType.ARRAY_UB, DataType.ARRAY_B -> + out(" tay | lda $variablename,y | sta $ESTACK_LO_HEX,x | dex") + DataType.ARRAY_UW, DataType.ARRAY_W -> + out(" tay | lda $variablename,y | sta $ESTACK_LO_HEX,x | iny | lda $variablename,y | sta $ESTACK_HI_HEX,x | dex") + DataType.ARRAY_F -> + out(""" + sta $ESTACK_LO_HEX,x + dex + jsr c64flt.push_float_from_indexed_var + """) + else -> + throw AssemblyError("weird array type") + } + } + + private fun saveRegister(register: Register) { + when(register) { + Register.A -> out(" pha") + Register.X -> out(" txa | pha") + Register.Y -> out(" tya | pha") + } + } + + private fun restoreRegister(register: Register) { + when(register) { + Register.A -> out(" pla") + Register.X -> out(" pla | tax") + Register.Y -> out(" pla | tay") + } + } + private fun translateSubroutine(sub: Subroutine) { out("") outputSourceLine(sub) @@ -579,20 +631,20 @@ internal class AsmGen2(val program: Program, literal!=null -> { // optimize when the argument is a constant literal when(arg.value.type) { - in ByteDatatypes -> assignByteConstant(target, literal.number.toShort()) - in WordDatatypes -> assignWordConstant(target, literal.number.toInt()) - DataType.FLOAT -> assignFloatConstant(target, literal.number.toDouble()) - in PassByReferenceDatatypes-> TODO( "str/array/struct sub arg") + in ByteDatatypes -> assignFromByteConstant(target, literal.number.toShort()) + in WordDatatypes -> assignFromWordConstant(target, literal.number.toInt()) + DataType.FLOAT -> assignFromFloatConstant(target, literal.number.toDouble()) + in PassByReferenceDatatypes -> throw AssemblyError("can't pass string/array as arguments?") else -> throw AssemblyError("weird arg datatype") } } value is IdentifierReference -> { // optimize when the argument is a variable when (arg.value.type) { - in ByteDatatypes -> assignByteVariable(target, value) - in WordDatatypes -> assignWordVariable(target, value) - DataType.FLOAT -> assignFloatVariable(target, value) - in PassByReferenceDatatypes -> TODO("str/array/struct sub arg") + in ByteDatatypes -> assignFromByteVariable(target, value) + in WordDatatypes -> assignFromWordVariable(target, value) + DataType.FLOAT -> assignFromFloatVariable(target, value) + in PassByReferenceDatatypes -> throw AssemblyError("can't pass string/array as arguments?") else -> throw AssemblyError("weird arg datatype") } } @@ -616,12 +668,12 @@ internal class AsmGen2(val program: Program, literal!=null -> { val target = AssignTarget(Register.valueOf(register.name), null, null, null, sub.position) target.linkParents(value.parent) - assignByteConstant(target, literal.number.toShort()) + assignFromByteConstant(target, literal.number.toShort()) } value is IdentifierReference -> { val target = AssignTarget(Register.valueOf(register.name), null, null, null, sub.position) target.linkParents(value.parent) - assignByteVariable(target, value) + assignFromByteVariable(target, value) } else -> { translateExpression(value) @@ -646,11 +698,20 @@ internal class AsmGen2(val program: Program, } else if(value is AddressOf) { // optimize when the argument is an address of something val sourceName = asmIdentifierName(value.identifier) - if (register == RegisterOrPair.AX) out(" lda #<$sourceName | ldx #>$sourceName") + if (register == RegisterOrPair.AX) out(" lda #<$sourceName | ldx #>$sourceName") + else if (register == RegisterOrPair.AY) out(" lda #<$sourceName | ldy #>$sourceName") + else if (register == RegisterOrPair.XY) out(" ldx #<$sourceName | ldy #>$sourceName") + } else if(value is IdentifierReference) { + val sourceName = asmIdentifierName(value) + if (register == RegisterOrPair.AX) out(" lda #<$sourceName | ldx #>$sourceName") else if (register == RegisterOrPair.AY) out(" lda #<$sourceName | ldy #>$sourceName") else if (register == RegisterOrPair.XY) out(" ldx #<$sourceName | ldy #>$sourceName") } else { - TODO("register pair param non-const $register = ${value}") + translateExpression(value) + if (register == RegisterOrPair.AX || register == RegisterOrPair.XY) + throw AssemblyError("can't use X register here - use a variable") + else if (register == RegisterOrPair.AY) + out(" inx | lda $ESTACK_LO_HEX,x | ldy $ESTACK_HI_HEX,x") } } } @@ -761,9 +822,13 @@ internal class AsmGen2(val program: Program, private fun translate(stmt: PostIncrDecr) { val incr = stmt.operator=="++" + val targetIdent = stmt.target.identifier + val targetMemory = stmt.target.memoryAddress + val targetArrayIdx = stmt.target.arrayindexed + val targetRegister = stmt.target.register when { - stmt.target.register!=null -> { - when(stmt.target.register!!) { + targetRegister!=null -> { + when(targetRegister) { Register.A -> { if(incr) out(" clc | adc #1 ") @@ -778,8 +843,8 @@ internal class AsmGen2(val program: Program, } } } - stmt.target.identifier!=null -> { - val what = asmIdentifierName(stmt.target.identifier!!) + targetIdent!=null -> { + val what = asmIdentifierName(targetIdent) val dt = stmt.target.inferType(program, stmt) when (dt) { in ByteDatatypes -> out(if (incr) " inc $what" else " dec $what") @@ -796,22 +861,39 @@ internal class AsmGen2(val program: Program, else -> throw AssemblyError("need numeric type") } } - stmt.target.memoryAddress!=null -> { - val target = stmt.target.memoryAddress!!.addressExpression - when (target) { + targetMemory!=null -> { + val addressExpr = targetMemory.addressExpression + when (addressExpr) { is NumericLiteralValue -> { - val what = target.number.toHex() + val what = addressExpr.number.toHex() out(if(incr) " inc $what" else " dec $what") } is IdentifierReference -> { - val what = asmIdentifierName(target) + val what = asmIdentifierName(addressExpr) out(if(incr) " inc $what" else " dec $what") } - else -> throw AssemblyError("weird target type $target") + else -> throw AssemblyError("weird target type $targetMemory") } } - stmt.target.arrayindexed!=null -> { - TODO("postincrdecr array element ${stmt.target.arrayindexed}") + targetArrayIdx!=null -> { + val index = targetArrayIdx.arrayspec.index + val targetName = asmIdentifierName(targetArrayIdx.identifier) + val elementDt = ArrayElementTypes.getValue(targetArrayIdx.identifier.targetVarDecl(program.namespace)!!.datatype) + when(index) { + is NumericLiteralValue -> { + val indexValue = index.number.toInt() * elementDt.memorySize() + out(if(incr) " inc $targetName+$indexValue" else " dec $targetName+$indexValue") + } + is RegisterExpr -> { + TODO("postincrdecr $elementDt array $targetName [ $index ]") + } + is IdentifierReference -> { + TODO("postincrdecr $elementDt array $targetName [ $index ]") + } + else -> { + TODO("postincrdecr $elementDt array $targetName [ $index ]") + } + } } else -> throw AssemblyError("weird target type ${stmt.target}") } @@ -848,21 +930,21 @@ internal class AsmGen2(val program: Program, is NumericLiteralValue -> { val numVal = assign.value as NumericLiteralValue when(numVal.type) { - DataType.UBYTE, DataType.BYTE -> assignByteConstant(assign.target, numVal.number.toShort()) - DataType.UWORD, DataType.WORD -> assignWordConstant(assign.target, numVal.number.toInt()) - DataType.FLOAT -> assignFloatConstant(assign.target, numVal.number.toDouble()) + DataType.UBYTE, DataType.BYTE -> assignFromByteConstant(assign.target, numVal.number.toShort()) + DataType.UWORD, DataType.WORD -> assignFromWordConstant(assign.target, numVal.number.toInt()) + DataType.FLOAT -> assignFromFloatConstant(assign.target, numVal.number.toDouble()) else -> throw AssemblyError("weird numval type") } } is RegisterExpr -> { - assignRegister(assign.target, (assign.value as RegisterExpr).register) + assignFromRegister(assign.target, (assign.value as RegisterExpr).register) } is IdentifierReference -> { val type = assign.target.inferType(program, assign)!! when(type) { - DataType.UBYTE, DataType.BYTE -> assignByteVariable(assign.target, assign.value as IdentifierReference) - DataType.UWORD, DataType.WORD -> assignWordVariable(assign.target, assign.value as IdentifierReference) - DataType.FLOAT -> assignFloatVariable(assign.target, assign.value as IdentifierReference) + DataType.UBYTE, DataType.BYTE -> assignFromByteVariable(assign.target, assign.value as IdentifierReference) + DataType.UWORD, DataType.WORD -> assignFromWordVariable(assign.target, assign.value as IdentifierReference) + DataType.FLOAT -> assignFromFloatVariable(assign.target, assign.value as IdentifierReference) in StringDatatypes -> TODO("str assignment") else -> throw AssemblyError("unsupported assignment target type $type") } @@ -870,17 +952,17 @@ internal class AsmGen2(val program: Program, is AddressOf -> { val identifier = (assign.value as AddressOf).identifier val scopedname = (assign.value as AddressOf).scopedname!! - assignAddressOf(assign.target, identifier, scopedname) + assignFromAddressOf(assign.target, identifier, scopedname) } is DirectMemoryRead -> { val read = (assign.value as DirectMemoryRead) when(read.addressExpression) { is NumericLiteralValue -> { val address = (read.addressExpression as NumericLiteralValue).number.toInt() - assignMemoryByte(assign.target, address, null) + assignFromMemoryByte(assign.target, address, null) } is IdentifierReference -> { - assignMemoryByte(assign.target, null, read.addressExpression as IdentifierReference) + assignFromMemoryByte(assign.target, null, read.addressExpression as IdentifierReference) } else -> { translateExpression(read.addressExpression) @@ -890,15 +972,15 @@ internal class AsmGen2(val program: Program, } is PrefixExpression -> { translateExpression(assign.value as PrefixExpression) - assignEvalResult(assign.target) + assignFromEvalResult(assign.target) } is BinaryExpression -> { translateExpression(assign.value as BinaryExpression) - assignEvalResult(assign.target) + assignFromEvalResult(assign.target) } is ArrayIndexedExpression -> { translateExpression(assign.value as ArrayIndexedExpression) - assignEvalResult(assign.target) + assignFromEvalResult(assign.target) } is TypecastExpression -> { val cast = assign.value as TypecastExpression @@ -911,12 +993,12 @@ internal class AsmGen2(val program: Program, translate(assign) } else { translateExpression(assign.value as TypecastExpression) - assignEvalResult(assign.target) + assignFromEvalResult(assign.target) } } is FunctionCall -> { translateExpression(assign.value as FunctionCall) - assignEvalResult(assign.target) + assignFromEvalResult(assign.target) } is ReferenceLiteralValue -> TODO("string/array/struct assignment?") is StructLiteralValue -> throw AssemblyError("struct literal value assignment should have been flattened") @@ -925,7 +1007,42 @@ internal class AsmGen2(val program: Program, } private fun translateExpression(expr: ArrayIndexedExpression) { - TODO("evaluate arrayindexed $expr") + val arrayDt = expr.identifier.targetVarDecl(program.namespace)!!.datatype + val sourceName = asmIdentifierName(expr.identifier) + val index = expr.arrayspec.index + when (index) { + is NumericLiteralValue -> { + val indexValue = index.number.toInt() * ArrayElementTypes.getValue(arrayDt).memorySize() + when (arrayDt) { + DataType.STR, DataType.STR_S, DataType.ARRAY_UB, DataType.ARRAY_B -> + out(" lda $sourceName+$indexValue | sta $ESTACK_LO_HEX,x | dex") + DataType.ARRAY_UW, DataType.ARRAY_W -> + out(" lda $sourceName+$indexValue | sta $ESTACK_LO_HEX,x | lda $sourceName+$indexValue+1 | sta $ESTACK_HI_HEX,x | dex") + DataType.ARRAY_F -> + out(" lda #<$sourceName+$indexValue | ldy #>$sourceName+$indexValue | jsr c64flt.push_float") + else -> + throw AssemblyError("weird array type") + } + } + is RegisterExpr -> { + when (index.register) { + Register.A -> {} + Register.X -> out(" txa") + Register.Y -> out(" tya") + } + readAndPushArrayvalueWithIndexA(arrayDt, sourceName) + } + is IdentifierReference -> { + val indexName = asmIdentifierName(index) + out(" lda $indexName") + readAndPushArrayvalueWithIndexA(arrayDt, sourceName) + } + else -> { + translateExpression(index) + out(" inx | lda $ESTACK_LO_HEX,x") + readAndPushArrayvalueWithIndexA(arrayDt, sourceName) + } + } } private fun translateExpression(expr: TypecastExpression) { @@ -1049,7 +1166,8 @@ internal class AsmGen2(val program: Program, DataType.UBYTE, DataType.BYTE -> { out(" lda $varname | sta $ESTACK_LO_HEX,x | dex") } - DataType.UWORD, DataType.WORD -> { + DataType.UWORD, DataType.WORD, in ArrayDatatypes, in StringDatatypes -> { + // (for arrays and strings, push their address) out(" lda $varname | sta $ESTACK_LO_HEX,x | lda $varname+1 | sta $ESTACK_HI_HEX,x | dex") } DataType.FLOAT -> { @@ -1120,8 +1238,8 @@ internal class AsmGen2(val program: Program, throw AssemblyError("remainder of signed integers is not properly defined/implemented, use unsigned instead") out(" jsr prog8_lib.remainder_ub") } - "+" -> {TODO("plus bytes")} - "-" -> {TODO("minus bytes")} + "+" -> out(" jsr prog8_lib.add_w") + "-" -> out(" jsr prog8_lib.sub_w") "<<" -> throw AssemblyError("<< should not operate via stack") ">>" -> throw AssemblyError(">> should not operate via stack") "<" -> out(if(types==DataType.UBYTE) " jsr prog8_lib.less_ub" else " jsr prog8_lib.less_b") @@ -1150,8 +1268,20 @@ internal class AsmGen2(val program: Program, throw AssemblyError("remainder of signed integers is not properly defined/implemented, use unsigned instead") out(" jsr prog8_lib.remainder_uw") } - "+" -> {TODO("plus word")} - "-" -> {TODO("minus word")} + "+" -> out(""" + lda $ESTACK_LO_PLUS2_HEX,x + clc + adc $ESTACK_LO_PLUS1_HEX,x + inx + sta $ESTACK_LO_PLUS1_HEX,x + """) + "-" -> out(""" + lda $ESTACK_LO_PLUS2_HEX,x + sec + sbc $ESTACK_LO_PLUS1_HEX,x + inx + sta $ESTACK_LO_PLUS1_HEX,x + """) "<<" -> throw AssemblyError("<< should not operate via stack") ">>" -> throw AssemblyError(">> should not operate via stack") "<" -> out(if(types==DataType.UWORD) " jsr prog8_lib.less_uw" else " jsr prog8_lib.less_w") @@ -1188,7 +1318,7 @@ internal class AsmGen2(val program: Program, } } - private fun assignEvalResult(target: AssignTarget) { + private fun assignFromEvalResult(target: AssignTarget) { val targetIdent = target.identifier when { target.register!=null -> { @@ -1237,43 +1367,47 @@ internal class AsmGen2(val program: Program, } } - private fun assignAddressOf(target: AssignTarget, name: IdentifierReference, scopedname: String) { + private fun assignFromAddressOf(target: AssignTarget, name: IdentifierReference, scopedname: String) { val targetIdent = target.identifier + val targetArrayIdx = target.arrayindexed + val struct = name.memberOfStruct(program.namespace) + val sourceName = if(struct!=null) { + // take the address of the first struct member instead + val decl = name.targetVarDecl(program.namespace)!! + val firstStructMember = struct.nameOfFirstMember() + // find the flattened var that belongs to this first struct member + val firstVarName = listOf(decl.name, firstStructMember) + val firstVar = name.definingScope().lookup(firstVarName, name) as VarDecl + firstVar.name + } else { + fixNameSymbols(scopedname) + } when { targetIdent!=null -> { val targetName = asmIdentifierName(targetIdent) - val struct = name.memberOfStruct(program.namespace) - if(struct!=null) { - // take the address of the first struct member instead - val decl = name.targetVarDecl(program.namespace)!! - val firstStructMember = struct.nameOfFirstMember() - // find the flattened var that belongs to this first struct member - val firstVarName = listOf(decl.name, firstStructMember) - val firstVar = name.definingScope().lookup(firstVarName, name) as VarDecl - val sourceName = firstVar.name - out(""" + out(""" lda #<$sourceName ldy #>$sourceName sta $targetName sty $targetName+1 """) - } else { - val sourceName = fixNameSymbols(scopedname) - out(""" - lda #<$sourceName - ldy #>$sourceName - sta $targetName - sty $targetName+1 - """) - } } - else -> TODO("assign address to $target") + target.memoryAddress!=null -> { + TODO("assign address $sourceName to memory word $target") + } + targetArrayIdx!=null -> { + val index = targetArrayIdx.arrayspec.index + val targetName = asmIdentifierName(targetArrayIdx.identifier) + TODO("assign address $sourceName to array $targetName [ $index ]") + } + else -> TODO("assign address $sourceName to $target") } } - private fun assignWordVariable(target: AssignTarget, variable: IdentifierReference) { + private fun assignFromWordVariable(target: AssignTarget, variable: IdentifierReference) { val sourceName = asmIdentifierName(variable) val targetIdent = target.identifier + val targetArrayIdx = target.arrayindexed when { targetIdent!=null -> { val targetName = asmIdentifierName(targetIdent) @@ -1284,13 +1418,22 @@ internal class AsmGen2(val program: Program, sty $targetName+1 """) } - else -> TODO("assign word to $target") + target.memoryAddress!=null -> { + TODO("assign wordvar $sourceName to memory ${target.memoryAddress}") + } + targetArrayIdx!=null -> { + val index = targetArrayIdx.arrayspec.index + val targetName = asmIdentifierName(targetArrayIdx.identifier) + TODO("assign wordvar $sourceName to array $targetName [ $index ]") + } + else -> TODO("assign wordvar to $target") } } - private fun assignFloatVariable(target: AssignTarget, variable: IdentifierReference) { + private fun assignFromFloatVariable(target: AssignTarget, variable: IdentifierReference) { val sourceName = asmIdentifierName(variable) val targetIdent = target.identifier + val targetArrayIdx = target.arrayindexed when { targetIdent!=null -> { val targetName = asmIdentifierName(targetIdent) @@ -1307,13 +1450,22 @@ internal class AsmGen2(val program: Program, sta $targetName+4 """) } - else -> TODO("assign float to $target") + target.memoryAddress!=null -> { + TODO("assign floatvar $sourceName to memory ${target.memoryAddress}") + } + targetArrayIdx!=null -> { + val index = targetArrayIdx.arrayspec.index + val targetName = asmIdentifierName(targetArrayIdx.identifier) + TODO("assign floatvar $sourceName to array $targetName [ $index ]") + } + else -> TODO("assign floatvar to $target") } } - private fun assignByteVariable(target: AssignTarget, variable: IdentifierReference) { + private fun assignFromByteVariable(target: AssignTarget, variable: IdentifierReference) { val sourceName = asmIdentifierName(variable) val targetIdent = target.identifier + val targetArrayIdx = target.arrayindexed when { target.register!=null -> { out(" ld${target.register.name.toLowerCase()} $sourceName") @@ -1325,11 +1477,39 @@ internal class AsmGen2(val program: Program, sta $targetName """) } - else -> TODO("assign byte to $target") + targetArrayIdx!=null -> { + val index = targetArrayIdx.arrayspec.index + val targetName = asmIdentifierName(targetArrayIdx.identifier) + TODO("assign bytevar to array $targetName [ $index ] ") + } + target.memoryAddress != null -> { + val addressExpr = target.memoryAddress.addressExpression + val addressLv = addressExpr as? NumericLiteralValue + when { + addressLv != null -> out(" lda $sourceName | sta ${addressLv.number.toHex()}") + addressExpr is IdentifierReference -> { + val targetName = asmIdentifierName(addressExpr) + out(" lda $sourceName | sta $targetName") + } + else -> { + translateExpression(addressExpr) + out(""" + inx + lda $ESTACK_LO_HEX,x + sta (+) +1 + lda $ESTACK_HI_HEX,x + sta (+) +2 + lda $sourceName ++ sta ${65535.toHex()} ; modified + """) + } + } + } + else -> TODO("assign bytevar to $target") } } - private fun assignRegister(target: AssignTarget, register: Register) { + private fun assignFromRegister(target: AssignTarget, register: Register) { val targetIdent = target.identifier val targetArrayIdx = target.arrayindexed when { @@ -1360,48 +1540,43 @@ internal class AsmGen2(val program: Program, } } - private fun saveRegister(register: Register) { - when(register) { - Register.A -> out(" pha") - Register.X -> out(" txa | pha") - Register.Y -> out(" tya | pha") - } - } - - private fun restoreRegister(register: Register) { - when(register) { - Register.A -> out(" pla") - Register.X -> out(" pla | tax") - Register.Y -> out(" pla | tay") - } - } - - private fun assignWordConstant(target: AssignTarget, word: Int) { + private fun assignFromWordConstant(target: AssignTarget, word: Int) { val targetIdent = target.identifier - if(targetIdent!=null) { - val targetName = asmIdentifierName(targetIdent) - if(word ushr 8 == word and 255) { - // lsb=msb - out(""" + val targetArrayIdx = target.arrayindexed + when { + targetIdent!=null -> { + val targetName = asmIdentifierName(targetIdent) + if(word ushr 8 == word and 255) { + // lsb=msb + out(""" lda #${(word and 255).toHex()} sta $targetName sta $targetName+1 """) - } else { - out(""" + } else { + out(""" lda #<${word.toHex()} ldy #>${word.toHex()} sta $targetName sty $targetName+1 """) + } } - } else { - TODO("assign word $word to $target") + target.memoryAddress!=null -> { + TODO("assign word $word to memory ${target.memoryAddress}") + } + targetArrayIdx!=null -> { + val index = targetArrayIdx.arrayspec.index + val targetName = asmIdentifierName(targetArrayIdx.identifier) + TODO("assign word $word to array $targetName [ $index ]") + } + else -> TODO("assign word $word to $target") } } - private fun assignByteConstant(target: AssignTarget, byte: Short) { + private fun assignFromByteConstant(target: AssignTarget, byte: Short) { val targetIdent = target.identifier + val targetArrayIdx = target.arrayindexed when { target.register!=null -> { out(" ld${target.register.name.toLowerCase()} #${byte.toHex()}") @@ -1410,26 +1585,44 @@ internal class AsmGen2(val program: Program, val targetName = asmIdentifierName(targetIdent) out(" lda #${byte.toHex()} | sta $targetName ") } + target.memoryAddress!=null -> { + TODO("assign byte $byte to memory ${target.memoryAddress}") + } + targetArrayIdx!=null -> { + val index = targetArrayIdx.arrayspec.index + val targetName = asmIdentifierName(targetArrayIdx.identifier) + TODO("assign byte $byte to array $targetName [ $index ]") + } else -> TODO("assign byte $byte to $target") } } - private fun assignFloatConstant(target: AssignTarget, float: Double) { + private fun assignFromFloatConstant(target: AssignTarget, float: Double) { val targetIdent = target.identifier + val targetArrayIdx = target.arrayindexed if(float==0.0) { // optimized case for float zero - if (targetIdent != null) { - val targetName = asmIdentifierName(targetIdent) - out(""" - lda #0 - sta $targetName - sta $targetName+1 - sta $targetName+2 - sta $targetName+3 - sta $targetName+4 - """) - } else { - TODO("assign float 0.0 to $target") + when { + targetIdent != null -> { + val targetName = asmIdentifierName(targetIdent) + out(""" + lda #0 + sta $targetName + sta $targetName+1 + sta $targetName+2 + sta $targetName+3 + sta $targetName+4 + """) + } + target.memoryAddress!=null -> { + TODO("assign float 0.0 to memory ${target.memoryAddress}") + } + targetArrayIdx!=null -> { + val index = targetArrayIdx.arrayspec.index + val targetName = asmIdentifierName(targetArrayIdx.identifier) + TODO("assign float 0.0 to array $targetName [ $index ]") + } + else -> TODO("assign float 0.0 to $target") } } else { // non-zero value @@ -1454,8 +1647,9 @@ internal class AsmGen2(val program: Program, } } - private fun assignMemoryByte(target: AssignTarget, address: Int?, identifier: IdentifierReference?) { + private fun assignFromMemoryByte(target: AssignTarget, address: Int?, identifier: IdentifierReference?) { val targetIdent = target.identifier + val targetArrayIdx = target.arrayindexed if(address!=null) { when { target.register!=null -> { @@ -1468,6 +1662,14 @@ internal class AsmGen2(val program: Program, sta $targetName """) } + target.memoryAddress!=null -> { + TODO("assign memory byte at $address to memory ${target.memoryAddress}") + } + targetArrayIdx!=null -> { + val index = targetArrayIdx.arrayspec.index + val targetName = asmIdentifierName(targetArrayIdx.identifier) + TODO("assign memory byte at $address to array $targetName [ $index ]") + } else -> TODO("assign memory byte $target") } } @@ -1493,6 +1695,14 @@ internal class AsmGen2(val program: Program, sta $targetName """) } + target.memoryAddress!=null -> { + TODO("assign memory byte $sourceName to memoyr ${target.memoryAddress}") + } + targetArrayIdx!=null -> { + val index = targetArrayIdx.arrayspec.index + val targetName = asmIdentifierName(targetArrayIdx.identifier) + TODO("assign memory byte $sourceName to array $targetName [ $index ]") + } else -> TODO("assign memory byte $target") } } diff --git a/compiler/src/prog8/compiler/target/c64/codegen2/BuiltinFunctionsAsmGen.kt b/compiler/src/prog8/compiler/target/c64/codegen2/BuiltinFunctionsAsmGen.kt index 1d31ae900..c9c451fb5 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen2/BuiltinFunctionsAsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen2/BuiltinFunctionsAsmGen.kt @@ -3,6 +3,7 @@ package prog8.compiler.target.c64.codegen2 import prog8.ast.IFunctionCall import prog8.ast.Program import prog8.ast.base.WordDatatypes +import prog8.ast.expressions.Expression import prog8.ast.expressions.FunctionCall import prog8.ast.expressions.IdentifierReference import prog8.ast.expressions.NumericLiteralValue @@ -32,7 +33,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, if(discardResult) { if(func.pure) return // can just ignore the whole function call altogether - else + else if(func.returntype!=null) throw AssemblyError("discarding result of non-pure function $fcall") } @@ -52,13 +53,24 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, } } "mkword" -> { - asmgen.translateExpression(fcall.arglist[0]) - asmgen.translateExpression(fcall.arglist[1]) + translateFunctionArguments(fcall.arglist) asmgen.out(" inx | lda $ESTACK_LO_HEX,x | sta $ESTACK_HI_PLUS1_HEX,x") } + "memset" -> { + translateFunctionArguments(fcall.arglist) + asmgen.out(" jsr prog8lib.func_memset") + } + "memsetw" -> { + translateFunctionArguments(fcall.arglist) + asmgen.out(" jsr prog8lib.func_memsetw") + } else -> TODO("builtin function $functionName") } } + private fun translateFunctionArguments(args: MutableList) { + args.forEach { asmgen.translateExpression(it) } + } + } diff --git a/examples/test.p8 b/examples/test.p8 index d644fce01..aa1e117b5 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -6,7 +6,57 @@ sub start() { -; + str s1 = "irmen" + str_s s2 = "hello" + + byte[4] barray + ubyte[4] ubarray + word[4] warray + uword[4] uwarray + float[4] flarray + + byte bb + ubyte ub + word ww + uword uw + float fl + + A=s1[2] + ub=s1[2] + ub=s2[2] + bb=barray[2] + ub=ubarray[2] + ww=warray[2] + uw=uwarray[2] + fl=flarray[2] + + A=s1[Y] + ub=s1[A] + ub=s2[A] + bb=barray[A] + ub=ubarray[A] + ww=warray[A] + uw=uwarray[A] + fl=flarray[A] + + A=s1[bb] + ub=s1[bb] + ub=s2[bb] + bb=barray[bb] + ub=ubarray[bb] + ww=warray[bb] + uw=uwarray[bb] + fl=flarray[bb] + + A=s1[bb*3] + ub=s1[bb*3] + ub=s2[bb*3] + bb=barray[bb*3] + ub=ubarray[bb*3] + ww=warray[bb*3] + uw=uwarray[bb*3] + fl=flarray[bb*3] + ; float f1 = 1.1 ; float f2 = 2.2 ; @@ -21,22 +71,22 @@ ; else ; c64scr.print("ok\n") - str s1 = "hello" - str s2 = "hello" - str s3 = "hello" - str s4 = "hello" - - if true { - ubyte ub1 = 33 - A=ub1 - c64scr.print("irmen") - } - - if true { - ubyte ub1 = 33 - A=ub1 - c64scr.print("irmen") - } +; str s1 = "hello" +; str s2 = "hello" +; str s3 = "hello" +; str s4 = "hello" +; +; if true { +; ubyte ub1 = 33 +; A=ub1 +; c64scr.print("irmen") +; } +; +; if true { +; ubyte ub1 = 33 +; A=ub1 +; c64scr.print("irmen") +; } } } diff --git a/examples/testarrays.p8 b/examples/testarrays.p8 new file mode 100644 index 000000000..973ac75cc --- /dev/null +++ b/examples/testarrays.p8 @@ -0,0 +1,144 @@ +%import c64flt +%zeropage basicsafe +%option enable_floats + +~ main { + + sub start() { + + str s1 = "irmen" + str_s s2 = "hello" + &str ms1 = $c000 + + + byte[4] barray + ubyte[4] ubarray + word[4] warray + uword[4] uwarray + float[4] flarray + + &byte[4] mbarray = $c000 + &ubyte[4] mubarray = $c000 + &word[4] mwarray = $c000 + &uword[4] muwarray = $c000 + &float[4] mflarray = $c000 + + byte bb + ubyte ub + word ww + uword uw + float fl + + ; read array + @($d020) = ub + + A=s1[2] + ub=s1[2] + ub=s2[2] + bb=barray[2] + ub=ubarray[2] + ww=warray[2] + uw=uwarray[2] + fl=flarray[2] + A=ms1[2] + ub=ms1[2] + bb=mbarray[2] + ub=mubarray[2] + ww=mwarray[2] + uw=muwarray[2] + fl=mflarray[2] + + A=s1[A] + ub=s2[A] + ub=s2[A] + bb=barray[A] + ub=ubarray[A] + ww=warray[A] + uw=uwarray[A] + fl=flarray[A] + A=ms1[A] + ub=ms1[A] + bb=mbarray[A] + ub=mubarray[A] + ww=mwarray[A] + uw=muwarray[A] + fl=mflarray[A] + + A=s1[bb] + ub=s1[bb] + ub=s2[bb] + bb=barray[bb] + ub=ubarray[bb] + ww=warray[bb] + uw=uwarray[bb] + fl=flarray[bb] + A=ms1[bb] + ub=ms1[bb] + bb=mbarray[bb] + ub=mubarray[bb] + ww=mwarray[bb] + uw=muwarray[bb] + fl=mflarray[bb] + + A=s1[bb*3] + ub=s1[bb*3] + ub=s2[bb*3] + bb=barray[bb*3] + ub=ubarray[bb*3] + ww=warray[bb*3] + uw=uwarray[bb*3] + fl=flarray[bb*3] + A=ms1[bb*3] + ub=ms1[bb*3] + bb=mbarray[bb*3] + ub=mubarray[bb*3] + ww=mwarray[bb*3] + uw=muwarray[bb*3] + fl=mflarray[bb*3] + + ; write array + barray[2]++ + barray[2]-- + s1[2] = A + s1[2] = ub + s2[2] = ub + barray[2] = bb + ubarray[2] = ub + warray[2] = ww + uwarray[2] = uw + flarray[2] = fl + ms1[2] = A + ms1[2] = ub + mbarray[2]++ + mbarray[2] = bb + mbarray[2] = bb + mubarray[2] = ub + mwarray[2] = ww + muwarray[2] = uw + mflarray[2] = fl + +; s1[A] = ub +; s2[A] = ub +; barray[A] = bb +; ubarray[A] = ub +; warray[A] = ww +; uwarray[A] = uw +; flarray[A] = fl +; +; s1[bb] = ub +; s2[bb] = ub +; barray[bb] = bb +; ubarray[bb] = ub +; warray[bb] = ww +; uwarray[bb] = uw +; flarray[bb] = fl +; +; s1[bb*3] = ub +; s2[bb*3] = ub +; barray[bb*3] = bb +; ubarray[bb*3] = ub +; warray[bb*3] = ww +; uwarray[bb*3] = uw +; flarray[bb*3] = fl + } +}