diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt index 53b30902b..4b1be02c4 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt @@ -161,7 +161,8 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express val targetIdent = assignment.target.identifier val targetMemory = assignment.target.memory val targetArray = assignment.target.array - val vmDt = codeGen.irType(assignment.value.type) + val valueDt = codeGen.irType(assignment.value.type) + val targetDt = codeGen.irType(assignment.target.type) val result = mutableListOf() var valueRegister = -1 @@ -169,30 +170,42 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express val zero = codeGen.isZero(assignment.value) if(!zero) { // calculate the assignment value - if (vmDt == IRDataType.FLOAT) { + if (valueDt == IRDataType.FLOAT) { val tr = expressionEval.translateExpression(assignment.value) valueFpRegister = tr.resultFpReg addToResult(result, tr, -1, valueFpRegister) } else { + val extendByteToWord = if(targetDt != valueDt) { + // usually an error EXCEPT when a byte is assigned to a word. + if(targetDt==IRDataType.WORD && valueDt==IRDataType.BYTE) + true + else + throw AssemblyError("assignment value and target dt mismatch") + } else false if (assignment.value is PtMachineRegister) { valueRegister = (assignment.value as PtMachineRegister).register + if(extendByteToWord) + addInstr(result, IRInstruction(Opcode.EXT, IRDataType.BYTE, reg1=valueRegister), null) } else { val tr = expressionEval.translateExpression(assignment.value) valueRegister = tr.resultReg addToResult(result, tr, valueRegister, -1) + if(extendByteToWord) { + val opcode = if(assignment.value.type in SignedDatatypes) Opcode.EXTS else Opcode.EXT + addInstr(result, IRInstruction(opcode, IRDataType.BYTE, reg1 = valueRegister), null) + } } } } if(targetIdent!=null) { val instruction = if(zero) { - IRInstruction(Opcode.STOREZM, vmDt, labelSymbol = targetIdent.name) + IRInstruction(Opcode.STOREZM, targetDt, labelSymbol = targetIdent.name) } else { - if (vmDt == IRDataType.FLOAT) { - IRInstruction(Opcode.STOREM, vmDt, fpReg1 = valueFpRegister, labelSymbol = targetIdent.name) - } + if (targetDt == IRDataType.FLOAT) + IRInstruction(Opcode.STOREM, targetDt, fpReg1 = valueFpRegister, labelSymbol = targetIdent.name) else - IRInstruction(Opcode.STOREM, vmDt, reg1 = valueRegister, labelSymbol = targetIdent.name) + IRInstruction(Opcode.STOREM, targetDt, reg1 = valueRegister, labelSymbol = targetIdent.name) } result += IRCodeChunk(null, null).also { it += instruction } return result @@ -214,9 +227,9 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express if(zero) { // there's no STOREZIX instruction valueRegister = codeGen.registers.nextFree() - code += IRInstruction(Opcode.LOAD, vmDt, reg1=valueRegister, immediate = 0) + code += IRInstruction(Opcode.LOAD, targetDt, reg1=valueRegister, immediate = 0) } - code += IRInstruction(Opcode.STOREIX, vmDt, reg1=valueRegister, reg2=idxReg, labelSymbol = variable) + code += IRInstruction(Opcode.STOREIX, targetDt, reg1=valueRegister, reg2=idxReg, labelSymbol = variable) result += code return result } @@ -225,59 +238,59 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express if(zero) { if(fixedIndex!=null) { val offset = fixedIndex*itemsize - val chunk = IRCodeChunk(null, null).also { it += IRInstruction(Opcode.STOREZM, vmDt, labelSymbol = "$variable+$offset") } + val chunk = IRCodeChunk(null, null).also { it += IRInstruction(Opcode.STOREZM, targetDt, labelSymbol = "$variable+$offset") } result += chunk } else { val (code, indexReg) = loadIndexReg(targetArray, itemsize) result += code - result += IRCodeChunk(null, null).also { it += IRInstruction(Opcode.STOREZX, vmDt, reg1=indexReg, labelSymbol = variable) } + result += IRCodeChunk(null, null).also { it += IRInstruction(Opcode.STOREZX, targetDt, reg1=indexReg, labelSymbol = variable) } } } else { - if(vmDt== IRDataType.FLOAT) { + if(targetDt== IRDataType.FLOAT) { if(fixedIndex!=null) { val offset = fixedIndex*itemsize - val chunk = IRCodeChunk(null, null).also { it += IRInstruction(Opcode.STOREM, vmDt, fpReg1 = valueFpRegister, labelSymbol = "$variable+$offset") } + val chunk = IRCodeChunk(null, null).also { it += IRInstruction(Opcode.STOREM, targetDt, fpReg1 = valueFpRegister, labelSymbol = "$variable+$offset") } result += chunk } else { val (code, indexReg) = loadIndexReg(targetArray, itemsize) result += code - result += IRCodeChunk(null, null).also { it += IRInstruction(Opcode.STOREX, vmDt, reg1 = indexReg, fpReg1 = valueFpRegister, labelSymbol = variable) } + result += IRCodeChunk(null, null).also { it += IRInstruction(Opcode.STOREX, targetDt, reg1 = indexReg, fpReg1 = valueFpRegister, labelSymbol = variable) } } } else { if(fixedIndex!=null) { val offset = fixedIndex*itemsize - val chunk = IRCodeChunk(null, null).also { it += IRInstruction(Opcode.STOREM, vmDt, reg1 = valueRegister, labelSymbol = "$variable+$offset") } + val chunk = IRCodeChunk(null, null).also { it += IRInstruction(Opcode.STOREM, targetDt, reg1 = valueRegister, labelSymbol = "$variable+$offset") } result += chunk } else { val (code, indexReg) = loadIndexReg(targetArray, itemsize) result += code - result += IRCodeChunk(null, null).also { it += IRInstruction(Opcode.STOREX, vmDt, reg1 = valueRegister, reg2=indexReg, labelSymbol = variable) } + result += IRCodeChunk(null, null).also { it += IRInstruction(Opcode.STOREX, targetDt, reg1 = valueRegister, reg2=indexReg, labelSymbol = variable) } } } } return result } else if(targetMemory!=null) { - require(vmDt== IRDataType.BYTE) { "must be byte type ${targetMemory.position}"} + require(targetDt == IRDataType.BYTE) { "must be byte type ${targetMemory.position}"} if(zero) { if(targetMemory.address is PtNumber) { - val chunk = IRCodeChunk(null, null).also { it += IRInstruction(Opcode.STOREZM, vmDt, address = (targetMemory.address as PtNumber).number.toInt()) } + val chunk = IRCodeChunk(null, null).also { it += IRInstruction(Opcode.STOREZM, targetDt, address = (targetMemory.address as PtNumber).number.toInt()) } result += chunk } else { val tr = expressionEval.translateExpression(targetMemory.address) val addressReg = tr.resultReg addToResult(result, tr, tr.resultReg, -1) - result += IRCodeChunk(null, null).also { it += IRInstruction(Opcode.STOREZI, vmDt, reg1=addressReg) } + result += IRCodeChunk(null, null).also { it += IRInstruction(Opcode.STOREZI, targetDt, reg1=addressReg) } } } else { if(targetMemory.address is PtNumber) { - val chunk = IRCodeChunk(null, null).also { it += IRInstruction(Opcode.STOREM, vmDt, reg1=valueRegister, address=(targetMemory.address as PtNumber).number.toInt()) } + val chunk = IRCodeChunk(null, null).also { it += IRInstruction(Opcode.STOREM, targetDt, reg1=valueRegister, address=(targetMemory.address as PtNumber).number.toInt()) } result += chunk } else { val tr = expressionEval.translateExpression(targetMemory.address) val addressReg = tr.resultReg addToResult(result, tr, tr.resultReg, -1) - result += IRCodeChunk(null, null).also { it += IRInstruction(Opcode.STOREI, vmDt, reg1=valueRegister, reg2=addressReg) } + result += IRCodeChunk(null, null).also { it += IRInstruction(Opcode.STOREI, targetDt, reg1=valueRegister, reg2=addressReg) } } } diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 4d9a6ab7a..81cedb0f5 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -4,7 +4,7 @@ TODO For next minor release ^^^^^^^^^^^^^^^^^^^^^^ - fix crash: uword remainder = seconds_uword % $0003 ==0 -- fix VM: void string.copy(".prg", &output_filename + string.length(output_filename)) +- fix VM problem with param passing: void string.copy(".prg", &output_filename + string.length(output_filename)) - try to optimize newexpr a bit more ... diff --git a/examples/test.p8 b/examples/test.p8 index 3c2712b54..e7b71fec9 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -5,9 +5,51 @@ main { sub start() { - str output_filename = "?????????\x00????????????" - void string.copy(".prg", &output_filename + string.length(output_filename)) - txt.print(output_filename) + str output_filename = "12345678\x00abcdefghij" + void myprint2("hallo", &output_filename+string.length(output_filename)) +; ubyte length = string.length(output_filename) +; txt.print_ub(length) +; txt.nl() +; txt.print_uw(&output_filename) +; txt.nl() +; output_filename[2]='!' +; txt.print(output_filename) +; txt.nl() +; +; void string_copy(".prg", &output_filename + string.length(output_filename)) +; txt.print(output_filename) + } + + sub myprint2(str source1, str source2) { + txt.print(source1) + txt.nl() + txt.print(source2) + txt.nl() + } + + sub string_copy(str source, str target) -> ubyte { + ; Copy a string to another, overwriting that one. + ; Returns the length of the string that was copied. + ; Often you don’t have to call this explicitly and can just write string1 = string2 + ; but this function is useful if you’re dealing with addresses for instance. + txt.print("src=") + txt.print(source) + txt.nl() + txt.print("target=") + txt.print(target) + txt.nl() + ubyte ix + repeat 5 { + ubyte qq=source[ix] + txt.print_ub(qq) + target[ix]=qq + txt.spc() + if qq==0 { + txt.nl() + return ix + } + ix++ + } } } diff --git a/intermediate/src/prog8/intermediate/IRInstructions.kt b/intermediate/src/prog8/intermediate/IRInstructions.kt index bd0f26195..115562d00 100644 --- a/intermediate/src/prog8/intermediate/IRInstructions.kt +++ b/intermediate/src/prog8/intermediate/IRInstructions.kt @@ -89,26 +89,26 @@ bgesr reg1, reg2, address - jump to location in program given by l ble reg1, value, address - jump to location in program given by location, if reg1 <= immediate value (unsigned) bles reg1, value, address - jump to location in program given by location, if reg1 <= immediate value (signed) ( NOTE: there are no bltr/bler instructions because these are equivalent to bgtr/bger with the register operands swapped around.) -sz reg1, reg2 - set reg1=1 if reg2==0, otherwise set reg1=0 -snz reg1, reg2 - set reg1=1 if reg2!=0, otherwise set reg1=0 -seq reg1, reg2 - set reg1=1 if reg1 == reg2, otherwise set reg1=0 -sne reg1, reg2 - set reg1=1 if reg1 != reg2, otherwise set reg1=0 -slt reg1, reg2 - set reg1=1 if reg1 < reg2 (unsigned), otherwise set reg1=0 -slts reg1, reg2 - set reg1=1 if reg1 < reg2 (signed), otherwise set reg1=0 -sle reg1, reg2 - set reg1=1 if reg1 <= reg2 (unsigned), otherwise set reg1=0 -sles reg1, reg2 - set reg1=1 if reg1 <= reg2 (signed), otherwise set reg1=0 -sgt reg1, reg2 - set reg1=1 if reg1 > reg2 (unsigned), otherwise set reg1=0 -sgts reg1, reg2 - set reg1=1 if reg1 > reg2 (signed), otherwise set reg1=0 -sge reg1, reg2 - set reg1=1 if reg1 >= reg2 (unsigned), otherwise set reg1=0 -sges reg1, reg2 - set reg1=1 if reg1 >= reg2 (signed), otherwise set reg1=0 +sz reg1, reg2 - set reg1=1.b if reg2==0, otherwise set reg1=0.b +snz reg1, reg2 - set reg1=1.b if reg2!=0, otherwise set reg1=0.b +seq reg1, reg2 - set reg1=1.b if reg1 == reg2, otherwise set reg1=0.b +sne reg1, reg2 - set reg1=1.b if reg1 != reg2, otherwise set reg1=0.b +slt reg1, reg2 - set reg1=1.b if reg1 < reg2 (unsigned), otherwise set reg1=0.b +slts reg1, reg2 - set reg1=1.b if reg1 < reg2 (signed), otherwise set reg1=0.b +sle reg1, reg2 - set reg1=1.b if reg1 <= reg2 (unsigned), otherwise set reg1=0.b +sles reg1, reg2 - set reg1=1.b if reg1 <= reg2 (signed), otherwise set reg1=0.b +sgt reg1, reg2 - set reg1=1.b if reg1 > reg2 (unsigned), otherwise set reg1=0.b +sgts reg1, reg2 - set reg1=1.b if reg1 > reg2 (signed), otherwise set reg1=0.b +sge reg1, reg2 - set reg1=1.b if reg1 >= reg2 (unsigned), otherwise set reg1=0.b +sges reg1, reg2 - set reg1=1.b if reg1 >= reg2 (signed), otherwise set reg1=0.b ARITHMETIC ---------- All have type b or w or f. Note: result types are the same as operand types! E.g. byte*byte->byte. -ext reg1 - reg1 = unsigned extension of reg1 (which in practice just means clearing the MSB / MSW) (ext.w not yet implemented as we don't have longs yet) exts reg1 - reg1 = signed extension of reg1 (byte to word, or word to long) (note: ext.w is not yet implemented as we don't have longs yet) +ext reg1 - reg1 = unsigned extension of reg1 (which in practice just means clearing the MSB / MSW) (ext.w not yet implemented as we don't have longs yet) inc reg1 - reg1 = reg1+1 incm address - memory at address += 1 dec reg1 - reg1 = reg1-1