mirror of
https://github.com/irmen/prog8.git
synced 2026-04-21 17:16:33 +00:00
Merge branch 'master' into structs
# Conflicts: # codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt # codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt # compiler/test/ast/TestConst.kt # docs/source/todo.rst # examples/test.p8
This commit is contained in:
@@ -438,19 +438,21 @@ internal class AssignmentAsmGen(
|
||||
private fun assignExpression(assign: AsmAssignment, scope: IPtSubroutine?) {
|
||||
when(val value = assign.source.expression!!) {
|
||||
is PtAddressOf -> {
|
||||
if(value.identifier!=null) {
|
||||
val arrayDt = value.identifier!!.type
|
||||
val identifier = value.identifier
|
||||
if(identifier==null) TODO("read &dereference")
|
||||
else {
|
||||
val source = asmgen.symbolTable.lookup(identifier.name)
|
||||
require(source !is StConstant) { "addressOf of a constant should have been rewritten to a simple addition expression" }
|
||||
val arrayDt = identifier.type
|
||||
val sourceName =
|
||||
if (value.isMsbForSplitArray)
|
||||
asmgen.asmSymbolName(value.identifier!!) + "_msb"
|
||||
asmgen.asmSymbolName(identifier) + "_msb"
|
||||
else if (arrayDt.isSplitWordArray)
|
||||
asmgen.asmSymbolName(value.identifier!!) + "_lsb" // the _lsb split array comes first in memory
|
||||
asmgen.asmSymbolName(identifier) + "_lsb" // the _lsb split array comes first in memory
|
||||
else
|
||||
asmgen.asmSymbolName(value.identifier!!)
|
||||
asmgen.asmSymbolName(identifier)
|
||||
assignAddressOf(assign.target, sourceName, value.isMsbForSplitArray, arrayDt, value.arrayIndexExpr)
|
||||
} else {
|
||||
TODO("read &dereference")
|
||||
}
|
||||
}
|
||||
}
|
||||
is PtBool -> throw AssemblyError("source kind should have been literalboolean")
|
||||
is PtNumber -> throw AssemblyError("source kind should have been literalnumber")
|
||||
@@ -1573,8 +1575,8 @@ internal class AssignmentAsmGen(
|
||||
if(ptrVar!=null && asmgen.isZpVar(ptrVar)) {
|
||||
assignExpressionToRegister(value, RegisterOrPair.A, false)
|
||||
val pointername = asmgen.asmVariableName(ptrVar)
|
||||
if (constOffset != null && constOffset < 256) {
|
||||
// we have value + @(zpptr + 255), or value - @(zpptr+255)
|
||||
if (constOffset != null) {
|
||||
// we have value + @(zpptr + 255), or value - @(zpptr+255). the offset is always <256.
|
||||
asmgen.out(" ldy #$constOffset")
|
||||
if (operator == "+")
|
||||
asmgen.out(" clc | adc ($pointername),y")
|
||||
@@ -2631,13 +2633,23 @@ $endLabel""")
|
||||
if (arrayDt.isUnsignedWord) {
|
||||
require(!msb)
|
||||
assignVariableToRegister(sourceName, RegisterOrPair.AY, false, arrayIndexExpr.definingISub(), arrayIndexExpr.position)
|
||||
if(constIndex>0)
|
||||
if(constIndex in 1..255)
|
||||
asmgen.out("""
|
||||
clc
|
||||
adc #$constIndex
|
||||
bcc +
|
||||
iny
|
||||
+""")
|
||||
else if(constIndex>=256) {
|
||||
asmgen.out("""
|
||||
clc
|
||||
adc #<$constIndex
|
||||
pha
|
||||
tya
|
||||
adc #>$constIndex
|
||||
tay
|
||||
pla""")
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(constIndex>0) {
|
||||
@@ -2655,15 +2667,33 @@ $endLabel""")
|
||||
assignVariableToRegister(sourceName, RegisterOrPair.AY, false, arrayIndexExpr.definingISub(), arrayIndexExpr.position)
|
||||
asmgen.saveRegisterStack(CpuRegister.A, false)
|
||||
asmgen.saveRegisterStack(CpuRegister.Y, false)
|
||||
assignExpressionToVariable(arrayIndexExpr, "P8ZP_SCRATCH_REG", DataType.UBYTE)
|
||||
asmgen.restoreRegisterStack(CpuRegister.Y, false)
|
||||
asmgen.restoreRegisterStack(CpuRegister.A, false)
|
||||
asmgen.out("""
|
||||
clc
|
||||
adc P8ZP_SCRATCH_REG
|
||||
bcc +
|
||||
iny
|
||||
if(arrayIndexExpr.type.isWord) {
|
||||
assignExpressionToRegister(arrayIndexExpr, RegisterOrPair.AY, false)
|
||||
asmgen.out("""
|
||||
sta P8ZP_SCRATCH_W1
|
||||
sty P8ZP_SCRATCH_W1+1
|
||||
pla
|
||||
tay
|
||||
pla
|
||||
clc
|
||||
adc P8ZP_SCRATCH_W1
|
||||
pha
|
||||
tya
|
||||
adc P8ZP_SCRATCH_W1+1
|
||||
tay
|
||||
pla""")
|
||||
}
|
||||
else {
|
||||
assignExpressionToVariable(arrayIndexExpr, "P8ZP_SCRATCH_REG", DataType.UBYTE)
|
||||
asmgen.restoreRegisterStack(CpuRegister.Y, false)
|
||||
asmgen.restoreRegisterStack(CpuRegister.A, false)
|
||||
asmgen.out("""
|
||||
clc
|
||||
adc P8ZP_SCRATCH_REG
|
||||
bcc +
|
||||
iny
|
||||
+""")
|
||||
}
|
||||
}
|
||||
else {
|
||||
assignExpressionToRegister(arrayIndexExpr, RegisterOrPair.A, false)
|
||||
|
||||
@@ -321,18 +321,21 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
if(expr.isFromArrayElement) {
|
||||
val indexTr = translateExpression(expr.arrayIndexExpr!!)
|
||||
addToResult(result, indexTr, indexTr.resultReg, -1)
|
||||
val indexWordReg = codeGen.registers.next(IRDataType.WORD)
|
||||
addInstr(
|
||||
result,
|
||||
IRInstruction(Opcode.EXT, IRDataType.BYTE, reg1 = indexWordReg, reg2 = indexTr.resultReg),
|
||||
null
|
||||
)
|
||||
val indexWordReg = if(indexTr.dt==IRDataType.BYTE) {
|
||||
val ixWord = codeGen.registers.next(IRDataType.WORD)
|
||||
addInstr(result, IRInstruction(Opcode.EXT, IRDataType.BYTE, reg1=ixWord, reg2=indexTr.resultReg), null)
|
||||
ixWord
|
||||
} else indexTr.resultReg
|
||||
val resultRegister = codeGen.registers.next(vmDt)
|
||||
if (identifier!!.type.isUnsignedWord) {
|
||||
if(identifier!!.type.isUnsignedWord) {
|
||||
require(!expr.isMsbForSplitArray)
|
||||
result += IRCodeChunk(null, null).also {
|
||||
it += IRInstruction(Opcode.LOADM, vmDt, reg1 = resultRegister, labelSymbol = identifier.name)
|
||||
it += IRInstruction(Opcode.ADDR, IRDataType.WORD, reg1 = resultRegister, reg2 = indexWordReg)
|
||||
val ptr = codeGen.symbolTable.lookup(identifier.name)
|
||||
it += if(ptr is StConstant)
|
||||
IRInstruction(Opcode.LOAD, vmDt, reg1 = resultRegister, immediate = ptr.value.toInt())
|
||||
else
|
||||
IRInstruction(Opcode.LOADM, vmDt, reg1 = resultRegister, labelSymbol = identifier.name)
|
||||
it += IRInstruction(Opcode.ADDR, IRDataType.WORD, reg1=resultRegister, reg2=indexWordReg)
|
||||
}
|
||||
} else {
|
||||
val eltSize = codeGen.program.memsizer.memorySize(identifier.type, 1)
|
||||
|
||||
@@ -449,4 +449,23 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter,
|
||||
}
|
||||
return noModifications
|
||||
}
|
||||
|
||||
override fun after(addressOf: AddressOf, parent: Node): Iterable<IAstModification> {
|
||||
if(addressOf.arrayIndex!=null) {
|
||||
val tgt = addressOf.identifier?.constValue(program)
|
||||
if (tgt != null && tgt.type.isWord) {
|
||||
// &constant[idx] --> constant + idx
|
||||
val indexExpr = addressOf.arrayIndex!!.indexExpr
|
||||
val right = if(indexExpr.inferType(program) issimpletype tgt.type)
|
||||
indexExpr
|
||||
else
|
||||
TypecastExpression(indexExpr, DataType.forDt(tgt.type), true, indexExpr.position)
|
||||
val add = BinaryExpression(tgt, "+", right, addressOf.position)
|
||||
return listOf(
|
||||
IAstModification.ReplaceNode(addressOf, add, parent)
|
||||
)
|
||||
}
|
||||
}
|
||||
return noModifications
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import io.kotest.matchers.shouldBe
|
||||
import io.kotest.matchers.shouldNotBe
|
||||
import io.kotest.matchers.string.shouldContain
|
||||
import io.kotest.matchers.types.instanceOf
|
||||
import prog8.ast.expressions.AddressOf
|
||||
import prog8.ast.expressions.BinaryExpression
|
||||
import prog8.ast.expressions.IdentifierReference
|
||||
import prog8.ast.expressions.NumericLiteral
|
||||
@@ -310,7 +309,7 @@ main {
|
||||
val src= """
|
||||
main {
|
||||
sub start() {
|
||||
const uword buffer = $2000
|
||||
const uword buffer = 2000
|
||||
uword @shared addr = &buffer[2]
|
||||
|
||||
const ubyte width = 100
|
||||
@@ -323,10 +322,9 @@ main {
|
||||
val st = result.compilerAst.entrypoint.statements
|
||||
st.size shouldBe 11
|
||||
val assignAddr = (st[2] as Assignment).value
|
||||
(assignAddr as NumericLiteral).number shouldBe 8194.0
|
||||
val assignAddr2 = ((st[9] as Assignment).value as AddressOf)
|
||||
assignAddr2.identifier!!.nameInSource shouldBe listOf("buffer")
|
||||
assignAddr2.arrayIndex!!.indexExpr shouldBe instanceOf<BinaryExpression>()
|
||||
(assignAddr as NumericLiteral).number shouldBe 2002.0
|
||||
val assignAddr2 = (st[9] as Assignment).value as BinaryExpression
|
||||
assignAddr2.operator shouldBe "+"
|
||||
}
|
||||
|
||||
test("out of range const byte and word give correct error") {
|
||||
|
||||
@@ -1061,6 +1061,24 @@ main {
|
||||
st2[4].children.dropLast(1).map { (it as PtAssignTarget).identifier!!.name } shouldBe listOf("p8b_main.p8s_start.p8v_x", "p8b_main.p8s_start.p8v_y", "p8b_main.p8s_start.p8v_z")
|
||||
((st2[4] as PtAssignment).value as PtFunctionCall).name shouldBe "p8b_main.p8s_multi"
|
||||
}
|
||||
|
||||
test("address-of a uword pointer with word index should not overflow") {
|
||||
val src= """
|
||||
main {
|
||||
sub start() {
|
||||
const uword cbuffer = $2000
|
||||
uword @shared buffer = $2000
|
||||
|
||||
cx16.r1 = &cbuffer[2000]
|
||||
cx16.r5 = &buffer[2000]
|
||||
|
||||
cx16.r3 = &cbuffer[cx16.r0]
|
||||
cx16.r4 = &buffer[cx16.r0]
|
||||
}
|
||||
}"""
|
||||
compileText(Cx16Target(), optimize=false, src, outputDir, writeAssembly=true) shouldNotBe null
|
||||
compileText(VMTarget(), optimize=false, src, outputDir, writeAssembly=true) shouldNotBe null
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
@@ -532,4 +532,22 @@ main {
|
||||
instructions[10].type shouldBe IRDataType.WORD
|
||||
}
|
||||
|
||||
test("typed address-of a const pointer with non-const array indexing") {
|
||||
val src= """
|
||||
main {
|
||||
sub start() {
|
||||
const uword cbuffer = $2000
|
||||
uword @shared buffer = $2000
|
||||
|
||||
cx16.r2 = @(cbuffer + cx16.r0)
|
||||
cx16.r1 = &cbuffer[cx16.r0]
|
||||
|
||||
cx16.r3 = @(buffer + cx16.r0)
|
||||
cx16.r4 = &buffer[cx16.r0]
|
||||
}
|
||||
}"""
|
||||
val result = compileText(VMTarget(), false, src, outputDir)!!
|
||||
val virtfile = result.compilationOptions.outputDir.resolve(result.compilerAst.name + ".p8ir")
|
||||
VmRunner().runProgram(virtfile.readText(), true)
|
||||
}
|
||||
})
|
||||
@@ -771,8 +771,8 @@ but perhaps the provided ones can be of service too.
|
||||
|
||||
``crc16 (uword data, uword length) -> uword``
|
||||
Returns a CRC-16 (XMODEM) checksum over the given data buffer.
|
||||
Note: on the Commander X16, there is a CRC-16 routine in the kernal: cx16.memory_crc().
|
||||
That one is faster, but yields different results. It is unclear to me what flavour of crc it is calculating.
|
||||
Note: on the Commander X16, there is a CRC-16/IBM-3740 routine in the kernal: cx16.memory_crc().
|
||||
That one is faster, but yields different results.
|
||||
|
||||
``crc16_start() / crc16_update(ubyte value) / crc16_end() -> uword``
|
||||
"streaming" crc16 calculation routines, when the data doesn't fit in a single buffer.
|
||||
|
||||
@@ -149,7 +149,7 @@ class VmProgramLoader {
|
||||
// placeholder is not a variable, so it must be a label of a code chunk instead
|
||||
val target: IRCodeChunk? = chunks.firstOrNull { it.label==label }
|
||||
if(target==null)
|
||||
throw IRParseException("label '$label' not found in variables nor labels. VM cannot reference other things such as blocks")
|
||||
throw IRParseException("label '$label' not found in variables nor labels. VM cannot reference other things such as blocks, and constants should have been replaced by their value")
|
||||
else if(instr.opcode in OpcodesThatBranch)
|
||||
chunk.instructions[line] = instr.copy(branchTarget = target, address = null)
|
||||
else {
|
||||
|
||||
Reference in New Issue
Block a user