vm: implemented some self-assign instructions

This commit is contained in:
Irmen de Jong 2022-05-18 22:15:42 +02:00
parent 4e1184a400
commit 181b98ef9e
11 changed files with 215 additions and 87 deletions

View File

@ -12,27 +12,24 @@ sealed class PtExpression(val type: DataType, position: Position) : PtNode(posit
print(type)
}
infix fun isSameTargetAs(other: PtExpression): Boolean = when(this) {
is PtArrayIndexer -> {
if(other is PtArrayIndexer && other.type==type) {
if(other.variable isSameTargetAs variable) {
other.index isSameTargetAs index
}
}
false
infix fun isSameAs(other: PtExpression): Boolean {
return when(this) {
is PtAddressOf -> other is PtAddressOf && other.type==type && other.identifier isSameAs identifier
is PtArrayIndexer -> other is PtArrayIndexer && other.type==type && other.variable isSameAs variable && other.index isSameAs index
is PtBinaryExpression -> other is PtBinaryExpression && other.left isSameAs left && other.right isSameAs right
is PtContainmentCheck -> other is PtContainmentCheck && other.type==type && other.element isSameAs element && other.iterable isSameAs iterable
is PtIdentifier -> other is PtIdentifier && other.type==type && other.targetName==targetName
is PtMachineRegister -> other is PtMachineRegister && other.type==type && other.register==register
is PtMemoryByte -> other is PtMemoryByte && other.address isSameAs address
is PtNumber -> other is PtNumber && other.type==type && other.number==number
is PtPrefix -> other is PtPrefix && other.type==type && other.operator==operator && other.value isSameAs value
is PtRange -> other is PtRange && other.type==type && other.from==from && other.to==to && other.step==step
is PtTypeCast -> other is PtTypeCast && other.type==type && other.value isSameAs value
else -> false
}
is PtIdentifier -> other is PtIdentifier && other.type==type && other.targetName==targetName
is PtMachineRegister -> other is PtMachineRegister && other.register==register
is PtMemoryByte -> other is PtMemoryByte && address isSameTargetAs other.address
is PtNumber -> other is PtNumber && other.type == type && other.number==number
is PtAddressOf -> other is PtAddressOf && other.identifier isSameTargetAs identifier
is PtPrefix -> other is PtPrefix && other.operator==operator && other.value isSameTargetAs value
is PtTypeCast -> other is PtTypeCast && other.type==type && other.value isSameTargetAs value
else -> false
}
}
class PtAddressOf(position: Position) : PtExpression(DataType.UWORD, position) {
val identifier: PtIdentifier
get() = children.single() as PtIdentifier

View File

@ -48,14 +48,33 @@ class PtAssignment(position: Position) : PtNode(position) {
val isInplaceAssign: Boolean by lazy {
val target = target.children.single() as PtExpression
if(value is PtBinaryExpression) {
target isSameTargetAs (value as PtBinaryExpression).left
} else
target isSameTargetAs value
when(val source = value) {
is PtArrayIndexer -> {
if(target is PtArrayIndexer && source.type==target.type) {
if(target.variable isSameAs source.variable) {
target.index isSameAs source.index
}
}
false
}
is PtIdentifier -> target is PtIdentifier && target.type==source.type && target.targetName==source.targetName
is PtMachineRegister -> target is PtMachineRegister && target.register==source.register
is PtMemoryByte -> target is PtMemoryByte && target.address isSameAs source.address
is PtNumber -> target is PtNumber && target.type == source.type && target.number==source.number
is PtAddressOf -> target is PtAddressOf && target.identifier isSameAs source.identifier
is PtPrefix -> {
(target is PtPrefix && target.operator==source.operator && target.value isSameAs source.value)
||
(target is PtIdentifier && (source.value as? PtIdentifier)?.targetName==target.targetName)
}
is PtTypeCast -> target is PtTypeCast && target.type==source.type && target.value isSameAs source.value
is PtBinaryExpression ->
target isSameAs source.left
else -> false
}
}
}
class PtAssignTarget(position: Position) : PtNode(position) {
val identifier: PtIdentifier?
get() = children.single() as? PtIdentifier

View File

@ -81,9 +81,9 @@ internal class VmCodeInstruction(
fpReg2: Int?=null, // 0-$ffff
value: Int?=null, // 0-$ffff
fpValue: Float?=null,
symbol: List<String>?=null // alternative to value
labelSymbol: List<String>?=null // alternative to value for branch/call/jump labels
): VmCodeLine() {
val ins = Instruction(opcode, type, reg1, reg2, fpReg1, fpReg2, value, fpValue, symbol)
val ins = Instruction(opcode, type, reg1, reg2, fpReg1, fpReg2, value, fpValue, labelSymbol)
init {
if(reg1!=null && (reg1<0 || reg1>65536))

View File

@ -3,12 +3,16 @@ package prog8.codegen.virtual
import prog8.code.ast.*
import prog8.code.core.AssemblyError
import prog8.code.core.DataType
import prog8.code.core.Position
import prog8.vm.Opcode
import prog8.vm.VmDataType
internal class AssignmentGen(private val codeGen: CodeGen, private val expressionEval: ExpressionGen) {
internal fun translate(assignment: PtAssignment): VmCodeChunk {
if(assignment.target.children.single() is PtMachineRegister)
throw AssemblyError("assigning to a register should be done by just evaluating the expression into resultregister")
return if (assignment.isInplaceAssign)
translateInplaceAssign(assignment)
else
@ -16,14 +20,104 @@ internal class AssignmentGen(private val codeGen: CodeGen, private val expressio
}
private fun translateInplaceAssign(assignment: PtAssignment): VmCodeChunk {
// TODO can in-place assignments be optimized more? use special memory versions of instructions instead of register ones?
return translateRegularAssign(assignment)
val ident = assignment.target.identifier
val memory = assignment.target.memory
val array = assignment.target.array
return if(ident!=null) {
val address = codeGen.allocations.get(ident.targetName)
assignSelfInMemory(address, assignment.value, assignment.position, assignment)
} else if(memory != null) {
if(memory.address is PtNumber) {
assignSelfInMemory((memory.address as PtNumber).number.toInt(), assignment.value, assignment.position, assignment)
} else {
fallbackAssign(assignment)
}
} else if(array!=null) {
// TODO in-place array element assignment?
fallbackAssign(assignment)
} else {
fallbackAssign(assignment)
}
}
private fun assignSelfInMemory(
targetAddress: Int,
value: PtExpression,
position: Position,
origAssign: PtAssignment
): VmCodeChunk {
val vmDt = codeGen.vmType(value.type)
val code = VmCodeChunk()
when(value) {
is PtIdentifier -> return code // do nothing, x=x null assignment.
is PtMachineRegister -> return code // do nothing, reg=reg null assignment
is PtPrefix -> return inplacePrefix(value.operator, vmDt, targetAddress)
is PtBinaryExpression -> return inplaceBinexpr(value.operator, value.right, vmDt, targetAddress, origAssign)
is PtMemoryByte -> {
return if (!codeGen.options.compTarget.machine.isIOAddress(targetAddress.toUInt()))
code // do nothing, mem=mem null assignment.
else {
// read and write a (i/o) memory location to itself.
code += VmCodeInstruction(Opcode.LOADM, vmDt, reg1 = 0, value = targetAddress.toInt())
code += VmCodeInstruction(Opcode.STOREM, vmDt, reg1 = 0, value = targetAddress.toInt())
code
}
}
else -> return fallbackAssign(origAssign)
}
}
private fun fallbackAssign(origAssign: PtAssignment): VmCodeChunk {
if (codeGen.options.slowCodegenWarnings)
codeGen.errors.warn("indirect code for in-place assignment", origAssign.position)
return translateRegularAssign(origAssign)
}
private fun inplaceBinexpr(
operator: String,
right: PtExpression,
vmDt: VmDataType,
targetAddress: Int,
origAssign: PtAssignment
): VmCodeChunk {
when(operator) {
"+" -> { /* TODO */ }
"-" -> { /* TODO */ }
"*" -> { /* TODO */ }
"/" -> { /* TODO */ }
"|" -> { /* TODO */ }
"&" -> { /* TODO */ }
"^" -> { /* TODO */ }
else -> {}
}
return fallbackAssign(origAssign)
}
private fun inplacePrefix(operator: String, vmDt: VmDataType, address: Int): VmCodeChunk {
val code= VmCodeChunk()
when(operator) {
"+" -> { }
"-" -> {
code += VmCodeInstruction(Opcode.NEGM, vmDt, value = address)
}
"~" -> {
val regMask = codeGen.vmRegisters.nextFree()
val mask = if(vmDt==VmDataType.BYTE) 0x00ff else 0xffff
code += VmCodeInstruction(Opcode.LOAD, vmDt, reg1=regMask, value = mask)
code += VmCodeInstruction(Opcode.XORM, vmDt, reg1=regMask, value = address)
}
"not" -> {
code += VmCodeInstruction(Opcode.NOTM, vmDt, value = address)
}
else -> throw AssemblyError("weird prefix operator")
}
return code
}
private fun translateRegularAssign(assignment: PtAssignment): VmCodeChunk {
// note: assigning array and string values is done via an explicit memcopy/stringcopy function call.
if(assignment.target.children.single() is PtMachineRegister)
throw AssemblyError("assigning to a register should be done by just evaluating the expression into resultregister")
val ident = assignment.target.identifier
val memory = assignment.target.memory
val array = assignment.target.array

View File

@ -116,7 +116,7 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
val notNegativeLabel = codeGen.createLabelName()
code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=andReg, value=0x80)
code += VmCodeInstruction(Opcode.AND, VmDataType.BYTE, reg1=andReg, reg2=resultRegister)
code += VmCodeInstruction(Opcode.BZ, VmDataType.BYTE, reg1=andReg, symbol = notNegativeLabel)
code += VmCodeInstruction(Opcode.BZ, VmDataType.BYTE, reg1=andReg, labelSymbol = notNegativeLabel)
code += VmCodeInstruction(Opcode.NEG, VmDataType.BYTE, reg1=resultRegister)
code += VmCodeInstruction(Opcode.EXT, VmDataType.BYTE, reg1=resultRegister)
code += VmCodeLabel(notNegativeLabel)
@ -126,7 +126,7 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
val notNegativeLabel = codeGen.createLabelName()
code += VmCodeInstruction(Opcode.LOAD, VmDataType.WORD, reg1=andReg, value=0x8000)
code += VmCodeInstruction(Opcode.AND, VmDataType.WORD, reg1=andReg, reg2=resultRegister)
code += VmCodeInstruction(Opcode.BZ, VmDataType.WORD, reg1=andReg, symbol = notNegativeLabel)
code += VmCodeInstruction(Opcode.BZ, VmDataType.WORD, reg1=andReg, labelSymbol = notNegativeLabel)
code += VmCodeInstruction(Opcode.NEG, VmDataType.WORD, reg1=resultRegister)
code += VmCodeLabel(notNegativeLabel)
}

View File

@ -123,19 +123,19 @@ class CodeGen(internal val program: PtProgram,
val elseLabel = createLabelName()
// note that the branch opcode used is the opposite as the branch condition, because the generated code jumps to the 'else' part
code += when(branch.condition) {
BranchCondition.CS -> VmCodeInstruction(Opcode.BSTCC, symbol = elseLabel)
BranchCondition.CC -> VmCodeInstruction(Opcode.BSTCS, symbol = elseLabel)
BranchCondition.EQ, BranchCondition.Z -> VmCodeInstruction(Opcode.BSTNE, symbol = elseLabel)
BranchCondition.NE, BranchCondition.NZ -> VmCodeInstruction(Opcode.BSTEQ, symbol = elseLabel)
BranchCondition.MI, BranchCondition.NEG -> VmCodeInstruction(Opcode.BSTPOS, symbol = elseLabel)
BranchCondition.PL, BranchCondition.POS -> VmCodeInstruction(Opcode.BSTNEG, symbol = elseLabel)
BranchCondition.CS -> VmCodeInstruction(Opcode.BSTCC, labelSymbol = elseLabel)
BranchCondition.CC -> VmCodeInstruction(Opcode.BSTCS, labelSymbol = elseLabel)
BranchCondition.EQ, BranchCondition.Z -> VmCodeInstruction(Opcode.BSTNE, labelSymbol = elseLabel)
BranchCondition.NE, BranchCondition.NZ -> VmCodeInstruction(Opcode.BSTEQ, labelSymbol = elseLabel)
BranchCondition.MI, BranchCondition.NEG -> VmCodeInstruction(Opcode.BSTPOS, labelSymbol = elseLabel)
BranchCondition.PL, BranchCondition.POS -> VmCodeInstruction(Opcode.BSTNEG, labelSymbol = elseLabel)
BranchCondition.VC,
BranchCondition.VS -> throw AssemblyError("conditional branch ${branch.condition} not supported in vm target due to lack of cpu V flag ${branch.position}")
}
code += translateNode(branch.trueScope)
if(branch.falseScope.children.isNotEmpty()) {
val endLabel = createLabelName()
code += VmCodeInstruction(Opcode.JUMP, symbol = endLabel)
code += VmCodeInstruction(Opcode.JUMP, labelSymbol = endLabel)
code += VmCodeLabel(elseLabel)
code += translateNode(branch.falseScope)
code += VmCodeLabel(endLabel)
@ -163,21 +163,21 @@ class CodeGen(internal val program: PtProgram,
val values = choice.values.children.map {it as PtNumber}
if(values.size==1) {
code += VmCodeInstruction(Opcode.LOAD, valueDt, reg1=choiceReg, value=values[0].number.toInt())
code += VmCodeInstruction(Opcode.BNE, valueDt, reg1=valueReg, reg2=choiceReg, symbol = skipLabel)
code += VmCodeInstruction(Opcode.BNE, valueDt, reg1=valueReg, reg2=choiceReg, labelSymbol = skipLabel)
code += translateNode(choice.statements)
if(choice.statements.children.last() !is PtReturn)
code += VmCodeInstruction(Opcode.JUMP, symbol = endLabel)
code += VmCodeInstruction(Opcode.JUMP, labelSymbol = endLabel)
} else {
val matchLabel = createLabelName()
for (value in values) {
code += VmCodeInstruction(Opcode.LOAD, valueDt, reg1=choiceReg, value=value.number.toInt())
code += VmCodeInstruction(Opcode.BEQ, valueDt, reg1=valueReg, reg2=choiceReg, symbol = matchLabel)
code += VmCodeInstruction(Opcode.BEQ, valueDt, reg1=valueReg, reg2=choiceReg, labelSymbol = matchLabel)
}
code += VmCodeInstruction(Opcode.JUMP, symbol = skipLabel)
code += VmCodeInstruction(Opcode.JUMP, labelSymbol = skipLabel)
code += VmCodeLabel(matchLabel)
code += translateNode(choice.statements)
if(choice.statements.children.last() !is PtReturn)
code += VmCodeInstruction(Opcode.JUMP, symbol = endLabel)
code += VmCodeInstruction(Opcode.JUMP, labelSymbol = endLabel)
}
code += VmCodeLabel(skipLabel)
}
@ -209,11 +209,11 @@ class CodeGen(internal val program: PtProgram,
code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=indexReg, value=0)
code += VmCodeLabel(loopLabel)
code += VmCodeInstruction(Opcode.LOADX, VmDataType.BYTE, reg1=0, reg2=indexReg, value = arrayAddress)
code += VmCodeInstruction(Opcode.BZ, VmDataType.BYTE, reg1=0, symbol = endLabel)
code += VmCodeInstruction(Opcode.BZ, VmDataType.BYTE, reg1=0, labelSymbol = endLabel)
code += VmCodeInstruction(Opcode.STOREM, VmDataType.BYTE, reg1=0, value = loopvarAddress)
code += translateNode(forLoop.statements)
code += VmCodeInstruction(Opcode.INC, VmDataType.BYTE, reg1=indexReg)
code += VmCodeInstruction(Opcode.JUMP, symbol = loopLabel)
code += VmCodeInstruction(Opcode.JUMP, labelSymbol = loopLabel)
code += VmCodeLabel(endLabel)
} else {
// iterate over array
@ -224,12 +224,12 @@ class CodeGen(internal val program: PtProgram,
code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=indexReg, value=0)
code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=lengthReg, value=lengthBytes)
code += VmCodeLabel(loopLabel)
code += VmCodeInstruction(Opcode.BEQ, VmDataType.BYTE, reg1=indexReg, reg2=lengthReg, symbol = endLabel)
code += VmCodeInstruction(Opcode.BEQ, VmDataType.BYTE, reg1=indexReg, reg2=lengthReg, labelSymbol = endLabel)
code += VmCodeInstruction(Opcode.LOADX, vmType(elementDt), reg1=0, reg2=indexReg, value=arrayAddress)
code += VmCodeInstruction(Opcode.STOREM, vmType(elementDt), reg1=0, value = loopvarAddress)
code += translateNode(forLoop.statements)
code += addConstReg(VmDataType.BYTE, indexReg, elementSize)
code += VmCodeInstruction(Opcode.JUMP, symbol = loopLabel)
code += VmCodeInstruction(Opcode.JUMP, labelSymbol = loopLabel)
code += VmCodeLabel(endLabel)
}
}
@ -264,7 +264,7 @@ class CodeGen(internal val program: PtProgram,
code += VmCodeInstruction(Opcode.STOREM, loopvarDt, reg1 = indexReg, value = loopvarAddress)
}
val branchOpcode = if(loopvar.dt in SignedDatatypes) Opcode.BLES else Opcode.BLE
code += VmCodeInstruction(branchOpcode, loopvarDt, reg1=indexReg, reg2=endvalueReg, symbol=loopLabel)
code += VmCodeInstruction(branchOpcode, loopvarDt, reg1=indexReg, reg2=endvalueReg, labelSymbol=loopLabel)
return code
}
@ -303,9 +303,9 @@ class CodeGen(internal val program: PtProgram,
code += VmCodeInstruction(Opcode.STOREM, loopvarDt, reg1 = indexReg, value = loopvarAddress)
}
code += if(rangeEndWrapped==0) {
VmCodeInstruction(Opcode.BNZ, loopvarDt, reg1 = indexReg, symbol = loopLabel)
VmCodeInstruction(Opcode.BNZ, loopvarDt, reg1 = indexReg, labelSymbol = loopLabel)
} else {
VmCodeInstruction(Opcode.BNE, loopvarDt, reg1 = indexReg, reg2 = endvalueReg, symbol = loopLabel)
VmCodeInstruction(Opcode.BNE, loopvarDt, reg1 = indexReg, reg2 = endvalueReg, labelSymbol = loopLabel)
}
return code
}
@ -492,16 +492,16 @@ class CodeGen(internal val program: PtProgram,
// if and else parts
val elseLabel = createLabelName()
val afterIfLabel = createLabelName()
code += VmCodeInstruction(elseBranch, vmDt, reg1=leftReg, reg2=rightReg, symbol = elseLabel)
code += VmCodeInstruction(elseBranch, vmDt, reg1=leftReg, reg2=rightReg, labelSymbol = elseLabel)
code += translateNode(ifElse.ifScope)
code += VmCodeInstruction(Opcode.JUMP, symbol = afterIfLabel)
code += VmCodeInstruction(Opcode.JUMP, labelSymbol = afterIfLabel)
code += VmCodeLabel(elseLabel)
code += translateNode(ifElse.elseScope)
code += VmCodeLabel(afterIfLabel)
} else {
// only if part
val afterIfLabel = createLabelName()
code += VmCodeInstruction(elseBranch, vmDt, reg1=leftReg, reg2=rightReg, symbol = afterIfLabel)
code += VmCodeInstruction(elseBranch, vmDt, reg1=leftReg, reg2=rightReg, labelSymbol = afterIfLabel)
code += translateNode(ifElse.ifScope)
code += VmCodeLabel(afterIfLabel)
}
@ -516,16 +516,16 @@ class CodeGen(internal val program: PtProgram,
// if and else parts
val elseLabel = createLabelName()
val afterIfLabel = createLabelName()
code += VmCodeInstruction(elseBranch, vmDt, reg1=leftReg, symbol = elseLabel)
code += VmCodeInstruction(elseBranch, vmDt, reg1=leftReg, labelSymbol = elseLabel)
code += translateNode(ifElse.ifScope)
code += VmCodeInstruction(Opcode.JUMP, symbol = afterIfLabel)
code += VmCodeInstruction(Opcode.JUMP, labelSymbol = afterIfLabel)
code += VmCodeLabel(elseLabel)
code += translateNode(ifElse.elseScope)
code += VmCodeLabel(afterIfLabel)
} else {
// only if part
val afterIfLabel = createLabelName()
code += VmCodeInstruction(elseBranch, vmDt, reg1=leftReg, symbol = afterIfLabel)
code += VmCodeInstruction(elseBranch, vmDt, reg1=leftReg, labelSymbol = afterIfLabel)
code += translateNode(ifElse.ifScope)
code += VmCodeLabel(afterIfLabel)
}
@ -629,7 +629,7 @@ class CodeGen(internal val program: PtProgram,
code += VmCodeLabel(repeatLabel)
code += translateNode(repeat.statements)
code += VmCodeInstruction(Opcode.DEC, vmDt, reg1=counterReg)
code += VmCodeInstruction(Opcode.BNZ, vmDt, reg1=counterReg, symbol = repeatLabel)
code += VmCodeInstruction(Opcode.BNZ, vmDt, reg1=counterReg, labelSymbol = repeatLabel)
return code
}
@ -638,9 +638,9 @@ class CodeGen(internal val program: PtProgram,
if(jump.address!=null)
throw AssemblyError("cannot jump to memory location in the vm target")
code += if(jump.generatedLabel!=null)
VmCodeInstruction(Opcode.JUMP, symbol = listOf(jump.generatedLabel!!))
VmCodeInstruction(Opcode.JUMP, labelSymbol = listOf(jump.generatedLabel!!))
else if(jump.identifier!=null)
VmCodeInstruction(Opcode.JUMP, symbol = jump.identifier!!.targetName)
VmCodeInstruction(Opcode.JUMP, labelSymbol = jump.identifier!!.targetName)
else
throw AssemblyError("weird jump")
return code

View File

@ -410,7 +410,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
val valueReg = codeGen.vmRegisters.nextFree()
code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=resultRegister, value=1)
code += VmCodeInstruction(Opcode.FCOMP, VmDataType.FLOAT, reg1=valueReg, fpReg1 = leftFpReg, fpReg2 = rightFpReg)
code += VmCodeInstruction(Opcode.BZ, VmDataType.BYTE, reg1=valueReg, symbol = label)
code += VmCodeInstruction(Opcode.BZ, VmDataType.BYTE, reg1=valueReg, labelSymbol = label)
code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=resultRegister, value=0)
code += VmCodeLabel(label)
}
@ -664,7 +664,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
}
}
}
code += VmCodeInstruction(Opcode.CALL, symbol=fcall.functionName)
code += VmCodeInstruction(Opcode.CALL, labelSymbol=fcall.functionName)
if(fcall.type==DataType.FLOAT) {
if (!fcall.void && resultFpRegister != 0) {
// Call convention: result value is in fr0, so put it in the required register instead.

View File

@ -3,8 +3,8 @@ TODO
For next release
^^^^^^^^^^^^^^^^
- vm: implement the sin/cos functions in math.p8 and make an example 'shader' that uses them
- vm: add more instructions operating directly on memory instead of only registers? (translate assignment self-assigns in AssignmentGen)
- vm: implement the missing in-place operators in inplaceBinexpr()
- vm: implement the new in-memory instructions in the VirtualMachine eval loop itself.
- complete the Inliner
- add McCarthy evaluation to shortcircuit and/or expressions. First do ifs by splitting them up? Then do expressions that compute a value?
@ -23,6 +23,7 @@ Future Things and Ideas
Compiler:
- vm: codeGen: various TODOs to tweak code
- vm: implement remaining sin/cos functions in math.p8
- vm: somehow deal with asmsubs otherwise the vm IR can't fully encode all of prog8
- vm: don't store symbol names in instructions to make optimizing the IR easier? but what about jumps to labels. And it's no longer readable by humans.
- vm: how to remove all unused subroutines? (in the assembly codegen, we let 64tass solve this for us)

View File

@ -4,19 +4,26 @@
main {
sub start() {
byte xx
byte yy
ubyte ubx
; a "pixelshader":
sys.gfx_enable(0) ; enable lo res screen
xx = xx
xx = xx*9
xx = yy*9
xx = xx+3*yy
xx = xx/yy
xx = -xx
@($4000) = @($4000)
@($4000) = @($4000) + 2
xx = xx | yy
xx = xx & yy
xx = xx ^ yy
xx = (not xx) as byte
xx = (~xx) as byte
xx++
ubyte angle
for angle in 0 to 180 {
ubyte xx = math.sinr8u(angle)
ubyte yy = math.cosr8u(angle) / 2
sys.gfx_plot(xx, yy, 255)
}
repeat {
}
ubx = not ubx
ubx = ~ubx
}
}

View File

@ -15,8 +15,6 @@ Currently NO support for 24 or 32 bits integers.
Floating point operations are just 'f' typed regular instructions, and additionally there are
a few fp conversion instructions to
*only* LOAD AND STORE instructions have a possible memory operand, all other instructions use only registers or immediate value.
LOAD/STORE
----------
@ -96,6 +94,7 @@ incm address - memory at address += 1
dec reg1 - reg1 = reg1-1
decm address - memory at address -= 1
neg reg1 - reg1 = sign negation of reg1
negm address - sign negate memory at address
add reg1, reg2 - reg1 += reg2 (unsigned + signed)
sub reg1, reg2 - reg1 -= reg2 (unsigned + signed)
mul reg1, reg2 - unsigned multiply reg1 *= reg2 note: byte*byte->byte, no type extension to word!
@ -116,7 +115,9 @@ All have type b or w.
and reg1, reg2 - reg1 = reg1 bitwise and reg2
or reg1, reg2 - reg1 = reg1 bitwise or reg2
xor reg1, reg2 - reg1 = reg1 bitwise xor reg2
xorm reg1, address - memory = memory bitwise xor reg1
not reg1 - reg1 = boolean not of reg1 (0->1 , ~0 -> 0)
notm address - memory = boolean not of that memory (0->1 , ~0 -> 0)
lsrn reg1, reg2 - reg1 = multi-shift reg1 right by reg2 bits + set Carry to shifted bit
asrn reg1, reg2 - reg1 = multi-shift reg1 right by reg2 bits (signed) + set Carry to shifted bit
lsln reg1, reg2 - reg1 = multi-shift reg1 left by reg2 bits + set Carry to shifted bit
@ -211,6 +212,7 @@ enum class Opcode {
DEC,
DECM,
NEG,
NEGM,
ADD,
SUB,
MUL,
@ -226,7 +228,9 @@ enum class Opcode {
AND,
OR,
XOR,
XORM,
NOT,
NOTM,
ASRN,
LSRN,
LSLN,
@ -277,7 +281,10 @@ val OpcodesWithAddress = setOf(
Opcode.STOREZM,
Opcode.STOREZX,
Opcode.INCM,
Opcode.DECM
Opcode.DECM,
Opcode.NEGM,
Opcode.NOTM,
Opcode.XORM
)
@ -297,7 +304,7 @@ data class Instruction(
val fpReg2: Int?=null, // 0-$ffff
val value: Int?=null, // 0-$ffff
val fpValue: Float?=null,
val symbol: List<String>?=null // alternative to value
val labelSymbol: List<String>?=null // symbolic label name as alternative to value (so only for Branch/jump/call Instructions!)
) {
init {
val formats = instructionFormats.getValue(opcode)
@ -318,11 +325,11 @@ data class Instruction(
throw IllegalArgumentException("too many registers (float)")
if (type==VmDataType.FLOAT) {
if(format.fpValue && (fpValue==null && symbol==null))
throw IllegalArgumentException("$opcode: missing a fp-value or symbol")
if(format.fpValue && (fpValue==null && labelSymbol==null))
throw IllegalArgumentException("$opcode: missing a fp-value or labelsymbol")
} else {
if(format.value && (value==null && symbol==null))
throw IllegalArgumentException("$opcode: missing a value or symbol")
if(format.value && (value==null && labelSymbol==null))
throw IllegalArgumentException("$opcode: missing a value or labelsymbol")
if (fpReg1 != null || fpReg2 != null)
throw java.lang.IllegalArgumentException("$opcode: integer point instruction can't use floating point registers")
}
@ -361,7 +368,7 @@ data class Instruction(
result.add(it.toString())
result.add(",")
}
symbol?.let {
labelSymbol?.let {
result.add("_" + it.joinToString("."))
}
if(result.last() == ",")
@ -464,6 +471,7 @@ val instructionFormats = mutableMapOf(
Opcode.DEC to InstructionFormat.from("BW,r1"),
Opcode.DECM to InstructionFormat.from("BW,v"),
Opcode.NEG to InstructionFormat.from("BW,r1 | F,fr1"),
Opcode.NEGM to InstructionFormat.from("BW,v | F,v"),
Opcode.ADD to InstructionFormat.from("BW,r1,r2 | F,fr1,fr2"),
Opcode.SUB to InstructionFormat.from("BW,r1,r2 | F,fr1,fr2"),
Opcode.MUL to InstructionFormat.from("BW,r1,r2 | F,fr1,fr2"),
@ -478,7 +486,9 @@ val instructionFormats = mutableMapOf(
Opcode.AND to InstructionFormat.from("BW,r1,r2"),
Opcode.OR to InstructionFormat.from("BW,r1,r2"),
Opcode.XOR to InstructionFormat.from("BW,r1,r2"),
Opcode.XORM to InstructionFormat.from("BW,r1,v"),
Opcode.NOT to InstructionFormat.from("BW,r1"),
Opcode.NOTM to InstructionFormat.from("BW,v"),
Opcode.ASRN to InstructionFormat.from("BW,r1,r2"),
Opcode.LSRN to InstructionFormat.from("BW,r1,r2"),
Opcode.LSLN to InstructionFormat.from("BW,r1,r2"),

View File

@ -17,7 +17,7 @@ class TestInstructions: FunSpec({
ins.reg1 shouldBe null
ins.reg2 shouldBe null
ins.value shouldBe null
ins.symbol shouldBe null
ins.labelSymbol shouldBe null
ins.toString() shouldBe "nop"
}
@ -28,18 +28,18 @@ class TestInstructions: FunSpec({
ins.reg1 shouldBe 42
ins.reg2 shouldBe null
ins.value shouldBe 9999
ins.symbol shouldBe null
ins.labelSymbol shouldBe null
ins.toString() shouldBe "bz.b r42,9999"
}
test("with label") {
val ins = Instruction(Opcode.BZ, VmDataType.WORD, reg1=11, symbol = listOf("a","b","c"))
val ins = Instruction(Opcode.BZ, VmDataType.WORD, reg1=11, labelSymbol = listOf("a","b","c"))
ins.opcode shouldBe Opcode.BZ
ins.type shouldBe VmDataType.WORD
ins.reg1 shouldBe 11
ins.reg2 shouldBe null
ins.value shouldBe null
ins.symbol shouldBe listOf("a","b","c")
ins.labelSymbol shouldBe listOf("a","b","c")
ins.toString() shouldBe "bz.w r11,_a.b.c"
}