fix the missing cases in certain expressions that need the address of a split word array

This commit is contained in:
Irmen de Jong
2024-12-25 16:07:09 +01:00
parent 0653d430a7
commit fe011de934
8 changed files with 70 additions and 76 deletions

View File

@@ -644,32 +644,6 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
val varname = asmgen.asmVariableName(fcall.args[0] as PtIdentifier) + if(msb) "+1" else "" val varname = asmgen.asmVariableName(fcall.args[0] as PtIdentifier) + if(msb) "+1" else ""
target = AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.forDt(BaseDataType.UBYTE), fcall.definingSub(), fcall.position, variableAsmName = varname) target = AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.forDt(BaseDataType.UBYTE), fcall.definingSub(), fcall.position, variableAsmName = varname)
} }
is PtNumber -> {
val num = (fcall.args[0] as PtNumber).number + if(msb) 1 else 0
val mem = PtMemoryByte(fcall.position)
mem.add(PtNumber(BaseDataType.UBYTE, num, fcall.position))
target = AsmAssignTarget(TargetStorageKind.MEMORY, asmgen, DataType.forDt(BaseDataType.UBYTE), fcall.definingSub(), fcall.position, memory = mem)
}
is PtAddressOf -> {
val addrof = fcall.args[0] as PtAddressOf
if(addrof.identifier.type.isSplitWordArray) {
TODO("address of split word array")
} else {
val mem = PtMemoryByte(fcall.position)
if(addrof.isFromArrayElement)
TODO("address-of arrayelement")
if(msb) {
val address = PtBinaryExpression("+", DataType.forDt(BaseDataType.UWORD), addrof.position)
address.add(addrof)
address.add(PtNumber(address.type.base, 1.0, addrof.position))
mem.add(address)
} else {
mem.add(addrof)
}
target = AsmAssignTarget(TargetStorageKind.MEMORY, asmgen, DataType.forDt(BaseDataType.UBYTE), fcall.definingSub(), fcall.position, memory = mem)
}
}
is PtArrayIndexer -> { is PtArrayIndexer -> {
val indexer = fcall.args[0] as PtArrayIndexer val indexer = fcall.args[0] as PtArrayIndexer
val elementSize: Int val elementSize: Int

View File

@@ -808,11 +808,11 @@ _jump jmp (${target.asmLabel})
asmgen.assignExpressionToRegister(value, RegisterOrPair.AY, true) asmgen.assignExpressionToRegister(value, RegisterOrPair.AY, true)
asmgen.out(" cpy #0") asmgen.out(" cpy #0")
} else { } else {
var varname = asmgen.asmVariableName(value.identifier)
if(value.identifier.type.isSplitWordArray) { if(value.identifier.type.isSplitWordArray) {
TODO("address of split word array") varname += if(value.isMsbForSplitArray) "_msb" else "_lsb"
} else {
asmgen.out(" lda #>${asmgen.asmVariableName(value.identifier)}")
} }
asmgen.out(" lda #>$varname")
} }
} }
else -> { else -> {
@@ -1607,13 +1607,13 @@ _jump jmp (${target.asmLabel})
if(left.isFromArrayElement) if(left.isFromArrayElement)
fallbackTranslateForSimpleCondition(stmt) fallbackTranslateForSimpleCondition(stmt)
else { else {
if(left.identifier.type.isSplitWordArray) { val varname = if(left.identifier.type.isSplitWordArray) {
TODO("address of split word array") if(left.isMsbForSplitArray) left.identifier.name+"_msb" else left.identifier.name+"_lsb"
} else { } else {
asmgen.assignExpressionToRegister(right, RegisterOrPair.AY, signed) left.identifier.name
val varname = left.identifier.name
translateAYNotEquals("#<$varname", "#>$varname")
} }
asmgen.assignExpressionToRegister(right, RegisterOrPair.AY, signed)
translateAYNotEquals("#<$varname", "#>$varname")
} }
} }
else -> { else -> {
@@ -1659,13 +1659,13 @@ _jump jmp (${target.asmLabel})
if(left.isFromArrayElement) if(left.isFromArrayElement)
fallbackTranslateForSimpleCondition(stmt) fallbackTranslateForSimpleCondition(stmt)
else { else {
if(left.identifier.type.isSplitWordArray) { val varname = if(left.identifier.type.isSplitWordArray) {
TODO("address of split word array") if(left.isMsbForSplitArray) left.identifier.name+"_msb" else left.identifier.name+"_lsb"
} else { } else {
asmgen.assignExpressionToRegister(right, RegisterOrPair.AY, signed) left.identifier.name
val varname = left.identifier.name
translateAYEquals("#<$varname", "#>$varname")
} }
asmgen.assignExpressionToRegister(right, RegisterOrPair.AY, signed)
translateAYEquals("#<$varname", "#>$varname")
} }
} }
else -> { else -> {

View File

@@ -1341,13 +1341,12 @@ internal class AssignmentAsmGen(
when (right) { when (right) {
is PtAddressOf -> { is PtAddressOf -> {
val symbol = asmgen.asmVariableName(right.identifier) var symbol = asmgen.asmVariableName(right.identifier)
if(right.isFromArrayElement) { if(right.isFromArrayElement) {
TODO("address-of array element $symbol at ${right.position}") TODO("address-of array element $symbol at ${right.position}")
} else { } else {
if(right.identifier.type.isSplitWordArray) { if(right.identifier.type.isSplitWordArray) {
TODO("address of split word array") symbol = if(right.isMsbForSplitArray) symbol+"_msb" else symbol+"_lsb"
return true
} }
assignExpressionToRegister(left, RegisterOrPair.AY, dt.isSigned) assignExpressionToRegister(left, RegisterOrPair.AY, dt.isSigned)
if(expr.operator=="+") if(expr.operator=="+")
@@ -2579,7 +2578,8 @@ $endLabel""")
private fun assignAddressOf(target: AsmAssignTarget, sourceName: String, arrayDt: DataType?, arrayIndexExpr: PtExpression?) { private fun assignAddressOf(target: AsmAssignTarget, sourceName: String, arrayDt: DataType?, arrayIndexExpr: PtExpression?) {
if(arrayIndexExpr!=null) { if(arrayIndexExpr!=null) {
require(arrayDt?.isSplitWordArray!=true) if(arrayDt?.isSplitWordArray==true)
TODO("address of element of a split word array")
val constIndex = arrayIndexExpr.asConstInteger() val constIndex = arrayIndexExpr.asConstInteger()
if(constIndex!=null) { if(constIndex!=null) {
if (arrayDt?.isUnsignedWord==true) { if (arrayDt?.isUnsignedWord==true) {
@@ -2930,14 +2930,12 @@ $endLabel""")
storeRegisterAInMemoryAddress(target.memory!!) storeRegisterAInMemoryAddress(target.memory!!)
} }
TargetStorageKind.ARRAY -> { TargetStorageKind.ARRAY -> {
if(target.array!!.splitWords)
TODO("assign into split words ${target.position}")
if (target.constArrayIndexValue!=null) { if (target.constArrayIndexValue!=null) {
val scaledIdx = program.memsizer.memorySize(target.datatype, target.constArrayIndexValue!!.toInt()) val scaledIdx = program.memsizer.memorySize(target.datatype, target.constArrayIndexValue!!.toInt())
asmgen.out(" lda $sourceName | sta ${target.asmVarname}+$scaledIdx") asmgen.out(" lda $sourceName | sta ${target.asmVarname}+$scaledIdx")
} }
else { else {
asmgen.loadScaledArrayIndexIntoRegister(target.array, CpuRegister.Y) asmgen.loadScaledArrayIndexIntoRegister(target.array!!, CpuRegister.Y)
asmgen.out(" lda $sourceName | sta ${target.asmVarname},y") asmgen.out(" lda $sourceName | sta ${target.asmVarname},y")
} }
} }
@@ -2979,19 +2977,33 @@ $endLabel""")
""") """)
} }
TargetStorageKind.ARRAY -> { TargetStorageKind.ARRAY -> {
if(wordtarget.array!!.splitWords) if(wordtarget.array!!.splitWords) {
TODO("assign byte into split words ${wordtarget.position}") // signed byte, we must sign-extend
if (wordtarget.constArrayIndexValue!=null) { if (wordtarget.constArrayIndexValue!=null) {
val scaledIdx = wordtarget.constArrayIndexValue!! * 2u val scaledIdx = wordtarget.constArrayIndexValue!!
asmgen.out(" lda $sourceName") asmgen.out(" lda $sourceName | sta ${wordtarget.asmVarname}_lsb+$scaledIdx")
asmgen.signExtendAYlsb(BaseDataType.BYTE) asmgen.signExtendAYlsb(BaseDataType.BYTE)
asmgen.out(" sta ${wordtarget.asmVarname}+$scaledIdx | sty ${wordtarget.asmVarname}+$scaledIdx+1") asmgen.out(" sty ${wordtarget.asmVarname}_msb+$scaledIdx")
}
else {
asmgen.loadScaledArrayIndexIntoRegister(wordtarget.array, CpuRegister.X)
asmgen.out(" lda $sourceName | sta ${wordtarget.asmVarname}_msb,x")
asmgen.signExtendAYlsb(BaseDataType.BYTE)
asmgen.out(" tya | sta ${wordtarget.asmVarname}_msb,x")
}
} }
else { else {
asmgen.loadScaledArrayIndexIntoRegister(wordtarget.array, CpuRegister.X) if (wordtarget.constArrayIndexValue != null) {
asmgen.out(" lda $sourceName") val scaledIdx = wordtarget.constArrayIndexValue!! * 2u
asmgen.signExtendAYlsb(BaseDataType.BYTE) asmgen.out(" lda $sourceName")
asmgen.out(" sta ${wordtarget.asmVarname},x | inx | tya | sta ${wordtarget.asmVarname},x") asmgen.signExtendAYlsb(BaseDataType.BYTE)
asmgen.out(" sta ${wordtarget.asmVarname}+$scaledIdx | sty ${wordtarget.asmVarname}+$scaledIdx+1")
} else {
asmgen.loadScaledArrayIndexIntoRegister(wordtarget.array, CpuRegister.X)
asmgen.out(" lda $sourceName")
asmgen.signExtendAYlsb(BaseDataType.BYTE)
asmgen.out(" sta ${wordtarget.asmVarname},x | inx | tya | sta ${wordtarget.asmVarname},x")
}
} }
} }
TargetStorageKind.REGISTER -> { TargetStorageKind.REGISTER -> {
@@ -3700,8 +3712,7 @@ $endLabel""")
storeRegisterAInMemoryAddress(target.memory!!) storeRegisterAInMemoryAddress(target.memory!!)
} }
TargetStorageKind.ARRAY -> { TargetStorageKind.ARRAY -> {
if(target.array!!.splitWords) require(!target.array!!.splitWords)
TODO("assign into split words ${target.position}")
if (target.constArrayIndexValue!=null) { if (target.constArrayIndexValue!=null) {
val indexValue = target.constArrayIndexValue!! val indexValue = target.constArrayIndexValue!!
asmgen.out(" lda #${byte.toHex()} | sta ${target.asmVarname}+$indexValue") asmgen.out(" lda #${byte.toHex()} | sta ${target.asmVarname}+$indexValue")

View File

@@ -904,10 +904,10 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
} }
return result return result
} else { } else {
return null // TODO("inplace split word array +") return null // TODO("inplace split word array -")
} }
} }
return null // TODO("inplace split word array +") return null // TODO("inplace split word array -")
} }
private fun operatorPlusInplace(symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression): IRCodeChunks? { private fun operatorPlusInplace(symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression): IRCodeChunks? {

View File

@@ -133,7 +133,8 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
val result = mutableListOf<IRCodeChunkBase>() val result = mutableListOf<IRCodeChunkBase>()
val resultRegister = codeGen.registers.nextFree() val resultRegister = codeGen.registers.nextFree()
if(expr.isFromArrayElement) { if(expr.isFromArrayElement) {
require(!expr.identifier.type.isSplitWordArray) if(expr.identifier.type.isSplitWordArray)
TODO("address of element of a split word array")
addInstr(result, IRInstruction(Opcode.LOAD, vmDt, reg1 = resultRegister, labelSymbol = symbol), null) addInstr(result, IRInstruction(Opcode.LOAD, vmDt, reg1 = resultRegister, labelSymbol = symbol), null)
val indexTr2 = translateExpression(expr.arrayIndexExpr!!) val indexTr2 = translateExpression(expr.arrayIndexExpr!!)
addToResult(result, indexTr2, indexTr2.resultReg, -1) addToResult(result, indexTr2, indexTr2.resultReg, -1)

View File

@@ -703,7 +703,12 @@ internal class AstChecker(private val program: Program,
if (variable!=null) { if (variable!=null) {
if (variable.type == VarDeclType.CONST && addressOf.arrayIndex == null) if (variable.type == VarDeclType.CONST && addressOf.arrayIndex == null)
errors.err("invalid pointer-of operand type",addressOf.position) errors.err("invalid pointer-of operand type",addressOf.position)
if(addressOf.arrayIndex!=null && variable.datatype.isSplitWordArray) {
errors.err("cannot take the adress of a word element that is in a split-word array", addressOf.position)
}
} }
super.visit(addressOf) super.visit(addressOf)
} }
@@ -1467,18 +1472,18 @@ internal class AstChecker(private val program: Program,
} }
if(funcName[0] in InplaceModifyingBuiltinFunctions) { if(funcName[0] in InplaceModifyingBuiltinFunctions) {
// in-place modification, can't be done on literals // in-place modification, can be done on specific types of arguments only (variables, array elements)
if(funcName[0]=="setlsb" || funcName[0]=="setmsb") { if(funcName[0]=="setlsb" || funcName[0]=="setmsb") {
val firstArg = functionCallStatement.args[0] val firstArg = functionCallStatement.args[0]
if(firstArg !is IdentifierReference && firstArg !is ArrayIndexedExpression) if(firstArg !is IdentifierReference && firstArg !is ArrayIndexedExpression)
errors.err("invalid argument to a in-place modifying function", firstArg.position) errors.err("this function can only act on an identifier or array element", firstArg.position)
} else if(funcName[0]=="divmod" || funcName[0].startsWith("divmod__")) { } else if(funcName[0]=="divmod" || funcName[0].startsWith("divmod__")) {
val thirdArg = functionCallStatement.args[2] val thirdArg = functionCallStatement.args[2]
val fourthArg = functionCallStatement.args[3] val fourthArg = functionCallStatement.args[3]
if(thirdArg !is IdentifierReference && thirdArg !is ArrayIndexedExpression) if(thirdArg !is IdentifierReference && thirdArg !is ArrayIndexedExpression)
errors.err("invalid argument to a in-place modifying function", thirdArg.position) errors.err("this function can only act on an identifier or array element", thirdArg.position)
if(fourthArg !is IdentifierReference && fourthArg !is ArrayIndexedExpression) if(fourthArg !is IdentifierReference && fourthArg !is ArrayIndexedExpression)
errors.err("invalid argument to a in-place modifying function", fourthArg.position) errors.err("this function can only act on an identifier or array element", fourthArg.position)
} else { } else {
if(functionCallStatement.args.any { it !is IdentifierReference && it !is ArrayIndexedExpression && it !is DirectMemoryRead }) if(functionCallStatement.args.any { it !is IdentifierReference && it !is ArrayIndexedExpression && it !is DirectMemoryRead })
errors.err("invalid argument to a in-place modifying function", functionCallStatement.args.first().position) errors.err("invalid argument to a in-place modifying function", functionCallStatement.args.first().position)

View File

@@ -10,6 +10,9 @@ TODO
Future Things and Ideas Future Things and Ideas
^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^
- support &, &< and &> on array elements from split word arrays too not just the array as a whole (to get rid of the error "&< is only valid on array variables"
and "cannot take the adress of a word element that is in a split-word array" and the TODOS "address of element of a split word array")
- fix leftover asmgen split word array todo's
- Kotlin: can we use inline value classes in certain spots? - Kotlin: can we use inline value classes in certain spots?
- Improve the SublimeText syntax file for prog8, you can also install this for 'bat': https://github.com/sharkdp/bat?tab=readme-ov-file#adding-new-syntaxes--language-definitions - Improve the SublimeText syntax file for prog8, you can also install this for 'bat': https://github.com/sharkdp/bat?tab=readme-ov-file#adding-new-syntaxes--language-definitions
@@ -28,7 +31,6 @@ Future Things and Ideas
- Allow normal subroutines to return multiple values as well (just as asmsubs already can) - Allow normal subroutines to return multiple values as well (just as asmsubs already can)
- Change scoping rules for qualified symbols so that they don't always start from the root but behave like other programming languages (look in local scope first) - Change scoping rules for qualified symbols so that they don't always start from the root but behave like other programming languages (look in local scope first)
- Fix missing cases where regular & has to return the start of the split array in memory whatever byte comes first. Search TODO("address of split word array")
- something to reduce the need to use fully qualified names all the time. 'with' ? Or 'using <prefix>'? - something to reduce the need to use fully qualified names all the time. 'with' ? Or 'using <prefix>'?
- Improve register load order in subroutine call args assignments: - Improve register load order in subroutine call args assignments:
in certain situations (need examples!), the "wrong" order of evaluation of function call arguments is done which results in certain situations (need examples!), the "wrong" order of evaluation of function call arguments is done which results
@@ -47,6 +49,8 @@ Future Things and Ideas
IR/VM IR/VM
----- -----
- fix TODO("IR rol/ror on split words array")
- fix "<< in array" / ">> in array"
- implement missing operators in AssignmentGen (array shifts etc) - implement missing operators in AssignmentGen (array shifts etc)
- support %align on code chunks - support %align on code chunks
- fix call() return value handling - fix call() return value handling

View File

@@ -5,18 +5,17 @@
main { main {
sub start() { sub start() {
&ubyte mmvar = $2000 uword[2] array1
txt.print_ub(@($2000)) array1[1] = $0122
txt.print_uwhex(array1[1], true)
txt.nl() txt.nl()
@($2000) = 123 rol(array1[1])
txt.print_ub(@($2000)) txt.print_uwhex(array1[1], true)
txt.nl() txt.nl()
sys.set_carry()
mmvar = 42 ror(array1[1])
txt.print_ub(@($2000)) txt.print_uwhex(array1[1], true)
txt.nl() txt.nl()
cx16.r0 = 123
} }
} }