mirror of
https://github.com/irmen/prog8.git
synced 2024-11-18 19:12:44 +00:00
vm: add in-place multiply
This commit is contained in:
parent
461b6499ef
commit
5e4eb92443
@ -3,7 +3,6 @@ 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.code.core.SignedDatatypes
|
||||
import prog8.vm.Opcode
|
||||
import prog8.vm.VmDataType
|
||||
@ -43,7 +42,7 @@ internal class AssignmentGen(private val codeGen: CodeGen, private val expressio
|
||||
}
|
||||
|
||||
private fun assignSelfInMemory(
|
||||
targetAddress: Int,
|
||||
address: Int,
|
||||
value: PtExpression,
|
||||
origAssign: PtAssignment
|
||||
): VmCodeChunk {
|
||||
@ -52,15 +51,15 @@ internal class AssignmentGen(private val codeGen: CodeGen, private val expressio
|
||||
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, value.type in SignedDatatypes, targetAddress, origAssign)
|
||||
is PtPrefix -> return inplacePrefix(value.operator, vmDt, address)
|
||||
is PtBinaryExpression -> return inplaceBinexpr(value.operator, value.right, vmDt, value.type in SignedDatatypes, address, origAssign)
|
||||
is PtMemoryByte -> {
|
||||
return if (!codeGen.options.compTarget.machine.isIOAddress(targetAddress.toUInt()))
|
||||
return if (!codeGen.options.compTarget.machine.isIOAddress(address.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)
|
||||
code += VmCodeInstruction(Opcode.STOREM, vmDt, reg1 = 0, value = targetAddress)
|
||||
code += VmCodeInstruction(Opcode.LOADM, vmDt, reg1 = 0, value = address)
|
||||
code += VmCodeInstruction(Opcode.STOREM, vmDt, reg1 = 0, value = address)
|
||||
code
|
||||
}
|
||||
}
|
||||
@ -77,16 +76,16 @@ internal class AssignmentGen(private val codeGen: CodeGen, private val expressio
|
||||
|
||||
private fun inplaceBinexpr(
|
||||
operator: String,
|
||||
right: PtExpression,
|
||||
operand: PtExpression,
|
||||
vmDt: VmDataType,
|
||||
signed: Boolean,
|
||||
targetAddress: Int,
|
||||
address: Int,
|
||||
origAssign: PtAssignment
|
||||
): VmCodeChunk {
|
||||
when(operator) {
|
||||
"+" -> return expressionEval.operatorPlusInplace(targetAddress, vmDt, right)
|
||||
"-" -> return expressionEval.operatorMinusInplace(targetAddress, vmDt, right)
|
||||
"*" -> { /* TODO */ }
|
||||
"+" -> return expressionEval.operatorPlusInplace(address, vmDt, operand)
|
||||
"-" -> return expressionEval.operatorMinusInplace(address, vmDt, operand)
|
||||
"*" -> return expressionEval.operatorMultiplyInplace(address, vmDt, operand)
|
||||
"/" -> { /* TODO */ }
|
||||
"|" -> { /* TODO */ }
|
||||
"&" -> { /* TODO */ }
|
||||
|
@ -395,6 +395,20 @@ class CodeGen(internal val program: PtProgram,
|
||||
return code
|
||||
}
|
||||
|
||||
internal fun multiplyByConstFloatInplace(address: Int, factor: Float): VmCodeChunk {
|
||||
val code = VmCodeChunk()
|
||||
if(factor==1f)
|
||||
return code
|
||||
if(factor==0f) {
|
||||
code += VmCodeInstruction(Opcode.STOREZM, VmDataType.FLOAT, value = address)
|
||||
} else {
|
||||
val factorReg = vmRegisters.nextFreeFloat()
|
||||
code += VmCodeInstruction(Opcode.LOAD, VmDataType.FLOAT, fpReg1=factorReg, fpValue = factor)
|
||||
code += VmCodeInstruction(Opcode.MULM, VmDataType.FLOAT, fpReg1 = factorReg, value = address)
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
internal val powersOfTwo = (0..16).map { 2.0.pow(it.toDouble()).toInt() }
|
||||
|
||||
internal fun multiplyByConst(dt: VmDataType, reg: Int, factor: Int): VmCodeChunk {
|
||||
@ -424,6 +438,41 @@ class CodeGen(internal val program: PtProgram,
|
||||
return code
|
||||
}
|
||||
|
||||
internal fun multiplyByConstInplace(dt: VmDataType, address: Int, factor: Int): VmCodeChunk {
|
||||
val code = VmCodeChunk()
|
||||
if(factor==1)
|
||||
return code
|
||||
val pow2 = powersOfTwo.indexOf(factor)
|
||||
if(pow2==1) {
|
||||
// just shift 1 bit
|
||||
// TODO use a memory shift instruction?
|
||||
val reg = vmRegisters.nextFree()
|
||||
code += VmCodeInstruction(Opcode.LOADM, dt, reg1=reg, value=address)
|
||||
code += VmCodeInstruction(Opcode.LSL, dt, reg1=reg)
|
||||
code += VmCodeInstruction(Opcode.STOREM, dt, reg1=reg, value=address)
|
||||
}
|
||||
else if(pow2>=1) {
|
||||
// just shift multiple bits
|
||||
// TODO use a memory shift instruction?
|
||||
val reg = vmRegisters.nextFree()
|
||||
val pow2reg = vmRegisters.nextFree()
|
||||
code += VmCodeInstruction(Opcode.LOADM, dt, reg1=reg, value=address)
|
||||
code += VmCodeInstruction(Opcode.LOAD, dt, reg1=pow2reg, value=pow2)
|
||||
code += VmCodeInstruction(Opcode.LSLN, dt, reg1=reg, reg2=pow2reg)
|
||||
code += VmCodeInstruction(Opcode.STOREM, dt, reg1=reg, value=address)
|
||||
} else {
|
||||
if (factor == 0) {
|
||||
code += VmCodeInstruction(Opcode.STOREZM, dt, value=address)
|
||||
}
|
||||
else {
|
||||
val factorReg = vmRegisters.nextFree()
|
||||
code += VmCodeInstruction(Opcode.LOAD, dt, reg1=factorReg, value = factor)
|
||||
code += VmCodeInstruction(Opcode.MULM, dt, reg1=factorReg, value = address)
|
||||
}
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
internal fun divideByConstFloat(fpReg: Int, factor: Float): VmCodeChunk {
|
||||
val code = VmCodeChunk()
|
||||
if(factor==1f)
|
||||
|
@ -583,6 +583,31 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
|
||||
return code
|
||||
}
|
||||
|
||||
internal fun operatorMultiplyInplace(address: Int, vmDt: VmDataType, operand: PtExpression): VmCodeChunk {
|
||||
val code = VmCodeChunk()
|
||||
val constFactorRight = operand as? PtNumber
|
||||
if(vmDt==VmDataType.FLOAT) {
|
||||
if(constFactorRight!=null) {
|
||||
val factor = constFactorRight.number.toFloat()
|
||||
code += codeGen.multiplyByConstFloatInplace(address, factor)
|
||||
} else {
|
||||
val operandFpReg = codeGen.vmRegisters.nextFreeFloat()
|
||||
code += translateExpression(operand, -1, operandFpReg)
|
||||
code += VmCodeInstruction(Opcode.MULM, vmDt, fpReg1 = operandFpReg, value = address)
|
||||
}
|
||||
} else {
|
||||
if(constFactorRight!=null && constFactorRight.type!=DataType.FLOAT) {
|
||||
val factor = constFactorRight.number.toInt()
|
||||
code += codeGen.multiplyByConstInplace(vmDt, address, factor)
|
||||
} else {
|
||||
val operandReg = codeGen.vmRegisters.nextFree()
|
||||
code += translateExpression(operand, operandReg, -1)
|
||||
code += VmCodeInstruction(Opcode.MULM, vmDt, reg1=operandReg, value = address)
|
||||
}
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
private fun operatorMinus(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int, resultFpRegister: Int): VmCodeChunk {
|
||||
val code = VmCodeChunk()
|
||||
if(vmDt==VmDataType.FLOAT) {
|
||||
@ -611,25 +636,25 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
|
||||
return code
|
||||
}
|
||||
|
||||
internal fun operatorMinusInplace(targetAddress: Int, vmDt: VmDataType, operand: PtExpression): VmCodeChunk {
|
||||
internal fun operatorMinusInplace(address: Int, vmDt: VmDataType, operand: PtExpression): VmCodeChunk {
|
||||
val code = VmCodeChunk()
|
||||
if(vmDt==VmDataType.FLOAT) {
|
||||
if((operand as? PtNumber)?.number==1.0) {
|
||||
code += VmCodeInstruction(Opcode.DECM, vmDt, value=targetAddress)
|
||||
code += VmCodeInstruction(Opcode.DECM, vmDt, value=address)
|
||||
}
|
||||
else {
|
||||
val operandFpReg = codeGen.vmRegisters.nextFreeFloat()
|
||||
code += translateExpression(operand, -1, operandFpReg)
|
||||
code += VmCodeInstruction(Opcode.SUBM, vmDt, fpReg1=operandFpReg, value=targetAddress)
|
||||
code += VmCodeInstruction(Opcode.SUBM, vmDt, fpReg1=operandFpReg, value=address)
|
||||
}
|
||||
} else {
|
||||
if((operand as? PtNumber)?.number==1.0) {
|
||||
code += VmCodeInstruction(Opcode.DECM, vmDt, value=targetAddress)
|
||||
code += VmCodeInstruction(Opcode.DECM, vmDt, value=address)
|
||||
}
|
||||
else {
|
||||
val operandReg = codeGen.vmRegisters.nextFree()
|
||||
code += translateExpression(operand, operandReg, -1)
|
||||
code += VmCodeInstruction(Opcode.SUBM, vmDt, reg1=operandReg, value = targetAddress)
|
||||
code += VmCodeInstruction(Opcode.SUBM, vmDt, reg1=operandReg, value = address)
|
||||
}
|
||||
}
|
||||
return code
|
||||
@ -671,25 +696,25 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
|
||||
return code
|
||||
}
|
||||
|
||||
internal fun operatorPlusInplace(targetAddress: Int, vmDt: VmDataType, operand: PtExpression): VmCodeChunk {
|
||||
internal fun operatorPlusInplace(address: Int, vmDt: VmDataType, operand: PtExpression): VmCodeChunk {
|
||||
val code = VmCodeChunk()
|
||||
if(vmDt==VmDataType.FLOAT) {
|
||||
if((operand as? PtNumber)?.number==1.0) {
|
||||
code += VmCodeInstruction(Opcode.INCM, vmDt, value = targetAddress)
|
||||
code += VmCodeInstruction(Opcode.INCM, vmDt, value = address)
|
||||
}
|
||||
else {
|
||||
val operandFpReg = codeGen.vmRegisters.nextFreeFloat()
|
||||
code += translateExpression(operand, -1, operandFpReg)
|
||||
code += VmCodeInstruction(Opcode.ADDM, vmDt, fpReg1=operandFpReg, value=targetAddress)
|
||||
code += VmCodeInstruction(Opcode.ADDM, vmDt, fpReg1=operandFpReg, value=address)
|
||||
}
|
||||
} else {
|
||||
if((operand as? PtNumber)?.number==1.0) {
|
||||
code += VmCodeInstruction(Opcode.INCM, vmDt, value = targetAddress)
|
||||
code += VmCodeInstruction(Opcode.INCM, vmDt, value = address)
|
||||
}
|
||||
else {
|
||||
val operandReg = codeGen.vmRegisters.nextFree()
|
||||
code += translateExpression(operand, operandReg, -1)
|
||||
code += VmCodeInstruction(Opcode.ADDM, vmDt, reg1=operandReg, value=targetAddress)
|
||||
code += VmCodeInstruction(Opcode.ADDM, vmDt, reg1=operandReg, value=address)
|
||||
}
|
||||
}
|
||||
return code
|
||||
|
@ -98,9 +98,13 @@ negm address - sign negate memory at address
|
||||
add reg1, reg2 - reg1 += reg2 (unsigned + signed)
|
||||
addm reg1, address - memory at address += reg1 (unsigned + signed)
|
||||
sub reg1, reg2 - reg1 -= reg2 (unsigned + signed)
|
||||
subm reg1, address - memory at address -= reg2 (unsigned + signed)
|
||||
mul reg1, reg2 - unsigned multiply reg1 *= reg2 note: byte*byte->byte, no type extension to word!
|
||||
mulm reg1, address - memory at address *= reg2 note: byte*byte->byte, no type extension to word!
|
||||
div reg1, reg2 - unsigned division reg1 /= reg2 note: division by zero yields max int $ff/$ffff
|
||||
divm reg1, address - memory at address /= reg2 note: division by zero yields max int $ff/$ffff
|
||||
divs reg1, reg2 - signed division reg1 /= reg2 note: division by zero yields max signed int 127 / 32767
|
||||
divsm reg1, address - signed memory at address /= reg2 note: division by zero yields max signed int 127 / 32767
|
||||
mod reg1, reg2 - remainder (modulo) of unsigned division reg1 %= reg2 note: division by zero yields max signed int $ff/$ffff
|
||||
sqrt reg1, reg2 - reg1 is the square root of reg2
|
||||
sgn reg1, reg2 - reg1 is the sign of reg2 (0, 1 or -1)
|
||||
@ -131,6 +135,8 @@ roxr reg1 - rotate reg1 right by 1 bits, usin
|
||||
rol reg1 - rotate reg1 left by 1 bits, not using carry + set Carry to shifted bit
|
||||
roxl reg1 - rotate reg1 left by 1 bits, using carry, + set Carry to shifted bit
|
||||
|
||||
TODO: add memory-shift instructions?
|
||||
|
||||
|
||||
FLOATING POINT CONVERSIONS AND FUNCTIONS
|
||||
----------------------------------------
|
||||
@ -291,6 +297,11 @@ val OpcodesWithAddress = setOf(
|
||||
Opcode.INCM,
|
||||
Opcode.DECM,
|
||||
Opcode.NEGM,
|
||||
Opcode.ADDM,
|
||||
Opcode.SUBM,
|
||||
Opcode.MULM,
|
||||
Opcode.DIVM,
|
||||
Opcode.DIVSM,
|
||||
Opcode.NOTM,
|
||||
Opcode.XORM
|
||||
)
|
||||
|
@ -142,7 +142,7 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
|
||||
Opcode.SUB -> InsSUB(ins)
|
||||
Opcode.SUBM -> InsSUBM(ins)
|
||||
Opcode.MUL -> InsMUL(ins)
|
||||
Opcode.MULM -> TODO()
|
||||
Opcode.MULM -> InsMULM(ins)
|
||||
Opcode.DIV -> InsDIV(ins)
|
||||
Opcode.DIVM -> TODO()
|
||||
Opcode.DIVS -> InsDIVS(ins)
|
||||
@ -735,6 +735,21 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
|
||||
pc++
|
||||
}
|
||||
|
||||
private fun InsMULM(i: Instruction) {
|
||||
val address = i.value!!
|
||||
when(i.type!!) {
|
||||
VmDataType.BYTE -> plusMinusMultAnyByteInplace("*", i.reg1!!, address)
|
||||
VmDataType.WORD -> plusMinusMultAnyWordInplace("*", i.reg1!!, address)
|
||||
VmDataType.FLOAT -> {
|
||||
val left = memory.getFloat(address)
|
||||
val right = registers.getFloat(i.fpReg1!!)
|
||||
val result = arithFloat(left, "*", right)
|
||||
memory.setFloat(address, result)
|
||||
}
|
||||
}
|
||||
pc++
|
||||
}
|
||||
|
||||
private fun InsDIV(i: Instruction) {
|
||||
when(i.type!!) {
|
||||
VmDataType.BYTE -> divModByteUnsigned("/", i.reg1!!, i.reg2!!)
|
||||
|
Loading…
Reference in New Issue
Block a user