diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt index 69a4ab4a6..de34d1051 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt @@ -1361,44 +1361,87 @@ class IRCodeGen( private fun translate(postIncrDecr: PtPostIncrDecr): IRCodeChunks { val result = mutableListOf() val array = postIncrDecr.target.array - val operationMem: Opcode - val operationRegister: Opcode - when(postIncrDecr.operator) { - "++" -> { - operationMem = Opcode.INCM - operationRegister = Opcode.INC - } - "--" -> { - operationMem = Opcode.DECM - operationRegister = Opcode.DEC - } - else -> throw AssemblyError("weird operator") - } - if(array?.splitWords==true) { val variable = array.variable.name val fixedIndex = constIntValue(array.index) val iterable = symbolTable.flat.getValue(array.variable.name) as StStaticVariable - val arrayLength = iterable.length!! if(fixedIndex!=null) { - TODO("split incr decr") - // addInstr(result, IRInstruction(operationMem, irDt, immediate = arrayLength, labelSymbol="$variable+$fixedIndex"), null) + val skipLabel = createLabelName() + when(postIncrDecr.operator) { + "++" -> { + result += IRCodeChunk(null, null).also { + it += IRInstruction(Opcode.INCM, IRDataType.BYTE, labelSymbol = "${variable}_lsb+$fixedIndex") + it += IRInstruction(Opcode.BSTNE, labelSymbol = skipLabel) + it += IRInstruction(Opcode.INCM, IRDataType.BYTE, labelSymbol = "${variable}_msb+$fixedIndex") + } + result += IRCodeChunk(skipLabel, null) + } + "--" -> { + val valueReg=registers.nextFree() + result += IRCodeChunk(null, null).also { + it += IRInstruction(Opcode.LOADM, IRDataType.BYTE, reg1=valueReg, labelSymbol = "${variable}_lsb+$fixedIndex") + it += IRInstruction(Opcode.BSTNE, labelSymbol = skipLabel) + it += IRInstruction(Opcode.DECM, IRDataType.BYTE, labelSymbol = "${variable}_msb+$fixedIndex") + } + result += IRCodeChunk(skipLabel, null).also { + it += IRInstruction(Opcode.DECM, IRDataType.BYTE, labelSymbol = "${variable}_lsb+$fixedIndex") + } + } + else -> throw AssemblyError("weird operator") + } } else { + val arrayLength = iterable.length!! val indexTr = expressionEval.translateExpression(array.index) addToResult(result, indexTr, indexTr.resultReg, -1) - val chunk = IRCodeChunk(null, null) val incReg = registers.nextFree() - TODO("load split") - // chunk += IRInstruction(Opcode.LOADXSPLIT, irDt, reg1=incReg, reg2=indexTr.resultReg, immediate = arrayLength, labelSymbol=variable) - // chunk += IRInstruction(operationRegister, irDt, reg1=incReg) - TODO("store split") - // chunk += IRInstruction(Opcode.STOREXSPLIT, irDt, reg1=incReg, reg2=indexTr.resultReg, immediate = arrayLength, labelSymbol=variable) - result += chunk + val skipLabel = createLabelName() + when(postIncrDecr.operator) { + "++" -> { + result += IRCodeChunk(null, null).also { + it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1=incReg, reg2=indexTr.resultReg, immediate = arrayLength, labelSymbol = "${variable}_lsb") + it += IRInstruction(Opcode.INC, IRDataType.BYTE, reg1=incReg) + it += IRInstruction(Opcode.STOREX, IRDataType.BYTE, reg1=incReg, reg2=indexTr.resultReg, immediate = arrayLength, labelSymbol = "${variable}_lsb") + it += IRInstruction(Opcode.BSTNE, labelSymbol = skipLabel) + it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1=incReg, reg2=indexTr.resultReg, immediate = arrayLength, labelSymbol = "${variable}_msb") + it += IRInstruction(Opcode.INC, IRDataType.BYTE, reg1=incReg) + it += IRInstruction(Opcode.STOREX, IRDataType.BYTE, reg1=incReg, reg2=indexTr.resultReg, immediate = arrayLength, labelSymbol = "${variable}_msb") + } + result += IRCodeChunk(skipLabel, null) + } + "--" -> { + result += IRCodeChunk(null, null).also { + it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1=incReg, reg2=indexTr.resultReg, immediate = arrayLength, labelSymbol = "${variable}_lsb") + it += IRInstruction(Opcode.BSTNE, labelSymbol = skipLabel) + it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1=incReg, reg2=indexTr.resultReg, immediate = arrayLength, labelSymbol = "${variable}_msb") + it += IRInstruction(Opcode.DEC, IRDataType.BYTE, reg1=incReg) + it += IRInstruction(Opcode.STOREX, IRDataType.BYTE, reg1=incReg, reg2=indexTr.resultReg, immediate = arrayLength, labelSymbol = "${variable}_msb") + } + result += IRCodeChunk(skipLabel, null).also { + it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1=incReg, reg2=indexTr.resultReg, immediate = arrayLength, labelSymbol = "${variable}_lsb") + it += IRInstruction(Opcode.DEC, IRDataType.BYTE, reg1=incReg) + it += IRInstruction(Opcode.STOREX, IRDataType.BYTE, reg1=incReg, reg2=indexTr.resultReg, immediate = arrayLength, labelSymbol = "${variable}_lsb") + } + } + else -> throw AssemblyError("weird operator") + } } } else { val ident = postIncrDecr.target.identifier val memory = postIncrDecr.target.memory val irDt = irType(postIncrDecr.target.type) + val operationMem: Opcode + val operationRegister: Opcode + when(postIncrDecr.operator) { + "++" -> { + operationMem = Opcode.INCM + operationRegister = Opcode.INC + } + "--" -> { + operationMem = Opcode.DECM + operationRegister = Opcode.DEC + } + else -> throw AssemblyError("weird operator") + } if(ident!=null) { addInstr(result, IRInstruction(operationMem, irDt, labelSymbol = ident.name), null) } else if(memory!=null) { diff --git a/docs/source/building.rst b/docs/source/building.rst index 2a8e8740d..25bfe069e 100644 --- a/docs/source/building.rst +++ b/docs/source/building.rst @@ -14,7 +14,7 @@ Then you can choose a few ways to get a compiler: **Download a precompiled version from github:** #. download a recent "fat-jar" (called something like "prog8compiler-all.jar") from `the releases on Github `_ -#. run the compiler with "java -jar prog8compiler-all.jar" to see how you can use it. +#. run the compiler with "java -jar prog8compiler.jar" to see how you can use it (use the correct name and version of the jar file you've downloaded). **Using the Gradle build system to build it yourself:** @@ -86,11 +86,12 @@ The compiler will link everything together into one output program at the end. If you start the compiler without arguments, it will print a short usage text. For normal use the compiler can be invoked with the command: - ``$ java -jar prog8compiler-8.14-all.jar sourcefile.p8`` + ``$ java -jar prog8compiler.jar -target cx16 sourcefile.p8`` (Use the appropriate name and version of the jar file downloaded from one of the Git releases. Other ways to invoke the compiler are also available: see the introduction page about how - to build and run the compiler yourself) + to build and run the compiler yourself. The -target option is required, in this case we + tell it to compile a program for the Commander X16) By default, assembly code is generated and written to ``sourcefile.asm``. diff --git a/docs/source/todo.rst b/docs/source/todo.rst index f68079da8..a842d6814 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -1,8 +1,6 @@ TODO ==== -- vm: fix the last replacement code for the now removed LOADSPLIT/STORESPLIT opcodes. - ... diff --git a/examples/test.p8 b/examples/test.p8 index 857ce20ec..92a7124b9 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -15,12 +15,12 @@ main { ; } ; txt.nl() ubyte idx=1 - names[idx] = 2000 - txt.print_uw(names[1]) + names[idx] = $20ff + txt.print_uwhex(names[1], true) names[idx]++ - txt.print_uw(names[1]) + txt.print_uwhex(names[1], true) names[idx]-- - txt.print_uw(names[1]) + txt.print_uwhex(names[1], true) names = [1111,2222,3333] for ww in names { diff --git a/intermediate/src/prog8/intermediate/IRInstructions.kt b/intermediate/src/prog8/intermediate/IRInstructions.kt index cbbd8b451..46325f87b 100644 --- a/intermediate/src/prog8/intermediate/IRInstructions.kt +++ b/intermediate/src/prog8/intermediate/IRInstructions.kt @@ -15,7 +15,9 @@ Program to execute is not stored in the system memory, it's just a separate list 65536 bytes of memory. Thus memory pointers (addresses) are limited to 16 bits. Value stack, max 128 entries of 1 byte each. Status flags: Carry, Zero, Negative. NOTE: status flags are only affected by the CMP instruction or explicit CLC/SEC!!! - logical or arithmetic operations DO NOT AFFECT THE STATUS FLAGS UNLESS EXPLICITLY NOTED! + LOAD instructions DO affect the Z and N flags + INC/DEC instructions DO affect the Z and N flags + other instructions such as logical or arithmetic operations DO NOT AFFECT THE STATUS FLAGS UNLESS EXPLICITLY NOTED! Instruction set is mostly a load/store architecture, there are few instructions operating on memory directly. diff --git a/virtualmachine/src/prog8/vm/VirtualMachine.kt b/virtualmachine/src/prog8/vm/VirtualMachine.kt index 9918fa3d5..7076f5071 100644 --- a/virtualmachine/src/prog8/vm/VirtualMachine.kt +++ b/virtualmachine/src/prog8/vm/VirtualMachine.kt @@ -375,8 +375,11 @@ class VirtualMachine(irProgram: IRProgram) { if(i.type==IRDataType.FLOAT) registers.setFloat(i.fpReg1!!, i.immediateFp!!) else { - if(i.immediate!=null) + if(i.immediate!=null) { setResultReg(i.reg1!!, i.immediate!!, i.type!!) + statusZero = i.immediate==0 + statusNegative = i.immediate!! <0 + } else { if(i.labelSymbol==null) throw IllegalArgumentException("expected LOAD of address of labelsymbol") @@ -388,8 +391,18 @@ class VirtualMachine(irProgram: IRProgram) { private fun InsLOADM(i: IRInstruction) { when(i.type!!) { - IRDataType.BYTE -> registers.setUB(i.reg1!!, memory.getUB(i.address!!)) - IRDataType.WORD -> registers.setUW(i.reg1!!, memory.getUW(i.address!!)) + IRDataType.BYTE -> { + val value = memory.getUB(i.address!!) + registers.setUB(i.reg1!!, value) + statusZero = value==0.toUByte() + statusNegative = value>=0x80u + } + IRDataType.WORD -> { + val value = memory.getUW(i.address!!) + registers.setUW(i.reg1!!, value) + statusZero = value== 0.toUShort() + statusNegative = value>=0x8000u + } IRDataType.FLOAT -> registers.setFloat(i.fpReg1!!, memory.getFloat(i.address!!)) } nextPc() @@ -397,8 +410,18 @@ class VirtualMachine(irProgram: IRProgram) { private fun InsLOADI(i: IRInstruction) { when(i.type!!) { - IRDataType.BYTE -> registers.setUB(i.reg1!!, memory.getUB(registers.getUW(i.reg2!!).toInt())) - IRDataType.WORD -> registers.setUW(i.reg1!!, memory.getUW(registers.getUW(i.reg2!!).toInt())) + IRDataType.BYTE -> { + val value = memory.getUB(registers.getUW(i.reg2!!).toInt()) + registers.setUB(i.reg1!!, value) + statusZero = value==0.toUByte() + statusNegative = value>=0x80u + } + IRDataType.WORD -> { + val value = memory.getUW(registers.getUW(i.reg2!!).toInt()) + registers.setUW(i.reg1!!, value) + statusZero = value== 0.toUShort() + statusNegative = value>=0x8000u + } IRDataType.FLOAT -> registers.setFloat(i.fpReg1!!, memory.getFloat(registers.getUW(i.reg1!!).toInt())) } nextPc() @@ -406,8 +429,18 @@ class VirtualMachine(irProgram: IRProgram) { private fun InsLOADX(i: IRInstruction) { when (i.type!!) { - IRDataType.BYTE -> registers.setUB(i.reg1!!, memory.getUB(i.address!! + registers.getUW(i.reg2!!).toInt())) - IRDataType.WORD -> registers.setUW(i.reg1!!, memory.getUW(i.address!! + registers.getUW(i.reg2!!).toInt())) + IRDataType.BYTE -> { + val value = memory.getUB(i.address!! + registers.getUW(i.reg2!!).toInt()) + registers.setUB(i.reg1!!, value) + statusZero = value==0.toUByte() + statusNegative = value>=0x80u + } + IRDataType.WORD -> { + val value = memory.getUW(i.address!! + registers.getUW(i.reg2!!).toInt()) + registers.setUW(i.reg1!!, value) + statusZero = value== 0.toUShort() + statusNegative = value>=0x8000u + } IRDataType.FLOAT -> registers.setFloat(i.fpReg1!!, memory.getFloat(i.address!! + registers.getUW(i.reg1!!).toInt())) } nextPc() @@ -417,11 +450,17 @@ class VirtualMachine(irProgram: IRProgram) { when (i.type!!) { IRDataType.BYTE -> { val pointer = memory.getUW(i.address!!) + registers.getUB(i.reg2!!) - registers.setUB(i.reg1!!, memory.getUB(pointer.toInt())) + val value = memory.getUB(pointer.toInt()) + registers.setUB(i.reg1!!, value) + statusZero = value==0.toUByte() + statusNegative = value>=0x80u } IRDataType.WORD -> { val pointer = memory.getUW(i.address!!) + registers.getUB(i.reg2!!) - registers.setUW(i.reg1!!, memory.getUW(pointer.toInt())) + val value = memory.getUW(pointer.toInt()) + registers.setUW(i.reg1!!, value) + statusZero = value== 0.toUShort() + statusNegative = value>=0x8000u } IRDataType.FLOAT -> { val pointer = memory.getUW(i.address!!) + registers.getUB(i.reg1!!) @@ -433,8 +472,18 @@ class VirtualMachine(irProgram: IRProgram) { private fun InsLOADR(i: IRInstruction) { when(i.type!!) { - IRDataType.BYTE -> registers.setUB(i.reg1!!, registers.getUB(i.reg2!!)) - IRDataType.WORD -> registers.setUW(i.reg1!!, registers.getUW(i.reg2!!)) + IRDataType.BYTE -> { + val value = registers.getUB(i.reg2!!) + registers.setUB(i.reg1!!, value) + statusZero = value==0.toUByte() + statusNegative = value>=0x80u + } + IRDataType.WORD -> { + val value = registers.getUW(i.reg2!!) + registers.setUW(i.reg1!!, value) + statusZero = value== 0.toUShort() + statusNegative = value>=0x8000u + } IRDataType.FLOAT -> registers.setFloat(i.fpReg1!!, registers.getFloat(i.fpReg2!!)) } nextPc() @@ -842,8 +891,18 @@ class VirtualMachine(irProgram: IRProgram) { private fun InsINC(i: IRInstruction) { when(i.type!!) { - IRDataType.BYTE -> registers.setUB(i.reg1!!, (registers.getUB(i.reg1!!)+1u).toUByte()) - IRDataType.WORD -> registers.setUW(i.reg1!!, (registers.getUW(i.reg1!!)+1u).toUShort()) + IRDataType.BYTE -> { + val value = (registers.getUB(i.reg1!!)+1u).toUByte() + registers.setUB(i.reg1!!, value) + statusZero = value==0.toUByte() + statusNegative = value>=0x80u + } + IRDataType.WORD -> { + val value = (registers.getUW(i.reg1!!)+1u).toUShort() + registers.setUW(i.reg1!!, value) + statusZero = value==0.toUShort() + statusNegative = value>=0x8000u + } IRDataType.FLOAT -> registers.setFloat(i.fpReg1!!, registers.getFloat(i.fpReg1!!)+1f) } nextPc() @@ -852,8 +911,18 @@ class VirtualMachine(irProgram: IRProgram) { private fun InsINCM(i: IRInstruction) { val address = i.address!! when(i.type!!) { - IRDataType.BYTE -> memory.setUB(address, (memory.getUB(address)+1u).toUByte()) - IRDataType.WORD -> memory.setUW(address, (memory.getUW(address)+1u).toUShort()) + IRDataType.BYTE -> { + val value = (memory.getUB(address)+1u).toUByte() + memory.setUB(address, value) + statusZero = value==0.toUByte() + statusNegative = value>=0x80u + } + IRDataType.WORD -> { + val value = (memory.getUW(address)+1u).toUShort() + memory.setUW(address, value) + statusZero = value== 0.toUShort() + statusNegative = value>=0x8000u + } IRDataType.FLOAT -> memory.setFloat(address, memory.getFloat(address)+1f) } nextPc() @@ -861,8 +930,18 @@ class VirtualMachine(irProgram: IRProgram) { private fun InsDEC(i: IRInstruction) { when(i.type!!) { - IRDataType.BYTE -> registers.setUB(i.reg1!!, (registers.getUB(i.reg1!!)-1u).toUByte()) - IRDataType.WORD -> registers.setUW(i.reg1!!, (registers.getUW(i.reg1!!)-1u).toUShort()) + IRDataType.BYTE -> { + val value = (registers.getUB(i.reg1!!)-1u).toUByte() + registers.setUB(i.reg1!!, value) + statusZero = value== 0.toUByte() + statusNegative = value>=0x80u + } + IRDataType.WORD -> { + val value = (registers.getUW(i.reg1!!)-1u).toUShort() + registers.setUW(i.reg1!!, value) + statusZero = value== 0.toUShort() + statusNegative = value>=0x8000u + } IRDataType.FLOAT -> registers.setFloat(i.fpReg1!!, registers.getFloat(i.fpReg1!!)-1f) } nextPc() @@ -870,8 +949,18 @@ class VirtualMachine(irProgram: IRProgram) { private fun InsDECM(i: IRInstruction) { when(i.type!!) { - IRDataType.BYTE -> memory.setUB(i.address!!, (memory.getUB(i.address!!)-1u).toUByte()) - IRDataType.WORD -> memory.setUW(i.address!!, (memory.getUW(i.address!!)-1u).toUShort()) + IRDataType.BYTE -> { + val value = (memory.getUB(i.address!!)-1u).toUByte() + memory.setUB(i.address!!, value) + statusZero = value== 0.toUByte() + statusNegative = value>=0x80u + } + IRDataType.WORD -> { + val value = (memory.getUW(i.address!!)-1u).toUShort() + memory.setUW(i.address!!, value) + statusZero = value== 0.toUShort() + statusNegative = value>=0x8000u + } IRDataType.FLOAT -> memory.setFloat(i.address!!, memory.getFloat(i.address!!)-1f) } nextPc()