mirror of
https://github.com/irmen/prog8.git
synced 2025-06-18 08:23:37 +00:00
Compare commits
14 Commits
Author | SHA1 | Date | |
---|---|---|---|
9f09784b55 | |||
e7a3a89bfb | |||
7ea7e63f44 | |||
1d2ce2cbeb | |||
06cf2e0bd7 | |||
9d219ae4b9 | |||
71f5a6c50e | |||
90b2be2bf4 | |||
db1aa8fcbd | |||
11c000f764 | |||
4d6dcbd173 | |||
0da117efd2 | |||
533c368e32 | |||
8883513b0e |
@ -173,8 +173,7 @@ class PtPrefix(val operator: String, type: DataType, position: Position): PtExpr
|
|||||||
|
|
||||||
init {
|
init {
|
||||||
// note: the "not" operator may no longer occur in the ast; not x should have been replaced with x==0
|
// note: the "not" operator may no longer occur in the ast; not x should have been replaced with x==0
|
||||||
if(operator !in setOf("+", "-", "~"))
|
require(operator in setOf("+", "-", "~")) { "invalid prefix operator: $operator" }
|
||||||
throw IllegalArgumentException("invalid prefix operator: $operator")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun printProperties() {
|
override fun printProperties() {
|
||||||
|
@ -4,12 +4,11 @@ import prog8.code.core.CompilationOptions
|
|||||||
import prog8.code.core.CpuType
|
import prog8.code.core.CpuType
|
||||||
import prog8.code.core.IMachineDefinition
|
import prog8.code.core.IMachineDefinition
|
||||||
import prog8.code.core.Zeropage
|
import prog8.code.core.Zeropage
|
||||||
import java.io.File
|
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
|
import kotlin.io.path.isReadable
|
||||||
import kotlin.io.path.name
|
import kotlin.io.path.name
|
||||||
import kotlin.io.path.readText
|
import kotlin.io.path.readText
|
||||||
|
|
||||||
|
|
||||||
class VirtualMachineDefinition: IMachineDefinition {
|
class VirtualMachineDefinition: IMachineDefinition {
|
||||||
|
|
||||||
override val cpu = CpuType.VIRTUAL
|
override val cpu = CpuType.VIRTUAL
|
||||||
@ -35,14 +34,15 @@ class VirtualMachineDefinition: IMachineDefinition {
|
|||||||
// to not have external module dependencies in our own module, we launch the virtual machine via reflection
|
// to not have external module dependencies in our own module, we launch the virtual machine via reflection
|
||||||
val vm = Class.forName("prog8.vm.VmRunner").getDeclaredConstructor().newInstance() as IVirtualMachineRunner
|
val vm = Class.forName("prog8.vm.VmRunner").getDeclaredConstructor().newInstance() as IVirtualMachineRunner
|
||||||
val filename = programNameWithPath.name
|
val filename = programNameWithPath.name
|
||||||
if(filename.endsWith(".p8virt")) {
|
if(programNameWithPath.isReadable()) {
|
||||||
vm.runProgram(programNameWithPath.readText())
|
vm.runProgram(programNameWithPath.readText())
|
||||||
} else if(File("$filename.p8virt").isFile) {
|
} else {
|
||||||
val source = File("$filename.p8virt").readText()
|
val withExt = programNameWithPath.resolveSibling("$filename.p8ir")
|
||||||
vm.runProgram(source)
|
if(withExt.isReadable())
|
||||||
|
vm.runProgram(withExt.readText())
|
||||||
|
else
|
||||||
|
throw NoSuchFileException(withExt.toFile(), reason="not a .p8ir file")
|
||||||
}
|
}
|
||||||
else
|
|
||||||
throw IllegalArgumentException("vm can only run .p8virt or .p8ir files")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun isIOAddress(address: UInt): Boolean = false
|
override fun isIOAddress(address: UInt): Boolean = false
|
||||||
@ -53,5 +53,5 @@ class VirtualMachineDefinition: IMachineDefinition {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface IVirtualMachineRunner {
|
interface IVirtualMachineRunner {
|
||||||
fun runProgram(source: String)
|
fun runProgram(irSource: CharSequence)
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,6 @@ import prog8.ast.Program
|
|||||||
import prog8.ast.base.FatalAstException
|
import prog8.ast.base.FatalAstException
|
||||||
import prog8.ast.expressions.*
|
import prog8.ast.expressions.*
|
||||||
import prog8.ast.statements.*
|
import prog8.ast.statements.*
|
||||||
import prog8.code.StMemorySlab
|
|
||||||
import prog8.code.SymbolTable
|
import prog8.code.SymbolTable
|
||||||
import prog8.code.core.*
|
import prog8.code.core.*
|
||||||
import prog8.codegen.cpu6502.assignment.*
|
import prog8.codegen.cpu6502.assignment.*
|
||||||
@ -42,7 +41,7 @@ class AsmGen(internal val program: Program,
|
|||||||
private val expressionsAsmGen = ExpressionsAsmGen(program, this, allocator)
|
private val expressionsAsmGen = ExpressionsAsmGen(program, this, allocator)
|
||||||
private val programGen = ProgramAndVarsGen(program, options, errors, symbolTable, functioncallAsmGen, this, allocator, zeropage)
|
private val programGen = ProgramAndVarsGen(program, options, errors, symbolTable, functioncallAsmGen, this, allocator, zeropage)
|
||||||
private val assignmentAsmGen = AssignmentAsmGen(program, this, allocator)
|
private val assignmentAsmGen = AssignmentAsmGen(program, this, allocator)
|
||||||
private val builtinFunctionsAsmGen = BuiltinFunctionsAsmGen(program, this, assignmentAsmGen, allocator)
|
private val builtinFunctionsAsmGen = BuiltinFunctionsAsmGen(program, this, assignmentAsmGen)
|
||||||
|
|
||||||
override fun compileToAssembly(): IAssemblyProgram? {
|
override fun compileToAssembly(): IAssemblyProgram? {
|
||||||
|
|
||||||
@ -78,7 +77,7 @@ class AsmGen(internal val program: Program,
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal fun out(str: String, splitlines: Boolean = true) {
|
internal fun out(str: String, splitlines: Boolean = true) {
|
||||||
val fragment = (if(splitlines && " | " in str) str.replace("|", "\n") else str).trim('\n')
|
val fragment = (if(splitlines && " | " in str) str.replace("|", "\n") else str).trim('\r', '\n')
|
||||||
if (splitlines) {
|
if (splitlines) {
|
||||||
for (line in fragment.splitToSequence('\n')) {
|
for (line in fragment.splitToSequence('\n')) {
|
||||||
val trimmed = if (line.startsWith(' ')) "\t" + line.trim() else line
|
val trimmed = if (line.startsWith(' ')) "\t" + line.trim() else line
|
||||||
@ -839,7 +838,7 @@ $repeatLabel lda $counterVar
|
|||||||
if(stmt.definingModule.source is SourceCode.Generated)
|
if(stmt.definingModule.source is SourceCode.Generated)
|
||||||
throw AssemblyError("%asminclude inside non-library/non-filesystem module not yet supported")
|
throw AssemblyError("%asminclude inside non-library/non-filesystem module not yet supported")
|
||||||
loadAsmIncludeFile(includedName, stmt.definingModule.source).fold(
|
loadAsmIncludeFile(includedName, stmt.definingModule.source).fold(
|
||||||
success = { assemblyLines.add(it.trimEnd().trimStart('\n')) },
|
success = { assemblyLines.add(it.trimEnd().trimStart('\r', '\n')) },
|
||||||
failure = { errors.err(it.toString(), stmt.position) }
|
failure = { errors.err(it.toString(), stmt.position) }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -910,7 +909,7 @@ $repeatLabel lda $counterVar
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun translate(asm: InlineAssembly) {
|
private fun translate(asm: InlineAssembly) {
|
||||||
val assembly = asm.assembly.trimEnd().trimStart('\n')
|
val assembly = asm.assembly.trimEnd().trimStart('\r', '\n')
|
||||||
assemblyLines.add(assembly)
|
assemblyLines.add(assembly)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2897,12 +2896,6 @@ $repeatLabel lda $counterVar
|
|||||||
else
|
else
|
||||||
extra
|
extra
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addMemorySlab(name: String, size: UInt, align: UInt, position: Position): String {
|
|
||||||
val prefixedName = "prog8_memoryslab_$name"
|
|
||||||
symbolTable.add(StMemorySlab(prefixedName, size, align, position))
|
|
||||||
return prefixedName
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -15,8 +15,7 @@ import prog8.compiler.FSignature
|
|||||||
|
|
||||||
internal class BuiltinFunctionsAsmGen(private val program: Program,
|
internal class BuiltinFunctionsAsmGen(private val program: Program,
|
||||||
private val asmgen: AsmGen,
|
private val asmgen: AsmGen,
|
||||||
private val assignAsmGen: AssignmentAsmGen,
|
private val assignAsmGen: AssignmentAsmGen) {
|
||||||
private val allocations: VariableAllocator) {
|
|
||||||
|
|
||||||
internal fun translateFunctioncallExpression(fcall: BuiltinFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?) {
|
internal fun translateFunctioncallExpression(fcall: BuiltinFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?) {
|
||||||
val func = BuiltinFunctions.getValue(fcall.target.nameInSource.single())
|
val func = BuiltinFunctions.getValue(fcall.target.nameInSource.single())
|
||||||
@ -309,10 +308,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program,
|
|||||||
throw AssemblyError("should not discard result of memory allocation at $fcall")
|
throw AssemblyError("should not discard result of memory allocation at $fcall")
|
||||||
val name = (fcall.args[0] as StringLiteral).value
|
val name = (fcall.args[0] as StringLiteral).value
|
||||||
require(name.all { it.isLetterOrDigit() || it=='_' }) {"memory name should be a valid symbol name"}
|
require(name.all { it.isLetterOrDigit() || it=='_' }) {"memory name should be a valid symbol name"}
|
||||||
val size = (fcall.args[1] as NumericLiteral).number.toUInt()
|
val slabname = IdentifierReference(listOf("prog8_slabs", "prog8_memoryslab_$name"), fcall.position)
|
||||||
val align = (fcall.args[2] as NumericLiteral).number.toUInt()
|
|
||||||
val prefixedName = asmgen.addMemorySlab(name, size, align, fcall.position)
|
|
||||||
val slabname = IdentifierReference(listOf("prog8_slabs", prefixedName), fcall.position)
|
|
||||||
slabname.linkParents(fcall)
|
slabname.linkParents(fcall)
|
||||||
val src = AsmAssignSource(SourceStorageKind.EXPRESSION, program, asmgen, DataType.UWORD, expression = AddressOf(slabname, fcall.position))
|
val src = AsmAssignSource(SourceStorageKind.EXPRESSION, program, asmgen, DataType.UWORD, expression = AddressOf(slabname, fcall.position))
|
||||||
val target =
|
val target =
|
||||||
|
@ -22,7 +22,7 @@ class CodeGen(private val program: PtProgram,
|
|||||||
val irProgram = irCodeGen.generate()
|
val irProgram = irCodeGen.generate()
|
||||||
|
|
||||||
// this stub only writes the IR program to disk but doesn't generate anything else.
|
// this stub only writes the IR program to disk but doesn't generate anything else.
|
||||||
IRFileWriter(irProgram).writeFile()
|
IRFileWriter(irProgram, null).write()
|
||||||
|
|
||||||
println("** experimental codegen stub: no assembly generated **")
|
println("** experimental codegen stub: no assembly generated **")
|
||||||
return null
|
return null
|
||||||
|
@ -6,7 +6,7 @@ import prog8.code.core.DataType
|
|||||||
import prog8.code.core.Position
|
import prog8.code.core.Position
|
||||||
import prog8.code.core.SignedDatatypes
|
import prog8.code.core.SignedDatatypes
|
||||||
import prog8.intermediate.IRCodeChunk
|
import prog8.intermediate.IRCodeChunk
|
||||||
import prog8.intermediate.IRCodeInstruction
|
import prog8.intermediate.IRInstruction
|
||||||
import prog8.intermediate.Opcode
|
import prog8.intermediate.Opcode
|
||||||
import prog8.intermediate.VmDataType
|
import prog8.intermediate.VmDataType
|
||||||
|
|
||||||
@ -62,8 +62,8 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
|||||||
else {
|
else {
|
||||||
// read and write a (i/o) memory location to itself.
|
// read and write a (i/o) memory location to itself.
|
||||||
val tempReg = codeGen.vmRegisters.nextFree()
|
val tempReg = codeGen.vmRegisters.nextFree()
|
||||||
code += IRCodeInstruction(Opcode.LOADM, vmDt, reg1 = tempReg, value = address)
|
code += IRInstruction(Opcode.LOADM, vmDt, reg1 = tempReg, value = address)
|
||||||
code += IRCodeInstruction(Opcode.STOREM, vmDt, reg1 = tempReg, value = address)
|
code += IRInstruction(Opcode.STOREM, vmDt, reg1 = tempReg, value = address)
|
||||||
code
|
code
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -85,8 +85,8 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
|||||||
is PtBinaryExpression -> return inplaceBinexpr(value.operator, value.right, vmDt, value.type in SignedDatatypes, null, symbol, origAssign)
|
is PtBinaryExpression -> return inplaceBinexpr(value.operator, value.right, vmDt, value.type in SignedDatatypes, null, symbol, origAssign)
|
||||||
is PtMemoryByte -> {
|
is PtMemoryByte -> {
|
||||||
val tempReg = codeGen.vmRegisters.nextFree()
|
val tempReg = codeGen.vmRegisters.nextFree()
|
||||||
code += IRCodeInstruction(Opcode.LOADM, vmDt, reg1 = tempReg, labelSymbol = symbol)
|
code += IRInstruction(Opcode.LOADM, vmDt, reg1 = tempReg, labelSymbol = symbol)
|
||||||
code += IRCodeInstruction(Opcode.STOREM, vmDt, reg1 = tempReg, labelSymbol = symbol)
|
code += IRInstruction(Opcode.STOREM, vmDt, reg1 = tempReg, labelSymbol = symbol)
|
||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
else -> return fallbackAssign(origAssign)
|
else -> return fallbackAssign(origAssign)
|
||||||
@ -145,18 +145,18 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
|||||||
"+" -> { }
|
"+" -> { }
|
||||||
"-" -> {
|
"-" -> {
|
||||||
code += if(knownAddress!=null)
|
code += if(knownAddress!=null)
|
||||||
IRCodeInstruction(Opcode.NEGM, vmDt, value = knownAddress)
|
IRInstruction(Opcode.NEGM, vmDt, value = knownAddress)
|
||||||
else
|
else
|
||||||
IRCodeInstruction(Opcode.NEGM, vmDt, labelSymbol = addressSymbol)
|
IRInstruction(Opcode.NEGM, vmDt, labelSymbol = addressSymbol)
|
||||||
}
|
}
|
||||||
"~" -> {
|
"~" -> {
|
||||||
val regMask = codeGen.vmRegisters.nextFree()
|
val regMask = codeGen.vmRegisters.nextFree()
|
||||||
val mask = if(vmDt==VmDataType.BYTE) 0x00ff else 0xffff
|
val mask = if(vmDt==VmDataType.BYTE) 0x00ff else 0xffff
|
||||||
code += IRCodeInstruction(Opcode.LOAD, vmDt, reg1=regMask, value = mask)
|
code += IRInstruction(Opcode.LOAD, vmDt, reg1=regMask, value = mask)
|
||||||
code += if(knownAddress!=null)
|
code += if(knownAddress!=null)
|
||||||
IRCodeInstruction(Opcode.XORM, vmDt, reg1=regMask, value = knownAddress)
|
IRInstruction(Opcode.XORM, vmDt, reg1=regMask, value = knownAddress)
|
||||||
else
|
else
|
||||||
IRCodeInstruction(Opcode.XORM, vmDt, reg1=regMask, labelSymbol = addressSymbol)
|
IRInstruction(Opcode.XORM, vmDt, reg1=regMask, labelSymbol = addressSymbol)
|
||||||
}
|
}
|
||||||
else -> throw AssemblyError("weird prefix operator")
|
else -> throw AssemblyError("weird prefix operator")
|
||||||
}
|
}
|
||||||
@ -192,12 +192,12 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
|||||||
if(ident!=null) {
|
if(ident!=null) {
|
||||||
val symbol = ident.targetName.joinToString(".")
|
val symbol = ident.targetName.joinToString(".")
|
||||||
code += if(zero) {
|
code += if(zero) {
|
||||||
IRCodeInstruction(Opcode.STOREZM, vmDt, labelSymbol = symbol)
|
IRInstruction(Opcode.STOREZM, vmDt, labelSymbol = symbol)
|
||||||
} else {
|
} else {
|
||||||
if (vmDt == VmDataType.FLOAT)
|
if (vmDt == VmDataType.FLOAT)
|
||||||
IRCodeInstruction(Opcode.STOREM, vmDt, fpReg1 = resultFpRegister, labelSymbol = symbol)
|
IRInstruction(Opcode.STOREM, vmDt, fpReg1 = resultFpRegister, labelSymbol = symbol)
|
||||||
else
|
else
|
||||||
IRCodeInstruction(Opcode.STOREM, vmDt, reg1 = resultRegister, labelSymbol = symbol)
|
IRInstruction(Opcode.STOREM, vmDt, reg1 = resultRegister, labelSymbol = symbol)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(array!=null) {
|
else if(array!=null) {
|
||||||
@ -215,9 +215,9 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
|||||||
if(zero) {
|
if(zero) {
|
||||||
// there's no STOREZIX instruction
|
// there's no STOREZIX instruction
|
||||||
resultRegister = codeGen.vmRegisters.nextFree()
|
resultRegister = codeGen.vmRegisters.nextFree()
|
||||||
code += IRCodeInstruction(Opcode.LOAD, vmDt, reg1=resultRegister, value=0)
|
code += IRInstruction(Opcode.LOAD, vmDt, reg1=resultRegister, value=0)
|
||||||
}
|
}
|
||||||
code += IRCodeInstruction(Opcode.STOREIX, vmDt, reg1=resultRegister, reg2=idxReg, labelSymbol = variable)
|
code += IRInstruction(Opcode.STOREIX, vmDt, reg1=resultRegister, reg2=idxReg, labelSymbol = variable)
|
||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -225,30 +225,30 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
|||||||
if(zero) {
|
if(zero) {
|
||||||
if(fixedIndex!=null) {
|
if(fixedIndex!=null) {
|
||||||
val offset = fixedIndex*itemsize
|
val offset = fixedIndex*itemsize
|
||||||
code += IRCodeInstruction(Opcode.STOREZM, vmDt, labelSymbol = "$variable+$offset")
|
code += IRInstruction(Opcode.STOREZM, vmDt, labelSymbol = "$variable+$offset")
|
||||||
} else {
|
} else {
|
||||||
val indexReg = codeGen.vmRegisters.nextFree()
|
val indexReg = codeGen.vmRegisters.nextFree()
|
||||||
code += loadIndexReg(array, itemsize, indexReg, array.position)
|
code += loadIndexReg(array, itemsize, indexReg, array.position)
|
||||||
code += IRCodeInstruction(Opcode.STOREZX, vmDt, reg1=indexReg, labelSymbol = variable)
|
code += IRInstruction(Opcode.STOREZX, vmDt, reg1=indexReg, labelSymbol = variable)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if(vmDt== VmDataType.FLOAT) {
|
if(vmDt== VmDataType.FLOAT) {
|
||||||
if(fixedIndex!=null) {
|
if(fixedIndex!=null) {
|
||||||
val offset = fixedIndex*itemsize
|
val offset = fixedIndex*itemsize
|
||||||
code += IRCodeInstruction(Opcode.STOREM, vmDt, fpReg1 = resultFpRegister, labelSymbol = "$variable+$offset")
|
code += IRInstruction(Opcode.STOREM, vmDt, fpReg1 = resultFpRegister, labelSymbol = "$variable+$offset")
|
||||||
} else {
|
} else {
|
||||||
val indexReg = codeGen.vmRegisters.nextFree()
|
val indexReg = codeGen.vmRegisters.nextFree()
|
||||||
code += loadIndexReg(array, itemsize, indexReg, array.position)
|
code += loadIndexReg(array, itemsize, indexReg, array.position)
|
||||||
code += IRCodeInstruction(Opcode.STOREX, vmDt, reg1 = resultRegister, reg2=indexReg, labelSymbol = variable)
|
code += IRInstruction(Opcode.STOREX, vmDt, reg1 = resultRegister, reg2=indexReg, labelSymbol = variable)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if(fixedIndex!=null) {
|
if(fixedIndex!=null) {
|
||||||
val offset = fixedIndex*itemsize
|
val offset = fixedIndex*itemsize
|
||||||
code += IRCodeInstruction(Opcode.STOREM, vmDt, reg1 = resultRegister, labelSymbol = "$variable+$offset")
|
code += IRInstruction(Opcode.STOREM, vmDt, reg1 = resultRegister, labelSymbol = "$variable+$offset")
|
||||||
} else {
|
} else {
|
||||||
val indexReg = codeGen.vmRegisters.nextFree()
|
val indexReg = codeGen.vmRegisters.nextFree()
|
||||||
code += loadIndexReg(array, itemsize, indexReg, array.position)
|
code += loadIndexReg(array, itemsize, indexReg, array.position)
|
||||||
code += IRCodeInstruction(Opcode.STOREX, vmDt, reg1 = resultRegister, reg2=indexReg, labelSymbol = variable)
|
code += IRInstruction(Opcode.STOREX, vmDt, reg1 = resultRegister, reg2=indexReg, labelSymbol = variable)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -257,19 +257,19 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
|||||||
require(vmDt== VmDataType.BYTE)
|
require(vmDt== VmDataType.BYTE)
|
||||||
if(zero) {
|
if(zero) {
|
||||||
if(memory.address is PtNumber) {
|
if(memory.address is PtNumber) {
|
||||||
code += IRCodeInstruction(Opcode.STOREZM, vmDt, value=(memory.address as PtNumber).number.toInt())
|
code += IRInstruction(Opcode.STOREZM, vmDt, value=(memory.address as PtNumber).number.toInt())
|
||||||
} else {
|
} else {
|
||||||
val addressReg = codeGen.vmRegisters.nextFree()
|
val addressReg = codeGen.vmRegisters.nextFree()
|
||||||
code += expressionEval.translateExpression(memory.address, addressReg, -1)
|
code += expressionEval.translateExpression(memory.address, addressReg, -1)
|
||||||
code += IRCodeInstruction(Opcode.STOREZI, vmDt, reg1=addressReg)
|
code += IRInstruction(Opcode.STOREZI, vmDt, reg1=addressReg)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if(memory.address is PtNumber) {
|
if(memory.address is PtNumber) {
|
||||||
code += IRCodeInstruction(Opcode.STOREM, vmDt, reg1=resultRegister, value=(memory.address as PtNumber).number.toInt())
|
code += IRInstruction(Opcode.STOREM, vmDt, reg1=resultRegister, value=(memory.address as PtNumber).number.toInt())
|
||||||
} else {
|
} else {
|
||||||
val addressReg = codeGen.vmRegisters.nextFree()
|
val addressReg = codeGen.vmRegisters.nextFree()
|
||||||
code += expressionEval.translateExpression(memory.address, addressReg, -1)
|
code += expressionEval.translateExpression(memory.address, addressReg, -1)
|
||||||
code += IRCodeInstruction(Opcode.STOREI, vmDt, reg1=resultRegister, reg2=addressReg)
|
code += IRInstruction(Opcode.STOREI, vmDt, reg1=resultRegister, reg2=addressReg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -55,7 +55,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
|||||||
val rightRegister = codeGen.vmRegisters.nextFree()
|
val rightRegister = codeGen.vmRegisters.nextFree()
|
||||||
code += exprGen.translateExpression(call.args[0], leftRegister, -1)
|
code += exprGen.translateExpression(call.args[0], leftRegister, -1)
|
||||||
code += exprGen.translateExpression(call.args[1], rightRegister, -1)
|
code += exprGen.translateExpression(call.args[1], rightRegister, -1)
|
||||||
code += IRCodeInstruction(Opcode.CMP, codeGen.vmType(call.args[0].type), reg1=leftRegister, reg2=rightRegister)
|
code += IRInstruction(Opcode.CMP, codeGen.vmType(call.args[0].type), reg1=leftRegister, reg2=rightRegister)
|
||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,10 +73,10 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
|||||||
else -> throw IllegalArgumentException("weird type")
|
else -> throw IllegalArgumentException("weird type")
|
||||||
}
|
}
|
||||||
code += exprGen.translateExpression(call.args[0], 0, -1)
|
code += exprGen.translateExpression(call.args[0], 0, -1)
|
||||||
code += IRCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1 = 1, value = array.length)
|
code += IRInstruction(Opcode.LOAD, VmDataType.BYTE, reg1 = 1, value = array.length)
|
||||||
code += IRCodeInstruction(Opcode.SYSCALL, value = syscall.ordinal)
|
code += IRInstruction(Opcode.SYSCALL, value=syscall.ordinal)
|
||||||
if (resultRegister != 0)
|
if (resultRegister != 0)
|
||||||
code += IRCodeInstruction(Opcode.LOADR, VmDataType.BYTE, reg1 = resultRegister, reg2 = 0)
|
code += IRInstruction(Opcode.LOADR, VmDataType.BYTE, reg1 = resultRegister, reg2 = 0)
|
||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,10 +94,10 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
|||||||
}
|
}
|
||||||
val code = IRCodeChunk(call.position)
|
val code = IRCodeChunk(call.position)
|
||||||
code += exprGen.translateExpression(call.args[0], 0, -1)
|
code += exprGen.translateExpression(call.args[0], 0, -1)
|
||||||
code += IRCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=1, value=array.length)
|
code += IRInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=1, value=array.length)
|
||||||
code += IRCodeInstruction(Opcode.SYSCALL, value=syscall.ordinal)
|
code += IRInstruction(Opcode.SYSCALL, value=syscall.ordinal)
|
||||||
if(resultRegister!=0)
|
if(resultRegister!=0)
|
||||||
code += IRCodeInstruction(Opcode.LOADR, VmDataType.BYTE, reg1=resultRegister, reg2=0)
|
code += IRInstruction(Opcode.LOADR, VmDataType.BYTE, reg1=resultRegister, reg2=0)
|
||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,25 +108,25 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
|||||||
code += exprGen.translateExpression(call.args[0], resultRegister, -1)
|
code += exprGen.translateExpression(call.args[0], resultRegister, -1)
|
||||||
when (sourceDt) {
|
when (sourceDt) {
|
||||||
DataType.UBYTE -> {
|
DataType.UBYTE -> {
|
||||||
code += IRCodeInstruction(Opcode.EXT, VmDataType.BYTE, reg1=resultRegister)
|
code += IRInstruction(Opcode.EXT, VmDataType.BYTE, reg1=resultRegister)
|
||||||
}
|
}
|
||||||
DataType.BYTE -> {
|
DataType.BYTE -> {
|
||||||
val notNegativeLabel = codeGen.createLabelName()
|
val notNegativeLabel = codeGen.createLabelName()
|
||||||
val compareReg = codeGen.vmRegisters.nextFree()
|
val compareReg = codeGen.vmRegisters.nextFree()
|
||||||
code += IRCodeInstruction(Opcode.LOADR, VmDataType.BYTE, reg1=compareReg, reg2=resultRegister)
|
code += IRInstruction(Opcode.LOADR, VmDataType.BYTE, reg1=compareReg, reg2=resultRegister)
|
||||||
code += IRCodeInstruction(Opcode.AND, VmDataType.BYTE, reg1=compareReg, value=0x80)
|
code += IRInstruction(Opcode.AND, VmDataType.BYTE, reg1=compareReg, value=0x80)
|
||||||
code += IRCodeInstruction(Opcode.BZ, VmDataType.BYTE, reg1=compareReg, labelSymbol = notNegativeLabel)
|
code += IRInstruction(Opcode.BZ, VmDataType.BYTE, reg1=compareReg, labelSymbol = notNegativeLabel)
|
||||||
code += IRCodeInstruction(Opcode.NEG, VmDataType.BYTE, reg1=resultRegister)
|
code += IRInstruction(Opcode.NEG, VmDataType.BYTE, reg1=resultRegister)
|
||||||
code += IRCodeInstruction(Opcode.EXT, VmDataType.BYTE, reg1=resultRegister)
|
code += IRInstruction(Opcode.EXT, VmDataType.BYTE, reg1=resultRegister)
|
||||||
code += IRCodeLabel(notNegativeLabel)
|
code += IRCodeLabel(notNegativeLabel)
|
||||||
}
|
}
|
||||||
DataType.WORD -> {
|
DataType.WORD -> {
|
||||||
val notNegativeLabel = codeGen.createLabelName()
|
val notNegativeLabel = codeGen.createLabelName()
|
||||||
val compareReg = codeGen.vmRegisters.nextFree()
|
val compareReg = codeGen.vmRegisters.nextFree()
|
||||||
code += IRCodeInstruction(Opcode.LOADR, VmDataType.WORD, reg1=compareReg, reg2=resultRegister)
|
code += IRInstruction(Opcode.LOADR, VmDataType.WORD, reg1=compareReg, reg2=resultRegister)
|
||||||
code += IRCodeInstruction(Opcode.AND, VmDataType.WORD, reg1=compareReg, value=0x8000)
|
code += IRInstruction(Opcode.AND, VmDataType.WORD, reg1=compareReg, value=0x8000)
|
||||||
code += IRCodeInstruction(Opcode.BZ, VmDataType.WORD, reg1=compareReg, labelSymbol = notNegativeLabel)
|
code += IRInstruction(Opcode.BZ, VmDataType.WORD, reg1=compareReg, labelSymbol = notNegativeLabel)
|
||||||
code += IRCodeInstruction(Opcode.NEG, VmDataType.WORD, reg1=resultRegister)
|
code += IRInstruction(Opcode.NEG, VmDataType.WORD, reg1=resultRegister)
|
||||||
code += IRCodeLabel(notNegativeLabel)
|
code += IRCodeLabel(notNegativeLabel)
|
||||||
}
|
}
|
||||||
else -> throw AssemblyError("weird type")
|
else -> throw AssemblyError("weird type")
|
||||||
@ -139,7 +139,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
|||||||
val code = IRCodeChunk(call.position)
|
val code = IRCodeChunk(call.position)
|
||||||
val reg = codeGen.vmRegisters.nextFree()
|
val reg = codeGen.vmRegisters.nextFree()
|
||||||
code += exprGen.translateExpression(call.args.single(), reg, -1)
|
code += exprGen.translateExpression(call.args.single(), reg, -1)
|
||||||
code += IRCodeInstruction(Opcode.SGN, codeGen.vmType(call.type), reg1=resultRegister, reg2=reg)
|
code += IRInstruction(Opcode.SGN, codeGen.vmType(call.type), reg1=resultRegister, reg2=reg)
|
||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,14 +147,14 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
|||||||
val code = IRCodeChunk(call.position)
|
val code = IRCodeChunk(call.position)
|
||||||
val reg = codeGen.vmRegisters.nextFree()
|
val reg = codeGen.vmRegisters.nextFree()
|
||||||
code += exprGen.translateExpression(call.args.single(), reg, -1)
|
code += exprGen.translateExpression(call.args.single(), reg, -1)
|
||||||
code += IRCodeInstruction(Opcode.SQRT, VmDataType.WORD, reg1=resultRegister, reg2=reg)
|
code += IRInstruction(Opcode.SQRT, VmDataType.WORD, reg1=resultRegister, reg2=reg)
|
||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun funcPop(call: PtBuiltinFunctionCall): IRCodeChunk {
|
private fun funcPop(call: PtBuiltinFunctionCall): IRCodeChunk {
|
||||||
val code = IRCodeChunk(call.position)
|
val code = IRCodeChunk(call.position)
|
||||||
val reg = codeGen.vmRegisters.nextFree()
|
val reg = codeGen.vmRegisters.nextFree()
|
||||||
code += IRCodeInstruction(Opcode.POP, VmDataType.BYTE, reg1=reg)
|
code += IRInstruction(Opcode.POP, VmDataType.BYTE, reg1=reg)
|
||||||
code += assignRegisterTo(call.args.single(), reg)
|
code += assignRegisterTo(call.args.single(), reg)
|
||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
@ -162,7 +162,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
|||||||
private fun funcPopw(call: PtBuiltinFunctionCall): IRCodeChunk {
|
private fun funcPopw(call: PtBuiltinFunctionCall): IRCodeChunk {
|
||||||
val code = IRCodeChunk(call.position)
|
val code = IRCodeChunk(call.position)
|
||||||
val reg = codeGen.vmRegisters.nextFree()
|
val reg = codeGen.vmRegisters.nextFree()
|
||||||
code += IRCodeInstruction(Opcode.POP, VmDataType.WORD, reg1=reg)
|
code += IRInstruction(Opcode.POP, VmDataType.WORD, reg1=reg)
|
||||||
code += assignRegisterTo(call.args.single(), reg)
|
code += assignRegisterTo(call.args.single(), reg)
|
||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
@ -171,7 +171,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
|||||||
val code = IRCodeChunk(call.position)
|
val code = IRCodeChunk(call.position)
|
||||||
val reg = codeGen.vmRegisters.nextFree()
|
val reg = codeGen.vmRegisters.nextFree()
|
||||||
code += exprGen.translateExpression(call.args.single(), reg, -1)
|
code += exprGen.translateExpression(call.args.single(), reg, -1)
|
||||||
code += IRCodeInstruction(Opcode.PUSH, VmDataType.BYTE, reg1=reg)
|
code += IRInstruction(Opcode.PUSH, VmDataType.BYTE, reg1=reg)
|
||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -179,7 +179,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
|||||||
val code = IRCodeChunk(call.position)
|
val code = IRCodeChunk(call.position)
|
||||||
val reg = codeGen.vmRegisters.nextFree()
|
val reg = codeGen.vmRegisters.nextFree()
|
||||||
code += exprGen.translateExpression(call.args.single(), reg, -1)
|
code += exprGen.translateExpression(call.args.single(), reg, -1)
|
||||||
code += IRCodeInstruction(Opcode.PUSH, VmDataType.WORD, reg1=reg)
|
code += IRInstruction(Opcode.PUSH, VmDataType.WORD, reg1=reg)
|
||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -195,8 +195,8 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
|||||||
}
|
}
|
||||||
val code = IRCodeChunk(call.position)
|
val code = IRCodeChunk(call.position)
|
||||||
code += exprGen.translateExpression(call.args[0], 0, -1)
|
code += exprGen.translateExpression(call.args[0], 0, -1)
|
||||||
code += IRCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=1, value=array.length)
|
code += IRInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=1, value=array.length)
|
||||||
code += IRCodeInstruction(Opcode.SYSCALL, value=syscall.ordinal)
|
code += IRInstruction(Opcode.SYSCALL, value=syscall.ordinal)
|
||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -215,8 +215,8 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
|||||||
}
|
}
|
||||||
val code = IRCodeChunk(call.position)
|
val code = IRCodeChunk(call.position)
|
||||||
code += exprGen.translateExpression(call.args[0], 0, -1)
|
code += exprGen.translateExpression(call.args[0], 0, -1)
|
||||||
code += IRCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=1, value=array.length)
|
code += IRInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=1, value=array.length)
|
||||||
code += IRCodeInstruction(Opcode.SYSCALL, value=syscall.ordinal)
|
code += IRInstruction(Opcode.SYSCALL, value=syscall.ordinal)
|
||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -225,7 +225,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
|||||||
val code = IRCodeChunk(call.position)
|
val code = IRCodeChunk(call.position)
|
||||||
code += exprGen.translateExpression(call.args[0], msbReg, -1)
|
code += exprGen.translateExpression(call.args[0], msbReg, -1)
|
||||||
code += exprGen.translateExpression(call.args[1], resultRegister, -1)
|
code += exprGen.translateExpression(call.args[1], resultRegister, -1)
|
||||||
code += IRCodeInstruction(Opcode.CONCAT, VmDataType.BYTE, reg1=resultRegister, reg2=msbReg)
|
code += IRInstruction(Opcode.CONCAT, VmDataType.BYTE, reg1=resultRegister, reg2=msbReg)
|
||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -234,23 +234,23 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
|||||||
if(codeGen.isZero(call.args[1])) {
|
if(codeGen.isZero(call.args[1])) {
|
||||||
if (call.args[0] is PtNumber) {
|
if (call.args[0] is PtNumber) {
|
||||||
val address = (call.args[0] as PtNumber).number.toInt()
|
val address = (call.args[0] as PtNumber).number.toInt()
|
||||||
code += IRCodeInstruction(Opcode.STOREZM, VmDataType.WORD, value = address)
|
code += IRInstruction(Opcode.STOREZM, VmDataType.WORD, value = address)
|
||||||
} else {
|
} else {
|
||||||
val addressReg = codeGen.vmRegisters.nextFree()
|
val addressReg = codeGen.vmRegisters.nextFree()
|
||||||
code += exprGen.translateExpression(call.args[0], addressReg, -1)
|
code += exprGen.translateExpression(call.args[0], addressReg, -1)
|
||||||
code += IRCodeInstruction(Opcode.STOREZI, VmDataType.WORD, reg2 = addressReg)
|
code += IRInstruction(Opcode.STOREZI, VmDataType.WORD, reg2 = addressReg)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
val valueReg = codeGen.vmRegisters.nextFree()
|
val valueReg = codeGen.vmRegisters.nextFree()
|
||||||
if (call.args[0] is PtNumber) {
|
if (call.args[0] is PtNumber) {
|
||||||
val address = (call.args[0] as PtNumber).number.toInt()
|
val address = (call.args[0] as PtNumber).number.toInt()
|
||||||
code += exprGen.translateExpression(call.args[1], valueReg, -1)
|
code += exprGen.translateExpression(call.args[1], valueReg, -1)
|
||||||
code += IRCodeInstruction(Opcode.STOREM, VmDataType.WORD, reg1 = valueReg, value = address)
|
code += IRInstruction(Opcode.STOREM, VmDataType.WORD, reg1 = valueReg, value = address)
|
||||||
} else {
|
} else {
|
||||||
val addressReg = codeGen.vmRegisters.nextFree()
|
val addressReg = codeGen.vmRegisters.nextFree()
|
||||||
code += exprGen.translateExpression(call.args[0], addressReg, -1)
|
code += exprGen.translateExpression(call.args[0], addressReg, -1)
|
||||||
code += exprGen.translateExpression(call.args[1], valueReg, -1)
|
code += exprGen.translateExpression(call.args[1], valueReg, -1)
|
||||||
code += IRCodeInstruction(Opcode.STOREI, VmDataType.WORD, reg1 = valueReg, reg2 = addressReg)
|
code += IRInstruction(Opcode.STOREI, VmDataType.WORD, reg1 = valueReg, reg2 = addressReg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return code
|
return code
|
||||||
@ -261,23 +261,23 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
|||||||
if(codeGen.isZero(call.args[1])) {
|
if(codeGen.isZero(call.args[1])) {
|
||||||
if (call.args[0] is PtNumber) {
|
if (call.args[0] is PtNumber) {
|
||||||
val address = (call.args[0] as PtNumber).number.toInt()
|
val address = (call.args[0] as PtNumber).number.toInt()
|
||||||
code += IRCodeInstruction(Opcode.STOREZM, VmDataType.BYTE, value = address)
|
code += IRInstruction(Opcode.STOREZM, VmDataType.BYTE, value = address)
|
||||||
} else {
|
} else {
|
||||||
val addressReg = codeGen.vmRegisters.nextFree()
|
val addressReg = codeGen.vmRegisters.nextFree()
|
||||||
code += exprGen.translateExpression(call.args[0], addressReg, -1)
|
code += exprGen.translateExpression(call.args[0], addressReg, -1)
|
||||||
code += IRCodeInstruction(Opcode.STOREZI, VmDataType.BYTE, reg2 = addressReg)
|
code += IRInstruction(Opcode.STOREZI, VmDataType.BYTE, reg2 = addressReg)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
val valueReg = codeGen.vmRegisters.nextFree()
|
val valueReg = codeGen.vmRegisters.nextFree()
|
||||||
if (call.args[0] is PtNumber) {
|
if (call.args[0] is PtNumber) {
|
||||||
val address = (call.args[0] as PtNumber).number.toInt()
|
val address = (call.args[0] as PtNumber).number.toInt()
|
||||||
code += exprGen.translateExpression(call.args[1], valueReg, -1)
|
code += exprGen.translateExpression(call.args[1], valueReg, -1)
|
||||||
code += IRCodeInstruction(Opcode.STOREM, VmDataType.BYTE, reg1 = valueReg, value = address)
|
code += IRInstruction(Opcode.STOREM, VmDataType.BYTE, reg1 = valueReg, value = address)
|
||||||
} else {
|
} else {
|
||||||
val addressReg = codeGen.vmRegisters.nextFree()
|
val addressReg = codeGen.vmRegisters.nextFree()
|
||||||
code += exprGen.translateExpression(call.args[0], addressReg, -1)
|
code += exprGen.translateExpression(call.args[0], addressReg, -1)
|
||||||
code += exprGen.translateExpression(call.args[1], valueReg, -1)
|
code += exprGen.translateExpression(call.args[1], valueReg, -1)
|
||||||
code += IRCodeInstruction(Opcode.STOREI, VmDataType.BYTE, reg1 = valueReg, reg2 = addressReg)
|
code += IRInstruction(Opcode.STOREI, VmDataType.BYTE, reg1 = valueReg, reg2 = addressReg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return code
|
return code
|
||||||
@ -287,11 +287,11 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
|||||||
val code = IRCodeChunk(call.position)
|
val code = IRCodeChunk(call.position)
|
||||||
if(call.args[0] is PtNumber) {
|
if(call.args[0] is PtNumber) {
|
||||||
val address = (call.args[0] as PtNumber).number.toInt()
|
val address = (call.args[0] as PtNumber).number.toInt()
|
||||||
code += IRCodeInstruction(Opcode.LOADM, VmDataType.WORD, reg1 = resultRegister, value = address)
|
code += IRInstruction(Opcode.LOADM, VmDataType.WORD, reg1 = resultRegister, value = address)
|
||||||
} else {
|
} else {
|
||||||
val addressReg = codeGen.vmRegisters.nextFree()
|
val addressReg = codeGen.vmRegisters.nextFree()
|
||||||
code += exprGen.translateExpression(call.args.single(), addressReg, -1)
|
code += exprGen.translateExpression(call.args.single(), addressReg, -1)
|
||||||
code += IRCodeInstruction(Opcode.LOADI, VmDataType.WORD, reg1 = resultRegister, reg2 = addressReg)
|
code += IRInstruction(Opcode.LOADI, VmDataType.WORD, reg1 = resultRegister, reg2 = addressReg)
|
||||||
}
|
}
|
||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
@ -300,34 +300,31 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
|||||||
val code = IRCodeChunk(call.position)
|
val code = IRCodeChunk(call.position)
|
||||||
if(call.args[0] is PtNumber) {
|
if(call.args[0] is PtNumber) {
|
||||||
val address = (call.args[0] as PtNumber).number.toInt()
|
val address = (call.args[0] as PtNumber).number.toInt()
|
||||||
code += IRCodeInstruction(Opcode.LOADM, VmDataType.BYTE, reg1 = resultRegister, value = address)
|
code += IRInstruction(Opcode.LOADM, VmDataType.BYTE, reg1 = resultRegister, value = address)
|
||||||
} else {
|
} else {
|
||||||
val addressReg = codeGen.vmRegisters.nextFree()
|
val addressReg = codeGen.vmRegisters.nextFree()
|
||||||
code += exprGen.translateExpression(call.args.single(), addressReg, -1)
|
code += exprGen.translateExpression(call.args.single(), addressReg, -1)
|
||||||
code += IRCodeInstruction(Opcode.LOADI, VmDataType.BYTE, reg1 = resultRegister, reg2 = addressReg)
|
code += IRInstruction(Opcode.LOADI, VmDataType.BYTE, reg1 = resultRegister, reg2 = addressReg)
|
||||||
}
|
}
|
||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun funcRnd(resultRegister: Int, position: Position): IRCodeChunk {
|
private fun funcRnd(resultRegister: Int, position: Position): IRCodeChunk {
|
||||||
val code = IRCodeChunk(position)
|
val code = IRCodeChunk(position)
|
||||||
code += IRCodeInstruction(Opcode.RND, VmDataType.BYTE, reg1=resultRegister)
|
code += IRInstruction(Opcode.RND, VmDataType.BYTE, reg1=resultRegister)
|
||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun funcRndw(resultRegister: Int, position: Position): IRCodeChunk {
|
private fun funcRndw(resultRegister: Int, position: Position): IRCodeChunk {
|
||||||
val code = IRCodeChunk(position)
|
val code = IRCodeChunk(position)
|
||||||
code += IRCodeInstruction(Opcode.RND, VmDataType.WORD, reg1=resultRegister)
|
code += IRInstruction(Opcode.RND, VmDataType.WORD, reg1=resultRegister)
|
||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun funcMemory(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunk {
|
private fun funcMemory(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunk {
|
||||||
val name = (call.args[0] as PtString).value
|
val name = (call.args[0] as PtString).value
|
||||||
val size = (call.args[1] as PtNumber).number.toUInt()
|
|
||||||
val align = (call.args[2] as PtNumber).number.toUInt()
|
|
||||||
val label = codeGen.addMemorySlab(name, size, align, call.position)
|
|
||||||
val code = IRCodeChunk(call.position)
|
val code = IRCodeChunk(call.position)
|
||||||
code += IRCodeInstruction(Opcode.LOAD, VmDataType.WORD, reg1=resultRegister, labelSymbol = label)
|
code += IRInstruction(Opcode.LOAD, VmDataType.WORD, reg1=resultRegister, labelSymbol = "prog8_slabs.prog8_memoryslab_$name")
|
||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -341,7 +338,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
|||||||
private fun funcMsb(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunk {
|
private fun funcMsb(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunk {
|
||||||
val code = IRCodeChunk(call.position)
|
val code = IRCodeChunk(call.position)
|
||||||
code += exprGen.translateExpression(call.args.single(), resultRegister, -1)
|
code += exprGen.translateExpression(call.args.single(), resultRegister, -1)
|
||||||
code += IRCodeInstruction(Opcode.MSIG, VmDataType.BYTE, reg1 = resultRegister, reg2=resultRegister)
|
code += IRInstruction(Opcode.MSIG, VmDataType.BYTE, reg1 = resultRegister, reg2=resultRegister)
|
||||||
// note: if a word result is needed, the upper byte is cleared by the typecast that follows. No need to do it here.
|
// note: if a word result is needed, the upper byte is cleared by the typecast that follows. No need to do it here.
|
||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
@ -350,7 +347,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
|||||||
val vmDt = codeGen.vmType(call.args[0].type)
|
val vmDt = codeGen.vmType(call.args[0].type)
|
||||||
val code = IRCodeChunk(call.position)
|
val code = IRCodeChunk(call.position)
|
||||||
code += exprGen.translateExpression(call.args[0], resultRegister, -1)
|
code += exprGen.translateExpression(call.args[0], resultRegister, -1)
|
||||||
code += IRCodeInstruction(opcode, vmDt, reg1=resultRegister)
|
code += IRInstruction(opcode, vmDt, reg1=resultRegister)
|
||||||
code += assignRegisterTo(call.args[0], resultRegister)
|
code += assignRegisterTo(call.args[0], resultRegister)
|
||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
|
@ -18,43 +18,43 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
|||||||
is PtMachineRegister -> {
|
is PtMachineRegister -> {
|
||||||
if(resultRegister!=expr.register) {
|
if(resultRegister!=expr.register) {
|
||||||
val vmDt = codeGen.vmType(expr.type)
|
val vmDt = codeGen.vmType(expr.type)
|
||||||
code += IRCodeInstruction(Opcode.LOADR, vmDt, reg1=resultRegister, reg2=expr.register)
|
code += IRInstruction(Opcode.LOADR, vmDt, reg1=resultRegister, reg2=expr.register)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is PtNumber -> {
|
is PtNumber -> {
|
||||||
val vmDt = codeGen.vmType(expr.type)
|
val vmDt = codeGen.vmType(expr.type)
|
||||||
code += if(vmDt==VmDataType.FLOAT)
|
code += if(vmDt==VmDataType.FLOAT)
|
||||||
IRCodeInstruction(Opcode.LOAD, vmDt, fpReg1 = resultFpRegister, fpValue = expr.number.toFloat())
|
IRInstruction(Opcode.LOAD, vmDt, fpReg1 = resultFpRegister, fpValue = expr.number.toFloat())
|
||||||
else
|
else
|
||||||
IRCodeInstruction(Opcode.LOAD, vmDt, reg1=resultRegister, value=expr.number.toInt())
|
IRInstruction(Opcode.LOAD, vmDt, reg1=resultRegister, value=expr.number.toInt())
|
||||||
}
|
}
|
||||||
is PtIdentifier -> {
|
is PtIdentifier -> {
|
||||||
val vmDt = codeGen.vmType(expr.type)
|
val vmDt = codeGen.vmType(expr.type)
|
||||||
val symbol = expr.targetName.joinToString(".")
|
val symbol = expr.targetName.joinToString(".")
|
||||||
code += if (expr.type in PassByValueDatatypes) {
|
code += if (expr.type in PassByValueDatatypes) {
|
||||||
if(vmDt==VmDataType.FLOAT)
|
if(vmDt==VmDataType.FLOAT)
|
||||||
IRCodeInstruction(Opcode.LOADM, vmDt, fpReg1 = resultFpRegister, labelSymbol = symbol)
|
IRInstruction(Opcode.LOADM, vmDt, fpReg1 = resultFpRegister, labelSymbol = symbol)
|
||||||
else
|
else
|
||||||
IRCodeInstruction(Opcode.LOADM, vmDt, reg1 = resultRegister, labelSymbol = symbol)
|
IRInstruction(Opcode.LOADM, vmDt, reg1 = resultRegister, labelSymbol = symbol)
|
||||||
} else {
|
} else {
|
||||||
// for strings and arrays etc., load the *address* of the value instead
|
// for strings and arrays etc., load the *address* of the value instead
|
||||||
IRCodeInstruction(Opcode.LOAD, vmDt, reg1 = resultRegister, labelSymbol = symbol)
|
IRInstruction(Opcode.LOAD, vmDt, reg1 = resultRegister, labelSymbol = symbol)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is PtAddressOf -> {
|
is PtAddressOf -> {
|
||||||
val vmDt = codeGen.vmType(expr.type)
|
val vmDt = codeGen.vmType(expr.type)
|
||||||
val symbol = expr.identifier.targetName.joinToString(".")
|
val symbol = expr.identifier.targetName.joinToString(".")
|
||||||
// note: LOAD <symbol> gets you the address of the symbol, whereas LOADM <symbol> would get you the value stored at that location
|
// note: LOAD <symbol> gets you the address of the symbol, whereas LOADM <symbol> would get you the value stored at that location
|
||||||
code += IRCodeInstruction(Opcode.LOAD, vmDt, reg1=resultRegister, labelSymbol = symbol)
|
code += IRInstruction(Opcode.LOAD, vmDt, reg1=resultRegister, labelSymbol = symbol)
|
||||||
}
|
}
|
||||||
is PtMemoryByte -> {
|
is PtMemoryByte -> {
|
||||||
if(expr.address is PtNumber) {
|
if(expr.address is PtNumber) {
|
||||||
val address = (expr.address as PtNumber).number.toInt()
|
val address = (expr.address as PtNumber).number.toInt()
|
||||||
code += IRCodeInstruction(Opcode.LOADM, VmDataType.BYTE, reg1=resultRegister, value = address)
|
code += IRInstruction(Opcode.LOADM, VmDataType.BYTE, reg1=resultRegister, value = address)
|
||||||
} else {
|
} else {
|
||||||
val addressRegister = codeGen.vmRegisters.nextFree()
|
val addressRegister = codeGen.vmRegisters.nextFree()
|
||||||
code += translateExpression(expr.address, addressRegister, -1)
|
code += translateExpression(expr.address, addressRegister, -1)
|
||||||
code += IRCodeInstruction(Opcode.LOADI, VmDataType.BYTE, reg1=resultRegister, reg2=addressRegister)
|
code += IRInstruction(Opcode.LOADI, VmDataType.BYTE, reg1=resultRegister, reg2=addressRegister)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is PtTypeCast -> code += translate(expr, resultRegister, resultFpRegister)
|
is PtTypeCast -> code += translate(expr, resultRegister, resultFpRegister)
|
||||||
@ -117,24 +117,24 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
|||||||
if(arrayIx.index.type!=DataType.UBYTE)
|
if(arrayIx.index.type!=DataType.UBYTE)
|
||||||
throw AssemblyError("non-array var indexing requires bytes index")
|
throw AssemblyError("non-array var indexing requires bytes index")
|
||||||
code += translateExpression(arrayIx.index, idxReg, -1)
|
code += translateExpression(arrayIx.index, idxReg, -1)
|
||||||
code += IRCodeInstruction(Opcode.LOADIX, vmDt, reg1=resultRegister, reg2=idxReg, labelSymbol = arrayVarSymbol)
|
code += IRInstruction(Opcode.LOADIX, vmDt, reg1=resultRegister, reg2=idxReg, labelSymbol = arrayVarSymbol)
|
||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
|
|
||||||
if(arrayIx.index is PtNumber) {
|
if(arrayIx.index is PtNumber) {
|
||||||
val memOffset = ((arrayIx.index as PtNumber).number.toInt() * eltSize).toString()
|
val memOffset = ((arrayIx.index as PtNumber).number.toInt() * eltSize).toString()
|
||||||
if(vmDt==VmDataType.FLOAT)
|
if(vmDt==VmDataType.FLOAT)
|
||||||
code += IRCodeInstruction(Opcode.LOADM, VmDataType.FLOAT, fpReg1=resultFpRegister, labelSymbol = "$arrayVarSymbol+$memOffset")
|
code += IRInstruction(Opcode.LOADM, VmDataType.FLOAT, fpReg1=resultFpRegister, labelSymbol = "$arrayVarSymbol+$memOffset")
|
||||||
else
|
else
|
||||||
code += IRCodeInstruction(Opcode.LOADM, vmDt, reg1=resultRegister, labelSymbol = "$arrayVarSymbol+$memOffset")
|
code += IRInstruction(Opcode.LOADM, vmDt, reg1=resultRegister, labelSymbol = "$arrayVarSymbol+$memOffset")
|
||||||
} else {
|
} else {
|
||||||
code += translateExpression(arrayIx.index, idxReg, -1)
|
code += translateExpression(arrayIx.index, idxReg, -1)
|
||||||
if(eltSize>1)
|
if(eltSize>1)
|
||||||
code += codeGen.multiplyByConst(VmDataType.BYTE, idxReg, eltSize, arrayIx.position)
|
code += codeGen.multiplyByConst(VmDataType.BYTE, idxReg, eltSize, arrayIx.position)
|
||||||
if(vmDt==VmDataType.FLOAT)
|
if(vmDt==VmDataType.FLOAT)
|
||||||
code += IRCodeInstruction(Opcode.LOADX, VmDataType.FLOAT, fpReg1 = resultFpRegister, reg1=idxReg, labelSymbol = arrayVarSymbol)
|
code += IRInstruction(Opcode.LOADX, VmDataType.FLOAT, fpReg1 = resultFpRegister, reg1=idxReg, labelSymbol = arrayVarSymbol)
|
||||||
else
|
else
|
||||||
code += IRCodeInstruction(Opcode.LOADX, vmDt, reg1=resultRegister, reg2=idxReg, labelSymbol = arrayVarSymbol)
|
code += IRInstruction(Opcode.LOADX, vmDt, reg1=resultRegister, reg2=idxReg, labelSymbol = arrayVarSymbol)
|
||||||
}
|
}
|
||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
@ -146,11 +146,11 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
|||||||
when(expr.operator) {
|
when(expr.operator) {
|
||||||
"+" -> { }
|
"+" -> { }
|
||||||
"-" -> {
|
"-" -> {
|
||||||
code += IRCodeInstruction(Opcode.NEG, vmDt, reg1=resultRegister)
|
code += IRInstruction(Opcode.NEG, vmDt, reg1=resultRegister)
|
||||||
}
|
}
|
||||||
"~" -> {
|
"~" -> {
|
||||||
val mask = if(vmDt==VmDataType.BYTE) 0x00ff else 0xffff
|
val mask = if(vmDt==VmDataType.BYTE) 0x00ff else 0xffff
|
||||||
code += IRCodeInstruction(Opcode.XOR, vmDt, reg1=resultRegister, value=mask)
|
code += IRInstruction(Opcode.XOR, vmDt, reg1=resultRegister, value=mask)
|
||||||
}
|
}
|
||||||
else -> throw AssemblyError("weird prefix operator")
|
else -> throw AssemblyError("weird prefix operator")
|
||||||
}
|
}
|
||||||
@ -173,14 +173,14 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
|||||||
DataType.UBYTE -> {
|
DataType.UBYTE -> {
|
||||||
when(cast.value.type) {
|
when(cast.value.type) {
|
||||||
DataType.BYTE, DataType.UWORD, DataType.WORD -> { /* just keep the LSB as it is */ }
|
DataType.BYTE, DataType.UWORD, DataType.WORD -> { /* just keep the LSB as it is */ }
|
||||||
DataType.FLOAT -> code += IRCodeInstruction(Opcode.FTOUB, VmDataType.FLOAT, reg1=actualResultReg, fpReg1 = actualResultFpReg)
|
DataType.FLOAT -> code += IRInstruction(Opcode.FTOUB, VmDataType.FLOAT, reg1=actualResultReg, fpReg1 = actualResultFpReg)
|
||||||
else -> throw AssemblyError("weird cast value type")
|
else -> throw AssemblyError("weird cast value type")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DataType.BYTE -> {
|
DataType.BYTE -> {
|
||||||
when(cast.value.type) {
|
when(cast.value.type) {
|
||||||
DataType.UBYTE, DataType.UWORD, DataType.WORD -> { /* just keep the LSB as it is */ }
|
DataType.UBYTE, DataType.UWORD, DataType.WORD -> { /* just keep the LSB as it is */ }
|
||||||
DataType.FLOAT -> code += IRCodeInstruction(Opcode.FTOSB, VmDataType.FLOAT, reg1=actualResultReg, fpReg1 = actualResultFpReg)
|
DataType.FLOAT -> code += IRInstruction(Opcode.FTOSB, VmDataType.FLOAT, reg1=actualResultReg, fpReg1 = actualResultFpReg)
|
||||||
else -> throw AssemblyError("weird cast value type")
|
else -> throw AssemblyError("weird cast value type")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -188,15 +188,15 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
|||||||
when(cast.value.type) {
|
when(cast.value.type) {
|
||||||
DataType.BYTE -> {
|
DataType.BYTE -> {
|
||||||
// byte -> uword: sign extend
|
// byte -> uword: sign extend
|
||||||
code += IRCodeInstruction(Opcode.EXTS, type = VmDataType.BYTE, reg1 = actualResultReg)
|
code += IRInstruction(Opcode.EXTS, type = VmDataType.BYTE, reg1 = actualResultReg)
|
||||||
}
|
}
|
||||||
DataType.UBYTE -> {
|
DataType.UBYTE -> {
|
||||||
// ubyte -> uword: sign extend
|
// ubyte -> uword: sign extend
|
||||||
code += IRCodeInstruction(Opcode.EXT, type = VmDataType.BYTE, reg1 = actualResultReg)
|
code += IRInstruction(Opcode.EXT, type = VmDataType.BYTE, reg1 = actualResultReg)
|
||||||
}
|
}
|
||||||
DataType.WORD -> { }
|
DataType.WORD -> { }
|
||||||
DataType.FLOAT -> {
|
DataType.FLOAT -> {
|
||||||
code += IRCodeInstruction(Opcode.FTOUW, VmDataType.FLOAT, reg1=actualResultReg, fpReg1 = actualResultFpReg)
|
code += IRInstruction(Opcode.FTOUW, VmDataType.FLOAT, reg1=actualResultReg, fpReg1 = actualResultFpReg)
|
||||||
}
|
}
|
||||||
else -> throw AssemblyError("weird cast value type")
|
else -> throw AssemblyError("weird cast value type")
|
||||||
}
|
}
|
||||||
@ -205,15 +205,15 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
|||||||
when(cast.value.type) {
|
when(cast.value.type) {
|
||||||
DataType.BYTE -> {
|
DataType.BYTE -> {
|
||||||
// byte -> word: sign extend
|
// byte -> word: sign extend
|
||||||
code += IRCodeInstruction(Opcode.EXTS, type = VmDataType.BYTE, reg1 = actualResultReg)
|
code += IRInstruction(Opcode.EXTS, type = VmDataType.BYTE, reg1 = actualResultReg)
|
||||||
}
|
}
|
||||||
DataType.UBYTE -> {
|
DataType.UBYTE -> {
|
||||||
// byte -> word: sign extend
|
// byte -> word: sign extend
|
||||||
code += IRCodeInstruction(Opcode.EXT, type = VmDataType.BYTE, reg1 = actualResultReg)
|
code += IRInstruction(Opcode.EXT, type = VmDataType.BYTE, reg1 = actualResultReg)
|
||||||
}
|
}
|
||||||
DataType.UWORD -> { }
|
DataType.UWORD -> { }
|
||||||
DataType.FLOAT -> {
|
DataType.FLOAT -> {
|
||||||
code += IRCodeInstruction(Opcode.FTOSW, VmDataType.FLOAT, reg1=actualResultReg, fpReg1 = actualResultFpReg)
|
code += IRInstruction(Opcode.FTOSW, VmDataType.FLOAT, reg1=actualResultReg, fpReg1 = actualResultFpReg)
|
||||||
}
|
}
|
||||||
else -> throw AssemblyError("weird cast value type")
|
else -> throw AssemblyError("weird cast value type")
|
||||||
}
|
}
|
||||||
@ -221,16 +221,16 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
|||||||
DataType.FLOAT -> {
|
DataType.FLOAT -> {
|
||||||
code += when(cast.value.type) {
|
code += when(cast.value.type) {
|
||||||
DataType.UBYTE -> {
|
DataType.UBYTE -> {
|
||||||
IRCodeInstruction(Opcode.FFROMUB, VmDataType.FLOAT, reg1=actualResultReg, fpReg1 = actualResultFpReg)
|
IRInstruction(Opcode.FFROMUB, VmDataType.FLOAT, reg1=actualResultReg, fpReg1 = actualResultFpReg)
|
||||||
}
|
}
|
||||||
DataType.BYTE -> {
|
DataType.BYTE -> {
|
||||||
IRCodeInstruction(Opcode.FFROMSB, VmDataType.FLOAT, reg1=actualResultReg, fpReg1 = actualResultFpReg)
|
IRInstruction(Opcode.FFROMSB, VmDataType.FLOAT, reg1=actualResultReg, fpReg1 = actualResultFpReg)
|
||||||
}
|
}
|
||||||
DataType.UWORD -> {
|
DataType.UWORD -> {
|
||||||
IRCodeInstruction(Opcode.FFROMUW, VmDataType.FLOAT, reg1=actualResultReg, fpReg1 = actualResultFpReg)
|
IRInstruction(Opcode.FFROMUW, VmDataType.FLOAT, reg1=actualResultReg, fpReg1 = actualResultFpReg)
|
||||||
}
|
}
|
||||||
DataType.WORD -> {
|
DataType.WORD -> {
|
||||||
IRCodeInstruction(Opcode.FFROMSW, VmDataType.FLOAT, reg1=actualResultReg, fpReg1 = actualResultFpReg)
|
IRInstruction(Opcode.FFROMSW, VmDataType.FLOAT, reg1=actualResultReg, fpReg1 = actualResultFpReg)
|
||||||
}
|
}
|
||||||
else -> throw AssemblyError("weird cast value type")
|
else -> throw AssemblyError("weird cast value type")
|
||||||
}
|
}
|
||||||
@ -278,14 +278,14 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
|||||||
val zeroRegister = codeGen.vmRegisters.nextFree()
|
val zeroRegister = codeGen.vmRegisters.nextFree()
|
||||||
code += translateExpression(binExpr.left, -1, leftFpReg)
|
code += translateExpression(binExpr.left, -1, leftFpReg)
|
||||||
code += translateExpression(binExpr.right, -1, rightFpReg)
|
code += translateExpression(binExpr.right, -1, rightFpReg)
|
||||||
code += IRCodeInstruction(Opcode.FCOMP, VmDataType.FLOAT, reg1=resultRegister, fpReg1 = leftFpReg, fpReg2 = rightFpReg)
|
code += IRInstruction(Opcode.FCOMP, VmDataType.FLOAT, reg1=resultRegister, fpReg1 = leftFpReg, fpReg2 = rightFpReg)
|
||||||
code += IRCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=zeroRegister, value=0)
|
code += IRInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=zeroRegister, value=0)
|
||||||
val ins = if (signed) {
|
val ins = if (signed) {
|
||||||
if (greaterEquals) Opcode.SGES else Opcode.SGTS
|
if (greaterEquals) Opcode.SGES else Opcode.SGTS
|
||||||
} else {
|
} else {
|
||||||
if (greaterEquals) Opcode.SGE else Opcode.SGT
|
if (greaterEquals) Opcode.SGE else Opcode.SGT
|
||||||
}
|
}
|
||||||
code += IRCodeInstruction(ins, VmDataType.BYTE, reg1 = resultRegister, reg2 = zeroRegister)
|
code += IRInstruction(ins, VmDataType.BYTE, reg1 = resultRegister, reg2 = zeroRegister)
|
||||||
} else {
|
} else {
|
||||||
if(binExpr.left.type==DataType.STR && binExpr.right.type==DataType.STR) {
|
if(binExpr.left.type==DataType.STR && binExpr.right.type==DataType.STR) {
|
||||||
val comparisonCall = PtFunctionCall(listOf("prog8_lib", "string_compare"), false, DataType.BYTE, Position.DUMMY)
|
val comparisonCall = PtFunctionCall(listOf("prog8_lib", "string_compare"), false, DataType.BYTE, Position.DUMMY)
|
||||||
@ -293,11 +293,11 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
|||||||
comparisonCall.children.add(binExpr.right)
|
comparisonCall.children.add(binExpr.right)
|
||||||
code += translate(comparisonCall, resultRegister, -1)
|
code += translate(comparisonCall, resultRegister, -1)
|
||||||
val zeroRegister = codeGen.vmRegisters.nextFree()
|
val zeroRegister = codeGen.vmRegisters.nextFree()
|
||||||
code += IRCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=zeroRegister, value=0)
|
code += IRInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=zeroRegister, value=0)
|
||||||
code += if(greaterEquals)
|
code += if(greaterEquals)
|
||||||
IRCodeInstruction(Opcode.SGES, VmDataType.BYTE, reg1=resultRegister, reg2=zeroRegister)
|
IRInstruction(Opcode.SGES, VmDataType.BYTE, reg1=resultRegister, reg2=zeroRegister)
|
||||||
else
|
else
|
||||||
IRCodeInstruction(Opcode.SGTS, VmDataType.BYTE, reg1=resultRegister, reg2=zeroRegister)
|
IRInstruction(Opcode.SGTS, VmDataType.BYTE, reg1=resultRegister, reg2=zeroRegister)
|
||||||
} else {
|
} else {
|
||||||
val rightResultReg = codeGen.vmRegisters.nextFree()
|
val rightResultReg = codeGen.vmRegisters.nextFree()
|
||||||
code += translateExpression(binExpr.left, resultRegister, -1)
|
code += translateExpression(binExpr.left, resultRegister, -1)
|
||||||
@ -307,7 +307,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
|||||||
} else {
|
} else {
|
||||||
if (greaterEquals) Opcode.SGE else Opcode.SGT
|
if (greaterEquals) Opcode.SGE else Opcode.SGT
|
||||||
}
|
}
|
||||||
code += IRCodeInstruction(ins, vmDt, reg1 = resultRegister, reg2 = rightResultReg)
|
code += IRInstruction(ins, vmDt, reg1 = resultRegister, reg2 = rightResultReg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return code
|
return code
|
||||||
@ -327,14 +327,14 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
|||||||
val zeroRegister = codeGen.vmRegisters.nextFree()
|
val zeroRegister = codeGen.vmRegisters.nextFree()
|
||||||
code += translateExpression(binExpr.left, -1, leftFpReg)
|
code += translateExpression(binExpr.left, -1, leftFpReg)
|
||||||
code += translateExpression(binExpr.right, -1, rightFpReg)
|
code += translateExpression(binExpr.right, -1, rightFpReg)
|
||||||
code += IRCodeInstruction(Opcode.FCOMP, VmDataType.FLOAT, reg1=resultRegister, fpReg1 = leftFpReg, fpReg2 = rightFpReg)
|
code += IRInstruction(Opcode.FCOMP, VmDataType.FLOAT, reg1=resultRegister, fpReg1 = leftFpReg, fpReg2 = rightFpReg)
|
||||||
code += IRCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=zeroRegister, value=0)
|
code += IRInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=zeroRegister, value=0)
|
||||||
val ins = if (signed) {
|
val ins = if (signed) {
|
||||||
if (lessEquals) Opcode.SLES else Opcode.SLTS
|
if (lessEquals) Opcode.SLES else Opcode.SLTS
|
||||||
} else {
|
} else {
|
||||||
if (lessEquals) Opcode.SLE else Opcode.SLT
|
if (lessEquals) Opcode.SLE else Opcode.SLT
|
||||||
}
|
}
|
||||||
code += IRCodeInstruction(ins, VmDataType.BYTE, reg1 = resultRegister, reg2 = zeroRegister)
|
code += IRInstruction(ins, VmDataType.BYTE, reg1 = resultRegister, reg2 = zeroRegister)
|
||||||
} else {
|
} else {
|
||||||
if(binExpr.left.type==DataType.STR && binExpr.right.type==DataType.STR) {
|
if(binExpr.left.type==DataType.STR && binExpr.right.type==DataType.STR) {
|
||||||
val comparisonCall = PtFunctionCall(listOf("prog8_lib", "string_compare"), false, DataType.BYTE, Position.DUMMY)
|
val comparisonCall = PtFunctionCall(listOf("prog8_lib", "string_compare"), false, DataType.BYTE, Position.DUMMY)
|
||||||
@ -342,11 +342,11 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
|||||||
comparisonCall.children.add(binExpr.right)
|
comparisonCall.children.add(binExpr.right)
|
||||||
code += translate(comparisonCall, resultRegister, -1)
|
code += translate(comparisonCall, resultRegister, -1)
|
||||||
val zeroRegister = codeGen.vmRegisters.nextFree()
|
val zeroRegister = codeGen.vmRegisters.nextFree()
|
||||||
code += IRCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=zeroRegister, value=0)
|
code += IRInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=zeroRegister, value=0)
|
||||||
code += if(lessEquals)
|
code += if(lessEquals)
|
||||||
IRCodeInstruction(Opcode.SLES, VmDataType.BYTE, reg1=resultRegister, reg2=zeroRegister)
|
IRInstruction(Opcode.SLES, VmDataType.BYTE, reg1=resultRegister, reg2=zeroRegister)
|
||||||
else
|
else
|
||||||
IRCodeInstruction(Opcode.SLTS, VmDataType.BYTE, reg1=resultRegister, reg2=zeroRegister)
|
IRInstruction(Opcode.SLTS, VmDataType.BYTE, reg1=resultRegister, reg2=zeroRegister)
|
||||||
} else {
|
} else {
|
||||||
val rightResultReg = codeGen.vmRegisters.nextFree()
|
val rightResultReg = codeGen.vmRegisters.nextFree()
|
||||||
code += translateExpression(binExpr.left, resultRegister, -1)
|
code += translateExpression(binExpr.left, resultRegister, -1)
|
||||||
@ -356,7 +356,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
|||||||
} else {
|
} else {
|
||||||
if (lessEquals) Opcode.SLE else Opcode.SLT
|
if (lessEquals) Opcode.SLE else Opcode.SLT
|
||||||
}
|
}
|
||||||
code += IRCodeInstruction(ins, vmDt, reg1 = resultRegister, reg2 = rightResultReg)
|
code += IRInstruction(ins, vmDt, reg1 = resultRegister, reg2 = rightResultReg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return code
|
return code
|
||||||
@ -370,14 +370,14 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
|||||||
code += translateExpression(binExpr.left, -1, leftFpReg)
|
code += translateExpression(binExpr.left, -1, leftFpReg)
|
||||||
code += translateExpression(binExpr.right, -1, rightFpReg)
|
code += translateExpression(binExpr.right, -1, rightFpReg)
|
||||||
if (notEquals) {
|
if (notEquals) {
|
||||||
code += IRCodeInstruction(Opcode.FCOMP, VmDataType.FLOAT, reg1=resultRegister, fpReg1 = leftFpReg, fpReg2 = rightFpReg)
|
code += IRInstruction(Opcode.FCOMP, VmDataType.FLOAT, reg1=resultRegister, fpReg1 = leftFpReg, fpReg2 = rightFpReg)
|
||||||
} else {
|
} else {
|
||||||
val label = codeGen.createLabelName()
|
val label = codeGen.createLabelName()
|
||||||
val valueReg = codeGen.vmRegisters.nextFree()
|
val valueReg = codeGen.vmRegisters.nextFree()
|
||||||
code += IRCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=resultRegister, value=1)
|
code += IRInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=resultRegister, value=1)
|
||||||
code += IRCodeInstruction(Opcode.FCOMP, VmDataType.FLOAT, reg1=valueReg, fpReg1 = leftFpReg, fpReg2 = rightFpReg)
|
code += IRInstruction(Opcode.FCOMP, VmDataType.FLOAT, reg1=valueReg, fpReg1 = leftFpReg, fpReg2 = rightFpReg)
|
||||||
code += IRCodeInstruction(Opcode.BZ, VmDataType.BYTE, reg1=valueReg, labelSymbol = label)
|
code += IRInstruction(Opcode.BZ, VmDataType.BYTE, reg1=valueReg, labelSymbol = label)
|
||||||
code += IRCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=resultRegister, value=0)
|
code += IRInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=resultRegister, value=0)
|
||||||
code += IRCodeLabel(label)
|
code += IRCodeLabel(label)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -387,14 +387,14 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
|||||||
comparisonCall.children.add(binExpr.right)
|
comparisonCall.children.add(binExpr.right)
|
||||||
code += translate(comparisonCall, resultRegister, -1)
|
code += translate(comparisonCall, resultRegister, -1)
|
||||||
if(!notEquals)
|
if(!notEquals)
|
||||||
code += IRCodeInstruction(Opcode.INV, vmDt, reg1=resultRegister)
|
code += IRInstruction(Opcode.INV, vmDt, reg1=resultRegister)
|
||||||
code += IRCodeInstruction(Opcode.AND, vmDt, reg1=resultRegister, value=1)
|
code += IRInstruction(Opcode.AND, vmDt, reg1=resultRegister, value=1)
|
||||||
} else {
|
} else {
|
||||||
val rightResultReg = codeGen.vmRegisters.nextFree()
|
val rightResultReg = codeGen.vmRegisters.nextFree()
|
||||||
code += translateExpression(binExpr.left, resultRegister, -1)
|
code += translateExpression(binExpr.left, resultRegister, -1)
|
||||||
code += translateExpression(binExpr.right, rightResultReg, -1)
|
code += translateExpression(binExpr.right, rightResultReg, -1)
|
||||||
val opcode = if (notEquals) Opcode.SNE else Opcode.SEQ
|
val opcode = if (notEquals) Opcode.SNE else Opcode.SEQ
|
||||||
code += IRCodeInstruction(opcode, vmDt, reg1 = resultRegister, reg2 = rightResultReg)
|
code += IRInstruction(opcode, vmDt, reg1 = resultRegister, reg2 = rightResultReg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return code
|
return code
|
||||||
@ -405,13 +405,13 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
|||||||
if(codeGen.isOne(binExpr.right)) {
|
if(codeGen.isOne(binExpr.right)) {
|
||||||
code += translateExpression(binExpr.left, resultRegister, -1)
|
code += translateExpression(binExpr.left, resultRegister, -1)
|
||||||
val opc = if (signed) Opcode.ASR else Opcode.LSR
|
val opc = if (signed) Opcode.ASR else Opcode.LSR
|
||||||
code += IRCodeInstruction(opc, vmDt, reg1 = resultRegister)
|
code += IRInstruction(opc, vmDt, reg1 = resultRegister)
|
||||||
} else {
|
} else {
|
||||||
val rightResultReg = codeGen.vmRegisters.nextFree()
|
val rightResultReg = codeGen.vmRegisters.nextFree()
|
||||||
code += translateExpression(binExpr.left, resultRegister, -1)
|
code += translateExpression(binExpr.left, resultRegister, -1)
|
||||||
code += translateExpression(binExpr.right, rightResultReg, -1)
|
code += translateExpression(binExpr.right, rightResultReg, -1)
|
||||||
val opc = if (signed) Opcode.ASRN else Opcode.LSRN
|
val opc = if (signed) Opcode.ASRN else Opcode.LSRN
|
||||||
code += IRCodeInstruction(opc, vmDt, reg1 = resultRegister, reg2 = rightResultReg)
|
code += IRInstruction(opc, vmDt, reg1 = resultRegister, reg2 = rightResultReg)
|
||||||
}
|
}
|
||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
@ -421,17 +421,17 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
|||||||
if(codeGen.isOne(operand)) {
|
if(codeGen.isOne(operand)) {
|
||||||
val opc = if (signed) Opcode.ASRM else Opcode.LSRM
|
val opc = if (signed) Opcode.ASRM else Opcode.LSRM
|
||||||
code += if(knownAddress!=null)
|
code += if(knownAddress!=null)
|
||||||
IRCodeInstruction(opc, vmDt, value=knownAddress)
|
IRInstruction(opc, vmDt, value=knownAddress)
|
||||||
else
|
else
|
||||||
IRCodeInstruction(opc, vmDt, labelSymbol = symbol)
|
IRInstruction(opc, vmDt, labelSymbol = symbol)
|
||||||
} else {
|
} else {
|
||||||
val operandReg = codeGen.vmRegisters.nextFree()
|
val operandReg = codeGen.vmRegisters.nextFree()
|
||||||
code += translateExpression(operand, operandReg, -1)
|
code += translateExpression(operand, operandReg, -1)
|
||||||
val opc = if (signed) Opcode.ASRNM else Opcode.LSRNM
|
val opc = if (signed) Opcode.ASRNM else Opcode.LSRNM
|
||||||
code += if(knownAddress!=null)
|
code += if(knownAddress!=null)
|
||||||
IRCodeInstruction(opc, vmDt, reg1 = operandReg, value=knownAddress)
|
IRInstruction(opc, vmDt, reg1 = operandReg, value=knownAddress)
|
||||||
else
|
else
|
||||||
IRCodeInstruction(opc, vmDt, reg1 = operandReg, labelSymbol = symbol)
|
IRInstruction(opc, vmDt, reg1 = operandReg, labelSymbol = symbol)
|
||||||
}
|
}
|
||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
@ -440,12 +440,12 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
|||||||
val code = IRCodeChunk(binExpr.position)
|
val code = IRCodeChunk(binExpr.position)
|
||||||
if(codeGen.isOne(binExpr.right)){
|
if(codeGen.isOne(binExpr.right)){
|
||||||
code += translateExpression(binExpr.left, resultRegister, -1)
|
code += translateExpression(binExpr.left, resultRegister, -1)
|
||||||
code += IRCodeInstruction(Opcode.LSL, vmDt, reg1=resultRegister)
|
code += IRInstruction(Opcode.LSL, vmDt, reg1=resultRegister)
|
||||||
} else {
|
} else {
|
||||||
val rightResultReg = codeGen.vmRegisters.nextFree()
|
val rightResultReg = codeGen.vmRegisters.nextFree()
|
||||||
code += translateExpression(binExpr.left, resultRegister, -1)
|
code += translateExpression(binExpr.left, resultRegister, -1)
|
||||||
code += translateExpression(binExpr.right, rightResultReg, -1)
|
code += translateExpression(binExpr.right, rightResultReg, -1)
|
||||||
code += IRCodeInstruction(Opcode.LSLN, vmDt, reg1=resultRegister, rightResultReg)
|
code += IRInstruction(Opcode.LSLN, vmDt, reg1=resultRegister, rightResultReg)
|
||||||
}
|
}
|
||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
@ -454,16 +454,16 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
|||||||
val code = IRCodeChunk(operand.position)
|
val code = IRCodeChunk(operand.position)
|
||||||
if(codeGen.isOne(operand)){
|
if(codeGen.isOne(operand)){
|
||||||
code += if(knownAddress!=null)
|
code += if(knownAddress!=null)
|
||||||
IRCodeInstruction(Opcode.LSLM, vmDt, value=knownAddress)
|
IRInstruction(Opcode.LSLM, vmDt, value=knownAddress)
|
||||||
else
|
else
|
||||||
IRCodeInstruction(Opcode.LSLM, vmDt, labelSymbol = symbol)
|
IRInstruction(Opcode.LSLM, vmDt, labelSymbol = symbol)
|
||||||
} else {
|
} else {
|
||||||
val operandReg = codeGen.vmRegisters.nextFree()
|
val operandReg = codeGen.vmRegisters.nextFree()
|
||||||
code += translateExpression(operand, operandReg, -1)
|
code += translateExpression(operand, operandReg, -1)
|
||||||
code += if(knownAddress!=null)
|
code += if(knownAddress!=null)
|
||||||
IRCodeInstruction(Opcode.LSLNM, vmDt, reg1=operandReg, value=knownAddress)
|
IRInstruction(Opcode.LSLNM, vmDt, reg1=operandReg, value=knownAddress)
|
||||||
else
|
else
|
||||||
IRCodeInstruction(Opcode.LSLNM, vmDt, reg1=operandReg, labelSymbol = symbol)
|
IRInstruction(Opcode.LSLNM, vmDt, reg1=operandReg, labelSymbol = symbol)
|
||||||
}
|
}
|
||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
@ -472,12 +472,12 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
|||||||
val code = IRCodeChunk(binExpr.position)
|
val code = IRCodeChunk(binExpr.position)
|
||||||
if(binExpr.right is PtNumber) {
|
if(binExpr.right is PtNumber) {
|
||||||
code += translateExpression(binExpr.left, resultRegister, -1)
|
code += translateExpression(binExpr.left, resultRegister, -1)
|
||||||
code += IRCodeInstruction(Opcode.XOR, vmDt, reg1 = resultRegister, value=(binExpr.right as PtNumber).number.toInt())
|
code += IRInstruction(Opcode.XOR, vmDt, reg1 = resultRegister, value=(binExpr.right as PtNumber).number.toInt())
|
||||||
} else {
|
} else {
|
||||||
val rightResultReg = codeGen.vmRegisters.nextFree()
|
val rightResultReg = codeGen.vmRegisters.nextFree()
|
||||||
code += translateExpression(binExpr.left, resultRegister, -1)
|
code += translateExpression(binExpr.left, resultRegister, -1)
|
||||||
code += translateExpression(binExpr.right, rightResultReg, -1)
|
code += translateExpression(binExpr.right, rightResultReg, -1)
|
||||||
code += IRCodeInstruction(Opcode.XORR, vmDt, reg1 = resultRegister, reg2 = rightResultReg)
|
code += IRInstruction(Opcode.XORR, vmDt, reg1 = resultRegister, reg2 = rightResultReg)
|
||||||
}
|
}
|
||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
@ -487,9 +487,9 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
|||||||
val operandReg = codeGen.vmRegisters.nextFree()
|
val operandReg = codeGen.vmRegisters.nextFree()
|
||||||
code += translateExpression(operand, operandReg, -1)
|
code += translateExpression(operand, operandReg, -1)
|
||||||
code += if(knownAddress!=null)
|
code += if(knownAddress!=null)
|
||||||
IRCodeInstruction(Opcode.XORM, vmDt, reg1=operandReg, value = knownAddress)
|
IRInstruction(Opcode.XORM, vmDt, reg1=operandReg, value = knownAddress)
|
||||||
else
|
else
|
||||||
IRCodeInstruction(Opcode.XORM, vmDt, reg1=operandReg, labelSymbol = symbol)
|
IRInstruction(Opcode.XORM, vmDt, reg1=operandReg, labelSymbol = symbol)
|
||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -497,12 +497,12 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
|||||||
val code = IRCodeChunk(binExpr.position)
|
val code = IRCodeChunk(binExpr.position)
|
||||||
if(binExpr.right is PtNumber) {
|
if(binExpr.right is PtNumber) {
|
||||||
code += translateExpression(binExpr.left, resultRegister, -1)
|
code += translateExpression(binExpr.left, resultRegister, -1)
|
||||||
code += IRCodeInstruction(Opcode.AND, vmDt, reg1 = resultRegister, value=(binExpr.right as PtNumber).number.toInt())
|
code += IRInstruction(Opcode.AND, vmDt, reg1 = resultRegister, value=(binExpr.right as PtNumber).number.toInt())
|
||||||
} else {
|
} else {
|
||||||
val rightResultReg = codeGen.vmRegisters.nextFree()
|
val rightResultReg = codeGen.vmRegisters.nextFree()
|
||||||
code += translateExpression(binExpr.left, resultRegister, -1)
|
code += translateExpression(binExpr.left, resultRegister, -1)
|
||||||
code += translateExpression(binExpr.right, rightResultReg, -1)
|
code += translateExpression(binExpr.right, rightResultReg, -1)
|
||||||
code += IRCodeInstruction(Opcode.ANDR, vmDt, reg1 = resultRegister, reg2 = rightResultReg)
|
code += IRInstruction(Opcode.ANDR, vmDt, reg1 = resultRegister, reg2 = rightResultReg)
|
||||||
}
|
}
|
||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
@ -512,9 +512,9 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
|||||||
val operandReg = codeGen.vmRegisters.nextFree()
|
val operandReg = codeGen.vmRegisters.nextFree()
|
||||||
code += translateExpression(operand, operandReg, -1)
|
code += translateExpression(operand, operandReg, -1)
|
||||||
code += if(knownAddress!=null)
|
code += if(knownAddress!=null)
|
||||||
IRCodeInstruction(Opcode.ANDM, vmDt, reg1=operandReg, value=knownAddress)
|
IRInstruction(Opcode.ANDM, vmDt, reg1=operandReg, value=knownAddress)
|
||||||
else
|
else
|
||||||
IRCodeInstruction(Opcode.ANDM, vmDt, reg1=operandReg, labelSymbol = symbol)
|
IRInstruction(Opcode.ANDM, vmDt, reg1=operandReg, labelSymbol = symbol)
|
||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -522,12 +522,12 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
|||||||
val code = IRCodeChunk(binExpr.position)
|
val code = IRCodeChunk(binExpr.position)
|
||||||
if(binExpr.right is PtNumber) {
|
if(binExpr.right is PtNumber) {
|
||||||
code += translateExpression(binExpr.left, resultRegister, -1)
|
code += translateExpression(binExpr.left, resultRegister, -1)
|
||||||
code += IRCodeInstruction(Opcode.OR, vmDt, reg1 = resultRegister, value=(binExpr.right as PtNumber).number.toInt())
|
code += IRInstruction(Opcode.OR, vmDt, reg1 = resultRegister, value=(binExpr.right as PtNumber).number.toInt())
|
||||||
} else {
|
} else {
|
||||||
val rightResultReg = codeGen.vmRegisters.nextFree()
|
val rightResultReg = codeGen.vmRegisters.nextFree()
|
||||||
code += translateExpression(binExpr.left, resultRegister, -1)
|
code += translateExpression(binExpr.left, resultRegister, -1)
|
||||||
code += translateExpression(binExpr.right, rightResultReg, -1)
|
code += translateExpression(binExpr.right, rightResultReg, -1)
|
||||||
code += IRCodeInstruction(Opcode.ORR, vmDt, reg1 = resultRegister, reg2 = rightResultReg)
|
code += IRInstruction(Opcode.ORR, vmDt, reg1 = resultRegister, reg2 = rightResultReg)
|
||||||
}
|
}
|
||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
@ -537,24 +537,23 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
|||||||
val operandReg = codeGen.vmRegisters.nextFree()
|
val operandReg = codeGen.vmRegisters.nextFree()
|
||||||
code += translateExpression(operand, operandReg, -1)
|
code += translateExpression(operand, operandReg, -1)
|
||||||
code += if(knownAddress!=null)
|
code += if(knownAddress!=null)
|
||||||
IRCodeInstruction(Opcode.ORM, vmDt, reg1=operandReg, value = knownAddress)
|
IRInstruction(Opcode.ORM, vmDt, reg1=operandReg, value = knownAddress)
|
||||||
else
|
else
|
||||||
IRCodeInstruction(Opcode.ORM, vmDt, reg1=operandReg, labelSymbol = symbol)
|
IRInstruction(Opcode.ORM, vmDt, reg1=operandReg, labelSymbol = symbol)
|
||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun operatorModulo(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int): IRCodeChunk {
|
private fun operatorModulo(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int): IRCodeChunk {
|
||||||
if(vmDt==VmDataType.FLOAT)
|
require(vmDt!=VmDataType.FLOAT) {"floating-point modulo not supported"}
|
||||||
throw IllegalArgumentException("floating-point modulo not supported")
|
|
||||||
val code = IRCodeChunk(binExpr.position)
|
val code = IRCodeChunk(binExpr.position)
|
||||||
val rightResultReg = codeGen.vmRegisters.nextFree()
|
val rightResultReg = codeGen.vmRegisters.nextFree()
|
||||||
if(binExpr.right is PtNumber) {
|
if(binExpr.right is PtNumber) {
|
||||||
code += translateExpression(binExpr.left, resultRegister, -1)
|
code += translateExpression(binExpr.left, resultRegister, -1)
|
||||||
code += IRCodeInstruction(Opcode.MOD, vmDt, reg1 = resultRegister, value=(binExpr.right as PtNumber).number.toInt())
|
code += IRInstruction(Opcode.MOD, vmDt, reg1 = resultRegister, value=(binExpr.right as PtNumber).number.toInt())
|
||||||
} else {
|
} else {
|
||||||
code += translateExpression(binExpr.left, resultRegister, -1)
|
code += translateExpression(binExpr.left, resultRegister, -1)
|
||||||
code += translateExpression(binExpr.right, rightResultReg, -1)
|
code += translateExpression(binExpr.right, rightResultReg, -1)
|
||||||
code += IRCodeInstruction(Opcode.MODR, vmDt, reg1 = resultRegister, reg2 = rightResultReg)
|
code += IRInstruction(Opcode.MODR, vmDt, reg1 = resultRegister, reg2 = rightResultReg)
|
||||||
}
|
}
|
||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
@ -576,9 +575,9 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
|||||||
code += translateExpression(binExpr.left, -1, resultFpRegister)
|
code += translateExpression(binExpr.left, -1, resultFpRegister)
|
||||||
code += translateExpression(binExpr.right, -1, rightResultFpReg)
|
code += translateExpression(binExpr.right, -1, rightResultFpReg)
|
||||||
code += if(signed)
|
code += if(signed)
|
||||||
IRCodeInstruction(Opcode.DIVSR, vmDt, fpReg1 = resultFpRegister, fpReg2=rightResultFpReg)
|
IRInstruction(Opcode.DIVSR, vmDt, fpReg1 = resultFpRegister, fpReg2=rightResultFpReg)
|
||||||
else
|
else
|
||||||
IRCodeInstruction(Opcode.DIVR, vmDt, fpReg1 = resultFpRegister, fpReg2=rightResultFpReg)
|
IRInstruction(Opcode.DIVR, vmDt, fpReg1 = resultFpRegister, fpReg2=rightResultFpReg)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if(constFactorRight!=null && constFactorRight.type!=DataType.FLOAT) {
|
if(constFactorRight!=null && constFactorRight.type!=DataType.FLOAT) {
|
||||||
@ -590,16 +589,16 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
|||||||
if(binExpr.right is PtNumber) {
|
if(binExpr.right is PtNumber) {
|
||||||
code += translateExpression(binExpr.left, resultRegister, -1)
|
code += translateExpression(binExpr.left, resultRegister, -1)
|
||||||
code += if (signed)
|
code += if (signed)
|
||||||
IRCodeInstruction(Opcode.DIVS, vmDt, reg1 = resultRegister, value=(binExpr.right as PtNumber).number.toInt())
|
IRInstruction(Opcode.DIVS, vmDt, reg1 = resultRegister, value=(binExpr.right as PtNumber).number.toInt())
|
||||||
else
|
else
|
||||||
IRCodeInstruction(Opcode.DIV, vmDt, reg1 = resultRegister, value=(binExpr.right as PtNumber).number.toInt())
|
IRInstruction(Opcode.DIV, vmDt, reg1 = resultRegister, value=(binExpr.right as PtNumber).number.toInt())
|
||||||
} else {
|
} else {
|
||||||
code += translateExpression(binExpr.left, resultRegister, -1)
|
code += translateExpression(binExpr.left, resultRegister, -1)
|
||||||
code += translateExpression(binExpr.right, rightResultReg, -1)
|
code += translateExpression(binExpr.right, rightResultReg, -1)
|
||||||
code += if (signed)
|
code += if (signed)
|
||||||
IRCodeInstruction(Opcode.DIVSR, vmDt, reg1 = resultRegister, reg2 = rightResultReg)
|
IRInstruction(Opcode.DIVSR, vmDt, reg1 = resultRegister, reg2 = rightResultReg)
|
||||||
else
|
else
|
||||||
IRCodeInstruction(Opcode.DIVR, vmDt, reg1 = resultRegister, reg2 = rightResultReg)
|
IRInstruction(Opcode.DIVR, vmDt, reg1 = resultRegister, reg2 = rightResultReg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -618,15 +617,15 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
|||||||
code += translateExpression(operand, -1, operandFpReg)
|
code += translateExpression(operand, -1, operandFpReg)
|
||||||
code += if(signed) {
|
code += if(signed) {
|
||||||
if(knownAddress!=null)
|
if(knownAddress!=null)
|
||||||
IRCodeInstruction(Opcode.DIVSM, vmDt, fpReg1 = operandFpReg, value = knownAddress)
|
IRInstruction(Opcode.DIVSM, vmDt, fpReg1 = operandFpReg, value = knownAddress)
|
||||||
else
|
else
|
||||||
IRCodeInstruction(Opcode.DIVSM, vmDt, fpReg1 = operandFpReg, labelSymbol = symbol)
|
IRInstruction(Opcode.DIVSM, vmDt, fpReg1 = operandFpReg, labelSymbol = symbol)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if(knownAddress!=null)
|
if(knownAddress!=null)
|
||||||
IRCodeInstruction(Opcode.DIVM, vmDt, fpReg1 = operandFpReg, value = knownAddress)
|
IRInstruction(Opcode.DIVM, vmDt, fpReg1 = operandFpReg, value = knownAddress)
|
||||||
else
|
else
|
||||||
IRCodeInstruction(Opcode.DIVM, vmDt, fpReg1 = operandFpReg, labelSymbol = symbol)
|
IRInstruction(Opcode.DIVM, vmDt, fpReg1 = operandFpReg, labelSymbol = symbol)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -638,15 +637,15 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
|||||||
code += translateExpression(operand, operandReg, -1)
|
code += translateExpression(operand, operandReg, -1)
|
||||||
code += if(signed) {
|
code += if(signed) {
|
||||||
if(knownAddress!=null)
|
if(knownAddress!=null)
|
||||||
IRCodeInstruction(Opcode.DIVSM, vmDt, reg1 = operandReg, value = knownAddress)
|
IRInstruction(Opcode.DIVSM, vmDt, reg1 = operandReg, value = knownAddress)
|
||||||
else
|
else
|
||||||
IRCodeInstruction(Opcode.DIVSM, vmDt, reg1 = operandReg, labelSymbol = symbol)
|
IRInstruction(Opcode.DIVSM, vmDt, reg1 = operandReg, labelSymbol = symbol)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if(knownAddress!=null)
|
if(knownAddress!=null)
|
||||||
IRCodeInstruction(Opcode.DIVM, vmDt, reg1 = operandReg, value = knownAddress)
|
IRInstruction(Opcode.DIVM, vmDt, reg1 = operandReg, value = knownAddress)
|
||||||
else
|
else
|
||||||
IRCodeInstruction(Opcode.DIVM, vmDt, reg1 = operandReg, labelSymbol = symbol)
|
IRInstruction(Opcode.DIVM, vmDt, reg1 = operandReg, labelSymbol = symbol)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -670,7 +669,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
|||||||
val rightResultFpReg = codeGen.vmRegisters.nextFreeFloat()
|
val rightResultFpReg = codeGen.vmRegisters.nextFreeFloat()
|
||||||
code += translateExpression(binExpr.left, -1, resultFpRegister)
|
code += translateExpression(binExpr.left, -1, resultFpRegister)
|
||||||
code += translateExpression(binExpr.right, -1, rightResultFpReg)
|
code += translateExpression(binExpr.right, -1, rightResultFpReg)
|
||||||
code += IRCodeInstruction(Opcode.MULR, vmDt, fpReg1 = resultFpRegister, fpReg2 = rightResultFpReg)
|
code += IRInstruction(Opcode.MULR, vmDt, fpReg1 = resultFpRegister, fpReg2 = rightResultFpReg)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if(constFactorLeft!=null && constFactorLeft.type!=DataType.FLOAT) {
|
if(constFactorLeft!=null && constFactorLeft.type!=DataType.FLOAT) {
|
||||||
@ -685,7 +684,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
|||||||
val rightResultReg = codeGen.vmRegisters.nextFree()
|
val rightResultReg = codeGen.vmRegisters.nextFree()
|
||||||
code += translateExpression(binExpr.left, resultRegister, -1)
|
code += translateExpression(binExpr.left, resultRegister, -1)
|
||||||
code += translateExpression(binExpr.right, rightResultReg, -1)
|
code += translateExpression(binExpr.right, rightResultReg, -1)
|
||||||
code += IRCodeInstruction(Opcode.MULR, vmDt, reg1 = resultRegister, reg2 = rightResultReg)
|
code += IRInstruction(Opcode.MULR, vmDt, reg1 = resultRegister, reg2 = rightResultReg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return code
|
return code
|
||||||
@ -702,9 +701,9 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
|||||||
val operandFpReg = codeGen.vmRegisters.nextFreeFloat()
|
val operandFpReg = codeGen.vmRegisters.nextFreeFloat()
|
||||||
code += translateExpression(operand, -1, operandFpReg)
|
code += translateExpression(operand, -1, operandFpReg)
|
||||||
code += if(knownAddress!=null)
|
code += if(knownAddress!=null)
|
||||||
IRCodeInstruction(Opcode.MULM, vmDt, fpReg1 = operandFpReg, value = knownAddress)
|
IRInstruction(Opcode.MULM, vmDt, fpReg1 = operandFpReg, value = knownAddress)
|
||||||
else
|
else
|
||||||
IRCodeInstruction(Opcode.MULM, vmDt, fpReg1 = operandFpReg, labelSymbol = symbol)
|
IRInstruction(Opcode.MULM, vmDt, fpReg1 = operandFpReg, labelSymbol = symbol)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if(constFactorRight!=null && constFactorRight.type!=DataType.FLOAT) {
|
if(constFactorRight!=null && constFactorRight.type!=DataType.FLOAT) {
|
||||||
@ -714,9 +713,9 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
|||||||
val operandReg = codeGen.vmRegisters.nextFree()
|
val operandReg = codeGen.vmRegisters.nextFree()
|
||||||
code += translateExpression(operand, operandReg, -1)
|
code += translateExpression(operand, operandReg, -1)
|
||||||
code += if(knownAddress!=null)
|
code += if(knownAddress!=null)
|
||||||
IRCodeInstruction(Opcode.MULM, vmDt, reg1=operandReg, value = knownAddress)
|
IRInstruction(Opcode.MULM, vmDt, reg1=operandReg, value = knownAddress)
|
||||||
else
|
else
|
||||||
IRCodeInstruction(Opcode.MULM, vmDt, reg1=operandReg, labelSymbol = symbol)
|
IRInstruction(Opcode.MULM, vmDt, reg1=operandReg, labelSymbol = symbol)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return code
|
return code
|
||||||
@ -727,33 +726,33 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
|||||||
if(vmDt==VmDataType.FLOAT) {
|
if(vmDt==VmDataType.FLOAT) {
|
||||||
if((binExpr.right as? PtNumber)?.number==1.0) {
|
if((binExpr.right as? PtNumber)?.number==1.0) {
|
||||||
code += translateExpression(binExpr.left, -1, resultFpRegister)
|
code += translateExpression(binExpr.left, -1, resultFpRegister)
|
||||||
code += IRCodeInstruction(Opcode.DEC, vmDt, fpReg1 = resultFpRegister)
|
code += IRInstruction(Opcode.DEC, vmDt, fpReg1 = resultFpRegister)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if(binExpr.right is PtNumber) {
|
if(binExpr.right is PtNumber) {
|
||||||
code += translateExpression(binExpr.left, -1, resultFpRegister)
|
code += translateExpression(binExpr.left, -1, resultFpRegister)
|
||||||
code += IRCodeInstruction(Opcode.SUB, vmDt, fpReg1 = resultFpRegister, fpValue = (binExpr.right as PtNumber).number.toFloat())
|
code += IRInstruction(Opcode.SUB, vmDt, fpReg1 = resultFpRegister, fpValue = (binExpr.right as PtNumber).number.toFloat())
|
||||||
} else {
|
} else {
|
||||||
val rightResultFpReg = codeGen.vmRegisters.nextFreeFloat()
|
val rightResultFpReg = codeGen.vmRegisters.nextFreeFloat()
|
||||||
code += translateExpression(binExpr.left, -1, resultFpRegister)
|
code += translateExpression(binExpr.left, -1, resultFpRegister)
|
||||||
code += translateExpression(binExpr.right, -1, rightResultFpReg)
|
code += translateExpression(binExpr.right, -1, rightResultFpReg)
|
||||||
code += IRCodeInstruction(Opcode.SUBR, vmDt, fpReg1 = resultFpRegister, fpReg2 = rightResultFpReg)
|
code += IRInstruction(Opcode.SUBR, vmDt, fpReg1 = resultFpRegister, fpReg2 = rightResultFpReg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if((binExpr.right as? PtNumber)?.number==1.0) {
|
if((binExpr.right as? PtNumber)?.number==1.0) {
|
||||||
code += translateExpression(binExpr.left, resultRegister, -1)
|
code += translateExpression(binExpr.left, resultRegister, -1)
|
||||||
code += IRCodeInstruction(Opcode.DEC, vmDt, reg1=resultRegister)
|
code += IRInstruction(Opcode.DEC, vmDt, reg1=resultRegister)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if(binExpr.right is PtNumber) {
|
if(binExpr.right is PtNumber) {
|
||||||
code += translateExpression(binExpr.left, resultRegister, -1)
|
code += translateExpression(binExpr.left, resultRegister, -1)
|
||||||
code += IRCodeInstruction(Opcode.SUB, vmDt, reg1 = resultRegister, value = (binExpr.right as PtNumber).number.toInt())
|
code += IRInstruction(Opcode.SUB, vmDt, reg1 = resultRegister, value = (binExpr.right as PtNumber).number.toInt())
|
||||||
} else {
|
} else {
|
||||||
val rightResultReg = codeGen.vmRegisters.nextFree()
|
val rightResultReg = codeGen.vmRegisters.nextFree()
|
||||||
code += translateExpression(binExpr.left, resultRegister, -1)
|
code += translateExpression(binExpr.left, resultRegister, -1)
|
||||||
code += translateExpression(binExpr.right, rightResultReg, -1)
|
code += translateExpression(binExpr.right, rightResultReg, -1)
|
||||||
code += IRCodeInstruction(Opcode.SUBR, vmDt, reg1 = resultRegister, reg2 = rightResultReg)
|
code += IRInstruction(Opcode.SUBR, vmDt, reg1 = resultRegister, reg2 = rightResultReg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -765,32 +764,32 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
|||||||
if(vmDt==VmDataType.FLOAT) {
|
if(vmDt==VmDataType.FLOAT) {
|
||||||
if((operand as? PtNumber)?.number==1.0) {
|
if((operand as? PtNumber)?.number==1.0) {
|
||||||
code += if(knownAddress!=null)
|
code += if(knownAddress!=null)
|
||||||
IRCodeInstruction(Opcode.DECM, vmDt, value=knownAddress)
|
IRInstruction(Opcode.DECM, vmDt, value=knownAddress)
|
||||||
else
|
else
|
||||||
IRCodeInstruction(Opcode.DECM, vmDt, labelSymbol = symbol)
|
IRInstruction(Opcode.DECM, vmDt, labelSymbol = symbol)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
val operandFpReg = codeGen.vmRegisters.nextFreeFloat()
|
val operandFpReg = codeGen.vmRegisters.nextFreeFloat()
|
||||||
code += translateExpression(operand, -1, operandFpReg)
|
code += translateExpression(operand, -1, operandFpReg)
|
||||||
code += if(knownAddress!=null)
|
code += if(knownAddress!=null)
|
||||||
IRCodeInstruction(Opcode.SUBM, vmDt, fpReg1=operandFpReg, value=knownAddress)
|
IRInstruction(Opcode.SUBM, vmDt, fpReg1=operandFpReg, value=knownAddress)
|
||||||
else
|
else
|
||||||
IRCodeInstruction(Opcode.SUBM, vmDt, fpReg1=operandFpReg, labelSymbol = symbol)
|
IRInstruction(Opcode.SUBM, vmDt, fpReg1=operandFpReg, labelSymbol = symbol)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if((operand as? PtNumber)?.number==1.0) {
|
if((operand as? PtNumber)?.number==1.0) {
|
||||||
code += if(knownAddress!=null)
|
code += if(knownAddress!=null)
|
||||||
IRCodeInstruction(Opcode.DECM, vmDt, value=knownAddress)
|
IRInstruction(Opcode.DECM, vmDt, value=knownAddress)
|
||||||
else
|
else
|
||||||
IRCodeInstruction(Opcode.DECM, vmDt, labelSymbol = symbol)
|
IRInstruction(Opcode.DECM, vmDt, labelSymbol = symbol)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
val operandReg = codeGen.vmRegisters.nextFree()
|
val operandReg = codeGen.vmRegisters.nextFree()
|
||||||
code += translateExpression(operand, operandReg, -1)
|
code += translateExpression(operand, operandReg, -1)
|
||||||
code += if(knownAddress!=null)
|
code += if(knownAddress!=null)
|
||||||
IRCodeInstruction(Opcode.SUBM, vmDt, reg1=operandReg, value = knownAddress)
|
IRInstruction(Opcode.SUBM, vmDt, reg1=operandReg, value = knownAddress)
|
||||||
else
|
else
|
||||||
IRCodeInstruction(Opcode.SUBM, vmDt, reg1=operandReg, labelSymbol = symbol)
|
IRInstruction(Opcode.SUBM, vmDt, reg1=operandReg, labelSymbol = symbol)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return code
|
return code
|
||||||
@ -801,41 +800,41 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
|||||||
if(vmDt==VmDataType.FLOAT) {
|
if(vmDt==VmDataType.FLOAT) {
|
||||||
if((binExpr.left as? PtNumber)?.number==1.0) {
|
if((binExpr.left as? PtNumber)?.number==1.0) {
|
||||||
code += translateExpression(binExpr.right, -1, resultFpRegister)
|
code += translateExpression(binExpr.right, -1, resultFpRegister)
|
||||||
code += IRCodeInstruction(Opcode.INC, vmDt, fpReg1=resultFpRegister)
|
code += IRInstruction(Opcode.INC, vmDt, fpReg1=resultFpRegister)
|
||||||
}
|
}
|
||||||
else if((binExpr.right as? PtNumber)?.number==1.0) {
|
else if((binExpr.right as? PtNumber)?.number==1.0) {
|
||||||
code += translateExpression(binExpr.left, -1, resultFpRegister)
|
code += translateExpression(binExpr.left, -1, resultFpRegister)
|
||||||
code += IRCodeInstruction(Opcode.INC, vmDt, fpReg1=resultFpRegister)
|
code += IRInstruction(Opcode.INC, vmDt, fpReg1=resultFpRegister)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if(binExpr.right is PtNumber) {
|
if(binExpr.right is PtNumber) {
|
||||||
code += translateExpression(binExpr.left, -1, resultFpRegister)
|
code += translateExpression(binExpr.left, -1, resultFpRegister)
|
||||||
code += IRCodeInstruction(Opcode.ADD, vmDt, fpReg1 = resultFpRegister, fpValue = (binExpr.right as PtNumber).number.toFloat())
|
code += IRInstruction(Opcode.ADD, vmDt, fpReg1 = resultFpRegister, fpValue = (binExpr.right as PtNumber).number.toFloat())
|
||||||
} else {
|
} else {
|
||||||
val rightResultFpReg = codeGen.vmRegisters.nextFreeFloat()
|
val rightResultFpReg = codeGen.vmRegisters.nextFreeFloat()
|
||||||
code += translateExpression(binExpr.left, -1, resultFpRegister)
|
code += translateExpression(binExpr.left, -1, resultFpRegister)
|
||||||
code += translateExpression(binExpr.right, -1, rightResultFpReg)
|
code += translateExpression(binExpr.right, -1, rightResultFpReg)
|
||||||
code += IRCodeInstruction(Opcode.ADDR, vmDt, fpReg1 = resultFpRegister, fpReg2 = rightResultFpReg)
|
code += IRInstruction(Opcode.ADDR, vmDt, fpReg1 = resultFpRegister, fpReg2 = rightResultFpReg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if((binExpr.left as? PtNumber)?.number==1.0) {
|
if((binExpr.left as? PtNumber)?.number==1.0) {
|
||||||
code += translateExpression(binExpr.right, resultRegister, -1)
|
code += translateExpression(binExpr.right, resultRegister, -1)
|
||||||
code += IRCodeInstruction(Opcode.INC, vmDt, reg1=resultRegister)
|
code += IRInstruction(Opcode.INC, vmDt, reg1=resultRegister)
|
||||||
}
|
}
|
||||||
else if((binExpr.right as? PtNumber)?.number==1.0) {
|
else if((binExpr.right as? PtNumber)?.number==1.0) {
|
||||||
code += translateExpression(binExpr.left, resultRegister, -1)
|
code += translateExpression(binExpr.left, resultRegister, -1)
|
||||||
code += IRCodeInstruction(Opcode.INC, vmDt, reg1=resultRegister)
|
code += IRInstruction(Opcode.INC, vmDt, reg1=resultRegister)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if(binExpr.right is PtNumber) {
|
if(binExpr.right is PtNumber) {
|
||||||
code += translateExpression(binExpr.left, resultRegister, -1)
|
code += translateExpression(binExpr.left, resultRegister, -1)
|
||||||
code += IRCodeInstruction(Opcode.ADD, vmDt, reg1 = resultRegister, value=(binExpr.right as PtNumber).number.toInt())
|
code += IRInstruction(Opcode.ADD, vmDt, reg1 = resultRegister, value=(binExpr.right as PtNumber).number.toInt())
|
||||||
} else {
|
} else {
|
||||||
val rightResultReg = codeGen.vmRegisters.nextFree()
|
val rightResultReg = codeGen.vmRegisters.nextFree()
|
||||||
code += translateExpression(binExpr.left, resultRegister, -1)
|
code += translateExpression(binExpr.left, resultRegister, -1)
|
||||||
code += translateExpression(binExpr.right, rightResultReg, -1)
|
code += translateExpression(binExpr.right, rightResultReg, -1)
|
||||||
code += IRCodeInstruction(Opcode.ADDR, vmDt, reg1 = resultRegister, reg2 = rightResultReg)
|
code += IRInstruction(Opcode.ADDR, vmDt, reg1 = resultRegister, reg2 = rightResultReg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -847,32 +846,32 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
|||||||
if(vmDt==VmDataType.FLOAT) {
|
if(vmDt==VmDataType.FLOAT) {
|
||||||
if((operand as? PtNumber)?.number==1.0) {
|
if((operand as? PtNumber)?.number==1.0) {
|
||||||
code += if(knownAddress!=null)
|
code += if(knownAddress!=null)
|
||||||
IRCodeInstruction(Opcode.INCM, vmDt, value = knownAddress)
|
IRInstruction(Opcode.INCM, vmDt, value = knownAddress)
|
||||||
else
|
else
|
||||||
IRCodeInstruction(Opcode.INCM, vmDt, labelSymbol = symbol)
|
IRInstruction(Opcode.INCM, vmDt, labelSymbol = symbol)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
val operandFpReg = codeGen.vmRegisters.nextFreeFloat()
|
val operandFpReg = codeGen.vmRegisters.nextFreeFloat()
|
||||||
code += translateExpression(operand, -1, operandFpReg)
|
code += translateExpression(operand, -1, operandFpReg)
|
||||||
code += if(knownAddress!=null)
|
code += if(knownAddress!=null)
|
||||||
IRCodeInstruction(Opcode.ADDM, vmDt, fpReg1=operandFpReg, value = knownAddress)
|
IRInstruction(Opcode.ADDM, vmDt, fpReg1=operandFpReg, value = knownAddress)
|
||||||
else
|
else
|
||||||
IRCodeInstruction(Opcode.ADDM, vmDt, fpReg1=operandFpReg, labelSymbol = symbol)
|
IRInstruction(Opcode.ADDM, vmDt, fpReg1=operandFpReg, labelSymbol = symbol)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if((operand as? PtNumber)?.number==1.0) {
|
if((operand as? PtNumber)?.number==1.0) {
|
||||||
code += if(knownAddress!=null)
|
code += if(knownAddress!=null)
|
||||||
IRCodeInstruction(Opcode.INCM, vmDt, value = knownAddress)
|
IRInstruction(Opcode.INCM, vmDt, value = knownAddress)
|
||||||
else
|
else
|
||||||
IRCodeInstruction(Opcode.INCM, vmDt, labelSymbol = symbol)
|
IRInstruction(Opcode.INCM, vmDt, labelSymbol = symbol)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
val operandReg = codeGen.vmRegisters.nextFree()
|
val operandReg = codeGen.vmRegisters.nextFree()
|
||||||
code += translateExpression(operand, operandReg, -1)
|
code += translateExpression(operand, operandReg, -1)
|
||||||
code += if(knownAddress!=null)
|
code += if(knownAddress!=null)
|
||||||
IRCodeInstruction(Opcode.ADDM, vmDt, reg1=operandReg, value=knownAddress)
|
IRInstruction(Opcode.ADDM, vmDt, reg1=operandReg, value=knownAddress)
|
||||||
else
|
else
|
||||||
IRCodeInstruction(Opcode.ADDM, vmDt, reg1=operandReg, labelSymbol = symbol)
|
IRInstruction(Opcode.ADDM, vmDt, reg1=operandReg, labelSymbol = symbol)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return code
|
return code
|
||||||
@ -886,29 +885,29 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
|||||||
val paramDt = codeGen.vmType(parameter.type)
|
val paramDt = codeGen.vmType(parameter.type)
|
||||||
val symbol = (fcall.functionName + parameter.name).joinToString(".")
|
val symbol = (fcall.functionName + parameter.name).joinToString(".")
|
||||||
if(codeGen.isZero(arg)) {
|
if(codeGen.isZero(arg)) {
|
||||||
code += IRCodeInstruction(Opcode.STOREZM, paramDt, labelSymbol = symbol)
|
code += IRInstruction(Opcode.STOREZM, paramDt, labelSymbol = symbol)
|
||||||
} else {
|
} else {
|
||||||
if (paramDt == VmDataType.FLOAT) {
|
if (paramDt == VmDataType.FLOAT) {
|
||||||
val argFpReg = codeGen.vmRegisters.nextFreeFloat()
|
val argFpReg = codeGen.vmRegisters.nextFreeFloat()
|
||||||
code += translateExpression(arg, -1, argFpReg)
|
code += translateExpression(arg, -1, argFpReg)
|
||||||
code += IRCodeInstruction(Opcode.STOREM, paramDt, fpReg1 = argFpReg, labelSymbol = symbol)
|
code += IRInstruction(Opcode.STOREM, paramDt, fpReg1 = argFpReg, labelSymbol = symbol)
|
||||||
} else {
|
} else {
|
||||||
val argReg = codeGen.vmRegisters.nextFree()
|
val argReg = codeGen.vmRegisters.nextFree()
|
||||||
code += translateExpression(arg, argReg, -1)
|
code += translateExpression(arg, argReg, -1)
|
||||||
code += IRCodeInstruction(Opcode.STOREM, paramDt, reg1 = argReg, labelSymbol = symbol)
|
code += IRInstruction(Opcode.STOREM, paramDt, reg1 = argReg, labelSymbol = symbol)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
code += IRCodeInstruction(Opcode.CALL, labelSymbol=fcall.functionName.joinToString("."))
|
code += IRInstruction(Opcode.CALL, labelSymbol=fcall.functionName.joinToString("."))
|
||||||
if(fcall.type==DataType.FLOAT) {
|
if(fcall.type==DataType.FLOAT) {
|
||||||
if (!fcall.void && resultFpRegister != 0) {
|
if (!fcall.void && resultFpRegister != 0) {
|
||||||
// Call convention: result value is in fr0, so put it in the required register instead.
|
// Call convention: result value is in fr0, so put it in the required register instead.
|
||||||
code += IRCodeInstruction(Opcode.LOADR, VmDataType.FLOAT, fpReg1 = resultFpRegister, fpReg2 = 0)
|
code += IRInstruction(Opcode.LOADR, VmDataType.FLOAT, fpReg1 = resultFpRegister, fpReg2 = 0)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!fcall.void && resultRegister != 0) {
|
if (!fcall.void && resultRegister != 0) {
|
||||||
// Call convention: result value is in r0, so put it in the required register instead.
|
// Call convention: result value is in r0, so put it in the required register instead.
|
||||||
code += IRCodeInstruction(Opcode.LOADR, codeGen.vmType(fcall.type), reg1 = resultRegister, reg2 = 0)
|
code += IRInstruction(Opcode.LOADR, codeGen.vmType(fcall.type), reg1 = resultRegister, reg2 = 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return code
|
return code
|
||||||
@ -919,16 +918,16 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
|||||||
val paramDt = codeGen.vmType(parameter.type)
|
val paramDt = codeGen.vmType(parameter.type)
|
||||||
val paramRegStr = if(parameter.register.registerOrPair!=null) parameter.register.registerOrPair.toString() else parameter.register.statusflag.toString()
|
val paramRegStr = if(parameter.register.registerOrPair!=null) parameter.register.registerOrPair.toString() else parameter.register.statusflag.toString()
|
||||||
if(codeGen.isZero(arg)) {
|
if(codeGen.isZero(arg)) {
|
||||||
code += IRCodeInstruction(Opcode.STOREZCPU, paramDt, labelSymbol = paramRegStr)
|
code += IRInstruction(Opcode.STOREZCPU, paramDt, labelSymbol = paramRegStr)
|
||||||
} else {
|
} else {
|
||||||
if (paramDt == VmDataType.FLOAT)
|
if (paramDt == VmDataType.FLOAT)
|
||||||
throw AssemblyError("doesn't support float register argument in asm romsub")
|
throw AssemblyError("doesn't support float register argument in asm romsub")
|
||||||
val argReg = codeGen.vmRegisters.nextFree()
|
val argReg = codeGen.vmRegisters.nextFree()
|
||||||
code += translateExpression(arg, argReg, -1)
|
code += translateExpression(arg, argReg, -1)
|
||||||
code += IRCodeInstruction(Opcode.STORECPU, paramDt, reg1 = argReg, labelSymbol = paramRegStr)
|
code += IRInstruction(Opcode.STORECPU, paramDt, reg1 = argReg, labelSymbol = paramRegStr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
code += IRCodeInstruction(Opcode.CALL, value=callTarget.address.toInt())
|
code += IRInstruction(Opcode.CALL, value=callTarget.address.toInt())
|
||||||
if(!fcall.void) {
|
if(!fcall.void) {
|
||||||
if(callTarget.returns.size!=1)
|
if(callTarget.returns.size!=1)
|
||||||
throw AssemblyError("expect precisely 1 return value")
|
throw AssemblyError("expect precisely 1 return value")
|
||||||
@ -936,7 +935,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
|||||||
throw AssemblyError("doesn't support float register result in asm romsub")
|
throw AssemblyError("doesn't support float register result in asm romsub")
|
||||||
val returns = callTarget.returns.single()
|
val returns = callTarget.returns.single()
|
||||||
val regStr = if(returns.registerOrPair!=null) returns.registerOrPair.toString() else returns.statusflag.toString()
|
val regStr = if(returns.registerOrPair!=null) returns.registerOrPair.toString() else returns.statusflag.toString()
|
||||||
code += IRCodeInstruction(Opcode.LOADCPU, codeGen.vmType(fcall.type), reg1=resultRegister, labelSymbol = regStr)
|
code += IRInstruction(Opcode.LOADCPU, codeGen.vmType(fcall.type), reg1=resultRegister, labelSymbol = regStr)
|
||||||
}
|
}
|
||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package prog8.codegen.intermediate
|
package prog8.codegen.intermediate
|
||||||
|
|
||||||
import prog8.code.StMemVar
|
import prog8.code.StMemVar
|
||||||
import prog8.code.StMemorySlab
|
|
||||||
import prog8.code.StStaticVariable
|
import prog8.code.StStaticVariable
|
||||||
import prog8.code.SymbolTable
|
import prog8.code.SymbolTable
|
||||||
import prog8.code.ast.*
|
import prog8.code.ast.*
|
||||||
@ -64,8 +63,8 @@ class IRCodeGen(
|
|||||||
val replacements = mutableListOf<Triple<IRCodeChunkBase, Int, UInt>>()
|
val replacements = mutableListOf<Triple<IRCodeChunkBase, Int, UInt>>()
|
||||||
irProg.blocks.asSequence().flatMap { it.subroutines }.flatMap { it.chunks }.forEach { chunk ->
|
irProg.blocks.asSequence().flatMap { it.subroutines }.flatMap { it.chunks }.forEach { chunk ->
|
||||||
chunk.lines.withIndex().forEach {
|
chunk.lines.withIndex().forEach {
|
||||||
(lineIndex, line)-> if(line is IRCodeInstruction) {
|
(lineIndex, line) -> if(line is IRInstruction) {
|
||||||
val symbolExpr = line.ins.labelSymbol?.single()
|
val symbolExpr = line.labelSymbol
|
||||||
if(symbolExpr!=null) {
|
if(symbolExpr!=null) {
|
||||||
val symbol: String
|
val symbol: String
|
||||||
val index: UInt
|
val index: UInt
|
||||||
@ -87,14 +86,14 @@ class IRCodeGen(
|
|||||||
}
|
}
|
||||||
|
|
||||||
replacements.forEach {
|
replacements.forEach {
|
||||||
val old = it.first.lines[it.second] as IRCodeInstruction
|
val old = it.first.lines[it.second] as IRInstruction
|
||||||
it.first.lines[it.second] = IRCodeInstruction(
|
it.first.lines[it.second] = IRInstruction(
|
||||||
old.ins.opcode,
|
old.opcode,
|
||||||
old.ins.type,
|
old.type,
|
||||||
old.ins.reg1,
|
old.reg1,
|
||||||
old.ins.reg2,
|
old.reg2,
|
||||||
old.ins.fpReg1,
|
old.fpReg1,
|
||||||
old.ins.fpReg2,
|
old.fpReg2,
|
||||||
it.third.toInt(),
|
it.third.toInt(),
|
||||||
null,
|
null,
|
||||||
null
|
null
|
||||||
@ -234,7 +233,7 @@ class IRCodeGen(
|
|||||||
}
|
}
|
||||||
is PtBreakpoint -> {
|
is PtBreakpoint -> {
|
||||||
val chunk = IRCodeChunk(node.position)
|
val chunk = IRCodeChunk(node.position)
|
||||||
chunk += IRCodeInstruction(Opcode.BREAKPOINT)
|
chunk += IRInstruction(Opcode.BREAKPOINT)
|
||||||
return chunk
|
return chunk
|
||||||
}
|
}
|
||||||
is PtConditionalBranch -> translate(node)
|
is PtConditionalBranch -> translate(node)
|
||||||
@ -244,7 +243,7 @@ class IRCodeGen(
|
|||||||
val data = node.file.readBytes()
|
val data = node.file.readBytes()
|
||||||
.drop(node.offset?.toInt() ?: 0)
|
.drop(node.offset?.toInt() ?: 0)
|
||||||
.take(node.length?.toInt() ?: Int.MAX_VALUE)
|
.take(node.length?.toInt() ?: Int.MAX_VALUE)
|
||||||
chunk += IRCodeInlineBinary(data.toByteArray())
|
chunk += IRCodeInlineBinary(data.map { it.toUByte() })
|
||||||
return chunk
|
return chunk
|
||||||
}
|
}
|
||||||
is PtAddressOf,
|
is PtAddressOf,
|
||||||
@ -275,19 +274,19 @@ class IRCodeGen(
|
|||||||
val elseLabel = createLabelName()
|
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
|
// 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) {
|
code += when(branch.condition) {
|
||||||
BranchCondition.CS -> IRCodeInstruction(Opcode.BSTCC, labelSymbol = elseLabel)
|
BranchCondition.CS -> IRInstruction(Opcode.BSTCC, labelSymbol = elseLabel)
|
||||||
BranchCondition.CC -> IRCodeInstruction(Opcode.BSTCS, labelSymbol = elseLabel)
|
BranchCondition.CC -> IRInstruction(Opcode.BSTCS, labelSymbol = elseLabel)
|
||||||
BranchCondition.EQ, BranchCondition.Z -> IRCodeInstruction(Opcode.BSTNE, labelSymbol = elseLabel)
|
BranchCondition.EQ, BranchCondition.Z -> IRInstruction(Opcode.BSTNE, labelSymbol = elseLabel)
|
||||||
BranchCondition.NE, BranchCondition.NZ -> IRCodeInstruction(Opcode.BSTEQ, labelSymbol = elseLabel)
|
BranchCondition.NE, BranchCondition.NZ -> IRInstruction(Opcode.BSTEQ, labelSymbol = elseLabel)
|
||||||
BranchCondition.MI, BranchCondition.NEG -> IRCodeInstruction(Opcode.BSTPOS, labelSymbol = elseLabel)
|
BranchCondition.MI, BranchCondition.NEG -> IRInstruction(Opcode.BSTPOS, labelSymbol = elseLabel)
|
||||||
BranchCondition.PL, BranchCondition.POS -> IRCodeInstruction(Opcode.BSTNEG, labelSymbol = elseLabel)
|
BranchCondition.PL, BranchCondition.POS -> IRInstruction(Opcode.BSTNEG, labelSymbol = elseLabel)
|
||||||
BranchCondition.VC,
|
BranchCondition.VC,
|
||||||
BranchCondition.VS -> throw AssemblyError("conditional branch ${branch.condition} not supported in vm target due to lack of cpu V flag ${branch.position}")
|
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)
|
code += translateNode(branch.trueScope)
|
||||||
if(branch.falseScope.children.isNotEmpty()) {
|
if(branch.falseScope.children.isNotEmpty()) {
|
||||||
val endLabel = createLabelName()
|
val endLabel = createLabelName()
|
||||||
code += IRCodeInstruction(Opcode.JUMP, labelSymbol = endLabel)
|
code += IRInstruction(Opcode.JUMP, labelSymbol = endLabel)
|
||||||
code += IRCodeLabel(elseLabel)
|
code += IRCodeLabel(elseLabel)
|
||||||
code += translateNode(branch.falseScope)
|
code += translateNode(branch.falseScope)
|
||||||
code += IRCodeLabel(endLabel)
|
code += IRCodeLabel(endLabel)
|
||||||
@ -314,22 +313,22 @@ class IRCodeGen(
|
|||||||
val skipLabel = createLabelName()
|
val skipLabel = createLabelName()
|
||||||
val values = choice.values.children.map {it as PtNumber}
|
val values = choice.values.children.map {it as PtNumber}
|
||||||
if(values.size==1) {
|
if(values.size==1) {
|
||||||
code += IRCodeInstruction(Opcode.LOAD, valueDt, reg1=choiceReg, value=values[0].number.toInt())
|
code += IRInstruction(Opcode.LOAD, valueDt, reg1=choiceReg, value=values[0].number.toInt())
|
||||||
code += IRCodeInstruction(Opcode.BNE, valueDt, reg1=valueReg, reg2=choiceReg, labelSymbol = skipLabel)
|
code += IRInstruction(Opcode.BNE, valueDt, reg1=valueReg, reg2=choiceReg, labelSymbol = skipLabel)
|
||||||
code += translateNode(choice.statements)
|
code += translateNode(choice.statements)
|
||||||
if(choice.statements.children.last() !is PtReturn)
|
if(choice.statements.children.last() !is PtReturn)
|
||||||
code += IRCodeInstruction(Opcode.JUMP, labelSymbol = endLabel)
|
code += IRInstruction(Opcode.JUMP, labelSymbol = endLabel)
|
||||||
} else {
|
} else {
|
||||||
val matchLabel = createLabelName()
|
val matchLabel = createLabelName()
|
||||||
for (value in values) {
|
for (value in values) {
|
||||||
code += IRCodeInstruction(Opcode.LOAD, valueDt, reg1=choiceReg, value=value.number.toInt())
|
code += IRInstruction(Opcode.LOAD, valueDt, reg1=choiceReg, value=value.number.toInt())
|
||||||
code += IRCodeInstruction(Opcode.BEQ, valueDt, reg1=valueReg, reg2=choiceReg, labelSymbol = matchLabel)
|
code += IRInstruction(Opcode.BEQ, valueDt, reg1=valueReg, reg2=choiceReg, labelSymbol = matchLabel)
|
||||||
}
|
}
|
||||||
code += IRCodeInstruction(Opcode.JUMP, labelSymbol = skipLabel)
|
code += IRInstruction(Opcode.JUMP, labelSymbol = skipLabel)
|
||||||
code += IRCodeLabel(matchLabel)
|
code += IRCodeLabel(matchLabel)
|
||||||
code += translateNode(choice.statements)
|
code += translateNode(choice.statements)
|
||||||
if(choice.statements.children.last() !is PtReturn)
|
if(choice.statements.children.last() !is PtReturn)
|
||||||
code += IRCodeInstruction(Opcode.JUMP, labelSymbol = endLabel)
|
code += IRInstruction(Opcode.JUMP, labelSymbol = endLabel)
|
||||||
}
|
}
|
||||||
code += IRCodeLabel(skipLabel)
|
code += IRCodeLabel(skipLabel)
|
||||||
}
|
}
|
||||||
@ -359,14 +358,14 @@ class IRCodeGen(
|
|||||||
val endLabel = createLabelName()
|
val endLabel = createLabelName()
|
||||||
if(iterableVar.dt==DataType.STR) {
|
if(iterableVar.dt==DataType.STR) {
|
||||||
// iterate over a zero-terminated string
|
// iterate over a zero-terminated string
|
||||||
code += IRCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=indexReg, value=0)
|
code += IRInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=indexReg, value=0)
|
||||||
code += IRCodeLabel(loopLabel)
|
code += IRCodeLabel(loopLabel)
|
||||||
code += IRCodeInstruction(Opcode.LOADX, VmDataType.BYTE, reg1=tmpReg, reg2=indexReg, labelSymbol = symbol)
|
code += IRInstruction(Opcode.LOADX, VmDataType.BYTE, reg1=tmpReg, reg2=indexReg, labelSymbol = symbol)
|
||||||
code += IRCodeInstruction(Opcode.BZ, VmDataType.BYTE, reg1=tmpReg, labelSymbol = endLabel)
|
code += IRInstruction(Opcode.BZ, VmDataType.BYTE, reg1=tmpReg, labelSymbol = endLabel)
|
||||||
code += IRCodeInstruction(Opcode.STOREM, VmDataType.BYTE, reg1=tmpReg, labelSymbol = loopvarSymbol)
|
code += IRInstruction(Opcode.STOREM, VmDataType.BYTE, reg1=tmpReg, labelSymbol = loopvarSymbol)
|
||||||
code += translateNode(forLoop.statements)
|
code += translateNode(forLoop.statements)
|
||||||
code += IRCodeInstruction(Opcode.INC, VmDataType.BYTE, reg1=indexReg)
|
code += IRInstruction(Opcode.INC, VmDataType.BYTE, reg1=indexReg)
|
||||||
code += IRCodeInstruction(Opcode.JUMP, labelSymbol = loopLabel)
|
code += IRInstruction(Opcode.JUMP, labelSymbol = loopLabel)
|
||||||
code += IRCodeLabel(endLabel)
|
code += IRCodeLabel(endLabel)
|
||||||
} else {
|
} else {
|
||||||
// iterate over array
|
// iterate over array
|
||||||
@ -375,22 +374,22 @@ class IRCodeGen(
|
|||||||
val lengthBytes = iterableVar.length!! * elementSize
|
val lengthBytes = iterableVar.length!! * elementSize
|
||||||
if(lengthBytes<256) {
|
if(lengthBytes<256) {
|
||||||
val lengthReg = vmRegisters.nextFree()
|
val lengthReg = vmRegisters.nextFree()
|
||||||
code += IRCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=indexReg, value=0)
|
code += IRInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=indexReg, value=0)
|
||||||
code += IRCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=lengthReg, value=lengthBytes)
|
code += IRInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=lengthReg, value=lengthBytes)
|
||||||
code += IRCodeLabel(loopLabel)
|
code += IRCodeLabel(loopLabel)
|
||||||
code += IRCodeInstruction(Opcode.LOADX, vmType(elementDt), reg1=tmpReg, reg2=indexReg, labelSymbol=symbol)
|
code += IRInstruction(Opcode.LOADX, vmType(elementDt), reg1=tmpReg, reg2=indexReg, labelSymbol=symbol)
|
||||||
code += IRCodeInstruction(Opcode.STOREM, vmType(elementDt), reg1=tmpReg, labelSymbol = loopvarSymbol)
|
code += IRInstruction(Opcode.STOREM, vmType(elementDt), reg1=tmpReg, labelSymbol = loopvarSymbol)
|
||||||
code += translateNode(forLoop.statements)
|
code += translateNode(forLoop.statements)
|
||||||
code += addConstReg(VmDataType.BYTE, indexReg, elementSize, iterable.position)
|
code += addConstReg(VmDataType.BYTE, indexReg, elementSize, iterable.position)
|
||||||
code += IRCodeInstruction(Opcode.BNE, VmDataType.BYTE, reg1=indexReg, reg2=lengthReg, labelSymbol = loopLabel)
|
code += IRInstruction(Opcode.BNE, VmDataType.BYTE, reg1=indexReg, reg2=lengthReg, labelSymbol = loopLabel)
|
||||||
} else if(lengthBytes==256) {
|
} else if(lengthBytes==256) {
|
||||||
code += IRCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=indexReg, value=0)
|
code += IRInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=indexReg, value=0)
|
||||||
code += IRCodeLabel(loopLabel)
|
code += IRCodeLabel(loopLabel)
|
||||||
code += IRCodeInstruction(Opcode.LOADX, vmType(elementDt), reg1=tmpReg, reg2=indexReg, labelSymbol=symbol)
|
code += IRInstruction(Opcode.LOADX, vmType(elementDt), reg1=tmpReg, reg2=indexReg, labelSymbol=symbol)
|
||||||
code += IRCodeInstruction(Opcode.STOREM, vmType(elementDt), reg1=tmpReg, labelSymbol = loopvarSymbol)
|
code += IRInstruction(Opcode.STOREM, vmType(elementDt), reg1=tmpReg, labelSymbol = loopvarSymbol)
|
||||||
code += translateNode(forLoop.statements)
|
code += translateNode(forLoop.statements)
|
||||||
code += addConstReg(VmDataType.BYTE, indexReg, elementSize, iterable.position)
|
code += addConstReg(VmDataType.BYTE, indexReg, elementSize, iterable.position)
|
||||||
code += IRCodeInstruction(Opcode.BNZ, VmDataType.BYTE, reg1=indexReg, labelSymbol = loopLabel)
|
code += IRInstruction(Opcode.BNZ, VmDataType.BYTE, reg1=indexReg, labelSymbol = loopLabel)
|
||||||
} else {
|
} else {
|
||||||
throw AssemblyError("iterator length should never exceed 256")
|
throw AssemblyError("iterator length should never exceed 256")
|
||||||
}
|
}
|
||||||
@ -415,13 +414,13 @@ class IRCodeGen(
|
|||||||
|
|
||||||
code += expressionEval.translateExpression(iterable.to, endvalueReg, -1)
|
code += expressionEval.translateExpression(iterable.to, endvalueReg, -1)
|
||||||
code += expressionEval.translateExpression(iterable.from, indexReg, -1)
|
code += expressionEval.translateExpression(iterable.from, indexReg, -1)
|
||||||
code += IRCodeInstruction(Opcode.STOREM, loopvarDt, reg1=indexReg, labelSymbol=loopvarSymbol)
|
code += IRInstruction(Opcode.STOREM, loopvarDt, reg1=indexReg, labelSymbol=loopvarSymbol)
|
||||||
code += IRCodeLabel(loopLabel)
|
code += IRCodeLabel(loopLabel)
|
||||||
code += translateNode(forLoop.statements)
|
code += translateNode(forLoop.statements)
|
||||||
code += addConstMem(loopvarDt, null, loopvarSymbol, step, iterable.position)
|
code += addConstMem(loopvarDt, null, loopvarSymbol, step, iterable.position)
|
||||||
code += IRCodeInstruction(Opcode.LOADM, loopvarDt, reg1 = indexReg, labelSymbol = loopvarSymbol)
|
code += IRInstruction(Opcode.LOADM, loopvarDt, reg1 = indexReg, labelSymbol = loopvarSymbol)
|
||||||
val branchOpcode = if(loopvar.dt in SignedDatatypes) Opcode.BLES else Opcode.BLE
|
val branchOpcode = if(loopvar.dt in SignedDatatypes) Opcode.BLES else Opcode.BLE
|
||||||
code += IRCodeInstruction(branchOpcode, loopvarDt, reg1=indexReg, reg2=endvalueReg, labelSymbol=loopLabel)
|
code += IRInstruction(branchOpcode, loopvarDt, reg1=indexReg, reg2=endvalueReg, labelSymbol=loopLabel)
|
||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -443,20 +442,20 @@ class IRCodeGen(
|
|||||||
val endvalueReg: Int
|
val endvalueReg: Int
|
||||||
if(rangeEndWrapped!=0) {
|
if(rangeEndWrapped!=0) {
|
||||||
endvalueReg = vmRegisters.nextFree()
|
endvalueReg = vmRegisters.nextFree()
|
||||||
code += IRCodeInstruction(Opcode.LOAD, loopvarDt, reg1 = endvalueReg, value = rangeEndWrapped)
|
code += IRInstruction(Opcode.LOAD, loopvarDt, reg1 = endvalueReg, value = rangeEndWrapped)
|
||||||
} else {
|
} else {
|
||||||
endvalueReg = -1 // not used
|
endvalueReg = -1 // not used
|
||||||
}
|
}
|
||||||
code += IRCodeInstruction(Opcode.LOAD, loopvarDt, reg1=indexReg, value=rangeStart)
|
code += IRInstruction(Opcode.LOAD, loopvarDt, reg1=indexReg, value=rangeStart)
|
||||||
code += IRCodeInstruction(Opcode.STOREM, loopvarDt, reg1=indexReg, labelSymbol=loopvarSymbol)
|
code += IRInstruction(Opcode.STOREM, loopvarDt, reg1=indexReg, labelSymbol=loopvarSymbol)
|
||||||
code += IRCodeLabel(loopLabel)
|
code += IRCodeLabel(loopLabel)
|
||||||
code += translateNode(forLoop.statements)
|
code += translateNode(forLoop.statements)
|
||||||
code += addConstMem(loopvarDt, null, loopvarSymbol, step, iterable.position)
|
code += addConstMem(loopvarDt, null, loopvarSymbol, step, iterable.position)
|
||||||
code += IRCodeInstruction(Opcode.LOADM, loopvarDt, reg1 = indexReg, labelSymbol = loopvarSymbol)
|
code += IRInstruction(Opcode.LOADM, loopvarDt, reg1 = indexReg, labelSymbol = loopvarSymbol)
|
||||||
code += if(rangeEndWrapped==0) {
|
code += if(rangeEndWrapped==0) {
|
||||||
IRCodeInstruction(Opcode.BNZ, loopvarDt, reg1 = indexReg, labelSymbol = loopLabel)
|
IRInstruction(Opcode.BNZ, loopvarDt, reg1 = indexReg, labelSymbol = loopLabel)
|
||||||
} else {
|
} else {
|
||||||
IRCodeInstruction(Opcode.BNE, loopvarDt, reg1 = indexReg, reg2 = endvalueReg, labelSymbol = loopLabel)
|
IRInstruction(Opcode.BNE, loopvarDt, reg1 = indexReg, reg2 = endvalueReg, labelSymbol = loopLabel)
|
||||||
}
|
}
|
||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
@ -466,24 +465,24 @@ class IRCodeGen(
|
|||||||
when(value) {
|
when(value) {
|
||||||
0 -> { /* do nothing */ }
|
0 -> { /* do nothing */ }
|
||||||
1 -> {
|
1 -> {
|
||||||
code += IRCodeInstruction(Opcode.INC, dt, reg1=reg)
|
code += IRInstruction(Opcode.INC, dt, reg1=reg)
|
||||||
}
|
}
|
||||||
2 -> {
|
2 -> {
|
||||||
code += IRCodeInstruction(Opcode.INC, dt, reg1=reg)
|
code += IRInstruction(Opcode.INC, dt, reg1=reg)
|
||||||
code += IRCodeInstruction(Opcode.INC, dt, reg1=reg)
|
code += IRInstruction(Opcode.INC, dt, reg1=reg)
|
||||||
}
|
}
|
||||||
-1 -> {
|
-1 -> {
|
||||||
code += IRCodeInstruction(Opcode.DEC, dt, reg1=reg)
|
code += IRInstruction(Opcode.DEC, dt, reg1=reg)
|
||||||
}
|
}
|
||||||
-2 -> {
|
-2 -> {
|
||||||
code += IRCodeInstruction(Opcode.DEC, dt, reg1=reg)
|
code += IRInstruction(Opcode.DEC, dt, reg1=reg)
|
||||||
code += IRCodeInstruction(Opcode.DEC, dt, reg1=reg)
|
code += IRInstruction(Opcode.DEC, dt, reg1=reg)
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
code += if(value>0) {
|
code += if(value>0) {
|
||||||
IRCodeInstruction(Opcode.ADD, dt, reg1 = reg, value=value)
|
IRInstruction(Opcode.ADD, dt, reg1 = reg, value=value)
|
||||||
} else {
|
} else {
|
||||||
IRCodeInstruction(Opcode.SUB, dt, reg1 = reg, value=-value)
|
IRInstruction(Opcode.SUB, dt, reg1 = reg, value=-value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -496,49 +495,49 @@ class IRCodeGen(
|
|||||||
0 -> { /* do nothing */ }
|
0 -> { /* do nothing */ }
|
||||||
1 -> {
|
1 -> {
|
||||||
code += if(knownAddress!=null)
|
code += if(knownAddress!=null)
|
||||||
IRCodeInstruction(Opcode.INCM, dt, value=knownAddress.toInt())
|
IRInstruction(Opcode.INCM, dt, value=knownAddress.toInt())
|
||||||
else
|
else
|
||||||
IRCodeInstruction(Opcode.INCM, dt, labelSymbol = symbol)
|
IRInstruction(Opcode.INCM, dt, labelSymbol = symbol)
|
||||||
}
|
}
|
||||||
2 -> {
|
2 -> {
|
||||||
if(knownAddress!=null) {
|
if(knownAddress!=null) {
|
||||||
code += IRCodeInstruction(Opcode.INCM, dt, value = knownAddress.toInt())
|
code += IRInstruction(Opcode.INCM, dt, value = knownAddress.toInt())
|
||||||
code += IRCodeInstruction(Opcode.INCM, dt, value = knownAddress.toInt())
|
code += IRInstruction(Opcode.INCM, dt, value = knownAddress.toInt())
|
||||||
} else {
|
} else {
|
||||||
code += IRCodeInstruction(Opcode.INCM, dt, labelSymbol = symbol)
|
code += IRInstruction(Opcode.INCM, dt, labelSymbol = symbol)
|
||||||
code += IRCodeInstruction(Opcode.INCM, dt, labelSymbol = symbol)
|
code += IRInstruction(Opcode.INCM, dt, labelSymbol = symbol)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
-1 -> {
|
-1 -> {
|
||||||
code += if(knownAddress!=null)
|
code += if(knownAddress!=null)
|
||||||
IRCodeInstruction(Opcode.DECM, dt, value=knownAddress.toInt())
|
IRInstruction(Opcode.DECM, dt, value=knownAddress.toInt())
|
||||||
else
|
else
|
||||||
IRCodeInstruction(Opcode.DECM, dt, labelSymbol = symbol)
|
IRInstruction(Opcode.DECM, dt, labelSymbol = symbol)
|
||||||
}
|
}
|
||||||
-2 -> {
|
-2 -> {
|
||||||
if(knownAddress!=null) {
|
if(knownAddress!=null) {
|
||||||
code += IRCodeInstruction(Opcode.DECM, dt, value = knownAddress.toInt())
|
code += IRInstruction(Opcode.DECM, dt, value = knownAddress.toInt())
|
||||||
code += IRCodeInstruction(Opcode.DECM, dt, value = knownAddress.toInt())
|
code += IRInstruction(Opcode.DECM, dt, value = knownAddress.toInt())
|
||||||
} else {
|
} else {
|
||||||
code += IRCodeInstruction(Opcode.DECM, dt, labelSymbol = symbol)
|
code += IRInstruction(Opcode.DECM, dt, labelSymbol = symbol)
|
||||||
code += IRCodeInstruction(Opcode.DECM, dt, labelSymbol = symbol)
|
code += IRInstruction(Opcode.DECM, dt, labelSymbol = symbol)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
val valueReg = vmRegisters.nextFree()
|
val valueReg = vmRegisters.nextFree()
|
||||||
if(value>0) {
|
if(value>0) {
|
||||||
code += IRCodeInstruction(Opcode.LOAD, dt, reg1=valueReg, value=value)
|
code += IRInstruction(Opcode.LOAD, dt, reg1=valueReg, value=value)
|
||||||
code += if(knownAddress!=null)
|
code += if(knownAddress!=null)
|
||||||
IRCodeInstruction(Opcode.ADDM, dt, reg1=valueReg, value=knownAddress.toInt())
|
IRInstruction(Opcode.ADDM, dt, reg1=valueReg, value=knownAddress.toInt())
|
||||||
else
|
else
|
||||||
IRCodeInstruction(Opcode.ADDM, dt, reg1=valueReg, labelSymbol = symbol)
|
IRInstruction(Opcode.ADDM, dt, reg1=valueReg, labelSymbol = symbol)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
code += IRCodeInstruction(Opcode.LOAD, dt, reg1=valueReg, value=-value)
|
code += IRInstruction(Opcode.LOAD, dt, reg1=valueReg, value=-value)
|
||||||
code += if(knownAddress!=null)
|
code += if(knownAddress!=null)
|
||||||
IRCodeInstruction(Opcode.SUBM, dt, reg1=valueReg, value=knownAddress.toInt())
|
IRInstruction(Opcode.SUBM, dt, reg1=valueReg, value=knownAddress.toInt())
|
||||||
else
|
else
|
||||||
IRCodeInstruction(Opcode.SUBM, dt, reg1=valueReg, labelSymbol = symbol)
|
IRInstruction(Opcode.SUBM, dt, reg1=valueReg, labelSymbol = symbol)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -550,9 +549,9 @@ class IRCodeGen(
|
|||||||
if(factor==1f)
|
if(factor==1f)
|
||||||
return code
|
return code
|
||||||
code += if(factor==0f) {
|
code += if(factor==0f) {
|
||||||
IRCodeInstruction(Opcode.LOAD, VmDataType.FLOAT, fpReg1 = fpReg, fpValue = 0f)
|
IRInstruction(Opcode.LOAD, VmDataType.FLOAT, fpReg1 = fpReg, fpValue = 0f)
|
||||||
} else {
|
} else {
|
||||||
IRCodeInstruction(Opcode.MUL, VmDataType.FLOAT, fpReg1 = fpReg, fpValue=factor)
|
IRInstruction(Opcode.MUL, VmDataType.FLOAT, fpReg1 = fpReg, fpValue=factor)
|
||||||
}
|
}
|
||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
@ -563,16 +562,16 @@ class IRCodeGen(
|
|||||||
return code
|
return code
|
||||||
if(factor==0f) {
|
if(factor==0f) {
|
||||||
code += if(knownAddress!=null)
|
code += if(knownAddress!=null)
|
||||||
IRCodeInstruction(Opcode.STOREZM, VmDataType.FLOAT, value = knownAddress)
|
IRInstruction(Opcode.STOREZM, VmDataType.FLOAT, value = knownAddress)
|
||||||
else
|
else
|
||||||
IRCodeInstruction(Opcode.STOREZM, VmDataType.FLOAT, labelSymbol = symbol)
|
IRInstruction(Opcode.STOREZM, VmDataType.FLOAT, labelSymbol = symbol)
|
||||||
} else {
|
} else {
|
||||||
val factorReg = vmRegisters.nextFreeFloat()
|
val factorReg = vmRegisters.nextFreeFloat()
|
||||||
code += IRCodeInstruction(Opcode.LOAD, VmDataType.FLOAT, fpReg1=factorReg, fpValue = factor)
|
code += IRInstruction(Opcode.LOAD, VmDataType.FLOAT, fpReg1=factorReg, fpValue = factor)
|
||||||
code += if(knownAddress!=null)
|
code += if(knownAddress!=null)
|
||||||
IRCodeInstruction(Opcode.MULM, VmDataType.FLOAT, fpReg1 = factorReg, value = knownAddress)
|
IRInstruction(Opcode.MULM, VmDataType.FLOAT, fpReg1 = factorReg, value = knownAddress)
|
||||||
else
|
else
|
||||||
IRCodeInstruction(Opcode.MULM, VmDataType.FLOAT, fpReg1 = factorReg, labelSymbol = symbol)
|
IRInstruction(Opcode.MULM, VmDataType.FLOAT, fpReg1 = factorReg, labelSymbol = symbol)
|
||||||
}
|
}
|
||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
@ -586,18 +585,18 @@ class IRCodeGen(
|
|||||||
val pow2 = powersOfTwo.indexOf(factor)
|
val pow2 = powersOfTwo.indexOf(factor)
|
||||||
if(pow2==1) {
|
if(pow2==1) {
|
||||||
// just shift 1 bit
|
// just shift 1 bit
|
||||||
code += IRCodeInstruction(Opcode.LSL, dt, reg1=reg)
|
code += IRInstruction(Opcode.LSL, dt, reg1=reg)
|
||||||
}
|
}
|
||||||
else if(pow2>=1) {
|
else if(pow2>=1) {
|
||||||
// just shift multiple bits
|
// just shift multiple bits
|
||||||
val pow2reg = vmRegisters.nextFree()
|
val pow2reg = vmRegisters.nextFree()
|
||||||
code += IRCodeInstruction(Opcode.LOAD, dt, reg1=pow2reg, value=pow2)
|
code += IRInstruction(Opcode.LOAD, dt, reg1=pow2reg, value=pow2)
|
||||||
code += IRCodeInstruction(Opcode.LSLN, dt, reg1=reg, reg2=pow2reg)
|
code += IRInstruction(Opcode.LSLN, dt, reg1=reg, reg2=pow2reg)
|
||||||
} else {
|
} else {
|
||||||
code += if (factor == 0) {
|
code += if (factor == 0) {
|
||||||
IRCodeInstruction(Opcode.LOAD, dt, reg1=reg, value=0)
|
IRInstruction(Opcode.LOAD, dt, reg1=reg, value=0)
|
||||||
} else {
|
} else {
|
||||||
IRCodeInstruction(Opcode.MUL, dt, reg1=reg, value=factor)
|
IRInstruction(Opcode.MUL, dt, reg1=reg, value=factor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return code
|
return code
|
||||||
@ -611,32 +610,32 @@ class IRCodeGen(
|
|||||||
if(pow2==1) {
|
if(pow2==1) {
|
||||||
// just shift 1 bit
|
// just shift 1 bit
|
||||||
code += if(knownAddress!=null)
|
code += if(knownAddress!=null)
|
||||||
IRCodeInstruction(Opcode.LSLM, dt, value = knownAddress)
|
IRInstruction(Opcode.LSLM, dt, value = knownAddress)
|
||||||
else
|
else
|
||||||
IRCodeInstruction(Opcode.LSLM, dt, labelSymbol = symbol)
|
IRInstruction(Opcode.LSLM, dt, labelSymbol = symbol)
|
||||||
}
|
}
|
||||||
else if(pow2>=1) {
|
else if(pow2>=1) {
|
||||||
// just shift multiple bits
|
// just shift multiple bits
|
||||||
val pow2reg = vmRegisters.nextFree()
|
val pow2reg = vmRegisters.nextFree()
|
||||||
code += IRCodeInstruction(Opcode.LOAD, dt, reg1=pow2reg, value=pow2)
|
code += IRInstruction(Opcode.LOAD, dt, reg1=pow2reg, value=pow2)
|
||||||
code += if(knownAddress!=null)
|
code += if(knownAddress!=null)
|
||||||
IRCodeInstruction(Opcode.LSLNM, dt, reg1=pow2reg, value=knownAddress)
|
IRInstruction(Opcode.LSLNM, dt, reg1=pow2reg, value=knownAddress)
|
||||||
else
|
else
|
||||||
IRCodeInstruction(Opcode.LSLNM, dt, reg1=pow2reg, labelSymbol = symbol)
|
IRInstruction(Opcode.LSLNM, dt, reg1=pow2reg, labelSymbol = symbol)
|
||||||
} else {
|
} else {
|
||||||
if (factor == 0) {
|
if (factor == 0) {
|
||||||
code += if(knownAddress!=null)
|
code += if(knownAddress!=null)
|
||||||
IRCodeInstruction(Opcode.STOREZM, dt, value=knownAddress)
|
IRInstruction(Opcode.STOREZM, dt, value=knownAddress)
|
||||||
else
|
else
|
||||||
IRCodeInstruction(Opcode.STOREZM, dt, labelSymbol = symbol)
|
IRInstruction(Opcode.STOREZM, dt, labelSymbol = symbol)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
val factorReg = vmRegisters.nextFree()
|
val factorReg = vmRegisters.nextFree()
|
||||||
code += IRCodeInstruction(Opcode.LOAD, dt, reg1=factorReg, value = factor)
|
code += IRInstruction(Opcode.LOAD, dt, reg1=factorReg, value = factor)
|
||||||
code += if(knownAddress!=null)
|
code += if(knownAddress!=null)
|
||||||
IRCodeInstruction(Opcode.MULM, dt, reg1=factorReg, value = knownAddress)
|
IRInstruction(Opcode.MULM, dt, reg1=factorReg, value = knownAddress)
|
||||||
else
|
else
|
||||||
IRCodeInstruction(Opcode.MULM, dt, reg1=factorReg, labelSymbol = symbol)
|
IRInstruction(Opcode.MULM, dt, reg1=factorReg, labelSymbol = symbol)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return code
|
return code
|
||||||
@ -647,9 +646,9 @@ class IRCodeGen(
|
|||||||
if(factor==1f)
|
if(factor==1f)
|
||||||
return code
|
return code
|
||||||
code += if(factor==0f) {
|
code += if(factor==0f) {
|
||||||
IRCodeInstruction(Opcode.LOAD, VmDataType.FLOAT, fpReg1 = fpReg, fpValue = Float.MAX_VALUE)
|
IRInstruction(Opcode.LOAD, VmDataType.FLOAT, fpReg1 = fpReg, fpValue = Float.MAX_VALUE)
|
||||||
} else {
|
} else {
|
||||||
IRCodeInstruction(Opcode.DIVS, VmDataType.FLOAT, fpReg1 = fpReg, fpValue=factor)
|
IRInstruction(Opcode.DIVS, VmDataType.FLOAT, fpReg1 = fpReg, fpValue=factor)
|
||||||
}
|
}
|
||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
@ -660,18 +659,18 @@ class IRCodeGen(
|
|||||||
return code
|
return code
|
||||||
if(factor==0f) {
|
if(factor==0f) {
|
||||||
val maxvalueReg = vmRegisters.nextFreeFloat()
|
val maxvalueReg = vmRegisters.nextFreeFloat()
|
||||||
code += IRCodeInstruction(Opcode.LOAD, VmDataType.FLOAT, fpReg1 = maxvalueReg, fpValue = Float.MAX_VALUE)
|
code += IRInstruction(Opcode.LOAD, VmDataType.FLOAT, fpReg1 = maxvalueReg, fpValue = Float.MAX_VALUE)
|
||||||
code += if(knownAddress!=null)
|
code += if(knownAddress!=null)
|
||||||
IRCodeInstruction(Opcode.STOREM, VmDataType.FLOAT, fpReg1 = maxvalueReg, value=knownAddress)
|
IRInstruction(Opcode.STOREM, VmDataType.FLOAT, fpReg1 = maxvalueReg, value=knownAddress)
|
||||||
else
|
else
|
||||||
IRCodeInstruction(Opcode.STOREM, VmDataType.FLOAT, fpReg1 = maxvalueReg, labelSymbol = symbol)
|
IRInstruction(Opcode.STOREM, VmDataType.FLOAT, fpReg1 = maxvalueReg, labelSymbol = symbol)
|
||||||
} else {
|
} else {
|
||||||
val factorReg = vmRegisters.nextFreeFloat()
|
val factorReg = vmRegisters.nextFreeFloat()
|
||||||
code += IRCodeInstruction(Opcode.LOAD, VmDataType.FLOAT, fpReg1=factorReg, fpValue = factor)
|
code += IRInstruction(Opcode.LOAD, VmDataType.FLOAT, fpReg1=factorReg, fpValue = factor)
|
||||||
code += if(knownAddress!=null)
|
code += if(knownAddress!=null)
|
||||||
IRCodeInstruction(Opcode.DIVSM, VmDataType.FLOAT, fpReg1 = factorReg, value=knownAddress)
|
IRInstruction(Opcode.DIVSM, VmDataType.FLOAT, fpReg1 = factorReg, value=knownAddress)
|
||||||
else
|
else
|
||||||
IRCodeInstruction(Opcode.DIVSM, VmDataType.FLOAT, fpReg1 = factorReg, labelSymbol = symbol)
|
IRInstruction(Opcode.DIVSM, VmDataType.FLOAT, fpReg1 = factorReg, labelSymbol = symbol)
|
||||||
}
|
}
|
||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
@ -682,24 +681,24 @@ class IRCodeGen(
|
|||||||
return code
|
return code
|
||||||
val pow2 = powersOfTwo.indexOf(factor)
|
val pow2 = powersOfTwo.indexOf(factor)
|
||||||
if(pow2==1 && !signed) {
|
if(pow2==1 && !signed) {
|
||||||
code += IRCodeInstruction(Opcode.LSR, dt, reg1=reg) // simple single bit shift
|
code += IRInstruction(Opcode.LSR, dt, reg1=reg) // simple single bit shift
|
||||||
}
|
}
|
||||||
else if(pow2>=1 &&!signed) {
|
else if(pow2>=1 &&!signed) {
|
||||||
// just shift multiple bits
|
// just shift multiple bits
|
||||||
val pow2reg = vmRegisters.nextFree()
|
val pow2reg = vmRegisters.nextFree()
|
||||||
code += IRCodeInstruction(Opcode.LOAD, dt, reg1=pow2reg, value=pow2)
|
code += IRInstruction(Opcode.LOAD, dt, reg1=pow2reg, value=pow2)
|
||||||
code += if(signed)
|
code += if(signed)
|
||||||
IRCodeInstruction(Opcode.ASRN, dt, reg1=reg, reg2=pow2reg)
|
IRInstruction(Opcode.ASRN, dt, reg1=reg, reg2=pow2reg)
|
||||||
else
|
else
|
||||||
IRCodeInstruction(Opcode.LSRN, dt, reg1=reg, reg2=pow2reg)
|
IRInstruction(Opcode.LSRN, dt, reg1=reg, reg2=pow2reg)
|
||||||
} else {
|
} else {
|
||||||
code += if (factor == 0) {
|
code += if (factor == 0) {
|
||||||
IRCodeInstruction(Opcode.LOAD, dt, reg1=reg, value=0xffff)
|
IRInstruction(Opcode.LOAD, dt, reg1=reg, value=0xffff)
|
||||||
} else {
|
} else {
|
||||||
if(signed)
|
if(signed)
|
||||||
IRCodeInstruction(Opcode.DIVS, dt, reg1=reg, value=factor)
|
IRInstruction(Opcode.DIVS, dt, reg1=reg, value=factor)
|
||||||
else
|
else
|
||||||
IRCodeInstruction(Opcode.DIV, dt, reg1=reg, value=factor)
|
IRInstruction(Opcode.DIV, dt, reg1=reg, value=factor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return code
|
return code
|
||||||
@ -713,49 +712,49 @@ class IRCodeGen(
|
|||||||
if(pow2==1 && !signed) {
|
if(pow2==1 && !signed) {
|
||||||
// just simple bit shift
|
// just simple bit shift
|
||||||
code += if(knownAddress!=null)
|
code += if(knownAddress!=null)
|
||||||
IRCodeInstruction(Opcode.LSRM, dt, value=knownAddress)
|
IRInstruction(Opcode.LSRM, dt, value=knownAddress)
|
||||||
else
|
else
|
||||||
IRCodeInstruction(Opcode.LSRM, dt, labelSymbol = symbol)
|
IRInstruction(Opcode.LSRM, dt, labelSymbol = symbol)
|
||||||
}
|
}
|
||||||
else if(pow2>=1 && !signed) {
|
else if(pow2>=1 && !signed) {
|
||||||
// just shift multiple bits
|
// just shift multiple bits
|
||||||
val pow2reg = vmRegisters.nextFree()
|
val pow2reg = vmRegisters.nextFree()
|
||||||
code += IRCodeInstruction(Opcode.LOAD, dt, reg1=pow2reg, value=pow2)
|
code += IRInstruction(Opcode.LOAD, dt, reg1=pow2reg, value=pow2)
|
||||||
code += if(signed) {
|
code += if(signed) {
|
||||||
if(knownAddress!=null)
|
if(knownAddress!=null)
|
||||||
IRCodeInstruction(Opcode.ASRNM, dt, reg1 = pow2reg, value = knownAddress)
|
IRInstruction(Opcode.ASRNM, dt, reg1 = pow2reg, value = knownAddress)
|
||||||
else
|
else
|
||||||
IRCodeInstruction(Opcode.ASRNM, dt, reg1 = pow2reg, labelSymbol = symbol)
|
IRInstruction(Opcode.ASRNM, dt, reg1 = pow2reg, labelSymbol = symbol)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if(knownAddress!=null)
|
if(knownAddress!=null)
|
||||||
IRCodeInstruction(Opcode.LSRNM, dt, reg1 = pow2reg, value = knownAddress)
|
IRInstruction(Opcode.LSRNM, dt, reg1 = pow2reg, value = knownAddress)
|
||||||
else
|
else
|
||||||
IRCodeInstruction(Opcode.LSRNM, dt, reg1 = pow2reg, labelSymbol = symbol)
|
IRInstruction(Opcode.LSRNM, dt, reg1 = pow2reg, labelSymbol = symbol)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (factor == 0) {
|
if (factor == 0) {
|
||||||
val reg = vmRegisters.nextFree()
|
val reg = vmRegisters.nextFree()
|
||||||
code += IRCodeInstruction(Opcode.LOAD, dt, reg1=reg, value=0xffff)
|
code += IRInstruction(Opcode.LOAD, dt, reg1=reg, value=0xffff)
|
||||||
code += if(knownAddress!=null)
|
code += if(knownAddress!=null)
|
||||||
IRCodeInstruction(Opcode.STOREM, dt, reg1=reg, value=knownAddress)
|
IRInstruction(Opcode.STOREM, dt, reg1=reg, value=knownAddress)
|
||||||
else
|
else
|
||||||
IRCodeInstruction(Opcode.STOREM, dt, reg1=reg, labelSymbol = symbol)
|
IRInstruction(Opcode.STOREM, dt, reg1=reg, labelSymbol = symbol)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
val factorReg = vmRegisters.nextFree()
|
val factorReg = vmRegisters.nextFree()
|
||||||
code += IRCodeInstruction(Opcode.LOAD, dt, reg1=factorReg, value= factor)
|
code += IRInstruction(Opcode.LOAD, dt, reg1=factorReg, value= factor)
|
||||||
code += if(signed) {
|
code += if(signed) {
|
||||||
if(knownAddress!=null)
|
if(knownAddress!=null)
|
||||||
IRCodeInstruction(Opcode.DIVSM, dt, reg1 = factorReg, value = knownAddress)
|
IRInstruction(Opcode.DIVSM, dt, reg1 = factorReg, value = knownAddress)
|
||||||
else
|
else
|
||||||
IRCodeInstruction(Opcode.DIVSM, dt, reg1 = factorReg, labelSymbol = symbol)
|
IRInstruction(Opcode.DIVSM, dt, reg1 = factorReg, labelSymbol = symbol)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if(knownAddress!=null)
|
if(knownAddress!=null)
|
||||||
IRCodeInstruction(Opcode.DIVM, dt, reg1 = factorReg, value = knownAddress)
|
IRInstruction(Opcode.DIVM, dt, reg1 = factorReg, value = knownAddress)
|
||||||
else
|
else
|
||||||
IRCodeInstruction(Opcode.DIVM, dt, reg1 = factorReg, labelSymbol = symbol)
|
IRInstruction(Opcode.DIVM, dt, reg1 = factorReg, labelSymbol = symbol)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -789,16 +788,16 @@ class IRCodeGen(
|
|||||||
// if and else parts
|
// if and else parts
|
||||||
val elseLabel = createLabelName()
|
val elseLabel = createLabelName()
|
||||||
val afterIfLabel = createLabelName()
|
val afterIfLabel = createLabelName()
|
||||||
code += IRCodeInstruction(elseBranch, vmDt, reg1=leftReg, reg2=rightReg, labelSymbol = elseLabel)
|
code += IRInstruction(elseBranch, vmDt, reg1=leftReg, reg2=rightReg, labelSymbol = elseLabel)
|
||||||
code += translateNode(ifElse.ifScope)
|
code += translateNode(ifElse.ifScope)
|
||||||
code += IRCodeInstruction(Opcode.JUMP, labelSymbol = afterIfLabel)
|
code += IRInstruction(Opcode.JUMP, labelSymbol = afterIfLabel)
|
||||||
code += IRCodeLabel(elseLabel)
|
code += IRCodeLabel(elseLabel)
|
||||||
code += translateNode(ifElse.elseScope)
|
code += translateNode(ifElse.elseScope)
|
||||||
code += IRCodeLabel(afterIfLabel)
|
code += IRCodeLabel(afterIfLabel)
|
||||||
} else {
|
} else {
|
||||||
// only if part
|
// only if part
|
||||||
val afterIfLabel = createLabelName()
|
val afterIfLabel = createLabelName()
|
||||||
code += IRCodeInstruction(elseBranch, vmDt, reg1=leftReg, reg2=rightReg, labelSymbol = afterIfLabel)
|
code += IRInstruction(elseBranch, vmDt, reg1=leftReg, reg2=rightReg, labelSymbol = afterIfLabel)
|
||||||
code += translateNode(ifElse.ifScope)
|
code += translateNode(ifElse.ifScope)
|
||||||
code += IRCodeLabel(afterIfLabel)
|
code += IRCodeLabel(afterIfLabel)
|
||||||
}
|
}
|
||||||
@ -813,16 +812,16 @@ class IRCodeGen(
|
|||||||
// if and else parts
|
// if and else parts
|
||||||
val elseLabel = createLabelName()
|
val elseLabel = createLabelName()
|
||||||
val afterIfLabel = createLabelName()
|
val afterIfLabel = createLabelName()
|
||||||
code += IRCodeInstruction(elseBranch, vmDt, reg1=leftReg, labelSymbol = elseLabel)
|
code += IRInstruction(elseBranch, vmDt, reg1=leftReg, labelSymbol = elseLabel)
|
||||||
code += translateNode(ifElse.ifScope)
|
code += translateNode(ifElse.ifScope)
|
||||||
code += IRCodeInstruction(Opcode.JUMP, labelSymbol = afterIfLabel)
|
code += IRInstruction(Opcode.JUMP, labelSymbol = afterIfLabel)
|
||||||
code += IRCodeLabel(elseLabel)
|
code += IRCodeLabel(elseLabel)
|
||||||
code += translateNode(ifElse.elseScope)
|
code += translateNode(ifElse.elseScope)
|
||||||
code += IRCodeLabel(afterIfLabel)
|
code += IRCodeLabel(afterIfLabel)
|
||||||
} else {
|
} else {
|
||||||
// only if part
|
// only if part
|
||||||
val afterIfLabel = createLabelName()
|
val afterIfLabel = createLabelName()
|
||||||
code += IRCodeInstruction(elseBranch, vmDt, reg1=leftReg, labelSymbol = afterIfLabel)
|
code += IRInstruction(elseBranch, vmDt, reg1=leftReg, labelSymbol = afterIfLabel)
|
||||||
code += translateNode(ifElse.ifScope)
|
code += translateNode(ifElse.ifScope)
|
||||||
code += IRCodeLabel(afterIfLabel)
|
code += IRCodeLabel(afterIfLabel)
|
||||||
}
|
}
|
||||||
@ -871,18 +870,18 @@ class IRCodeGen(
|
|||||||
val array = postIncrDecr.target.array
|
val array = postIncrDecr.target.array
|
||||||
val vmDt = vmType(postIncrDecr.target.type)
|
val vmDt = vmType(postIncrDecr.target.type)
|
||||||
if(ident!=null) {
|
if(ident!=null) {
|
||||||
code += IRCodeInstruction(operationMem, vmDt, labelSymbol = ident.targetName.joinToString("."))
|
code += IRInstruction(operationMem, vmDt, labelSymbol = ident.targetName.joinToString("."))
|
||||||
} else if(memory!=null) {
|
} else if(memory!=null) {
|
||||||
if(memory.address is PtNumber) {
|
if(memory.address is PtNumber) {
|
||||||
val address = (memory.address as PtNumber).number.toInt()
|
val address = (memory.address as PtNumber).number.toInt()
|
||||||
code += IRCodeInstruction(operationMem, vmDt, value = address)
|
code += IRInstruction(operationMem, vmDt, value = address)
|
||||||
} else {
|
} else {
|
||||||
val incReg = vmRegisters.nextFree()
|
val incReg = vmRegisters.nextFree()
|
||||||
val addressReg = vmRegisters.nextFree()
|
val addressReg = vmRegisters.nextFree()
|
||||||
code += expressionEval.translateExpression(memory.address, addressReg, -1)
|
code += expressionEval.translateExpression(memory.address, addressReg, -1)
|
||||||
code += IRCodeInstruction(Opcode.LOADI, vmDt, reg1 = incReg, reg2 = addressReg)
|
code += IRInstruction(Opcode.LOADI, vmDt, reg1 = incReg, reg2 = addressReg)
|
||||||
code += IRCodeInstruction(operationRegister, vmDt, reg1 = incReg)
|
code += IRInstruction(operationRegister, vmDt, reg1 = incReg)
|
||||||
code += IRCodeInstruction(Opcode.STOREI, vmDt, reg1 = incReg, reg2 = addressReg)
|
code += IRInstruction(Opcode.STOREI, vmDt, reg1 = incReg, reg2 = addressReg)
|
||||||
}
|
}
|
||||||
} else if (array!=null) {
|
} else if (array!=null) {
|
||||||
val variable = array.variable.targetName.joinToString(".")
|
val variable = array.variable.targetName.joinToString(".")
|
||||||
@ -890,14 +889,14 @@ class IRCodeGen(
|
|||||||
val fixedIndex = constIntValue(array.index)
|
val fixedIndex = constIntValue(array.index)
|
||||||
if(fixedIndex!=null) {
|
if(fixedIndex!=null) {
|
||||||
val offset = fixedIndex*itemsize
|
val offset = fixedIndex*itemsize
|
||||||
code += IRCodeInstruction(operationMem, vmDt, labelSymbol="$variable+$offset")
|
code += IRInstruction(operationMem, vmDt, labelSymbol="$variable+$offset")
|
||||||
} else {
|
} else {
|
||||||
val incReg = vmRegisters.nextFree()
|
val incReg = vmRegisters.nextFree()
|
||||||
val indexReg = vmRegisters.nextFree()
|
val indexReg = vmRegisters.nextFree()
|
||||||
code += expressionEval.translateExpression(array.index, indexReg, -1)
|
code += expressionEval.translateExpression(array.index, indexReg, -1)
|
||||||
code += IRCodeInstruction(Opcode.LOADX, vmDt, reg1=incReg, reg2=indexReg, labelSymbol=variable)
|
code += IRInstruction(Opcode.LOADX, vmDt, reg1=incReg, reg2=indexReg, labelSymbol=variable)
|
||||||
code += IRCodeInstruction(operationRegister, vmDt, reg1=incReg)
|
code += IRInstruction(operationRegister, vmDt, reg1=incReg)
|
||||||
code += IRCodeInstruction(Opcode.STOREX, vmDt, reg1=incReg, reg2=indexReg, labelSymbol=variable)
|
code += IRInstruction(Opcode.STOREX, vmDt, reg1=incReg, reg2=indexReg, labelSymbol=variable)
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
throw AssemblyError("weird assigntarget")
|
throw AssemblyError("weird assigntarget")
|
||||||
@ -921,11 +920,11 @@ class IRCodeGen(
|
|||||||
val counterReg = vmRegisters.nextFree()
|
val counterReg = vmRegisters.nextFree()
|
||||||
val vmDt = vmType(repeat.count.type)
|
val vmDt = vmType(repeat.count.type)
|
||||||
code += expressionEval.translateExpression(repeat.count, counterReg, -1)
|
code += expressionEval.translateExpression(repeat.count, counterReg, -1)
|
||||||
code += IRCodeInstruction(Opcode.BZ, vmDt, reg1=counterReg, labelSymbol = skipRepeatLabel)
|
code += IRInstruction(Opcode.BZ, vmDt, reg1=counterReg, labelSymbol = skipRepeatLabel)
|
||||||
code += IRCodeLabel(repeatLabel)
|
code += IRCodeLabel(repeatLabel)
|
||||||
code += translateNode(repeat.statements)
|
code += translateNode(repeat.statements)
|
||||||
code += IRCodeInstruction(Opcode.DEC, vmDt, reg1=counterReg)
|
code += IRInstruction(Opcode.DEC, vmDt, reg1=counterReg)
|
||||||
code += IRCodeInstruction(Opcode.BNZ, vmDt, reg1=counterReg, labelSymbol = repeatLabel)
|
code += IRInstruction(Opcode.BNZ, vmDt, reg1=counterReg, labelSymbol = repeatLabel)
|
||||||
code += IRCodeLabel(skipRepeatLabel)
|
code += IRCodeLabel(skipRepeatLabel)
|
||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
@ -935,9 +934,9 @@ class IRCodeGen(
|
|||||||
if(jump.address!=null)
|
if(jump.address!=null)
|
||||||
throw AssemblyError("cannot jump to memory location in the vm target")
|
throw AssemblyError("cannot jump to memory location in the vm target")
|
||||||
code += if(jump.generatedLabel!=null)
|
code += if(jump.generatedLabel!=null)
|
||||||
IRCodeInstruction(Opcode.JUMP, labelSymbol = jump.generatedLabel!!)
|
IRInstruction(Opcode.JUMP, labelSymbol = jump.generatedLabel!!)
|
||||||
else if(jump.identifier!=null)
|
else if(jump.identifier!=null)
|
||||||
IRCodeInstruction(Opcode.JUMP, labelSymbol = jump.identifier!!.targetName.joinToString("."))
|
IRInstruction(Opcode.JUMP, labelSymbol = jump.identifier!!.targetName.joinToString("."))
|
||||||
else
|
else
|
||||||
throw AssemblyError("weird jump")
|
throw AssemblyError("weird jump")
|
||||||
return code
|
return code
|
||||||
@ -959,7 +958,7 @@ class IRCodeGen(
|
|||||||
else
|
else
|
||||||
expressionEval.translateExpression(value, 0, -1)
|
expressionEval.translateExpression(value, 0, -1)
|
||||||
}
|
}
|
||||||
code += IRCodeInstruction(Opcode.RETURN)
|
code += IRInstruction(Opcode.RETURN)
|
||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1037,10 +1036,4 @@ class IRCodeGen(
|
|||||||
internal fun isZero(expression: PtExpression): Boolean = expression is PtNumber && expression.number==0.0
|
internal fun isZero(expression: PtExpression): Boolean = expression is PtNumber && expression.number==0.0
|
||||||
|
|
||||||
internal fun isOne(expression: PtExpression): Boolean = expression is PtNumber && expression.number==1.0
|
internal fun isOne(expression: PtExpression): Boolean = expression is PtNumber && expression.number==1.0
|
||||||
|
|
||||||
fun addMemorySlab(name: String, size: UInt, align: UInt, position: Position): String {
|
|
||||||
val scopedName = "prog8_memoryslab_$name"
|
|
||||||
symbolTable.add(StMemorySlab(scopedName, size, align, position))
|
|
||||||
return scopedName
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -10,8 +10,8 @@ internal class IRPeepholeOptimizer(private val irprog: IRProgram) {
|
|||||||
if(chunk is IRCodeChunk) {
|
if(chunk is IRCodeChunk) {
|
||||||
do {
|
do {
|
||||||
val indexedInstructions = chunk.lines.withIndex()
|
val indexedInstructions = chunk.lines.withIndex()
|
||||||
.filter { it.value is IRCodeInstruction }
|
.filter { it.value is IRInstruction }
|
||||||
.map { IndexedValue(it.index, (it.value as IRCodeInstruction).ins) }
|
.map { IndexedValue(it.index, it.value as IRInstruction) }
|
||||||
val changed = removeNops(chunk, indexedInstructions)
|
val changed = removeNops(chunk, indexedInstructions)
|
||||||
|| removeDoubleLoadsAndStores(chunk, indexedInstructions) // TODO not yet implemented
|
|| removeDoubleLoadsAndStores(chunk, indexedInstructions) // TODO not yet implemented
|
||||||
|| removeUselessArithmetic(chunk, indexedInstructions)
|
|| removeUselessArithmetic(chunk, indexedInstructions)
|
||||||
@ -26,19 +26,19 @@ internal class IRPeepholeOptimizer(private val irprog: IRProgram) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun cleanupPushPop(chunk: IRCodeChunk, indexedInstructions: List<IndexedValue<Instruction>>): Boolean {
|
private fun cleanupPushPop(chunk: IRCodeChunk, indexedInstructions: List<IndexedValue<IRInstruction>>): Boolean {
|
||||||
// push followed by pop to same target, or different target->replace with load
|
// push followed by pop to same target, or different target->replace with load
|
||||||
var changed = false
|
var changed = false
|
||||||
indexedInstructions.reversed().forEach { (idx, ins) ->
|
indexedInstructions.reversed().forEach { (idx, ins) ->
|
||||||
if(ins.opcode== Opcode.PUSH) {
|
if(ins.opcode== Opcode.PUSH) {
|
||||||
if(idx < chunk.lines.size-1) {
|
if(idx < chunk.lines.size-1) {
|
||||||
val insAfter = chunk.lines[idx+1] as? IRCodeInstruction
|
val insAfter = chunk.lines[idx+1] as? IRInstruction
|
||||||
if(insAfter!=null && insAfter.ins.opcode == Opcode.POP) {
|
if(insAfter!=null && insAfter.opcode == Opcode.POP) {
|
||||||
if(ins.reg1==insAfter.ins.reg1) {
|
if(ins.reg1==insAfter.reg1) {
|
||||||
chunk.lines.removeAt(idx)
|
chunk.lines.removeAt(idx)
|
||||||
chunk.lines.removeAt(idx)
|
chunk.lines.removeAt(idx)
|
||||||
} else {
|
} else {
|
||||||
chunk.lines[idx] = IRCodeInstruction(Opcode.LOADR, ins.type, reg1=insAfter.ins.reg1, reg2=ins.reg1)
|
chunk.lines[idx] = IRInstruction(Opcode.LOADR, ins.type, reg1=insAfter.reg1, reg2=ins.reg1)
|
||||||
chunk.lines.removeAt(idx+1)
|
chunk.lines.removeAt(idx+1)
|
||||||
}
|
}
|
||||||
changed = true
|
changed = true
|
||||||
@ -49,23 +49,23 @@ internal class IRPeepholeOptimizer(private val irprog: IRProgram) {
|
|||||||
return changed
|
return changed
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun removeDoubleSecClc(chunk: IRCodeChunk, indexedInstructions: List<IndexedValue<Instruction>>): Boolean {
|
private fun removeDoubleSecClc(chunk: IRCodeChunk, indexedInstructions: List<IndexedValue<IRInstruction>>): Boolean {
|
||||||
// double sec, clc
|
// double sec, clc
|
||||||
// sec+clc or clc+sec
|
// sec+clc or clc+sec
|
||||||
var changed = false
|
var changed = false
|
||||||
indexedInstructions.reversed().forEach { (idx, ins) ->
|
indexedInstructions.reversed().forEach { (idx, ins) ->
|
||||||
if(ins.opcode== Opcode.SEC || ins.opcode== Opcode.CLC) {
|
if(ins.opcode== Opcode.SEC || ins.opcode== Opcode.CLC) {
|
||||||
if(idx < chunk.lines.size-1) {
|
if(idx < chunk.lines.size-1) {
|
||||||
val insAfter = chunk.lines[idx+1] as? IRCodeInstruction
|
val insAfter = chunk.lines[idx+1] as? IRInstruction
|
||||||
if(insAfter?.ins?.opcode == ins.opcode) {
|
if(insAfter?.opcode == ins.opcode) {
|
||||||
chunk.lines.removeAt(idx)
|
chunk.lines.removeAt(idx)
|
||||||
changed = true
|
changed = true
|
||||||
}
|
}
|
||||||
else if(ins.opcode== Opcode.SEC && insAfter?.ins?.opcode== Opcode.CLC) {
|
else if(ins.opcode== Opcode.SEC && insAfter?.opcode== Opcode.CLC) {
|
||||||
chunk.lines.removeAt(idx)
|
chunk.lines.removeAt(idx)
|
||||||
changed = true
|
changed = true
|
||||||
}
|
}
|
||||||
else if(ins.opcode== Opcode.CLC && insAfter?.ins?.opcode== Opcode.SEC) {
|
else if(ins.opcode== Opcode.CLC && insAfter?.opcode== Opcode.SEC) {
|
||||||
chunk.lines.removeAt(idx)
|
chunk.lines.removeAt(idx)
|
||||||
changed = true
|
changed = true
|
||||||
}
|
}
|
||||||
@ -75,7 +75,7 @@ internal class IRPeepholeOptimizer(private val irprog: IRProgram) {
|
|||||||
return changed
|
return changed
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun removeWeirdBranches(chunk: IRCodeChunk, indexedInstructions: List<IndexedValue<Instruction>>): Boolean {
|
private fun removeWeirdBranches(chunk: IRCodeChunk, indexedInstructions: List<IndexedValue<IRInstruction>>): Boolean {
|
||||||
// jump/branch to label immediately below
|
// jump/branch to label immediately below
|
||||||
var changed = false
|
var changed = false
|
||||||
indexedInstructions.reversed().forEach { (idx, ins) ->
|
indexedInstructions.reversed().forEach { (idx, ins) ->
|
||||||
@ -84,7 +84,7 @@ internal class IRPeepholeOptimizer(private val irprog: IRProgram) {
|
|||||||
// if jumping to label immediately following this
|
// if jumping to label immediately following this
|
||||||
if(idx < chunk.lines.size-1) {
|
if(idx < chunk.lines.size-1) {
|
||||||
val label = chunk.lines[idx+1] as? IRCodeLabel
|
val label = chunk.lines[idx+1] as? IRCodeLabel
|
||||||
if(labelSymbol.size==1 && label?.name == labelSymbol[0]) {
|
if(label?.name == labelSymbol) {
|
||||||
chunk.lines.removeAt(idx)
|
chunk.lines.removeAt(idx)
|
||||||
changed = true
|
changed = true
|
||||||
}
|
}
|
||||||
@ -94,7 +94,7 @@ internal class IRPeepholeOptimizer(private val irprog: IRProgram) {
|
|||||||
return changed
|
return changed
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun removeUselessArithmetic(chunk: IRCodeChunk, indexedInstructions: List<IndexedValue<Instruction>>): Boolean {
|
private fun removeUselessArithmetic(chunk: IRCodeChunk, indexedInstructions: List<IndexedValue<IRInstruction>>): Boolean {
|
||||||
// note: this is hard to solve for the non-immediate instructions atm because the values are loaded into registers first
|
// note: this is hard to solve for the non-immediate instructions atm because the values are loaded into registers first
|
||||||
var changed = false
|
var changed = false
|
||||||
indexedInstructions.reversed().forEach { (idx, ins) ->
|
indexedInstructions.reversed().forEach { (idx, ins) ->
|
||||||
@ -107,7 +107,7 @@ internal class IRPeepholeOptimizer(private val irprog: IRProgram) {
|
|||||||
}
|
}
|
||||||
Opcode.ADD, Opcode.SUB -> {
|
Opcode.ADD, Opcode.SUB -> {
|
||||||
if (ins.value == 1) {
|
if (ins.value == 1) {
|
||||||
chunk.lines[idx] = IRCodeInstruction(
|
chunk.lines[idx] = IRInstruction(
|
||||||
if (ins.opcode == Opcode.ADD) Opcode.INC else Opcode.DEC,
|
if (ins.opcode == Opcode.ADD) Opcode.INC else Opcode.DEC,
|
||||||
ins.type,
|
ins.type,
|
||||||
ins.reg1
|
ins.reg1
|
||||||
@ -120,7 +120,7 @@ internal class IRPeepholeOptimizer(private val irprog: IRProgram) {
|
|||||||
}
|
}
|
||||||
Opcode.AND -> {
|
Opcode.AND -> {
|
||||||
if (ins.value == 0) {
|
if (ins.value == 0) {
|
||||||
chunk.lines[idx] = IRCodeInstruction(Opcode.LOAD, ins.type, reg1 = ins.reg1, value = 0)
|
chunk.lines[idx] = IRInstruction(Opcode.LOAD, ins.type, reg1 = ins.reg1, value = 0)
|
||||||
changed = true
|
changed = true
|
||||||
} else if (ins.value == 255 && ins.type == VmDataType.BYTE) {
|
} else if (ins.value == 255 && ins.type == VmDataType.BYTE) {
|
||||||
chunk.lines.removeAt(idx)
|
chunk.lines.removeAt(idx)
|
||||||
@ -135,7 +135,7 @@ internal class IRPeepholeOptimizer(private val irprog: IRProgram) {
|
|||||||
chunk.lines.removeAt(idx)
|
chunk.lines.removeAt(idx)
|
||||||
changed = true
|
changed = true
|
||||||
} else if ((ins.value == 255 && ins.type == VmDataType.BYTE) || (ins.value == 65535 && ins.type == VmDataType.WORD)) {
|
} else if ((ins.value == 255 && ins.type == VmDataType.BYTE) || (ins.value == 65535 && ins.type == VmDataType.WORD)) {
|
||||||
chunk.lines[idx] = IRCodeInstruction(Opcode.LOAD, ins.type, reg1 = ins.reg1, value = ins.value)
|
chunk.lines[idx] = IRInstruction(Opcode.LOAD, ins.type, reg1 = ins.reg1, value = ins.value)
|
||||||
changed = true
|
changed = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -151,7 +151,7 @@ internal class IRPeepholeOptimizer(private val irprog: IRProgram) {
|
|||||||
return changed
|
return changed
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun removeNops(chunk: IRCodeChunk, indexedInstructions: List<IndexedValue<Instruction>>): Boolean {
|
private fun removeNops(chunk: IRCodeChunk, indexedInstructions: List<IndexedValue<IRInstruction>>): Boolean {
|
||||||
var changed = false
|
var changed = false
|
||||||
indexedInstructions.reversed().forEach { (idx, ins) ->
|
indexedInstructions.reversed().forEach { (idx, ins) ->
|
||||||
if (ins.opcode == Opcode.NOP) {
|
if (ins.opcode == Opcode.NOP) {
|
||||||
@ -162,7 +162,7 @@ internal class IRPeepholeOptimizer(private val irprog: IRProgram) {
|
|||||||
return changed
|
return changed
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun removeDoubleLoadsAndStores(chunk: IRCodeChunk, indexedInstructions: List<IndexedValue<Instruction>>): Boolean {
|
private fun removeDoubleLoadsAndStores(chunk: IRCodeChunk, indexedInstructions: List<IndexedValue<IRInstruction>>): Boolean {
|
||||||
var changed = false
|
var changed = false
|
||||||
indexedInstructions.forEach { (idx, ins) ->
|
indexedInstructions.forEach { (idx, ins) ->
|
||||||
|
|
||||||
|
@ -34,9 +34,9 @@ class TestIRPeepholeOpt: FunSpec({
|
|||||||
|
|
||||||
test("remove nops") {
|
test("remove nops") {
|
||||||
val irProg = makeIRProgram(listOf(
|
val irProg = makeIRProgram(listOf(
|
||||||
IRCodeInstruction(Opcode.JUMP, labelSymbol = "dummy"),
|
IRInstruction(Opcode.JUMP, labelSymbol = "dummy"),
|
||||||
IRCodeInstruction(Opcode.NOP),
|
IRInstruction(Opcode.NOP),
|
||||||
IRCodeInstruction(Opcode.NOP)
|
IRInstruction(Opcode.NOP)
|
||||||
))
|
))
|
||||||
irProg.lines().size shouldBe 3
|
irProg.lines().size shouldBe 3
|
||||||
val opt = IRPeepholeOptimizer(irProg)
|
val opt = IRPeepholeOptimizer(irProg)
|
||||||
@ -46,13 +46,13 @@ class TestIRPeepholeOpt: FunSpec({
|
|||||||
|
|
||||||
test("remove jmp to label below") {
|
test("remove jmp to label below") {
|
||||||
val irProg = makeIRProgram(listOf(
|
val irProg = makeIRProgram(listOf(
|
||||||
IRCodeInstruction(Opcode.JUMP, labelSymbol = "label"), // removed
|
IRInstruction(Opcode.JUMP, labelSymbol = "label"), // removed
|
||||||
IRCodeLabel("label"),
|
IRCodeLabel("label"),
|
||||||
IRCodeInstruction(Opcode.JUMP, labelSymbol = "label2"), // removed
|
IRInstruction(Opcode.JUMP, labelSymbol = "label2"), // removed
|
||||||
IRCodeInstruction(Opcode.NOP), // removed
|
IRInstruction(Opcode.NOP), // removed
|
||||||
IRCodeLabel("label2"),
|
IRCodeLabel("label2"),
|
||||||
IRCodeInstruction(Opcode.JUMP, labelSymbol = "label3"),
|
IRInstruction(Opcode.JUMP, labelSymbol = "label3"),
|
||||||
IRCodeInstruction(Opcode.INC, VmDataType.BYTE, reg1=1),
|
IRInstruction(Opcode.INC, VmDataType.BYTE, reg1=1),
|
||||||
IRCodeLabel("label3")
|
IRCodeLabel("label3")
|
||||||
))
|
))
|
||||||
irProg.lines().size shouldBe 8
|
irProg.lines().size shouldBe 8
|
||||||
@ -62,57 +62,57 @@ class TestIRPeepholeOpt: FunSpec({
|
|||||||
lines.size shouldBe 5
|
lines.size shouldBe 5
|
||||||
(lines[0] as IRCodeLabel).name shouldBe "label"
|
(lines[0] as IRCodeLabel).name shouldBe "label"
|
||||||
(lines[1] as IRCodeLabel).name shouldBe "label2"
|
(lines[1] as IRCodeLabel).name shouldBe "label2"
|
||||||
(lines[2] as IRCodeInstruction).ins.opcode shouldBe Opcode.JUMP
|
(lines[2] as IRInstruction).opcode shouldBe Opcode.JUMP
|
||||||
(lines[3] as IRCodeInstruction).ins.opcode shouldBe Opcode.INC
|
(lines[3] as IRInstruction).opcode shouldBe Opcode.INC
|
||||||
(lines[4] as IRCodeLabel).name shouldBe "label3"
|
(lines[4] as IRCodeLabel).name shouldBe "label3"
|
||||||
}
|
}
|
||||||
|
|
||||||
test("remove double sec/clc") {
|
test("remove double sec/clc") {
|
||||||
val irProg = makeIRProgram(listOf(
|
val irProg = makeIRProgram(listOf(
|
||||||
IRCodeInstruction(Opcode.SEC),
|
IRInstruction(Opcode.SEC),
|
||||||
IRCodeInstruction(Opcode.SEC),
|
IRInstruction(Opcode.SEC),
|
||||||
IRCodeInstruction(Opcode.SEC),
|
IRInstruction(Opcode.SEC),
|
||||||
IRCodeInstruction(Opcode.CLC),
|
IRInstruction(Opcode.CLC),
|
||||||
IRCodeInstruction(Opcode.CLC),
|
IRInstruction(Opcode.CLC),
|
||||||
IRCodeInstruction(Opcode.CLC)
|
IRInstruction(Opcode.CLC)
|
||||||
))
|
))
|
||||||
irProg.lines().size shouldBe 6
|
irProg.lines().size shouldBe 6
|
||||||
val opt = IRPeepholeOptimizer(irProg)
|
val opt = IRPeepholeOptimizer(irProg)
|
||||||
opt.optimize()
|
opt.optimize()
|
||||||
val lines = irProg.lines()
|
val lines = irProg.lines()
|
||||||
lines.size shouldBe 1
|
lines.size shouldBe 1
|
||||||
(lines[0] as IRCodeInstruction).ins.opcode shouldBe Opcode.CLC
|
(lines[0] as IRInstruction).opcode shouldBe Opcode.CLC
|
||||||
}
|
}
|
||||||
|
|
||||||
test("push followed by pop") {
|
test("push followed by pop") {
|
||||||
val irProg = makeIRProgram(listOf(
|
val irProg = makeIRProgram(listOf(
|
||||||
IRCodeInstruction(Opcode.PUSH, VmDataType.BYTE, reg1=42),
|
IRInstruction(Opcode.PUSH, VmDataType.BYTE, reg1=42),
|
||||||
IRCodeInstruction(Opcode.POP, VmDataType.BYTE, reg1=42),
|
IRInstruction(Opcode.POP, VmDataType.BYTE, reg1=42),
|
||||||
IRCodeInstruction(Opcode.PUSH, VmDataType.BYTE, reg1=99),
|
IRInstruction(Opcode.PUSH, VmDataType.BYTE, reg1=99),
|
||||||
IRCodeInstruction(Opcode.POP, VmDataType.BYTE, reg1=222)
|
IRInstruction(Opcode.POP, VmDataType.BYTE, reg1=222)
|
||||||
))
|
))
|
||||||
irProg.lines().size shouldBe 4
|
irProg.lines().size shouldBe 4
|
||||||
val opt = IRPeepholeOptimizer(irProg)
|
val opt = IRPeepholeOptimizer(irProg)
|
||||||
opt.optimize()
|
opt.optimize()
|
||||||
val lines = irProg.lines()
|
val lines = irProg.lines()
|
||||||
lines.size shouldBe 1
|
lines.size shouldBe 1
|
||||||
(lines[0] as IRCodeInstruction).ins.opcode shouldBe Opcode.LOADR
|
(lines[0] as IRInstruction).opcode shouldBe Opcode.LOADR
|
||||||
(lines[0] as IRCodeInstruction).ins.reg1 shouldBe 222
|
(lines[0] as IRInstruction).reg1 shouldBe 222
|
||||||
(lines[0] as IRCodeInstruction).ins.reg2 shouldBe 99
|
(lines[0] as IRInstruction).reg2 shouldBe 99
|
||||||
}
|
}
|
||||||
|
|
||||||
test("remove useless div/mul, add/sub") {
|
test("remove useless div/mul, add/sub") {
|
||||||
val irProg = makeIRProgram(listOf(
|
val irProg = makeIRProgram(listOf(
|
||||||
IRCodeInstruction(Opcode.DIV, VmDataType.BYTE, reg1=42, value = 1),
|
IRInstruction(Opcode.DIV, VmDataType.BYTE, reg1=42, value = 1),
|
||||||
IRCodeInstruction(Opcode.DIVS, VmDataType.BYTE, reg1=42, value = 1),
|
IRInstruction(Opcode.DIVS, VmDataType.BYTE, reg1=42, value = 1),
|
||||||
IRCodeInstruction(Opcode.MUL, VmDataType.BYTE, reg1=42, value = 1),
|
IRInstruction(Opcode.MUL, VmDataType.BYTE, reg1=42, value = 1),
|
||||||
IRCodeInstruction(Opcode.MOD, VmDataType.BYTE, reg1=42, value = 1),
|
IRInstruction(Opcode.MOD, VmDataType.BYTE, reg1=42, value = 1),
|
||||||
IRCodeInstruction(Opcode.DIV, VmDataType.BYTE, reg1=42, value = 2),
|
IRInstruction(Opcode.DIV, VmDataType.BYTE, reg1=42, value = 2),
|
||||||
IRCodeInstruction(Opcode.DIVS, VmDataType.BYTE, reg1=42, value = 2),
|
IRInstruction(Opcode.DIVS, VmDataType.BYTE, reg1=42, value = 2),
|
||||||
IRCodeInstruction(Opcode.MUL, VmDataType.BYTE, reg1=42, value = 2),
|
IRInstruction(Opcode.MUL, VmDataType.BYTE, reg1=42, value = 2),
|
||||||
IRCodeInstruction(Opcode.MOD, VmDataType.BYTE, reg1=42, value = 2),
|
IRInstruction(Opcode.MOD, VmDataType.BYTE, reg1=42, value = 2),
|
||||||
IRCodeInstruction(Opcode.ADD, VmDataType.BYTE, reg1=42, value = 0),
|
IRInstruction(Opcode.ADD, VmDataType.BYTE, reg1=42, value = 0),
|
||||||
IRCodeInstruction(Opcode.SUB, VmDataType.BYTE, reg1=42, value = 0)
|
IRInstruction(Opcode.SUB, VmDataType.BYTE, reg1=42, value = 0)
|
||||||
))
|
))
|
||||||
irProg.lines().size shouldBe 10
|
irProg.lines().size shouldBe 10
|
||||||
val opt = IRPeepholeOptimizer(irProg)
|
val opt = IRPeepholeOptimizer(irProg)
|
||||||
@ -123,28 +123,28 @@ class TestIRPeepholeOpt: FunSpec({
|
|||||||
|
|
||||||
test("replace add/sub 1 by inc/dec") {
|
test("replace add/sub 1 by inc/dec") {
|
||||||
val irProg = makeIRProgram(listOf(
|
val irProg = makeIRProgram(listOf(
|
||||||
IRCodeInstruction(Opcode.ADD, VmDataType.BYTE, reg1=42, value = 1),
|
IRInstruction(Opcode.ADD, VmDataType.BYTE, reg1=42, value = 1),
|
||||||
IRCodeInstruction(Opcode.SUB, VmDataType.BYTE, reg1=42, value = 1)
|
IRInstruction(Opcode.SUB, VmDataType.BYTE, reg1=42, value = 1)
|
||||||
))
|
))
|
||||||
irProg.lines().size shouldBe 2
|
irProg.lines().size shouldBe 2
|
||||||
val opt = IRPeepholeOptimizer(irProg)
|
val opt = IRPeepholeOptimizer(irProg)
|
||||||
opt.optimize()
|
opt.optimize()
|
||||||
val lines = irProg.lines()
|
val lines = irProg.lines()
|
||||||
lines.size shouldBe 2
|
lines.size shouldBe 2
|
||||||
(lines[0] as IRCodeInstruction).ins.opcode shouldBe Opcode.INC
|
(lines[0] as IRInstruction).opcode shouldBe Opcode.INC
|
||||||
(lines[1] as IRCodeInstruction).ins.opcode shouldBe Opcode.DEC
|
(lines[1] as IRInstruction).opcode shouldBe Opcode.DEC
|
||||||
}
|
}
|
||||||
|
|
||||||
test("remove useless and/or/xor") {
|
test("remove useless and/or/xor") {
|
||||||
val irProg = makeIRProgram(listOf(
|
val irProg = makeIRProgram(listOf(
|
||||||
IRCodeInstruction(Opcode.AND, VmDataType.BYTE, reg1=42, value = 255),
|
IRInstruction(Opcode.AND, VmDataType.BYTE, reg1=42, value = 255),
|
||||||
IRCodeInstruction(Opcode.AND, VmDataType.WORD, reg1=42, value = 65535),
|
IRInstruction(Opcode.AND, VmDataType.WORD, reg1=42, value = 65535),
|
||||||
IRCodeInstruction(Opcode.OR, VmDataType.BYTE, reg1=42, value = 0),
|
IRInstruction(Opcode.OR, VmDataType.BYTE, reg1=42, value = 0),
|
||||||
IRCodeInstruction(Opcode.XOR, VmDataType.BYTE, reg1=42, value = 0),
|
IRInstruction(Opcode.XOR, VmDataType.BYTE, reg1=42, value = 0),
|
||||||
IRCodeInstruction(Opcode.AND, VmDataType.BYTE, reg1=42, value = 200),
|
IRInstruction(Opcode.AND, VmDataType.BYTE, reg1=42, value = 200),
|
||||||
IRCodeInstruction(Opcode.AND, VmDataType.WORD, reg1=42, value = 60000),
|
IRInstruction(Opcode.AND, VmDataType.WORD, reg1=42, value = 60000),
|
||||||
IRCodeInstruction(Opcode.OR, VmDataType.BYTE, reg1=42, value = 1),
|
IRInstruction(Opcode.OR, VmDataType.BYTE, reg1=42, value = 1),
|
||||||
IRCodeInstruction(Opcode.XOR, VmDataType.BYTE, reg1=42, value = 1)
|
IRInstruction(Opcode.XOR, VmDataType.BYTE, reg1=42, value = 1)
|
||||||
))
|
))
|
||||||
irProg.lines().size shouldBe 8
|
irProg.lines().size shouldBe 8
|
||||||
val opt = IRPeepholeOptimizer(irProg)
|
val opt = IRPeepholeOptimizer(irProg)
|
||||||
@ -155,23 +155,23 @@ class TestIRPeepholeOpt: FunSpec({
|
|||||||
|
|
||||||
test("replace and/or/xor by constant number") {
|
test("replace and/or/xor by constant number") {
|
||||||
val irProg = makeIRProgram(listOf(
|
val irProg = makeIRProgram(listOf(
|
||||||
IRCodeInstruction(Opcode.AND, VmDataType.BYTE, reg1=42, value = 0),
|
IRInstruction(Opcode.AND, VmDataType.BYTE, reg1=42, value = 0),
|
||||||
IRCodeInstruction(Opcode.AND, VmDataType.WORD, reg1=42, value = 0),
|
IRInstruction(Opcode.AND, VmDataType.WORD, reg1=42, value = 0),
|
||||||
IRCodeInstruction(Opcode.OR, VmDataType.BYTE, reg1=42, value = 255),
|
IRInstruction(Opcode.OR, VmDataType.BYTE, reg1=42, value = 255),
|
||||||
IRCodeInstruction(Opcode.OR, VmDataType.WORD, reg1=42, value = 65535)
|
IRInstruction(Opcode.OR, VmDataType.WORD, reg1=42, value = 65535)
|
||||||
))
|
))
|
||||||
irProg.lines().size shouldBe 4
|
irProg.lines().size shouldBe 4
|
||||||
val opt = IRPeepholeOptimizer(irProg)
|
val opt = IRPeepholeOptimizer(irProg)
|
||||||
opt.optimize()
|
opt.optimize()
|
||||||
val lines = irProg.lines()
|
val lines = irProg.lines()
|
||||||
lines.size shouldBe 4
|
lines.size shouldBe 4
|
||||||
(lines[0] as IRCodeInstruction).ins.opcode shouldBe Opcode.LOAD
|
(lines[0] as IRInstruction).opcode shouldBe Opcode.LOAD
|
||||||
(lines[1] as IRCodeInstruction).ins.opcode shouldBe Opcode.LOAD
|
(lines[1] as IRInstruction).opcode shouldBe Opcode.LOAD
|
||||||
(lines[2] as IRCodeInstruction).ins.opcode shouldBe Opcode.LOAD
|
(lines[2] as IRInstruction).opcode shouldBe Opcode.LOAD
|
||||||
(lines[3] as IRCodeInstruction).ins.opcode shouldBe Opcode.LOAD
|
(lines[3] as IRInstruction).opcode shouldBe Opcode.LOAD
|
||||||
(lines[0] as IRCodeInstruction).ins.value shouldBe 0
|
(lines[0] as IRInstruction).value shouldBe 0
|
||||||
(lines[1] as IRCodeInstruction).ins.value shouldBe 0
|
(lines[1] as IRInstruction).value shouldBe 0
|
||||||
(lines[2] as IRCodeInstruction).ins.value shouldBe 255
|
(lines[2] as IRInstruction).value shouldBe 255
|
||||||
(lines[3] as IRCodeInstruction).ins.value shouldBe 65535
|
(lines[3] as IRInstruction).value shouldBe 65535
|
||||||
}
|
}
|
||||||
})
|
})
|
@ -1,66 +0,0 @@
|
|||||||
|
|
||||||
plugins {
|
|
||||||
id 'java'
|
|
||||||
id 'application'
|
|
||||||
id "org.jetbrains.kotlin.jvm"
|
|
||||||
id "io.kotest" version "0.3.9"
|
|
||||||
}
|
|
||||||
|
|
||||||
java {
|
|
||||||
toolchain {
|
|
||||||
languageVersion = JavaLanguageVersion.of(javaVersion)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
compileKotlin {
|
|
||||||
kotlinOptions {
|
|
||||||
jvmTarget = javaVersion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
compileTestKotlin {
|
|
||||||
kotlinOptions {
|
|
||||||
jvmTarget = javaVersion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
implementation project(':codeCore')
|
|
||||||
implementation project(':intermediate')
|
|
||||||
implementation project(':codeGenIntermediate')
|
|
||||||
implementation project(':virtualmachine')
|
|
||||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
|
|
||||||
// implementation "org.jetbrains.kotlin:kotlin-reflect"
|
|
||||||
implementation "com.michael-bull.kotlin-result:kotlin-result-jvm:1.1.16"
|
|
||||||
|
|
||||||
testImplementation 'io.kotest:kotest-runner-junit5-jvm:5.3.2'
|
|
||||||
}
|
|
||||||
|
|
||||||
sourceSets {
|
|
||||||
main {
|
|
||||||
java {
|
|
||||||
srcDirs = ["${project.projectDir}/src"]
|
|
||||||
}
|
|
||||||
resources {
|
|
||||||
srcDirs = ["${project.projectDir}/res"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
test {
|
|
||||||
java {
|
|
||||||
srcDir "${project.projectDir}/test"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
test {
|
|
||||||
// Enable JUnit 5 (Gradle 4.6+).
|
|
||||||
useJUnitPlatform()
|
|
||||||
|
|
||||||
// Always run tests, even when nothing changed.
|
|
||||||
dependsOn 'cleanTest'
|
|
||||||
|
|
||||||
// Show test results.
|
|
||||||
testLogging {
|
|
||||||
events "skipped", "failed"
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,21 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<module type="JAVA_MODULE" version="4">
|
|
||||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
|
||||||
<exclude-output />
|
|
||||||
<content url="file://$MODULE_DIR$">
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build" />
|
|
||||||
</content>
|
|
||||||
<orderEntry type="inheritedJdk" />
|
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
|
||||||
<orderEntry type="library" name="KotlinJavaRuntime" level="project" />
|
|
||||||
<orderEntry type="library" name="michael.bull.kotlin.result.jvm" level="project" />
|
|
||||||
<orderEntry type="library" name="io.kotest.assertions.core.jvm" level="project" />
|
|
||||||
<orderEntry type="library" name="io.kotest.runner.junit5.jvm" level="project" />
|
|
||||||
<orderEntry type="module" module-name="codeCore" />
|
|
||||||
<orderEntry type="module" module-name="intermediate" />
|
|
||||||
<orderEntry type="module" module-name="codeGenIntermediate" />
|
|
||||||
<orderEntry type="module" module-name="virtualmachine" />
|
|
||||||
</component>
|
|
||||||
</module>
|
|
@ -1,125 +0,0 @@
|
|||||||
package prog8.codegen.virtual
|
|
||||||
|
|
||||||
import prog8.code.core.AssemblyError
|
|
||||||
import prog8.code.core.CompilationOptions
|
|
||||||
import prog8.code.core.IAssemblyProgram
|
|
||||||
import prog8.intermediate.*
|
|
||||||
import prog8.vm.Syscall
|
|
||||||
import java.io.BufferedWriter
|
|
||||||
import kotlin.io.path.bufferedWriter
|
|
||||||
import kotlin.io.path.div
|
|
||||||
|
|
||||||
internal class VmAssemblyProgram(override val name: String, private val irProgram: IRProgram): IAssemblyProgram {
|
|
||||||
|
|
||||||
override fun assemble(dummyOptions: CompilationOptions): Boolean {
|
|
||||||
val outfile = irProgram.options.outputDir / ("$name.p8virt")
|
|
||||||
println("write code to $outfile")
|
|
||||||
|
|
||||||
// at last, allocate the variables in memory.
|
|
||||||
val allocations = VmVariableAllocator(irProgram.st, irProgram.encoding, irProgram.options.compTarget)
|
|
||||||
|
|
||||||
outfile.bufferedWriter().use { out ->
|
|
||||||
allocations.asVmMemory().forEach { (name, alloc) ->
|
|
||||||
out.write("var ${name} $alloc\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
out.write("------PROGRAM------\n")
|
|
||||||
|
|
||||||
if(!irProgram.options.dontReinitGlobals) {
|
|
||||||
out.write("; global var inits\n")
|
|
||||||
irProgram.globalInits.forEach { out.writeLine(it) }
|
|
||||||
}
|
|
||||||
irProgram.blocks.firstOrNull()?.let {
|
|
||||||
if(it.subroutines.any { it.name=="main.start" }) {
|
|
||||||
// there is a "main.start" entrypoint, jump to it
|
|
||||||
out.writeLine(IRCodeInstruction(Opcode.JUMP, labelSymbol = "main.start"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
out.write("; actual program code\n")
|
|
||||||
|
|
||||||
irProgram.blocks.forEach { block ->
|
|
||||||
if(block.address!=null)
|
|
||||||
TODO("blocks can't have a load address for vm")
|
|
||||||
out.write("; BLOCK ${block.name} ${block.position}\n")
|
|
||||||
block.inlineAssembly.forEach { asm ->
|
|
||||||
out.write("; ASM ${asm.position}\n")
|
|
||||||
out.write(asm.assembly)
|
|
||||||
out.write("\n")
|
|
||||||
}
|
|
||||||
block.subroutines.forEach { sub ->
|
|
||||||
out.write("; SUB ${sub.name} ${sub.position}\n")
|
|
||||||
out.write("_${sub.name}:\n")
|
|
||||||
sub.chunks.forEach { chunk ->
|
|
||||||
if(chunk is IRInlineAsmChunk) {
|
|
||||||
out.write("; ASM ${chunk.position}\n")
|
|
||||||
out.write(processInlinedAsm(chunk.assembly, allocations))
|
|
||||||
out.write("\n")
|
|
||||||
} else {
|
|
||||||
chunk.lines.forEach { out.writeLine(it) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
out.write("; END SUB ${sub.name}\n")
|
|
||||||
}
|
|
||||||
block.asmSubroutines.forEach { sub ->
|
|
||||||
out.write("; ASMSUB ${sub.name} ${sub.position}\n")
|
|
||||||
out.write("_${sub.name}:\n")
|
|
||||||
out.write(processInlinedAsm(sub.assembly, allocations))
|
|
||||||
out.write("\n; END ASMSUB ${sub.name}\n")
|
|
||||||
}
|
|
||||||
out.write("; END BLOCK ${block.name}\n")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun processInlinedAsm(asm: String, allocations: VmVariableAllocator): String {
|
|
||||||
// TODO do we have to replace variable names by their allocated address???
|
|
||||||
return asm
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun BufferedWriter.writeLine(line: IRCodeLine) {
|
|
||||||
when(line) {
|
|
||||||
is IRCodeComment -> {
|
|
||||||
write("; ${line.comment}\n")
|
|
||||||
}
|
|
||||||
is IRCodeInstruction -> {
|
|
||||||
if(line.ins.opcode==Opcode.SYSCALL) {
|
|
||||||
// convert IM Syscall to VM Syscall
|
|
||||||
val vmSyscall = when(line.ins.value!!) {
|
|
||||||
IMSyscall.SORT_UBYTE.ordinal -> Syscall.SORT_UBYTE
|
|
||||||
IMSyscall.SORT_BYTE.ordinal -> Syscall.SORT_BYTE
|
|
||||||
IMSyscall.SORT_UWORD.ordinal -> Syscall.SORT_UWORD
|
|
||||||
IMSyscall.SORT_WORD.ordinal -> Syscall.SORT_WORD
|
|
||||||
IMSyscall.ANY_BYTE.ordinal -> Syscall.ANY_BYTE
|
|
||||||
IMSyscall.ANY_WORD.ordinal -> Syscall.ANY_WORD
|
|
||||||
IMSyscall.ANY_FLOAT.ordinal -> Syscall.ANY_FLOAT
|
|
||||||
IMSyscall.ALL_BYTE.ordinal -> Syscall.ALL_BYTE
|
|
||||||
IMSyscall.ALL_WORD.ordinal -> Syscall.ALL_WORD
|
|
||||||
IMSyscall.ALL_FLOAT.ordinal -> Syscall.ALL_FLOAT
|
|
||||||
IMSyscall.REVERSE_BYTES.ordinal -> Syscall.REVERSE_BYTES
|
|
||||||
IMSyscall.REVERSE_WORDS.ordinal -> Syscall.REVERSE_WORDS
|
|
||||||
IMSyscall.REVERSE_FLOATS.ordinal -> Syscall.REVERSE_FLOATS
|
|
||||||
else -> throw IllegalArgumentException("invalid IM syscall number ${line.ins.value}")
|
|
||||||
}
|
|
||||||
val newIns = line.ins.copy(value = vmSyscall.ordinal)
|
|
||||||
write(newIns.toString() + "\n")
|
|
||||||
} else
|
|
||||||
write(line.ins.toString() + "\n")
|
|
||||||
}
|
|
||||||
is IRCodeInlineBinary -> {
|
|
||||||
write("!binary ")
|
|
||||||
line.data.withIndex().forEach {(index, byte) ->
|
|
||||||
write(byte.toString(16).padStart(2,'0'))
|
|
||||||
if(index and 63 == 63 && index<line.data.size-1)
|
|
||||||
write("\n!binary ")
|
|
||||||
}
|
|
||||||
write("\n")
|
|
||||||
}
|
|
||||||
is IRCodeLabel -> {
|
|
||||||
write("_${line.name}:\n")
|
|
||||||
}
|
|
||||||
else -> throw AssemblyError("invalid IR code line")
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,97 +0,0 @@
|
|||||||
package prog8.codegen.virtual
|
|
||||||
|
|
||||||
import prog8.code.core.*
|
|
||||||
import prog8.intermediate.IRSymbolTable
|
|
||||||
import prog8.intermediate.getTypeString
|
|
||||||
|
|
||||||
internal class VmVariableAllocator(val st: IRSymbolTable, val encoding: IStringEncoding, memsizer: IMemSizer) {
|
|
||||||
|
|
||||||
internal val allocations = mutableMapOf<String, Int>()
|
|
||||||
private var freeMemoryStart: Int
|
|
||||||
|
|
||||||
val freeMem: Int
|
|
||||||
get() = freeMemoryStart
|
|
||||||
|
|
||||||
|
|
||||||
init {
|
|
||||||
var nextLocation = 0
|
|
||||||
for (variable in st.allVariables()) {
|
|
||||||
val memsize =
|
|
||||||
when (variable.dt) {
|
|
||||||
DataType.STR -> variable.onetimeInitializationStringValue!!.first.length + 1 // include the zero byte
|
|
||||||
in NumericDatatypes -> memsizer.memorySize(variable.dt)
|
|
||||||
in ArrayDatatypes -> memsizer.memorySize(variable.dt, variable.length!!)
|
|
||||||
else -> throw InternalCompilerException("weird dt")
|
|
||||||
}
|
|
||||||
|
|
||||||
allocations[variable.name] = nextLocation
|
|
||||||
nextLocation += memsize
|
|
||||||
}
|
|
||||||
for(slab in st.allMemorySlabs()) {
|
|
||||||
// we ignore the alignment for the VM.
|
|
||||||
allocations[slab.name] = nextLocation
|
|
||||||
nextLocation += slab.size.toInt()
|
|
||||||
}
|
|
||||||
|
|
||||||
freeMemoryStart = nextLocation
|
|
||||||
}
|
|
||||||
|
|
||||||
fun asVmMemory(): List<Pair<String, String>> {
|
|
||||||
val mm = mutableListOf<Pair<String, String>>()
|
|
||||||
|
|
||||||
// normal variables
|
|
||||||
for (variable in st.allVariables()) {
|
|
||||||
val location = allocations.getValue(variable.name)
|
|
||||||
val value = when(variable.dt) {
|
|
||||||
DataType.FLOAT -> (variable.onetimeInitializationNumericValue ?: 0.0).toString()
|
|
||||||
in NumericDatatypes -> (variable.onetimeInitializationNumericValue ?: 0).toHex()
|
|
||||||
DataType.STR -> {
|
|
||||||
val encoded = encoding.encodeString(variable.onetimeInitializationStringValue!!.first, variable.onetimeInitializationStringValue!!.second) + listOf(0u)
|
|
||||||
encoded.joinToString(",") { it.toInt().toHex() }
|
|
||||||
}
|
|
||||||
DataType.ARRAY_F -> {
|
|
||||||
if(variable.onetimeInitializationArrayValue!=null) {
|
|
||||||
variable.onetimeInitializationArrayValue!!.joinToString(",") { it.number!!.toString() }
|
|
||||||
} else {
|
|
||||||
(1..variable.length!!).joinToString(",") { "0" }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
in ArrayDatatypes -> {
|
|
||||||
if(variable.onetimeInitializationArrayValue!==null) {
|
|
||||||
variable.onetimeInitializationArrayValue!!.joinToString(",") {
|
|
||||||
if(it.number!=null)
|
|
||||||
it.number!!.toHex()
|
|
||||||
else
|
|
||||||
"&${it.addressOf!!.joinToString(".")}"
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
(1..variable.length!!).joinToString(",") { "0" }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else -> throw InternalCompilerException("weird dt")
|
|
||||||
}
|
|
||||||
mm.add(Pair(variable.name, "@$location ${getTypeString(variable)} $value"))
|
|
||||||
}
|
|
||||||
|
|
||||||
// memory mapped variables
|
|
||||||
for (variable in st.allMemMappedVariables()) {
|
|
||||||
val value = when(variable.dt) {
|
|
||||||
DataType.FLOAT -> "0.0"
|
|
||||||
in NumericDatatypes -> "0"
|
|
||||||
DataType.ARRAY_F -> (1..variable.length!!).joinToString(",") { "0.0" }
|
|
||||||
in ArrayDatatypes -> (1..variable.length!!).joinToString(",") { "0" }
|
|
||||||
else -> throw InternalCompilerException("weird dt for mem mapped var")
|
|
||||||
}
|
|
||||||
mm.add(Pair(variable.name, "@${variable.address} ${getTypeString(variable)} $value"))
|
|
||||||
}
|
|
||||||
|
|
||||||
// memory slabs.
|
|
||||||
for(slab in st.allMemorySlabs()) {
|
|
||||||
val address = allocations.getValue(slab.name)
|
|
||||||
mm.add(Pair(slab.name, "@$address ubyte[${slab.size}] 0"))
|
|
||||||
}
|
|
||||||
|
|
||||||
return mm
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -31,7 +31,6 @@ dependencies {
|
|||||||
implementation project(':codeOptimizers')
|
implementation project(':codeOptimizers')
|
||||||
implementation project(':compilerAst')
|
implementation project(':compilerAst')
|
||||||
implementation project(':codeGenCpu6502')
|
implementation project(':codeGenCpu6502')
|
||||||
implementation project(':codeGenVirtual')
|
|
||||||
implementation project(':codeGenExperimental')
|
implementation project(':codeGenExperimental')
|
||||||
implementation project(':virtualmachine')
|
implementation project(':virtualmachine')
|
||||||
implementation 'org.antlr:antlr4-runtime:4.10.1'
|
implementation 'org.antlr:antlr4-runtime:4.10.1'
|
||||||
|
@ -21,7 +21,6 @@
|
|||||||
<orderEntry type="module" module-name="codeOptimizers" />
|
<orderEntry type="module" module-name="codeOptimizers" />
|
||||||
<orderEntry type="module" module-name="codeGenCpu6502" />
|
<orderEntry type="module" module-name="codeGenCpu6502" />
|
||||||
<orderEntry type="module" module-name="codeGenExperimental" />
|
<orderEntry type="module" module-name="codeGenExperimental" />
|
||||||
<orderEntry type="module" module-name="codeGenVirtual" />
|
|
||||||
<orderEntry type="module" module-name="virtualmachine" />
|
<orderEntry type="module" module-name="virtualmachine" />
|
||||||
</component>
|
</component>
|
||||||
</module>
|
</module>
|
||||||
|
@ -1 +1 @@
|
|||||||
8.6.1
|
8.6.2
|
||||||
|
@ -2,18 +2,21 @@ package prog8
|
|||||||
|
|
||||||
import kotlinx.cli.*
|
import kotlinx.cli.*
|
||||||
import prog8.ast.base.AstException
|
import prog8.ast.base.AstException
|
||||||
import prog8.code.core.*
|
import prog8.code.core.CbmPrgLauncherType
|
||||||
|
import prog8.code.core.toHex
|
||||||
import prog8.code.target.*
|
import prog8.code.target.*
|
||||||
import prog8.code.target.virtual.VirtualMachineDefinition
|
import prog8.code.target.virtual.VirtualMachineDefinition
|
||||||
import prog8.codegen.virtual.VmCodeGen
|
|
||||||
import prog8.compiler.CompilationResult
|
import prog8.compiler.CompilationResult
|
||||||
import prog8.compiler.CompilerArguments
|
import prog8.compiler.CompilerArguments
|
||||||
import prog8.compiler.compileProgram
|
import prog8.compiler.compileProgram
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.nio.file.*
|
import java.nio.file.FileSystems
|
||||||
|
import java.nio.file.Path
|
||||||
|
import java.nio.file.StandardWatchEventKinds
|
||||||
|
import java.nio.file.WatchKey
|
||||||
import java.time.LocalDateTime
|
import java.time.LocalDateTime
|
||||||
import kotlin.system.exitProcess
|
|
||||||
import kotlin.io.path.Path
|
import kotlin.io.path.Path
|
||||||
|
import kotlin.system.exitProcess
|
||||||
|
|
||||||
|
|
||||||
fun main(args: Array<String>) {
|
fun main(args: Array<String>) {
|
||||||
@ -48,7 +51,7 @@ private fun compileMain(args: Array<String>): Boolean {
|
|||||||
val slowCodegenWarnings by cli.option(ArgType.Boolean, fullName = "slowwarn", description="show debug warnings about slow/problematic assembly code generation")
|
val slowCodegenWarnings by cli.option(ArgType.Boolean, fullName = "slowwarn", description="show debug warnings about slow/problematic assembly code generation")
|
||||||
val sourceDirs by cli.option(ArgType.String, fullName="srcdirs", description = "list of extra paths, separated with ${File.pathSeparator}, to search in for imported modules").multiple().delimiter(File.pathSeparator)
|
val sourceDirs by cli.option(ArgType.String, fullName="srcdirs", description = "list of extra paths, separated with ${File.pathSeparator}, to search in for imported modules").multiple().delimiter(File.pathSeparator)
|
||||||
val compilationTarget by cli.option(ArgType.String, fullName = "target", description = "target output of the compiler (one of '${C64Target.NAME}', '${C128Target.NAME}', '${Cx16Target.NAME}', '${AtariTarget.NAME}', '${VMTarget.NAME}')").default(C64Target.NAME)
|
val compilationTarget by cli.option(ArgType.String, fullName = "target", description = "target output of the compiler (one of '${C64Target.NAME}', '${C128Target.NAME}', '${Cx16Target.NAME}', '${AtariTarget.NAME}', '${VMTarget.NAME}')").default(C64Target.NAME)
|
||||||
val startVm by cli.option(ArgType.Boolean, fullName = "vm", description = "load and run a p8-virt or p8-ir listing in the VM instead")
|
val startVm by cli.option(ArgType.Boolean, fullName = "vm", description = "load and run a .p8ir IR source file in the VM")
|
||||||
val watchMode by cli.option(ArgType.Boolean, fullName = "watch", description = "continuous compilation mode (watch for file changes)")
|
val watchMode by cli.option(ArgType.Boolean, fullName = "watch", description = "continuous compilation mode (watch for file changes)")
|
||||||
val moduleFiles by cli.argument(ArgType.String, fullName = "modules", description = "main module file(s) to compile").multiple(999)
|
val moduleFiles by cli.argument(ArgType.String, fullName = "modules", description = "main module file(s) to compile").multiple(999)
|
||||||
|
|
||||||
@ -245,28 +248,9 @@ private fun processSymbolDefs(symbolDefs: List<String>): Map<String, String>? {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
fun runVm(listingFilename: String): Boolean {
|
fun runVm(irFilename: String): Boolean {
|
||||||
if(listingFilename.endsWith(".p8ir")) {
|
val irFile = Path(irFilename)
|
||||||
val withoutSuffix = listingFilename.substring(0, listingFilename.length-5)
|
|
||||||
val compiled = VmCodeGen.compileIR(withoutSuffix)
|
|
||||||
if (!compiled.assemble(CompilationOptions( // these are just dummy options, the actual options are inside the .p8ir file itself:
|
|
||||||
OutputType.PRG,
|
|
||||||
CbmPrgLauncherType.NONE,
|
|
||||||
ZeropageType.DONTUSE,
|
|
||||||
emptyList(),
|
|
||||||
floats = true,
|
|
||||||
noSysInit = true,
|
|
||||||
compTarget = VMTarget(),
|
|
||||||
loadAddress = VMTarget().machine.PROGRAM_LOAD_ADDRESS
|
|
||||||
))
|
|
||||||
) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
val vmdef = VirtualMachineDefinition()
|
|
||||||
vmdef.launchEmulator(0, Paths.get(withoutSuffix))
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
val vmdef = VirtualMachineDefinition()
|
val vmdef = VirtualMachineDefinition()
|
||||||
vmdef.launchEmulator(0, Paths.get(listingFilename))
|
vmdef.launchEmulator(0, irFile)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ import prog8.code.target.*
|
|||||||
import prog8.compiler.astprocessing.*
|
import prog8.compiler.astprocessing.*
|
||||||
import prog8.optimizer.*
|
import prog8.optimizer.*
|
||||||
import prog8.parser.ParseError
|
import prog8.parser.ParseError
|
||||||
|
import prog8.vm.codegen.VmCodeGen
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
import kotlin.io.path.Path
|
import kotlin.io.path.Path
|
||||||
import kotlin.io.path.nameWithoutExtension
|
import kotlin.io.path.nameWithoutExtension
|
||||||
@ -455,7 +456,7 @@ internal fun asmGeneratorFor(program: Program,
|
|||||||
return prog8.codegen.cpu6502.AsmGen(program, symbolTable, options, errors)
|
return prog8.codegen.cpu6502.AsmGen(program, symbolTable, options, errors)
|
||||||
if (options.compTarget.name == VMTarget.NAME) {
|
if (options.compTarget.name == VMTarget.NAME) {
|
||||||
val intermediateAst = IntermediateAstMaker(program).transform()
|
val intermediateAst = IntermediateAstMaker(program).transform()
|
||||||
return prog8.codegen.virtual.VmCodeGen(intermediateAst, symbolTable, options, errors)
|
return VmCodeGen(intermediateAst, symbolTable, options, errors)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,4 +104,16 @@ internal class SymbolTableMaker: IAstVisitor {
|
|||||||
scopestack.peek().add(node)
|
scopestack.peek().add(node)
|
||||||
// st.origAstLinks[label] = node
|
// st.origAstLinks[label] = node
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun visit(fcall: BuiltinFunctionCall) {
|
||||||
|
if(fcall.name=="memory") {
|
||||||
|
// memory slab allocations are a builtin functioncall in the program, but end up named as well in the symboltable
|
||||||
|
val name = (fcall.args[0] as StringLiteral).value
|
||||||
|
require(name.all { it.isLetterOrDigit() || it=='_' }) {"memory name should be a valid symbol name"}
|
||||||
|
val size = (fcall.args[1] as NumericLiteral).number.toUInt()
|
||||||
|
val align = (fcall.args[2] as NumericLiteral).number.toUInt()
|
||||||
|
st.add(StMemorySlab("prog8_memoryslab_$name", size, align, fcall.position))
|
||||||
|
}
|
||||||
|
super.visit(fcall)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,8 +10,27 @@ class TestLaunchEmu: FunSpec({
|
|||||||
|
|
||||||
test("test launch virtualmachine via target") {
|
test("test launch virtualmachine via target") {
|
||||||
val target = VMTarget()
|
val target = VMTarget()
|
||||||
val tmpfile = kotlin.io.path.createTempFile(suffix=".p8virt")
|
val tmpfile = kotlin.io.path.createTempFile(suffix=".p8ir")
|
||||||
tmpfile.writeText(";comment\n------PROGRAM------\n;comment\n")
|
tmpfile.writeText("""<PROGRAM NAME=test>
|
||||||
|
<OPTIONS>
|
||||||
|
</OPTIONS>
|
||||||
|
|
||||||
|
<VARIABLES>
|
||||||
|
</VARIABLES>
|
||||||
|
|
||||||
|
<MEMORYMAPPEDVARIABLES>
|
||||||
|
</MEMORYMAPPEDVARIABLES>
|
||||||
|
|
||||||
|
<MEMORYSLABS>
|
||||||
|
</MEMORYSLABS>
|
||||||
|
|
||||||
|
<INITGLOBALS>
|
||||||
|
</INITGLOBALS>
|
||||||
|
|
||||||
|
<BLOCK NAME=main ADDRESS=null ALIGN=NONE POS=[unittest: line 42 col 1-9]>
|
||||||
|
</BLOCK>
|
||||||
|
</PROGRAM>
|
||||||
|
""")
|
||||||
target.machine.launchEmulator(0, tmpfile)
|
target.machine.launchEmulator(0, tmpfile)
|
||||||
tmpfile.deleteExisting()
|
tmpfile.deleteExisting()
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,10 @@
|
|||||||
package prog8tests.helpers
|
package prog8tests.helpers
|
||||||
|
|
||||||
import prog8.ast.Program
|
import prog8.code.core.ICompilationTarget
|
||||||
import prog8.code.core.*
|
import prog8.code.core.IErrorReporter
|
||||||
import prog8.code.target.C64Target
|
|
||||||
import prog8.code.target.c64.C64Zeropage
|
|
||||||
import prog8.codegen.cpu6502.AsmGen
|
|
||||||
import prog8.compiler.CompilationResult
|
import prog8.compiler.CompilationResult
|
||||||
import prog8.compiler.CompilerArguments
|
import prog8.compiler.CompilerArguments
|
||||||
import prog8.compiler.astprocessing.SymbolTableMaker
|
|
||||||
import prog8.compiler.compileProgram
|
import prog8.compiler.compileProgram
|
||||||
import prog8.compiler.determineProgramLoadAddress
|
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
import kotlin.io.path.name
|
import kotlin.io.path.name
|
||||||
|
|
||||||
@ -67,23 +62,3 @@ internal fun compileText(
|
|||||||
return compileFile(platform, optimize, filePath.parent, filePath.name,
|
return compileFile(platform, optimize, filePath.parent, filePath.name,
|
||||||
errors=errors, writeAssembly=writeAssembly, optFloatExpr = optFloatExpr, keepIR=keepIR)
|
errors=errors, writeAssembly=writeAssembly, optFloatExpr = optFloatExpr, keepIR=keepIR)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
internal fun generateAssembly(
|
|
||||||
program: Program,
|
|
||||||
options: CompilationOptions? = null
|
|
||||||
): IAssemblyProgram? {
|
|
||||||
val coptions = options ?: CompilationOptions(OutputType.RAW, CbmPrgLauncherType.BASIC, ZeropageType.DONTUSE, emptyList(),
|
|
||||||
floats = true,
|
|
||||||
noSysInit = true,
|
|
||||||
compTarget = C64Target(),
|
|
||||||
loadAddress = 0u, outputDir = outputDir)
|
|
||||||
coptions.compTarget.machine.zeropage = C64Zeropage(coptions)
|
|
||||||
val st = SymbolTableMaker().makeFrom(program)
|
|
||||||
val errors = ErrorReporterForTests()
|
|
||||||
determineProgramLoadAddress(program, coptions, errors)
|
|
||||||
errors.report()
|
|
||||||
val asmgen = AsmGen(program, st, coptions, errors)
|
|
||||||
errors.report()
|
|
||||||
return asmgen.compileToAssembly()
|
|
||||||
}
|
|
||||||
|
@ -3,6 +3,8 @@ package prog8tests.vm
|
|||||||
import io.kotest.core.spec.style.FunSpec
|
import io.kotest.core.spec.style.FunSpec
|
||||||
import io.kotest.matchers.shouldBe
|
import io.kotest.matchers.shouldBe
|
||||||
import io.kotest.matchers.shouldNotBe
|
import io.kotest.matchers.shouldNotBe
|
||||||
|
import prog8.ast.expressions.BuiltinFunctionCall
|
||||||
|
import prog8.ast.statements.Assignment
|
||||||
import prog8.code.target.Cx16Target
|
import prog8.code.target.Cx16Target
|
||||||
import prog8.code.target.VMTarget
|
import prog8.code.target.VMTarget
|
||||||
import prog8.vm.VmRunner
|
import prog8.vm.VmRunner
|
||||||
@ -25,12 +27,9 @@ main {
|
|||||||
}
|
}
|
||||||
}"""
|
}"""
|
||||||
val target = VMTarget()
|
val target = VMTarget()
|
||||||
val result = compileText(target, true, src, writeAssembly = true, keepIR=true)!!
|
val result = compileText(target, true, src, writeAssembly = true)!!
|
||||||
val virtfile = result.compilationOptions.outputDir.resolve(result.program.name + ".p8virt")
|
val virtfile = result.compilationOptions.outputDir.resolve(result.program.name + ".p8ir")
|
||||||
VmRunner().runProgram(virtfile.readText())
|
VmRunner().runProgram(virtfile.readText())
|
||||||
val result2 = compileText(target, true, src, writeAssembly = true, keepIR=false)!!
|
|
||||||
val virtfile2 = result2.compilationOptions.outputDir.resolve(result2.program.name + ".p8virt")
|
|
||||||
VmRunner().runProgram(virtfile2.readText())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
test("compile virtual: array with pointers") {
|
test("compile virtual: array with pointers") {
|
||||||
@ -50,12 +49,9 @@ main {
|
|||||||
val othertarget = Cx16Target()
|
val othertarget = Cx16Target()
|
||||||
compileText(othertarget, true, src, writeAssembly = true, keepIR=true) shouldNotBe null
|
compileText(othertarget, true, src, writeAssembly = true, keepIR=true) shouldNotBe null
|
||||||
val target = VMTarget()
|
val target = VMTarget()
|
||||||
val result = compileText(target, true, src, writeAssembly = true, keepIR=true)!!
|
val result = compileText(target, true, src, writeAssembly = true)!!
|
||||||
val virtfile = result.compilationOptions.outputDir.resolve(result.program.name + ".p8virt")
|
val virtfile = result.compilationOptions.outputDir.resolve(result.program.name + ".p8ir")
|
||||||
VmRunner().runProgram(virtfile.readText())
|
VmRunner().runProgram(virtfile.readText())
|
||||||
val result2 = compileText(target, true, src, writeAssembly = true, keepIR=false)!!
|
|
||||||
val virtfile2 = result2.compilationOptions.outputDir.resolve(result2.program.name + ".p8virt")
|
|
||||||
VmRunner().runProgram(virtfile2.readText())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
test("compile virtual: str args and return type") {
|
test("compile virtual: str args and return type") {
|
||||||
@ -71,12 +67,9 @@ main {
|
|||||||
}
|
}
|
||||||
}"""
|
}"""
|
||||||
val target = VMTarget()
|
val target = VMTarget()
|
||||||
val result = compileText(target, true, src, writeAssembly = true, keepIR=true)!!
|
val result = compileText(target, true, src, writeAssembly = true)!!
|
||||||
val virtfile = result.compilationOptions.outputDir.resolve(result.program.name + ".p8virt")
|
val virtfile = result.compilationOptions.outputDir.resolve(result.program.name + ".p8ir")
|
||||||
VmRunner().runProgram(virtfile.readText())
|
VmRunner().runProgram(virtfile.readText())
|
||||||
val result2 = compileText(target, true, src, writeAssembly = true, keepIR=false)!!
|
|
||||||
val virtfile2 = result2.compilationOptions.outputDir.resolve(result2.program.name + ".p8virt")
|
|
||||||
VmRunner().runProgram(virtfile2.readText())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
test("compile virtual: nested labels") {
|
test("compile virtual: nested labels") {
|
||||||
@ -114,18 +107,13 @@ mylabel_inside:
|
|||||||
}"""
|
}"""
|
||||||
|
|
||||||
val target = VMTarget()
|
val target = VMTarget()
|
||||||
val result = compileText(target, true, src, writeAssembly = true, keepIR=true)!!
|
val result = compileText(target, true, src, writeAssembly = true)!!
|
||||||
val virtfile = result.compilationOptions.outputDir.resolve(result.program.name + ".p8virt")
|
val virtfile = result.compilationOptions.outputDir.resolve(result.program.name + ".p8ir")
|
||||||
VmRunner().runProgram(virtfile.readText())
|
VmRunner().runProgram(virtfile.readText())
|
||||||
val result2 = compileText(target, true, src, writeAssembly = true, keepIR=false)!!
|
|
||||||
val virtfile2 = result2.compilationOptions.outputDir.resolve(result2.program.name + ".p8virt")
|
|
||||||
VmRunner().runProgram(virtfile2.readText())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
test("case sensitive symbols") {
|
test("case sensitive symbols") {
|
||||||
val src = """
|
val src = """
|
||||||
%zeropage basicsafe
|
|
||||||
|
|
||||||
main {
|
main {
|
||||||
sub start() {
|
sub start() {
|
||||||
ubyte bytevar = 11 ; var at 0
|
ubyte bytevar = 11 ; var at 0
|
||||||
@ -142,18 +130,34 @@ skipLABEL:
|
|||||||
val othertarget = Cx16Target()
|
val othertarget = Cx16Target()
|
||||||
compileText(othertarget, true, src, writeAssembly = true, keepIR=true) shouldNotBe null
|
compileText(othertarget, true, src, writeAssembly = true, keepIR=true) shouldNotBe null
|
||||||
val target = VMTarget()
|
val target = VMTarget()
|
||||||
val result = compileText(target, true, src, writeAssembly = true, keepIR=true)!!
|
val result = compileText(target, true, src, writeAssembly = true)!!
|
||||||
val virtfile = result.compilationOptions.outputDir.resolve(result.program.name + ".p8virt")
|
val virtfile = result.compilationOptions.outputDir.resolve(result.program.name + ".p8ir")
|
||||||
VmRunner().runAndTestProgram(virtfile.readText()) { vm ->
|
VmRunner().runAndTestProgram(virtfile.readText()) { vm ->
|
||||||
vm.memory.getUB(0) shouldBe 42u
|
vm.memory.getUB(0) shouldBe 42u
|
||||||
vm.memory.getUB(3) shouldBe 66u
|
vm.memory.getUB(3) shouldBe 66u
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val result2 = compileText(target, true, src, writeAssembly = true, keepIR=false)!!
|
test("memory slabs") {
|
||||||
val virtfile2 = result2.compilationOptions.outputDir.resolve(result2.program.name + ".p8virt")
|
val src = """
|
||||||
VmRunner().runAndTestProgram(virtfile2.readText()) { vm ->
|
main {
|
||||||
vm.memory.getUB(0) shouldBe 42u
|
sub start() {
|
||||||
vm.memory.getUB(3) shouldBe 66u
|
uword slab1 = memory("slab1", 2000, 64)
|
||||||
|
slab1[10]=42
|
||||||
|
slab1[11]=43
|
||||||
|
ubyte @shared value1 = slab1[10] ; var at 2
|
||||||
|
ubyte @shared value2 = slab1[11] ; var at 3
|
||||||
|
}
|
||||||
|
}"""
|
||||||
|
val target = VMTarget()
|
||||||
|
val result = compileText(target, true, src, writeAssembly = true)!!
|
||||||
|
val start = result.program.entrypoint
|
||||||
|
start.statements.size shouldBe 9
|
||||||
|
((start.statements[1] as Assignment).value as BuiltinFunctionCall).name shouldBe "memory"
|
||||||
|
val virtfile = result.compilationOptions.outputDir.resolve(result.program.name + ".p8ir")
|
||||||
|
VmRunner().runAndTestProgram(virtfile.readText()) { vm ->
|
||||||
|
vm.memory.getUB(2) shouldBe 42u
|
||||||
|
vm.memory.getUB(3) shouldBe 43u
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
@ -1,2 +1,2 @@
|
|||||||
sphinx>=4.0
|
sphinx>=4.4.0, !=5.2.0.post0 # https://github.com/sphinx-doc/sphinx/issues/10860
|
||||||
sphinx_rtd_theme==1.0.0
|
sphinx_rtd_theme>=1.0.0
|
||||||
|
Binary file not shown.
@ -13,13 +13,10 @@
|
|||||||
<font id="EmbeddedFont_1" horiz-adv-x="2048">
|
<font id="EmbeddedFont_1" horiz-adv-x="2048">
|
||||||
<font-face font-family="Bitstream Vera Sans Mono embedded" units-per-em="2048" font-weight="normal" font-style="normal" ascent="1879" descent="476"/>
|
<font-face font-family="Bitstream Vera Sans Mono embedded" units-per-em="2048" font-weight="normal" font-style="normal" ascent="1879" descent="476"/>
|
||||||
<missing-glyph horiz-adv-x="2048" d="M 0,0 L 2047,0 2047,2047 0,2047 0,0 Z"/>
|
<missing-glyph horiz-adv-x="2048" d="M 0,0 L 2047,0 2047,2047 0,2047 0,0 Z"/>
|
||||||
<glyph unicode="v" horiz-adv-x="1060" d="M 100,1120 L 291,1120 616,180 942,1120 1133,1120 735,0 498,0 100,1120 Z"/>
|
|
||||||
<glyph unicode="t" horiz-adv-x="927" d="M 614,1438 L 614,1120 1032,1120 1032,977 614,977 614,369 C 614,286 630,229 661,196 692,163 747,147 825,147 L 1032,147 1032,0 807,0 C 669,0 572,28 515,83 458,138 430,234 430,369 L 430,977 131,977 131,1120 430,1120 430,1438 614,1438 Z"/>
|
|
||||||
<glyph unicode="r" horiz-adv-x="821" d="M 1155,889 C 1116,920 1076,942 1035,956 994,970 950,977 901,977 786,977 699,941 638,869 577,797 547,693 547,557 L 547,0 362,0 362,1120 547,1120 547,901 C 578,980 625,1041 689,1084 752,1126 828,1147 915,1147 960,1147 1003,1141 1042,1130 1081,1119 1119,1101 1155,1077 L 1155,889 Z"/>
|
<glyph unicode="r" horiz-adv-x="821" d="M 1155,889 C 1116,920 1076,942 1035,956 994,970 950,977 901,977 786,977 699,941 638,869 577,797 547,693 547,557 L 547,0 362,0 362,1120 547,1120 547,901 C 578,980 625,1041 689,1084 752,1126 828,1147 915,1147 960,1147 1003,1141 1042,1130 1081,1119 1119,1101 1155,1077 L 1155,889 Z"/>
|
||||||
<glyph unicode="p" horiz-adv-x="927" d="M 375,141 L 375,-426 190,-426 190,1120 375,1120 375,977 C 406,1032 447,1075 498,1104 549,1133 607,1147 674,1147 809,1147 916,1095 993,990 1070,885 1108,740 1108,555 1108,373 1069,230 992,127 915,23 809,-29 674,-29 606,-29 547,-14 496,15 445,44 404,86 375,141 Z M 915,559 C 915,702 893,809 848,882 803,955 736,991 647,991 558,991 490,955 444,882 398,809 375,701 375,559 375,418 398,310 444,237 490,164 558,127 647,127 736,127 803,163 848,236 893,309 915,416 915,559 Z"/>
|
<glyph unicode="p" horiz-adv-x="927" d="M 375,141 L 375,-426 190,-426 190,1120 375,1120 375,977 C 406,1032 447,1075 498,1104 549,1133 607,1147 674,1147 809,1147 916,1095 993,990 1070,885 1108,740 1108,555 1108,373 1069,230 992,127 915,23 809,-29 674,-29 606,-29 547,-14 496,15 445,44 404,86 375,141 Z M 915,559 C 915,702 893,809 848,882 803,955 736,991 647,991 558,991 490,955 444,882 398,809 375,701 375,559 375,418 398,310 444,237 490,164 558,127 647,127 736,127 803,163 848,236 893,309 915,416 915,559 Z"/>
|
||||||
<glyph unicode="o" horiz-adv-x="980" d="M 616,991 C 523,991 452,955 404,882 356,809 332,702 332,559 332,417 356,310 404,237 452,164 523,127 616,127 710,127 781,164 829,237 877,310 901,417 901,559 901,702 877,809 829,882 781,955 710,991 616,991 Z M 616,1147 C 771,1147 890,1097 973,996 1055,895 1096,750 1096,559 1096,368 1055,222 973,122 891,21 772,-29 616,-29 461,-29 342,21 260,122 178,222 137,368 137,559 137,750 178,895 260,996 342,1097 461,1147 616,1147 Z"/>
|
<glyph unicode="o" horiz-adv-x="980" d="M 616,991 C 523,991 452,955 404,882 356,809 332,702 332,559 332,417 356,310 404,237 452,164 523,127 616,127 710,127 781,164 829,237 877,310 901,417 901,559 901,702 877,809 829,882 781,955 710,991 616,991 Z M 616,1147 C 771,1147 890,1097 973,996 1055,895 1096,750 1096,559 1096,368 1055,222 973,122 891,21 772,-29 616,-29 461,-29 342,21 260,122 178,222 137,368 137,559 137,750 178,895 260,996 342,1097 461,1147 616,1147 Z"/>
|
||||||
<glyph unicode="l" horiz-adv-x="874" d="M 639,406 C 639,323 654,261 685,219 715,177 760,156 819,156 L 1034,156 1034,0 801,0 C 691,0 606,35 546,106 485,177 455,277 455,406 L 455,1423 160,1423 160,1567 639,1567 639,406 Z"/>
|
<glyph unicode="l" horiz-adv-x="874" d="M 639,406 C 639,323 654,261 685,219 715,177 760,156 819,156 L 1034,156 1034,0 801,0 C 691,0 606,35 546,106 485,177 455,277 455,406 L 455,1423 160,1423 160,1567 639,1567 639,406 Z"/>
|
||||||
<glyph unicode="i" horiz-adv-x="953" d="M 256,1120 L 727,1120 727,143 1092,143 1092,0 178,0 178,143 543,143 543,977 256,977 256,1120 Z M 543,1556 L 727,1556 727,1323 543,1323 543,1556 Z"/>
|
|
||||||
<glyph unicode="h" horiz-adv-x="874" d="M 1051,694 L 1051,0 866,0 866,694 C 866,795 848,869 813,916 778,963 722,987 647,987 561,987 495,957 449,896 402,835 379,747 379,633 L 379,0 195,0 195,1556 379,1556 379,952 C 412,1016 456,1065 512,1098 568,1131 634,1147 711,1147 825,1147 910,1110 967,1035 1023,960 1051,846 1051,694 Z"/>
|
<glyph unicode="h" horiz-adv-x="874" d="M 1051,694 L 1051,0 866,0 866,694 C 866,795 848,869 813,916 778,963 722,987 647,987 561,987 495,957 449,896 402,835 379,747 379,633 L 379,0 195,0 195,1556 379,1556 379,952 C 412,1016 456,1065 512,1098 568,1131 634,1147 711,1147 825,1147 910,1110 967,1035 1023,960 1051,846 1051,694 Z"/>
|
||||||
<glyph unicode="g" horiz-adv-x="953" d="M 858,569 C 858,707 836,812 791,884 746,955 680,991 594,991 504,991 435,955 388,884 341,812 317,707 317,569 317,431 341,326 389,254 436,181 505,145 596,145 681,145 746,181 791,254 836,327 858,432 858,569 Z M 1042,72 C 1042,-96 1002,-223 923,-310 844,-397 727,-440 573,-440 522,-440 469,-435 414,-426 359,-417 303,-403 248,-385 L 248,-203 C 313,-234 373,-256 426,-271 479,-286 528,-293 573,-293 672,-293 745,-266 790,-212 835,-158 858,-72 858,45 L 858,53 858,178 C 829,115 789,69 738,38 687,7 626,-8 553,-8 422,-8 318,44 240,149 162,254 123,394 123,569 123,745 162,885 240,990 318,1095 422,1147 553,1147 625,1147 686,1133 736,1104 786,1075 827,1031 858,971 L 858,1116 1042,1116 1042,72 Z"/>
|
<glyph unicode="g" horiz-adv-x="953" d="M 858,569 C 858,707 836,812 791,884 746,955 680,991 594,991 504,991 435,955 388,884 341,812 317,707 317,569 317,431 341,326 389,254 436,181 505,145 596,145 681,145 746,181 791,254 836,327 858,432 858,569 Z M 1042,72 C 1042,-96 1002,-223 923,-310 844,-397 727,-440 573,-440 522,-440 469,-435 414,-426 359,-417 303,-403 248,-385 L 248,-203 C 313,-234 373,-256 426,-271 479,-286 528,-293 573,-293 672,-293 745,-266 790,-212 835,-158 858,-72 858,45 L 858,53 858,178 C 829,115 789,69 738,38 687,7 626,-8 553,-8 422,-8 318,44 240,149 162,254 123,394 123,569 123,745 162,885 240,990 318,1095 422,1147 553,1147 625,1147 686,1133 736,1104 786,1075 827,1031 858,971 L 858,1116 1042,1116 1042,72 Z"/>
|
||||||
<glyph unicode="e" horiz-adv-x="1006" d="M 1112,606 L 1112,516 315,516 315,510 C 315,388 347,294 411,227 474,160 564,127 680,127 739,127 800,136 864,155 928,174 996,202 1069,240 L 1069,57 C 999,28 932,7 867,-8 802,-22 739,-29 678,-29 504,-29 368,23 270,128 172,232 123,376 123,559 123,738 171,880 267,987 363,1094 491,1147 651,1147 794,1147 906,1099 989,1002 1071,905 1112,773 1112,606 Z M 928,659 C 925,767 900,850 852,906 803,963 734,991 643,991 554,991 481,962 424,903 367,844 333,763 322,659 L 928,659 Z"/>
|
<glyph unicode="e" horiz-adv-x="1006" d="M 1112,606 L 1112,516 315,516 315,510 C 315,388 347,294 411,227 474,160 564,127 680,127 739,127 800,136 864,155 928,174 996,202 1069,240 L 1069,57 C 999,28 932,7 867,-8 802,-22 739,-29 678,-29 504,-29 368,23 270,128 172,232 123,376 123,559 123,738 171,880 267,987 363,1094 491,1147 651,1147 794,1147 906,1099 989,1002 1071,905 1112,773 1112,606 Z M 928,659 C 925,767 900,850 852,906 803,963 734,991 643,991 554,991 481,962 424,903 367,844 333,763 322,659 L 928,659 Z"/>
|
||||||
@ -63,6 +60,7 @@
|
|||||||
<glyph unicode="I" horiz-adv-x="636" d="M 78,0 L 78,86 104,86 C 127,86 149,88 170,91 190,94 208,101 223,112 238,122 250,137 259,156 268,175 272,201 272,233 L 272,1229 C 272,1261 268,1287 259,1306 250,1325 238,1340 223,1351 208,1361 190,1368 170,1371 149,1374 127,1376 104,1376 L 78,1376 78,1462 674,1462 674,1376 647,1376 C 624,1376 603,1374 582,1371 561,1368 544,1361 529,1351 514,1340 502,1325 493,1306 484,1287 479,1261 479,1229 L 479,233 C 479,201 484,175 493,156 502,137 514,122 529,112 544,101 561,94 582,91 603,88 624,86 647,86 L 674,86 674,0 78,0 Z"/>
|
<glyph unicode="I" horiz-adv-x="636" d="M 78,0 L 78,86 104,86 C 127,86 149,88 170,91 190,94 208,101 223,112 238,122 250,137 259,156 268,175 272,201 272,233 L 272,1229 C 272,1261 268,1287 259,1306 250,1325 238,1340 223,1351 208,1361 190,1368 170,1371 149,1374 127,1376 104,1376 L 78,1376 78,1462 674,1462 674,1376 647,1376 C 624,1376 603,1374 582,1371 561,1368 544,1361 529,1351 514,1340 502,1325 493,1306 484,1287 479,1261 479,1229 L 479,233 C 479,201 484,175 493,156 502,137 514,122 529,112 544,101 561,94 582,91 603,88 624,86 647,86 L 674,86 674,0 78,0 Z"/>
|
||||||
<glyph unicode="G" horiz-adv-x="1324" d="M 821,-20 C 702,-20 599,-2 511,34 422,70 349,121 291,187 232,253 189,332 160,425 131,518 117,620 117,733 117,844 132,945 163,1037 193,1129 238,1208 299,1274 359,1340 434,1391 523,1428 612,1465 716,1483 834,1483 910,1483 976,1477 1033,1466 1089,1454 1136,1438 1174,1417 1211,1396 1239,1372 1258,1344 1277,1316 1286,1286 1286,1253 1286,1231 1281,1211 1271,1194 1261,1176 1248,1161 1231,1149 1214,1136 1194,1127 1171,1120 1148,1113 1123,1110 1096,1110 1096,1142 1091,1174 1082,1205 1073,1236 1057,1265 1036,1290 1015,1315 987,1335 952,1351 917,1366 875,1374 825,1374 738,1374 665,1360 604,1332 543,1303 493,1262 454,1208 415,1153 387,1086 370,1007 353,927 344,836 344,733 344,631 353,540 371,461 389,382 418,315 459,261 500,207 552,166 617,138 682,110 761,96 854,96 893,96 932,98 969,102 1006,106 1038,112 1067,121 L 1067,451 C 1067,481 1063,505 1054,524 1045,542 1032,556 1017,566 1002,575 984,582 964,585 943,588 922,590 899,590 L 891,590 891,676 1423,676 1423,590 1415,590 C 1396,590 1377,588 1360,585 1343,582 1328,575 1315,565 1302,554 1292,539 1285,520 1278,500 1274,474 1274,442 L 1274,74 C 1205,42 1135,18 1062,3 989,-12 909,-20 821,-20 Z"/>
|
<glyph unicode="G" horiz-adv-x="1324" d="M 821,-20 C 702,-20 599,-2 511,34 422,70 349,121 291,187 232,253 189,332 160,425 131,518 117,620 117,733 117,844 132,945 163,1037 193,1129 238,1208 299,1274 359,1340 434,1391 523,1428 612,1465 716,1483 834,1483 910,1483 976,1477 1033,1466 1089,1454 1136,1438 1174,1417 1211,1396 1239,1372 1258,1344 1277,1316 1286,1286 1286,1253 1286,1231 1281,1211 1271,1194 1261,1176 1248,1161 1231,1149 1214,1136 1194,1127 1171,1120 1148,1113 1123,1110 1096,1110 1096,1142 1091,1174 1082,1205 1073,1236 1057,1265 1036,1290 1015,1315 987,1335 952,1351 917,1366 875,1374 825,1374 738,1374 665,1360 604,1332 543,1303 493,1262 454,1208 415,1153 387,1086 370,1007 353,927 344,836 344,733 344,631 353,540 371,461 389,382 418,315 459,261 500,207 552,166 617,138 682,110 761,96 854,96 893,96 932,98 969,102 1006,106 1038,112 1067,121 L 1067,451 C 1067,481 1063,505 1054,524 1045,542 1032,556 1017,566 1002,575 984,582 964,585 943,588 922,590 899,590 L 891,590 891,676 1423,676 1423,590 1415,590 C 1396,590 1377,588 1360,585 1343,582 1328,575 1315,565 1302,554 1292,539 1285,520 1278,500 1274,474 1274,442 L 1274,74 C 1205,42 1135,18 1062,3 989,-12 909,-20 821,-20 Z"/>
|
||||||
<glyph unicode="C" horiz-adv-x="1086" d="M 774,1483 C 844,1483 905,1477 957,1466 1008,1454 1051,1438 1086,1417 1120,1396 1146,1372 1163,1344 1180,1316 1188,1286 1188,1253 1188,1231 1184,1211 1175,1194 1166,1176 1153,1161 1137,1149 1121,1136 1102,1127 1081,1120 1059,1113 1035,1110 1010,1110 1010,1142 1006,1174 998,1205 989,1236 976,1265 957,1290 938,1315 913,1335 883,1351 852,1366 815,1374 770,1374 693,1374 627,1360 573,1332 519,1303 475,1262 441,1208 407,1153 382,1086 367,1007 352,927 344,836 344,733 344,642 352,558 368,482 384,406 409,341 444,287 479,232 523,190 577,160 630,130 695,115 770,115 820,115 864,120 903,130 941,139 975,152 1004,168 1033,184 1059,203 1082,224 1104,245 1124,266 1141,289 1152,282 1162,272 1169,259 1176,246 1180,230 1180,209 1180,183 1171,157 1154,130 1136,103 1109,78 1073,56 1037,34 991,16 936,2 881,-13 815,-20 739,-20 637,-20 547,-2 470,34 393,70 328,121 276,187 223,253 184,332 157,425 130,518 117,620 117,733 117,844 131,945 159,1037 187,1129 229,1208 284,1274 339,1340 407,1391 489,1428 571,1465 666,1483 774,1483 Z"/>
|
<glyph unicode="C" horiz-adv-x="1086" d="M 774,1483 C 844,1483 905,1477 957,1466 1008,1454 1051,1438 1086,1417 1120,1396 1146,1372 1163,1344 1180,1316 1188,1286 1188,1253 1188,1231 1184,1211 1175,1194 1166,1176 1153,1161 1137,1149 1121,1136 1102,1127 1081,1120 1059,1113 1035,1110 1010,1110 1010,1142 1006,1174 998,1205 989,1236 976,1265 957,1290 938,1315 913,1335 883,1351 852,1366 815,1374 770,1374 693,1374 627,1360 573,1332 519,1303 475,1262 441,1208 407,1153 382,1086 367,1007 352,927 344,836 344,733 344,642 352,558 368,482 384,406 409,341 444,287 479,232 523,190 577,160 630,130 695,115 770,115 820,115 864,120 903,130 941,139 975,152 1004,168 1033,184 1059,203 1082,224 1104,245 1124,266 1141,289 1152,282 1162,272 1169,259 1176,246 1180,230 1180,209 1180,183 1171,157 1154,130 1136,103 1109,78 1073,56 1037,34 991,16 936,2 881,-13 815,-20 739,-20 637,-20 547,-2 470,34 393,70 328,121 276,187 223,253 184,332 157,425 130,518 117,620 117,733 117,844 131,945 159,1037 187,1129 229,1208 284,1274 339,1340 407,1391 489,1428 571,1465 666,1483 774,1483 Z"/>
|
||||||
|
<glyph unicode="B" horiz-adv-x="1165" d="M 1153,1096 C 1153,1050 1147,1010 1134,975 1121,940 1103,910 1080,884 1057,858 1031,836 1000,819 969,801 935,786 899,774 L 899,766 C 946,758 988,744 1027,725 1066,706 1099,681 1127,650 1154,619 1176,582 1191,540 1206,497 1214,449 1214,395 1214,263 1171,164 1084,99 997,33 865,0 688,0 L 78,0 78,86 104,86 C 127,86 149,88 170,91 190,94 208,101 223,112 238,122 250,137 259,156 268,175 272,201 272,233 L 272,1237 C 272,1267 268,1291 259,1310 250,1328 237,1342 222,1352 207,1362 189,1369 169,1372 148,1375 127,1376 104,1376 L 78,1376 78,1462 627,1462 C 804,1462 936,1433 1023,1374 1110,1315 1153,1222 1153,1096 Z M 479,102 L 678,102 C 736,102 785,107 825,118 865,129 898,146 923,170 948,193 967,224 978,262 989,300 995,346 995,401 995,454 990,501 980,540 970,579 953,612 929,638 904,664 872,683 832,696 792,709 742,715 682,715 L 479,715 479,102 Z M 479,817 L 621,817 C 681,817 731,822 771,833 811,844 843,860 867,883 891,905 908,934 919,969 929,1004 934,1047 934,1096 934,1146 928,1188 917,1222 906,1255 887,1282 862,1303 837,1324 804,1338 764,1347 723,1356 674,1360 616,1360 L 479,1360 479,817 Z"/>
|
||||||
<glyph unicode="A" horiz-adv-x="1456" d="M 414,489 L 336,274 C 330,258 325,242 322,227 319,211 317,197 317,186 317,151 328,126 351,110 373,94 407,86 453,86 L 500,86 500,0 0,0 0,86 39,86 C 59,86 76,88 90,93 104,97 117,105 128,117 139,129 150,145 161,166 171,187 182,213 195,246 L 649,1462 809,1462 1272,195 C 1280,174 1288,156 1297,142 1305,128 1315,117 1326,109 1337,100 1350,94 1365,91 1380,88 1397,86 1417,86 L 1444,86 1444,0 881,0 881,86 928,86 C 1010,86 1051,119 1051,184 1051,195 1050,207 1047,219 1044,231 1039,245 1034,260 L 952,489 414,489 Z M 788,950 C 767,1011 747,1068 730,1121 712,1174 697,1225 686,1274 681,1249 676,1226 670,1203 663,1180 656,1156 649,1132 642,1108 633,1083 624,1057 615,1030 604,1001 592,969 L 453,592 915,592 788,950 Z"/>
|
<glyph unicode="A" horiz-adv-x="1456" d="M 414,489 L 336,274 C 330,258 325,242 322,227 319,211 317,197 317,186 317,151 328,126 351,110 373,94 407,86 453,86 L 500,86 500,0 0,0 0,86 39,86 C 59,86 76,88 90,93 104,97 117,105 128,117 139,129 150,145 161,166 171,187 182,213 195,246 L 649,1462 809,1462 1272,195 C 1280,174 1288,156 1297,142 1305,128 1315,117 1326,109 1337,100 1350,94 1365,91 1380,88 1397,86 1417,86 L 1444,86 1444,0 881,0 881,86 928,86 C 1010,86 1051,119 1051,184 1051,195 1050,207 1047,219 1044,231 1039,245 1034,260 L 952,489 414,489 Z M 788,950 C 767,1011 747,1068 730,1121 712,1174 697,1225 686,1274 681,1249 676,1226 670,1203 663,1180 656,1156 649,1132 642,1108 633,1083 624,1057 615,1030 604,1001 592,969 L 453,592 915,592 788,950 Z"/>
|
||||||
<glyph unicode="8" horiz-adv-x="980" d="M 94,367 C 94,416 102,460 118,497 133,534 155,567 183,596 211,625 244,651 282,674 320,697 361,720 406,741 367,763 332,787 299,813 266,838 238,866 215,897 192,928 174,961 161,998 148,1034 141,1073 141,1116 141,1163 149,1209 166,1253 183,1297 209,1336 244,1370 279,1404 325,1431 382,1452 438,1473 505,1483 584,1483 648,1483 705,1474 755,1457 805,1439 847,1414 882,1383 916,1352 942,1315 960,1272 978,1229 987,1181 987,1130 987,1085 980,1046 967,1012 954,978 935,948 911,921 887,894 858,869 824,848 790,826 752,805 711,784 762,760 808,734 850,707 891,680 927,650 957,618 987,586 1010,551 1027,514 1043,477 1051,436 1051,391 1051,326 1039,269 1016,218 993,167 960,123 917,88 874,53 823,26 762,8 701,-11 634,-20 559,-20 482,-20 415,-10 357,10 299,30 251,58 212,93 173,128 143,169 124,216 104,263 94,313 94,367 Z M 569,74 C 614,74 654,81 691,95 727,108 758,127 784,151 809,175 829,204 843,237 857,270 864,307 864,346 864,381 858,413 845,443 832,472 812,501 783,529 754,556 717,583 672,610 626,636 570,663 504,692 439,657 388,612 350,557 312,502 293,435 293,358 293,315 299,277 311,242 322,207 340,178 363,153 386,128 414,108 449,95 484,81 524,74 569,74 Z M 805,1135 C 805,1166 801,1197 793,1227 784,1257 771,1284 753,1308 734,1331 710,1350 681,1365 651,1379 614,1386 571,1386 533,1386 499,1380 470,1368 440,1355 415,1338 395,1317 375,1295 360,1269 350,1239 339,1209 334,1176 334,1141 334,1104 340,1071 352,1042 363,1013 381,986 404,962 427,938 455,916 490,895 525,874 565,852 610,831 649,850 681,870 706,891 731,911 750,933 765,958 780,982 790,1009 796,1038 802,1067 805,1099 805,1135 Z"/>
|
<glyph unicode="8" horiz-adv-x="980" d="M 94,367 C 94,416 102,460 118,497 133,534 155,567 183,596 211,625 244,651 282,674 320,697 361,720 406,741 367,763 332,787 299,813 266,838 238,866 215,897 192,928 174,961 161,998 148,1034 141,1073 141,1116 141,1163 149,1209 166,1253 183,1297 209,1336 244,1370 279,1404 325,1431 382,1452 438,1473 505,1483 584,1483 648,1483 705,1474 755,1457 805,1439 847,1414 882,1383 916,1352 942,1315 960,1272 978,1229 987,1181 987,1130 987,1085 980,1046 967,1012 954,978 935,948 911,921 887,894 858,869 824,848 790,826 752,805 711,784 762,760 808,734 850,707 891,680 927,650 957,618 987,586 1010,551 1027,514 1043,477 1051,436 1051,391 1051,326 1039,269 1016,218 993,167 960,123 917,88 874,53 823,26 762,8 701,-11 634,-20 559,-20 482,-20 415,-10 357,10 299,30 251,58 212,93 173,128 143,169 124,216 104,263 94,313 94,367 Z M 569,74 C 614,74 654,81 691,95 727,108 758,127 784,151 809,175 829,204 843,237 857,270 864,307 864,346 864,381 858,413 845,443 832,472 812,501 783,529 754,556 717,583 672,610 626,636 570,663 504,692 439,657 388,612 350,557 312,502 293,435 293,358 293,315 299,277 311,242 322,207 340,178 363,153 386,128 414,108 449,95 484,81 524,74 569,74 Z M 805,1135 C 805,1166 801,1197 793,1227 784,1257 771,1284 753,1308 734,1331 710,1350 681,1365 651,1379 614,1386 571,1386 533,1386 499,1380 470,1368 440,1355 415,1338 395,1317 375,1295 360,1269 350,1239 339,1209 334,1176 334,1141 334,1104 340,1071 352,1042 363,1013 381,986 404,962 427,938 455,916 490,895 525,874 565,852 610,831 649,850 681,870 706,891 731,911 750,933 765,958 780,982 790,1009 796,1038 802,1067 805,1099 805,1135 Z"/>
|
||||||
<glyph unicode="6" horiz-adv-x="953" d="M 659,1384 C 556,1384 479,1334 426,1233 373,1132 343,981 336,782 353,796 371,810 392,823 412,836 434,847 458,857 482,866 508,874 537,880 565,886 596,889 629,889 692,889 748,879 799,860 850,841 893,813 929,777 964,741 992,697 1011,645 1030,593 1040,534 1040,469 1040,397 1030,331 1011,271 991,211 962,160 925,117 887,74 841,40 787,16 732,-8 670,-20 600,-20 532,-20 469,-6 411,23 353,51 303,96 261,157 218,218 185,296 161,392 137,487 125,602 125,737 125,802 130,865 140,927 149,989 164,1048 183,1103 202,1158 227,1209 256,1256 285,1303 320,1343 360,1377 399,1410 444,1436 494,1455 544,1474 599,1483 659,1483 716,1483 766,1477 809,1465 851,1453 886,1437 914,1417 942,1397 963,1374 977,1348 990,1322 997,1295 997,1268 997,1229 984,1198 957,1177 930,1156 891,1145 840,1145 840,1178 837,1210 831,1239 824,1268 814,1293 799,1315 784,1336 766,1353 743,1366 720,1378 692,1384 659,1384 Z M 588,784 C 561,784 536,781 511,774 486,767 463,758 442,747 420,736 400,723 382,709 364,694 348,680 334,666 335,563 343,476 356,403 369,330 387,271 410,225 433,179 462,145 495,124 528,103 565,92 606,92 679,92 735,121 774,178 812,235 831,325 831,449 831,566 810,651 769,704 727,757 667,784 588,784 Z"/>
|
<glyph unicode="6" horiz-adv-x="953" d="M 659,1384 C 556,1384 479,1334 426,1233 373,1132 343,981 336,782 353,796 371,810 392,823 412,836 434,847 458,857 482,866 508,874 537,880 565,886 596,889 629,889 692,889 748,879 799,860 850,841 893,813 929,777 964,741 992,697 1011,645 1030,593 1040,534 1040,469 1040,397 1030,331 1011,271 991,211 962,160 925,117 887,74 841,40 787,16 732,-8 670,-20 600,-20 532,-20 469,-6 411,23 353,51 303,96 261,157 218,218 185,296 161,392 137,487 125,602 125,737 125,802 130,865 140,927 149,989 164,1048 183,1103 202,1158 227,1209 256,1256 285,1303 320,1343 360,1377 399,1410 444,1436 494,1455 544,1474 599,1483 659,1483 716,1483 766,1477 809,1465 851,1453 886,1437 914,1417 942,1397 963,1374 977,1348 990,1322 997,1295 997,1268 997,1229 984,1198 957,1177 930,1156 891,1145 840,1145 840,1178 837,1210 831,1239 824,1268 814,1293 799,1315 784,1336 766,1353 743,1366 720,1378 692,1384 659,1384 Z M 588,784 C 561,784 536,781 511,774 486,767 463,758 442,747 420,736 400,723 382,709 364,694 348,680 334,666 335,563 343,476 356,403 369,330 387,271 410,225 433,179 462,145 495,124 528,103 565,92 606,92 679,92 735,121 774,178 812,235 831,325 831,449 831,566 810,651 769,704 727,757 667,784 588,784 Z"/>
|
||||||
@ -120,7 +118,7 @@
|
|||||||
</font>
|
</font>
|
||||||
</defs>
|
</defs>
|
||||||
<defs class="TextShapeIndex">
|
<defs class="TextShapeIndex">
|
||||||
<g ooo:slide="id1" ooo:id-list="id3 id4 id5 id6 id7 id8 id9 id10 id11 id12 id13 id14 id15 id16 id17 id18 id19 id20 id21 id22 id23 id24 id25 id26 id27 id28 id29 id30 id31 id32 id33 id34 id35 id36 id37 id38 id39 id40 id41 id42 id43 id44 id45"/>
|
<g ooo:slide="id1" ooo:id-list="id3 id4 id5 id6 id7 id8 id9 id10 id11 id12 id13 id14 id15 id16 id17 id18 id19 id20 id21 id22 id23 id24 id25 id26 id27 id28 id29 id30 id31 id32 id33 id34 id35 id36 id37 id38 id39 id40 id41 id42 id43 id44 id45 id46"/>
|
||||||
</defs>
|
</defs>
|
||||||
<defs class="EmbeddedBulletChars">
|
<defs class="EmbeddedBulletChars">
|
||||||
<g id="bullet-char-template-57356" transform="scale(0.00048828125,-0.00048828125)">
|
<g id="bullet-char-template-57356" transform="scale(0.00048828125,-0.00048828125)">
|
||||||
@ -177,7 +175,7 @@
|
|||||||
<rect class="BoundingBox" stroke="none" fill="none" x="1704" y="3500" width="5611" height="1213"/>
|
<rect class="BoundingBox" stroke="none" fill="none" x="1704" y="3500" width="5611" height="1213"/>
|
||||||
<path fill="rgb(142,134,174)" stroke="none" d="M 4509,4685 L 1731,4685 1731,3527 7287,3527 7287,4685 4509,4685 Z"/>
|
<path fill="rgb(142,134,174)" stroke="none" d="M 4509,4685 L 1731,4685 1731,3527 7287,3527 7287,4685 4509,4685 Z"/>
|
||||||
<path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 4509,4685 L 1731,4685 1731,3527 7287,3527 7287,4685 4509,4685 Z"/>
|
<path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 4509,4685 L 1731,4685 1731,3527 7287,3527 7287,4685 4509,4685 Z"/>
|
||||||
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Droid Serif, serif" font-size="493px" font-weight="400"><tspan class="TextPosition" x="2619" y="4277"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">Read module.p8</tspan></tspan></tspan></text>
|
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Droid Serif, serif" font-size="494px" font-weight="400"><tspan class="TextPosition" x="2600" y="4277"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">Read module.p8</tspan></tspan></tspan></text>
|
||||||
</g>
|
</g>
|
||||||
</g>
|
</g>
|
||||||
<g class="com.sun.star.drawing.CustomShape">
|
<g class="com.sun.star.drawing.CustomShape">
|
||||||
@ -185,7 +183,7 @@
|
|||||||
<rect class="BoundingBox" stroke="none" fill="none" x="1704" y="5583" width="5611" height="1212"/>
|
<rect class="BoundingBox" stroke="none" fill="none" x="1704" y="5583" width="5611" height="1212"/>
|
||||||
<path fill="rgb(142,134,174)" stroke="none" d="M 4509,6767 L 1731,6767 1731,5610 7287,5610 7287,6767 4509,6767 Z"/>
|
<path fill="rgb(142,134,174)" stroke="none" d="M 4509,6767 L 1731,6767 1731,5610 7287,5610 7287,6767 4509,6767 Z"/>
|
||||||
<path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 4509,6767 L 1731,6767 1731,5610 7287,5610 7287,6767 4509,6767 Z"/>
|
<path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 4509,6767 L 1731,6767 1731,5610 7287,5610 7287,6767 4509,6767 Z"/>
|
||||||
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Droid Serif, serif" font-size="493px" font-weight="400"><tspan class="TextPosition" x="3459" y="6360"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">Tokenize</tspan></tspan></tspan></text>
|
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Droid Serif, serif" font-size="494px" font-weight="400"><tspan class="TextPosition" x="3451" y="6360"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">Tokenize</tspan></tspan></tspan></text>
|
||||||
</g>
|
</g>
|
||||||
</g>
|
</g>
|
||||||
<g class="com.sun.star.drawing.CustomShape">
|
<g class="com.sun.star.drawing.CustomShape">
|
||||||
@ -193,7 +191,7 @@
|
|||||||
<rect class="BoundingBox" stroke="none" fill="none" x="1704" y="9750" width="5611" height="1213"/>
|
<rect class="BoundingBox" stroke="none" fill="none" x="1704" y="9750" width="5611" height="1213"/>
|
||||||
<path fill="rgb(114,159,207)" stroke="none" d="M 4509,10935 L 1731,10935 1731,9777 7287,9777 7287,10935 4509,10935 Z"/>
|
<path fill="rgb(114,159,207)" stroke="none" d="M 4509,10935 L 1731,10935 1731,9777 7287,9777 7287,10935 4509,10935 Z"/>
|
||||||
<path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 4509,10935 L 1731,10935 1731,9777 7287,9777 7287,10935 4509,10935 Z"/>
|
<path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 4509,10935 L 1731,10935 1731,9777 7287,9777 7287,10935 4509,10935 Z"/>
|
||||||
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Droid Serif, serif" font-size="493px" font-weight="400"><tspan class="TextPosition" x="2774" y="10527"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">Convert to AST</tspan></tspan></tspan></text>
|
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Droid Serif, serif" font-size="494px" font-weight="400"><tspan class="TextPosition" x="2761" y="10527"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">Convert to AST</tspan></tspan></tspan></text>
|
||||||
</g>
|
</g>
|
||||||
</g>
|
</g>
|
||||||
<g class="com.sun.star.drawing.CustomShape">
|
<g class="com.sun.star.drawing.CustomShape">
|
||||||
@ -201,7 +199,7 @@
|
|||||||
<rect class="BoundingBox" stroke="none" fill="none" x="1704" y="13916" width="5611" height="1444"/>
|
<rect class="BoundingBox" stroke="none" fill="none" x="1704" y="13916" width="5611" height="1444"/>
|
||||||
<path fill="rgb(114,159,207)" stroke="none" d="M 4509,15332 L 1731,15332 1731,13943 7287,13943 7287,15332 4509,15332 Z"/>
|
<path fill="rgb(114,159,207)" stroke="none" d="M 4509,15332 L 1731,15332 1731,13943 7287,13943 7287,15332 4509,15332 Z"/>
|
||||||
<path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 4509,15332 L 1731,15332 1731,13943 7287,13943 7287,15332 4509,15332 Z"/>
|
<path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 4509,15332 L 1731,15332 1731,13943 7287,13943 7287,15332 4509,15332 Z"/>
|
||||||
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Droid Serif, serif" font-size="493px" font-weight="400"><tspan class="TextPosition" x="2285" y="14523"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">Semantic and Type </tspan></tspan><tspan class="TextPosition" x="3468" y="15095"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">checking</tspan></tspan></tspan></text>
|
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Droid Serif, serif" font-size="494px" font-weight="400"><tspan class="TextPosition" x="2263" y="14519"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">Semantic and Type </tspan></tspan><tspan class="TextPosition" x="3459" y="15099"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">checking</tspan></tspan></tspan></text>
|
||||||
</g>
|
</g>
|
||||||
</g>
|
</g>
|
||||||
<g class="com.sun.star.drawing.CustomShape">
|
<g class="com.sun.star.drawing.CustomShape">
|
||||||
@ -209,7 +207,7 @@
|
|||||||
<rect class="BoundingBox" stroke="none" fill="none" x="1704" y="11833" width="5611" height="1212"/>
|
<rect class="BoundingBox" stroke="none" fill="none" x="1704" y="11833" width="5611" height="1212"/>
|
||||||
<path fill="rgb(114,159,207)" stroke="none" d="M 4509,13017 L 1731,13017 1731,11860 7287,11860 7287,13017 4509,13017 Z"/>
|
<path fill="rgb(114,159,207)" stroke="none" d="M 4509,13017 L 1731,13017 1731,11860 7287,11860 7287,13017 4509,13017 Z"/>
|
||||||
<path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 4509,13017 L 1731,13017 1731,11860 7287,11860 7287,13017 4509,13017 Z"/>
|
<path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 4509,13017 L 1731,13017 1731,11860 7287,11860 7287,13017 4509,13017 Z"/>
|
||||||
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Droid Serif, serif" font-size="493px" font-weight="400"><tspan class="TextPosition" x="2716" y="12610"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">Preprocess AST</tspan></tspan></tspan></text>
|
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Droid Serif, serif" font-size="494px" font-weight="400"><tspan class="TextPosition" x="2697" y="12610"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">Preprocess AST</tspan></tspan></tspan></text>
|
||||||
</g>
|
</g>
|
||||||
</g>
|
</g>
|
||||||
<g class="com.sun.star.drawing.ConnectorShape">
|
<g class="com.sun.star.drawing.ConnectorShape">
|
||||||
@ -260,7 +258,7 @@
|
|||||||
<rect class="BoundingBox" stroke="none" fill="none" x="5269" y="16315" width="3758" height="1212"/>
|
<rect class="BoundingBox" stroke="none" fill="none" x="5269" y="16315" width="3758" height="1212"/>
|
||||||
<path fill="rgb(114,159,207)" stroke="none" d="M 7148,17499 L 5296,17499 5296,16342 8999,16342 8999,17499 7148,17499 Z"/>
|
<path fill="rgb(114,159,207)" stroke="none" d="M 7148,17499 L 5296,17499 5296,16342 8999,16342 8999,17499 7148,17499 Z"/>
|
||||||
<path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 7148,17499 L 5296,17499 5296,16342 8999,16342 8999,17499 7148,17499 Z"/>
|
<path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 7148,17499 L 5296,17499 5296,16342 8999,16342 8999,17499 7148,17499 Z"/>
|
||||||
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Droid Serif, serif" font-size="493px" font-weight="400"><tspan class="TextPosition" x="6083" y="17092"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">Optimize</tspan></tspan></tspan></text>
|
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Droid Serif, serif" font-size="494px" font-weight="400"><tspan class="TextPosition" x="6072" y="17092"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">Optimize</tspan></tspan></tspan></text>
|
||||||
</g>
|
</g>
|
||||||
</g>
|
</g>
|
||||||
<g class="com.sun.star.drawing.CustomShape">
|
<g class="com.sun.star.drawing.CustomShape">
|
||||||
@ -268,7 +266,7 @@
|
|||||||
<rect class="BoundingBox" stroke="none" fill="none" x="1704" y="18315" width="5611" height="1213"/>
|
<rect class="BoundingBox" stroke="none" fill="none" x="1704" y="18315" width="5611" height="1213"/>
|
||||||
<path fill="rgb(114,159,207)" stroke="none" d="M 4509,19500 L 1731,19500 1731,18342 7287,18342 7287,19500 4509,19500 Z"/>
|
<path fill="rgb(114,159,207)" stroke="none" d="M 4509,19500 L 1731,19500 1731,18342 7287,18342 7287,19500 4509,19500 Z"/>
|
||||||
<path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 4509,19500 L 1731,19500 1731,18342 7287,18342 7287,19500 4509,19500 Z"/>
|
<path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 4509,19500 L 1731,19500 1731,18342 7287,18342 7287,19500 4509,19500 Z"/>
|
||||||
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Droid Serif, serif" font-size="493px" font-weight="400"><tspan class="TextPosition" x="2625" y="19092"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">Postprocess AST</tspan></tspan></tspan></text>
|
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Droid Serif, serif" font-size="494px" font-weight="400"><tspan class="TextPosition" x="2604" y="19092"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">Postprocess AST</tspan></tspan></tspan></text>
|
||||||
</g>
|
</g>
|
||||||
</g>
|
</g>
|
||||||
<g class="com.sun.star.drawing.ConnectorShape">
|
<g class="com.sun.star.drawing.ConnectorShape">
|
||||||
@ -290,7 +288,7 @@
|
|||||||
<rect class="BoundingBox" stroke="none" fill="none" x="1704" y="7665" width="5611" height="1213"/>
|
<rect class="BoundingBox" stroke="none" fill="none" x="1704" y="7665" width="5611" height="1213"/>
|
||||||
<path fill="rgb(142,134,174)" stroke="none" d="M 4509,8850 L 1731,8850 1731,7692 7287,7692 7287,8850 4509,8850 Z"/>
|
<path fill="rgb(142,134,174)" stroke="none" d="M 4509,8850 L 1731,8850 1731,7692 7287,7692 7287,8850 4509,8850 Z"/>
|
||||||
<path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 4509,8850 L 1731,8850 1731,7692 7287,7692 7287,8850 4509,8850 Z"/>
|
<path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 4509,8850 L 1731,8850 1731,7692 7287,7692 7287,8850 4509,8850 Z"/>
|
||||||
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Droid Serif, serif" font-size="493px" font-weight="400"><tspan class="TextPosition" x="3866" y="8442"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">Parse</tspan></tspan></tspan></text>
|
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Droid Serif, serif" font-size="494px" font-weight="400"><tspan class="TextPosition" x="3857" y="8442"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">Parse</tspan></tspan></tspan></text>
|
||||||
</g>
|
</g>
|
||||||
</g>
|
</g>
|
||||||
<g class="com.sun.star.drawing.ConnectorShape">
|
<g class="com.sun.star.drawing.ConnectorShape">
|
||||||
@ -311,7 +309,7 @@
|
|||||||
<rect class="BoundingBox" stroke="none" fill="none" x="13167" y="3306" width="5611" height="1213"/>
|
<rect class="BoundingBox" stroke="none" fill="none" x="13167" y="3306" width="5611" height="1213"/>
|
||||||
<path fill="rgb(129,172,166)" stroke="none" d="M 15972,4491 L 13194,4491 13194,3333 18750,3333 18750,4491 15972,4491 Z"/>
|
<path fill="rgb(129,172,166)" stroke="none" d="M 15972,4491 L 13194,4491 13194,3333 18750,3333 18750,4491 15972,4491 Z"/>
|
||||||
<path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 15972,4491 L 13194,4491 13194,3333 18750,3333 18750,4491 15972,4491 Z"/>
|
<path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 15972,4491 L 13194,4491 13194,3333 18750,3333 18750,4491 15972,4491 Z"/>
|
||||||
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Droid Serif, serif" font-size="493px" font-weight="400"><tspan class="TextPosition" x="14190" y="3797"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">Select CodeGen</tspan></tspan><tspan class="TextPosition" x="14869" y="4369"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">for target</tspan></tspan></tspan></text>
|
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Droid Serif, serif" font-size="494px" font-weight="400"><tspan class="TextPosition" x="14169" y="3793"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">Select CodeGen</tspan></tspan><tspan class="TextPosition" x="14861" y="4373"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">for target</tspan></tspan></tspan></text>
|
||||||
</g>
|
</g>
|
||||||
</g>
|
</g>
|
||||||
<g class="com.sun.star.drawing.ConnectorShape">
|
<g class="com.sun.star.drawing.ConnectorShape">
|
||||||
@ -333,7 +331,7 @@
|
|||||||
<rect class="BoundingBox" stroke="none" fill="none" x="14723" y="5621" width="4305" height="1907"/>
|
<rect class="BoundingBox" stroke="none" fill="none" x="14723" y="5621" width="4305" height="1907"/>
|
||||||
<path fill="rgb(129,172,166)" stroke="none" d="M 16875,7500 L 14750,7500 14750,5648 19000,5648 19000,7500 16875,7500 Z"/>
|
<path fill="rgb(129,172,166)" stroke="none" d="M 16875,7500 L 14750,7500 14750,5648 19000,5648 19000,7500 16875,7500 Z"/>
|
||||||
<path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16875,7500 L 14750,7500 14750,5648 19000,5648 19000,7500 16875,7500 Z"/>
|
<path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16875,7500 L 14750,7500 14750,5648 19000,5648 19000,7500 16875,7500 Z"/>
|
||||||
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Droid Serif, serif" font-size="493px" font-weight="400"><tspan class="TextPosition" x="16236" y="6173"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">Make </tspan></tspan><tspan class="TextPosition" x="15343" y="6745"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">Intermediate </tspan></tspan><tspan class="TextPosition" x="16422" y="7317"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">AST</tspan></tspan></tspan></text>
|
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Droid Serif, serif" font-size="494px" font-weight="400"><tspan class="TextPosition" x="16230" y="6165"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">Make </tspan></tspan><tspan class="TextPosition" x="15330" y="6745"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">Intermediate </tspan></tspan><tspan class="TextPosition" x="16420" y="7325"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">AST</tspan></tspan></tspan></text>
|
||||||
</g>
|
</g>
|
||||||
</g>
|
</g>
|
||||||
<g class="com.sun.star.drawing.ConnectorShape">
|
<g class="com.sun.star.drawing.ConnectorShape">
|
||||||
@ -348,7 +346,7 @@
|
|||||||
<rect class="BoundingBox" stroke="none" fill="none" x="14723" y="8472" width="4305" height="1444"/>
|
<rect class="BoundingBox" stroke="none" fill="none" x="14723" y="8472" width="4305" height="1444"/>
|
||||||
<path fill="rgb(129,172,166)" stroke="none" d="M 16875,9888 L 14750,9888 14750,8499 19000,8499 19000,9888 16875,9888 Z"/>
|
<path fill="rgb(129,172,166)" stroke="none" d="M 16875,9888 L 14750,9888 14750,8499 19000,8499 19000,9888 16875,9888 Z"/>
|
||||||
<path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16875,9888 L 14750,9888 14750,8499 19000,8499 19000,9888 16875,9888 Z"/>
|
<path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16875,9888 L 14750,9888 14750,8499 19000,8499 19000,9888 16875,9888 Z"/>
|
||||||
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Droid Serif, serif" font-size="493px" font-weight="400"><tspan class="TextPosition" x="15434" y="9365"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">Generate IR </tspan></tspan></tspan></text>
|
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Droid Serif, serif" font-size="494px" font-weight="400"><tspan class="TextPosition" x="15419" y="9365"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">Generate IR </tspan></tspan></tspan></text>
|
||||||
</g>
|
</g>
|
||||||
</g>
|
</g>
|
||||||
<g class="com.sun.star.drawing.ConnectorShape">
|
<g class="com.sun.star.drawing.ConnectorShape">
|
||||||
@ -363,7 +361,7 @@
|
|||||||
<rect class="BoundingBox" stroke="none" fill="none" x="14723" y="10972" width="4305" height="1444"/>
|
<rect class="BoundingBox" stroke="none" fill="none" x="14723" y="10972" width="4305" height="1444"/>
|
||||||
<path fill="rgb(129,172,166)" stroke="none" d="M 16875,12388 L 14750,12388 14750,10999 19000,10999 19000,12388 16875,12388 Z"/>
|
<path fill="rgb(129,172,166)" stroke="none" d="M 16875,12388 L 14750,12388 14750,10999 19000,10999 19000,12388 16875,12388 Z"/>
|
||||||
<path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16875,12388 L 14750,12388 14750,10999 19000,10999 19000,12388 16875,12388 Z"/>
|
<path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16875,12388 L 14750,12388 14750,10999 19000,10999 19000,12388 16875,12388 Z"/>
|
||||||
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Droid Serif, serif" font-size="493px" font-weight="400"><tspan class="TextPosition" x="15495" y="11865"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">Optimize IR</tspan></tspan></tspan></text>
|
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Droid Serif, serif" font-size="494px" font-weight="400"><tspan class="TextPosition" x="15482" y="11865"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">Optimize IR</tspan></tspan></tspan></text>
|
||||||
</g>
|
</g>
|
||||||
</g>
|
</g>
|
||||||
<g class="com.sun.star.drawing.ConnectorShape">
|
<g class="com.sun.star.drawing.ConnectorShape">
|
||||||
@ -375,17 +373,17 @@
|
|||||||
</g>
|
</g>
|
||||||
<g class="com.sun.star.drawing.CustomShape">
|
<g class="com.sun.star.drawing.CustomShape">
|
||||||
<g id="id31">
|
<g id="id31">
|
||||||
<rect class="BoundingBox" stroke="none" fill="none" x="13157" y="14223" width="3620" height="1305"/>
|
<rect class="BoundingBox" stroke="none" fill="none" x="13157" y="14223" width="3620" height="1457"/>
|
||||||
<path fill="rgb(255,166,166)" stroke="none" d="M 14967,15500 L 13184,15500 13184,14250 16749,14250 16749,15500 14967,15500 Z"/>
|
<path fill="rgb(255,166,166)" stroke="none" d="M 14967,15652 L 13184,15652 13184,14250 16749,14250 16749,15652 14967,15652 Z"/>
|
||||||
<path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 14967,15500 L 13184,15500 13184,14250 16749,14250 16749,15500 14967,15500 Z"/>
|
<path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 14967,15652 L 13184,15652 13184,14250 16749,14250 16749,15652 14967,15652 Z"/>
|
||||||
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Droid Serif, serif" font-size="493px" font-weight="400"><tspan class="TextPosition" x="13904" y="14760"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">Generate </tspan></tspan><tspan class="TextPosition" x="13836" y="15332"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">6502 Asm</tspan></tspan></tspan></text>
|
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Droid Serif, serif" font-size="494px" font-weight="400"><tspan class="TextPosition" x="13891" y="14832"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">Generate </tspan></tspan><tspan class="TextPosition" x="13832" y="15412"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">6502 Asm</tspan></tspan></tspan></text>
|
||||||
</g>
|
</g>
|
||||||
</g>
|
</g>
|
||||||
<g class="com.sun.star.drawing.ConnectorShape">
|
<g class="com.sun.star.drawing.ConnectorShape">
|
||||||
<g id="id32">
|
<g id="id32">
|
||||||
<rect class="BoundingBox" stroke="none" fill="none" x="12223" y="4464" width="3777" height="10552"/>
|
<rect class="BoundingBox" stroke="none" fill="none" x="12223" y="4464" width="3777" height="10628"/>
|
||||||
<path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="miter" stroke-linecap="round" d="M 15972,4491 L 15972,5019 12250,5019 12250,14875 12925,14875"/>
|
<path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="miter" stroke-linecap="round" d="M 15972,4491 L 15972,5019 12250,5019 12250,14951 12925,14951"/>
|
||||||
<path fill="rgb(52,101,164)" stroke="none" d="M 12906,14736 L 13185,14875 12906,15015 12906,14736 Z"/>
|
<path fill="rgb(52,101,164)" stroke="none" d="M 12906,14812 L 13185,14951 12906,15091 12906,14812 Z"/>
|
||||||
</g>
|
</g>
|
||||||
</g>
|
</g>
|
||||||
<g class="TextShape">
|
<g class="TextShape">
|
||||||
@ -399,13 +397,13 @@
|
|||||||
<rect class="BoundingBox" stroke="none" fill="none" x="13167" y="16269" width="3611" height="1509"/>
|
<rect class="BoundingBox" stroke="none" fill="none" x="13167" y="16269" width="3611" height="1509"/>
|
||||||
<path fill="rgb(255,166,166)" stroke="none" d="M 14972,17750 L 13194,17750 13194,16296 16750,16296 16750,17750 14972,17750 Z"/>
|
<path fill="rgb(255,166,166)" stroke="none" d="M 14972,17750 L 13194,17750 13194,16296 16750,16296 16750,17750 14972,17750 Z"/>
|
||||||
<path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 14972,17750 L 13194,17750 13194,16296 16750,16296 16750,17750 14972,17750 Z"/>
|
<path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 14972,17750 L 13194,17750 13194,16296 16750,16296 16750,17750 14972,17750 Z"/>
|
||||||
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Droid Serif, serif" font-size="493px" font-weight="400"><tspan class="TextPosition" x="13857" y="16908"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">Assemble </tspan></tspan><tspan class="TextPosition" x="14083" y="17480"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">(64tass)</tspan></tspan></tspan></text>
|
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Droid Serif, serif" font-size="494px" font-weight="400"><tspan class="TextPosition" x="13844" y="16904"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">Assemble </tspan></tspan><tspan class="TextPosition" x="14073" y="17484"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">(64tass)</tspan></tspan></tspan></text>
|
||||||
</g>
|
</g>
|
||||||
</g>
|
</g>
|
||||||
<g class="com.sun.star.drawing.ConnectorShape">
|
<g class="com.sun.star.drawing.ConnectorShape">
|
||||||
<g id="id35">
|
<g id="id35">
|
||||||
<rect class="BoundingBox" stroke="none" fill="none" x="14832" y="15473" width="281" height="824"/>
|
<rect class="BoundingBox" stroke="none" fill="none" x="14832" y="15625" width="281" height="672"/>
|
||||||
<path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="miter" stroke-linecap="round" d="M 14967,15500 L 14967,15898 14972,15898 14972,16036"/>
|
<path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="miter" stroke-linecap="round" d="M 14967,15652 L 14967,15974 14972,15974 14972,16036"/>
|
||||||
<path fill="rgb(52,101,164)" stroke="none" d="M 15112,16017 L 14972,16296 14833,16017 15112,16017 Z"/>
|
<path fill="rgb(52,101,164)" stroke="none" d="M 15112,16017 L 14972,16296 14833,16017 15112,16017 Z"/>
|
||||||
</g>
|
</g>
|
||||||
</g>
|
</g>
|
||||||
@ -444,44 +442,52 @@
|
|||||||
<rect class="BoundingBox" stroke="none" fill="none" x="17473" y="14222" width="3305" height="1212"/>
|
<rect class="BoundingBox" stroke="none" fill="none" x="17473" y="14222" width="3305" height="1212"/>
|
||||||
<path fill="rgb(255,166,166)" stroke="none" d="M 19125,15406 L 17500,15406 17500,14249 20750,14249 20750,15406 19125,15406 Z"/>
|
<path fill="rgb(255,166,166)" stroke="none" d="M 19125,15406 L 17500,15406 17500,14249 20750,14249 20750,15406 19125,15406 Z"/>
|
||||||
<path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 19125,15406 L 17500,15406 17500,14249 20750,14249 20750,15406 19125,15406 Z"/>
|
<path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 19125,15406 L 17500,15406 17500,14249 20750,14249 20750,15406 19125,15406 Z"/>
|
||||||
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Droid Serif, serif" font-size="493px" font-weight="400"><tspan class="TextPosition" x="18063" y="14713"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">Generate </tspan></tspan><tspan class="TextPosition" x="18122" y="15285"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">VM code</tspan></tspan></tspan></text>
|
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Droid Serif, serif" font-size="494px" font-weight="400"><tspan class="TextPosition" x="18050" y="14709"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">Generate </tspan></tspan><tspan class="TextPosition" x="18109" y="15289"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">VM code</tspan></tspan></tspan></text>
|
||||||
</g>
|
</g>
|
||||||
</g>
|
</g>
|
||||||
<g class="com.sun.star.drawing.CustomShape">
|
<g class="com.sun.star.drawing.ConnectorShape">
|
||||||
<g id="id41">
|
<g id="id41">
|
||||||
<rect class="BoundingBox" stroke="none" fill="none" x="17595" y="16498" width="3157" height="1393"/>
|
<rect class="BoundingBox" stroke="none" fill="none" x="18934" y="15625" width="281" height="778"/>
|
||||||
<path fill="rgb(255,245,206)" stroke="none" d="M 17596,16499 L 20750,16499 20750,17616 C 19501,17607 19543,17835 18416,17889 18013,17856 17866,17831 17596,17793 L 17596,16499 Z"/>
|
<path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="miter" stroke-linecap="round" d="M 19119,15652 L 19119,16027 19074,16027 19074,16142"/>
|
||||||
<path fill="none" stroke="rgb(52,101,164)" d="M 17596,16499 L 20750,16499 20750,17616 C 19501,17607 19543,17835 18416,17889 18013,17856 17866,17831 17596,17793 L 17596,16499 Z"/>
|
<path fill="rgb(52,101,164)" stroke="none" d="M 19214,16123 L 19074,16402 18935,16123 19214,16123 Z"/>
|
||||||
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Bitstream Vera Sans Mono, monospace" font-size="370px" font-weight="400"><tspan class="TextPosition" x="17852" y="17185"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">hello.p8virt</tspan></tspan></tspan></text>
|
|
||||||
</g>
|
</g>
|
||||||
</g>
|
</g>
|
||||||
<g class="com.sun.star.drawing.ConnectorShape">
|
<g class="com.sun.star.drawing.ConnectorShape">
|
||||||
<g id="id42">
|
<g id="id42">
|
||||||
<rect class="BoundingBox" stroke="none" fill="none" x="19034" y="15380" width="281" height="1121"/>
|
|
||||||
<path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="miter" stroke-linecap="round" d="M 19125,15407 L 19125,15966 19174,15966 19174,16240"/>
|
|
||||||
<path fill="rgb(52,101,164)" stroke="none" d="M 19314,16221 L 19174,16500 19035,16221 19314,16221 Z"/>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
<g class="com.sun.star.drawing.ConnectorShape">
|
|
||||||
<g id="id43">
|
|
||||||
<rect class="BoundingBox" stroke="none" fill="none" x="14827" y="12362" width="2076" height="1889"/>
|
<rect class="BoundingBox" stroke="none" fill="none" x="14827" y="12362" width="2076" height="1889"/>
|
||||||
<path fill="none" stroke="rgb(183,179,202)" stroke-width="53" stroke-linejoin="miter" stroke-linecap="round" d="M 16875,12389 L 16875,13319 14967,13319 14967,13990"/>
|
<path fill="none" stroke="rgb(183,179,202)" stroke-width="53" stroke-linejoin="miter" stroke-linecap="round" d="M 16875,12389 L 16875,13319 14967,13319 14967,13990"/>
|
||||||
<path fill="rgb(183,179,202)" stroke="none" d="M 15107,13971 L 14967,14250 14828,13971 15107,13971 Z"/>
|
<path fill="rgb(183,179,202)" stroke="none" d="M 15107,13971 L 14967,14250 14828,13971 15107,13971 Z"/>
|
||||||
</g>
|
</g>
|
||||||
</g>
|
</g>
|
||||||
<g class="com.sun.star.drawing.ConnectorShape">
|
<g class="com.sun.star.drawing.ConnectorShape">
|
||||||
<g id="id44">
|
<g id="id43">
|
||||||
<rect class="BoundingBox" stroke="none" fill="none" x="16848" y="12362" width="2418" height="1889"/>
|
<rect class="BoundingBox" stroke="none" fill="none" x="16848" y="12362" width="2418" height="1889"/>
|
||||||
<path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="miter" stroke-linecap="round" d="M 16875,12389 L 16875,13319 19125,13319 19125,13990"/>
|
<path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="miter" stroke-linecap="round" d="M 16875,12389 L 16875,13319 19125,13319 19125,13990"/>
|
||||||
<path fill="rgb(52,101,164)" stroke="none" d="M 19265,13971 L 19125,14250 18986,13971 19265,13971 Z"/>
|
<path fill="rgb(52,101,164)" stroke="none" d="M 19265,13971 L 19125,14250 18986,13971 19265,13971 Z"/>
|
||||||
</g>
|
</g>
|
||||||
</g>
|
</g>
|
||||||
<g class="TextShape">
|
<g class="TextShape">
|
||||||
<g id="id45">
|
<g id="id44">
|
||||||
<rect class="BoundingBox" stroke="none" fill="none" x="13473" y="13084" width="2778" height="1167"/>
|
<rect class="BoundingBox" stroke="none" fill="none" x="13473" y="13084" width="2778" height="1167"/>
|
||||||
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Serif, serif" font-size="388px" font-style="italic" font-weight="400"><tspan class="TextPosition" x="13723" y="13556"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">(future)</tspan></tspan></tspan></text>
|
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Serif, serif" font-size="388px" font-style="italic" font-weight="400"><tspan class="TextPosition" x="13723" y="13556"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">(future)</tspan></tspan></tspan></text>
|
||||||
</g>
|
</g>
|
||||||
</g>
|
</g>
|
||||||
|
<g class="com.sun.star.drawing.CustomShape">
|
||||||
|
<g id="id45">
|
||||||
|
<rect class="BoundingBox" stroke="none" fill="none" x="17375" y="16375" width="3397" height="1806"/>
|
||||||
|
<path fill="rgb(255,166,166)" stroke="none" d="M 17938,18153 L 17939,18153 C 17845,18153 17752,18113 17670,18036 17589,17959 17521,17848 17474,17715 17427,17582 17402,17431 17402,17278 L 17402,17278 C 17402,17124 17427,16973 17474,16840 17521,16707 17589,16596 17670,16519 17752,16442 17845,16402 17939,16402 L 20207,16402 20207,16402 C 20301,16402 20394,16442 20476,16519 20557,16596 20625,16707 20672,16840 20719,16973 20744,17124 20744,17278 L 20744,17278 20744,17278 C 20744,17431 20719,17582 20672,17715 20625,17848 20557,17959 20476,18036 20394,18113 20301,18153 20207,18153 L 17938,18153 Z"/>
|
||||||
|
<path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 17938,18153 L 17939,18153 C 17845,18153 17752,18113 17670,18036 17589,17959 17521,17848 17474,17715 17427,17582 17402,17431 17402,17278 L 17402,17278 C 17402,17124 17427,16973 17474,16840 17521,16707 17589,16596 17670,16519 17752,16442 17845,16402 17939,16402 L 20207,16402 20207,16402 C 20301,16402 20394,16442 20476,16519 20557,16596 20625,16707 20672,16840 20719,16973 20744,17124 20744,17278 L 20744,17278 20744,17278 C 20744,17431 20719,17582 20672,17715 20625,17848 20557,17959 20476,18036 20394,18113 20301,18153 20207,18153 L 17938,18153 Z"/>
|
||||||
|
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Droid Serif, serif" font-size="423px" font-weight="400"><tspan class="TextPosition" x="18402" y="16927"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">Run in </tspan></tspan><tspan class="TextPosition" x="18391" y="17423"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">virtual </tspan></tspan><tspan class="TextPosition" x="18199" y="17919"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">machine</tspan></tspan></tspan></text>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g class="com.sun.star.drawing.CustomShape">
|
||||||
|
<g id="id46">
|
||||||
|
<rect class="BoundingBox" stroke="none" fill="none" x="17467" y="14223" width="3305" height="1457"/>
|
||||||
|
<path fill="rgb(255,166,166)" stroke="none" d="M 19119,15652 L 17494,15652 17494,14250 20744,14250 20744,15652 19119,15652 Z"/>
|
||||||
|
<path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 19119,15652 L 17494,15652 17494,14250 20744,14250 20744,15652 19119,15652 Z"/>
|
||||||
|
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Droid Serif, serif" font-size="494px" font-weight="400"><tspan class="TextPosition" x="18031" y="14832"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">Build VM </tspan></tspan><tspan class="TextPosition" x="18086" y="15412"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">program</tspan></tspan></tspan></text>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
</g>
|
</g>
|
||||||
</g>
|
</g>
|
||||||
</g>
|
</g>
|
||||||
|
Before Width: | Height: | Size: 92 KiB After Width: | Height: | Size: 94 KiB |
@ -139,7 +139,7 @@ Some notes and references into the compiler's source code modules:
|
|||||||
#. An *Intermediate Representation* has been defined that is generated from the intermediate AST. This IR
|
#. An *Intermediate Representation* has been defined that is generated from the intermediate AST. This IR
|
||||||
is more or less a machine code language for a virtual machine - and indeed this is what the built-in
|
is more or less a machine code language for a virtual machine - and indeed this is what the built-in
|
||||||
prog8 VM will execute if you use the 'virtual' compilaton target and use ``-emu`` to launch the VM.
|
prog8 VM will execute if you use the 'virtual' compilaton target and use ``-emu`` to launch the VM.
|
||||||
(``intermediate`` and ``codeGenIntermediate`` modules, and ``codeGenVirtual`` and ``virtualmachine`` module for the VM related stuff)
|
(``intermediate`` and ``codeGenIntermediate`` modules, and ``virtualmachine`` module for the VM related stuff)
|
||||||
#. Currently the 6502 ASM code generator still works directly on the *Compiler AST*. A future version
|
#. Currently the 6502 ASM code generator still works directly on the *Compiler AST*. A future version
|
||||||
should replace this by working on the IR code, and should be much smaller and simpler.
|
should replace this by working on the IR code, and should be much smaller and simpler.
|
||||||
(``codeGenCpu6502`` module)
|
(``codeGenCpu6502`` module)
|
||||||
|
@ -17,7 +17,6 @@ Future Things and Ideas
|
|||||||
^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
Compiler:
|
Compiler:
|
||||||
|
|
||||||
- vm: get rid of p8virt format and Assembler, run p8ir directly
|
|
||||||
- vm/ir: put variables and arrays in BSS section (unless -noreinit is specified)
|
- vm/ir: put variables and arrays in BSS section (unless -noreinit is specified)
|
||||||
- vm: Jumps go to a code block rather than a specific address(label) -> also helps future dead code elimination?
|
- vm: Jumps go to a code block rather than a specific address(label) -> also helps future dead code elimination?
|
||||||
- vm: the above means that every label introduces a new code block. This eliminates the use of actual labels altogether.
|
- vm: the above means that every label introduces a new code block. This eliminates the use of actual labels altogether.
|
||||||
@ -57,12 +56,9 @@ Libraries:
|
|||||||
|
|
||||||
Expressions:
|
Expressions:
|
||||||
|
|
||||||
- rethink the whole "isAugmentable" business. Because the way this is determined, should always also be exactly mirrorred in the AugmentableAssignmentAsmGen or you'll get a crash at code gen time.
|
|
||||||
note: the new Ast doesn't need this any more so maybe we can get rid of it altogether in the old AST - but it's still used for something in the UnusedCodeRemover.
|
|
||||||
- can we get rid of pieces of asmgen.AssignmentAsmGen by just reusing the AugmentableAssignment ? generated code should not suffer
|
- can we get rid of pieces of asmgen.AssignmentAsmGen by just reusing the AugmentableAssignment ? generated code should not suffer
|
||||||
- rewrite expression tree evaluation such that it doesn't use an eval stack but flatten the tree into linear code that uses a fixed number of predetermined value 'variables'?
|
- rewrite expression tree evaluation such that it doesn't use an eval stack but flatten the tree into linear code
|
||||||
"Three address code" was mentioned. https://en.wikipedia.org/wiki/Three-address_code
|
that, for instance, uses a fixed number of predetermined value 'variables'?
|
||||||
these variables have to be unique for each subroutine because they could otherwise be interfered with from irq routines etc.
|
|
||||||
The VM IL solves this already (by using unlimited registers) but that still lacks a translation to 6502.
|
The VM IL solves this already (by using unlimited registers) but that still lacks a translation to 6502.
|
||||||
- this removes the need for the BinExprSplitter? (which is problematic and very limited now)
|
- this removes the need for the BinExprSplitter? (which is problematic and very limited now)
|
||||||
and perhaps the assignment splitting in BeforeAsmAstChanger too
|
and perhaps the assignment splitting in BeforeAsmAstChanger too
|
||||||
|
@ -19,7 +19,8 @@ main {
|
|||||||
const uword SIZEPL = 8191
|
const uword SIZEPL = 8191
|
||||||
uword @zp flags_ptr = memory("flags", SIZEPL, $100)
|
uword @zp flags_ptr = memory("flags", SIZEPL, $100)
|
||||||
|
|
||||||
txt.print("calculating...\n")
|
txt.print_ub(ITERS)
|
||||||
|
txt.print(" iterations, calculating...\n")
|
||||||
|
|
||||||
repeat ITERS {
|
repeat ITERS {
|
||||||
sys.memset(flags_ptr, SIZEPL, 1)
|
sys.memset(flags_ptr, SIZEPL, 1)
|
||||||
|
@ -1,69 +1,5 @@
|
|||||||
%import textio
|
|
||||||
%zeropage basicsafe
|
|
||||||
|
|
||||||
main {
|
main {
|
||||||
|
|
||||||
sub start() {
|
sub start() {
|
||||||
|
%asmbinary "bsieve.prg", 10, 200
|
||||||
ubyte v1 = 1
|
|
||||||
uword v2 = 1
|
|
||||||
|
|
||||||
ubyte counterb
|
|
||||||
uword counter
|
|
||||||
|
|
||||||
repeat v1-1 {
|
|
||||||
txt.print("!")
|
|
||||||
}
|
|
||||||
|
|
||||||
repeat v2-1 {
|
|
||||||
txt.print("?")
|
|
||||||
}
|
|
||||||
|
|
||||||
for counterb in 0 to v1 {
|
|
||||||
txt.print("y1")
|
|
||||||
}
|
|
||||||
for counter in 0 to v2 {
|
|
||||||
txt.print("y2")
|
|
||||||
}
|
|
||||||
|
|
||||||
repeat v1 {
|
|
||||||
txt.print("ok1")
|
|
||||||
}
|
|
||||||
|
|
||||||
repeat v2 {
|
|
||||||
txt.print("ok2")
|
|
||||||
}
|
|
||||||
|
|
||||||
repeat v1-1 {
|
|
||||||
txt.print("!")
|
|
||||||
}
|
|
||||||
|
|
||||||
repeat v2-1 {
|
|
||||||
txt.print("?")
|
|
||||||
}
|
|
||||||
|
|
||||||
while v1-1 {
|
|
||||||
txt.print("%")
|
|
||||||
}
|
|
||||||
|
|
||||||
while v2-1 {
|
|
||||||
txt.print("*")
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
for counterb in 0 to v1-1 {
|
|
||||||
txt.print("@")
|
|
||||||
}
|
|
||||||
for counter in 0 to v2-1 {
|
|
||||||
txt.print("y#")
|
|
||||||
}
|
|
||||||
|
|
||||||
repeat 0 {
|
|
||||||
txt.print("zero1")
|
|
||||||
}
|
|
||||||
repeat $0000 {
|
|
||||||
txt.print("zero2")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
main {
|
main {
|
||||||
sub start() {
|
sub start() {
|
||||||
|
|
||||||
const ubyte ITERS = 10
|
|
||||||
uword count
|
uword count
|
||||||
uword i
|
uword i
|
||||||
uword prime
|
uword prime
|
||||||
@ -15,21 +14,19 @@ main {
|
|||||||
|
|
||||||
txt.print("calculating...\n")
|
txt.print("calculating...\n")
|
||||||
|
|
||||||
repeat ITERS {
|
sys.memset(flags_ptr, SIZEPL, 1)
|
||||||
sys.memset(flags_ptr, SIZEPL, 1)
|
count = 0
|
||||||
count = 0
|
for i in 0 to SIZEPL-1 {
|
||||||
for i in 0 to SIZEPL-1 {
|
if @(flags_ptr+i) {
|
||||||
if @(flags_ptr+i) {
|
prime = i + i + 3
|
||||||
prime = i + i + 3
|
k = i + prime
|
||||||
k = i + prime
|
while k <= SIZEPL-1 {
|
||||||
while k <= SIZEPL-1 {
|
@(flags_ptr + k) = false
|
||||||
@(flags_ptr + k) = false
|
k += prime
|
||||||
k += prime
|
|
||||||
}
|
|
||||||
txt.print_uw(prime)
|
|
||||||
txt.nl()
|
|
||||||
count++
|
|
||||||
}
|
}
|
||||||
|
txt.print_uw(prime)
|
||||||
|
txt.nl()
|
||||||
|
count++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
package prog8.intermediate
|
package prog8.intermediate
|
||||||
|
|
||||||
// calls to builtin operations that are too complex to be implemented as an IR instruction
|
// Calls to builtin operations that are too complex to be implemented as an IR instruction
|
||||||
// these use the SYSCALL instruction instead.
|
// these use the SYSCALL instruction instead.
|
||||||
|
// Note that in the VM these are translated into whatever the corresponding Syscall number in the VM is.
|
||||||
|
|
||||||
enum class IMSyscall {
|
enum class IMSyscall {
|
||||||
SORT_UBYTE,
|
SORT_UBYTE,
|
||||||
|
@ -6,17 +6,18 @@ import prog8.code.target.*
|
|||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
import kotlin.io.path.Path
|
import kotlin.io.path.Path
|
||||||
import kotlin.io.path.bufferedReader
|
import kotlin.io.path.bufferedReader
|
||||||
import kotlin.io.path.div
|
|
||||||
|
|
||||||
|
|
||||||
class IRFileReader(outputDir: Path, programName: String) {
|
class IRFileReader {
|
||||||
private val infile = outputDir / ("${programName}.p8ir")
|
|
||||||
|
|
||||||
fun readFile(): IRProgram {
|
fun read(irSourceCode: CharSequence): IRProgram {
|
||||||
println("Reading intermediate representation from $infile")
|
return parseProgram(irSourceCode.lineSequence().iterator())
|
||||||
infile.bufferedReader().use { reader ->
|
}
|
||||||
val lines = reader.readText().lines()
|
|
||||||
return parseProgram(lines.iterator())
|
fun read(irSourceFile: Path): IRProgram {
|
||||||
|
println("Reading intermediate representation from $irSourceFile")
|
||||||
|
irSourceFile.bufferedReader().use { reader ->
|
||||||
|
return parseProgram(reader.lineSequence().iterator())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -253,8 +254,6 @@ class IRFileReader(outputDir: Path, programName: String) {
|
|||||||
private val asmsubPattern = Regex("<ASMSUB NAME=(.+) ADDRESS=(.+) CLOBBERS=(.*) RETURNS=(.*) POS=(.+)>")
|
private val asmsubPattern = Regex("<ASMSUB NAME=(.+) ADDRESS=(.+) CLOBBERS=(.*) RETURNS=(.*) POS=(.+)>")
|
||||||
private val subPattern = Regex("<SUB NAME=(.+) RETURNTYPE=(.+) POS=(.+)>")
|
private val subPattern = Regex("<SUB NAME=(.+) RETURNTYPE=(.+) POS=(.+)>")
|
||||||
private val posPattern = Regex("\\[(.+): line (.+) col (.+)-(.+)\\]")
|
private val posPattern = Regex("\\[(.+): line (.+) col (.+)-(.+)\\]")
|
||||||
private val instructionPattern = Regex("""([a-z]+)(\.b|\.w|\.f)?(.*)""", RegexOption.IGNORE_CASE)
|
|
||||||
private val labelPattern = Regex("""_([a-zA-Z\d\._]+):""")
|
|
||||||
|
|
||||||
private fun parseBlock(startline: String, lines: Iterator<String>, variables: List<StStaticVariable>): IRBlock {
|
private fun parseBlock(startline: String, lines: Iterator<String>, variables: List<StStaticVariable>): IRBlock {
|
||||||
var line = startline
|
var line = startline
|
||||||
@ -396,201 +395,21 @@ class IRFileReader(outputDir: Path, programName: String) {
|
|||||||
if (line.isBlank() || line.startsWith(';'))
|
if (line.isBlank() || line.startsWith(';'))
|
||||||
continue
|
continue
|
||||||
if(line=="<BYTES>") {
|
if(line=="<BYTES>") {
|
||||||
val bytes = mutableListOf<Byte>()
|
val bytes = mutableListOf<UByte>()
|
||||||
line = lines.next()
|
line = lines.next()
|
||||||
while(line!="</BYTES>") {
|
while(line!="</BYTES>") {
|
||||||
line.trimEnd().windowed(size=2, step=2) {
|
line.trimEnd().windowed(size=2, step=2) {
|
||||||
bytes.add(it.toString().toByte(16))
|
bytes.add(it.toString().toUByte(16))
|
||||||
}
|
}
|
||||||
line = lines.next()
|
line = lines.next()
|
||||||
}
|
}
|
||||||
chunk += IRCodeInlineBinary(bytes.toByteArray())
|
chunk += IRCodeInlineBinary(bytes)
|
||||||
} else {
|
} else {
|
||||||
chunk += parseCodeLine(line)
|
chunk += parseIRCodeLine(line, 0, mutableMapOf())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun parseCodeLine(line: String): IRCodeLine {
|
|
||||||
val match = instructionPattern.matchEntire(line.trim())
|
|
||||||
if(match==null) {
|
|
||||||
// it's a label.
|
|
||||||
val labelmatch = labelPattern.matchEntire(line.trim()) ?: throw IRParseException("invalid label")
|
|
||||||
return IRCodeLabel(labelmatch.groupValues[1])
|
|
||||||
}
|
|
||||||
|
|
||||||
// it's an instruction.
|
|
||||||
val (_, instr, typestr, rest) = match.groupValues
|
|
||||||
val opcode = try {
|
|
||||||
Opcode.valueOf(instr.uppercase())
|
|
||||||
} catch (ax: IllegalArgumentException) {
|
|
||||||
throw IRParseException("invalid vmasm instruction: $instr")
|
|
||||||
}
|
|
||||||
var type: VmDataType? = convertVmType(typestr)
|
|
||||||
val formats = instructionFormats.getValue(opcode)
|
|
||||||
val format: InstructionFormat
|
|
||||||
if(type !in formats) {
|
|
||||||
type = VmDataType.BYTE
|
|
||||||
format = if(type !in formats)
|
|
||||||
formats.getValue(null)
|
|
||||||
else
|
|
||||||
formats.getValue(type)
|
|
||||||
} else {
|
|
||||||
format = formats.getValue(type)
|
|
||||||
}
|
|
||||||
// parse the operands
|
|
||||||
val operands = rest.lowercase().split(",").toMutableList()
|
|
||||||
var reg1: Int? = null
|
|
||||||
var reg2: Int? = null
|
|
||||||
var reg3: Int? = null
|
|
||||||
var fpReg1: Int? = null
|
|
||||||
var fpReg2: Int? = null
|
|
||||||
var fpReg3: Int? = null
|
|
||||||
var value: Float? = null
|
|
||||||
var operand: String?
|
|
||||||
var labelSymbol: String? = null
|
|
||||||
if(operands.isNotEmpty() && operands[0].isNotEmpty()) {
|
|
||||||
operand = operands.removeFirst().trim()
|
|
||||||
if(operand[0]=='r')
|
|
||||||
reg1 = operand.substring(1).toInt()
|
|
||||||
else if(operand[0]=='f' && operand[1]=='r')
|
|
||||||
fpReg1 = operand.substring(2).toInt()
|
|
||||||
else {
|
|
||||||
if(operand.startsWith('_')) {
|
|
||||||
// it's a label
|
|
||||||
labelSymbol = rest.split(",")[0].trim().substring(1) // keep the original case
|
|
||||||
value = null
|
|
||||||
} else {
|
|
||||||
value = parseValue(operand)
|
|
||||||
}
|
|
||||||
operands.clear()
|
|
||||||
}
|
|
||||||
if(operands.isNotEmpty()) {
|
|
||||||
operand = operands.removeFirst().trim()
|
|
||||||
if(operand[0]=='r')
|
|
||||||
reg2 = operand.substring(1).toInt()
|
|
||||||
else if(operand[0]=='f' && operand[1]=='r')
|
|
||||||
fpReg2 = operand.substring(2).toInt()
|
|
||||||
else {
|
|
||||||
if(operand.startsWith('_')) {
|
|
||||||
// it's a label
|
|
||||||
labelSymbol = rest.split(",")[1].trim().substring(1) // keep the original case
|
|
||||||
value = null
|
|
||||||
} else {
|
|
||||||
value = parseValue(operand)
|
|
||||||
}
|
|
||||||
operands.clear()
|
|
||||||
}
|
|
||||||
if(operands.isNotEmpty()) {
|
|
||||||
operand = operands.removeFirst().trim()
|
|
||||||
if(operand[0]=='r')
|
|
||||||
reg3 = operand.substring(1).toInt()
|
|
||||||
else if(operand[0]=='f' && operand[1]=='r')
|
|
||||||
fpReg3 = operand.substring(2).toInt()
|
|
||||||
else {
|
|
||||||
if(operand.startsWith('_')) {
|
|
||||||
// it's a label
|
|
||||||
labelSymbol = rest.split(",")[2].trim().substring(1) // keep the original case
|
|
||||||
value = null
|
|
||||||
} else {
|
|
||||||
value = parseValue(operand)
|
|
||||||
}
|
|
||||||
operands.clear()
|
|
||||||
}
|
|
||||||
if(operands.isNotEmpty()) {
|
|
||||||
operand = operands.removeFirst().trim()
|
|
||||||
if(operand.startsWith('_')) {
|
|
||||||
// it's a label
|
|
||||||
labelSymbol = rest.split(",")[3].trim().substring(1) // keep the original case
|
|
||||||
value = null
|
|
||||||
} else {
|
|
||||||
value = parseValue(operand)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// shift the operands back into place
|
|
||||||
while(reg1==null && reg2!=null) {
|
|
||||||
reg1 = reg2
|
|
||||||
reg2 = reg3
|
|
||||||
reg3 = null
|
|
||||||
}
|
|
||||||
while(fpReg1==null && fpReg2!=null) {
|
|
||||||
fpReg1 = fpReg2
|
|
||||||
fpReg2 = fpReg3
|
|
||||||
fpReg3 = null
|
|
||||||
}
|
|
||||||
if(reg3!=null)
|
|
||||||
throw IRParseException("too many reg arguments $line")
|
|
||||||
if(fpReg3!=null)
|
|
||||||
throw IRParseException("too many fpreg arguments $line")
|
|
||||||
|
|
||||||
if(type!=null && type !in formats)
|
|
||||||
throw IRParseException("invalid type code for $line")
|
|
||||||
if(format.reg1 && reg1==null)
|
|
||||||
throw IRParseException("needs reg1 for $line")
|
|
||||||
if(format.reg2 && reg2==null)
|
|
||||||
throw IRParseException("needs reg2 for $line")
|
|
||||||
if(format.value && value==null && labelSymbol==null)
|
|
||||||
throw IRParseException("needs value or label for $line")
|
|
||||||
if(!format.reg1 && reg1!=null)
|
|
||||||
throw IRParseException("invalid reg1 for $line")
|
|
||||||
if(!format.reg2 && reg2!=null)
|
|
||||||
throw IRParseException("invalid reg2 for $line")
|
|
||||||
if(value!=null && opcode !in OpcodesWithAddress) {
|
|
||||||
when (type) {
|
|
||||||
VmDataType.BYTE -> {
|
|
||||||
if (value < -128 || value > 255)
|
|
||||||
throw IRParseException("value out of range for byte: $value")
|
|
||||||
}
|
|
||||||
VmDataType.WORD -> {
|
|
||||||
if (value < -32768 || value > 65535)
|
|
||||||
throw IRParseException("value out of range for word: $value")
|
|
||||||
}
|
|
||||||
VmDataType.FLOAT -> {}
|
|
||||||
null -> {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var floatValue: Float? = null
|
|
||||||
var intValue: Int? = null
|
|
||||||
|
|
||||||
if(format.value && value!=null)
|
|
||||||
intValue = value.toInt()
|
|
||||||
if(format.fpValue && value!=null)
|
|
||||||
floatValue = value
|
|
||||||
|
|
||||||
return IRCodeInstruction(opcode, type, reg1, reg2, fpReg1, fpReg2, intValue, floatValue, labelSymbol)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun convertVmType(typestr: String): VmDataType? {
|
|
||||||
return when(typestr.lowercase()) {
|
|
||||||
"" -> null
|
|
||||||
".b" -> VmDataType.BYTE
|
|
||||||
".w" -> VmDataType.WORD
|
|
||||||
".f" -> VmDataType.FLOAT
|
|
||||||
else -> throw IRParseException("invalid type $typestr")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun parseValue(value: String): Float {
|
|
||||||
return if(value.startsWith("-"))
|
|
||||||
-parseValue(value.substring(1))
|
|
||||||
else if(value.startsWith('$'))
|
|
||||||
value.substring(1).toInt(16).toFloat()
|
|
||||||
else if(value.startsWith('%'))
|
|
||||||
value.substring(1).toInt(2).toFloat()
|
|
||||||
else if(value.startsWith("0x"))
|
|
||||||
value.substring(2).toInt(16).toFloat()
|
|
||||||
else if(value.startsWith('_'))
|
|
||||||
throw IRParseException("attempt to parse a label as numeric value")
|
|
||||||
else if(value.startsWith('&'))
|
|
||||||
throw IRParseException("address-of should be done with normal LOAD <symbol>")
|
|
||||||
else
|
|
||||||
return value.toFloat()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun parseRegisterOrStatusflag(regs: String): RegisterOrStatusflag {
|
private fun parseRegisterOrStatusflag(regs: String): RegisterOrStatusflag {
|
||||||
var reg: RegisterOrPair? = null
|
var reg: RegisterOrPair? = null
|
||||||
var sf: Statusflag? = null
|
var sf: Statusflag? = null
|
||||||
|
@ -2,15 +2,16 @@ package prog8.intermediate
|
|||||||
|
|
||||||
import prog8.code.core.*
|
import prog8.code.core.*
|
||||||
import java.io.BufferedWriter
|
import java.io.BufferedWriter
|
||||||
|
import java.nio.file.Path
|
||||||
import kotlin.io.path.bufferedWriter
|
import kotlin.io.path.bufferedWriter
|
||||||
import kotlin.io.path.div
|
import kotlin.io.path.div
|
||||||
|
|
||||||
|
|
||||||
class IRFileWriter(private val irProgram: IRProgram) {
|
class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
|
||||||
private val outfile = irProgram.options.outputDir / ("${irProgram.name}.p8ir")
|
private val outfile = outfileOverride ?: (irProgram.options.outputDir / ("${irProgram.name}.p8ir"))
|
||||||
private val out = outfile.bufferedWriter()
|
private val out = outfile.bufferedWriter()
|
||||||
|
|
||||||
fun writeFile() {
|
fun write(): Path {
|
||||||
println("Writing intermediate representation to $outfile")
|
println("Writing intermediate representation to $outfile")
|
||||||
out.write("<PROGRAM NAME=${irProgram.name}>\n")
|
out.write("<PROGRAM NAME=${irProgram.name}>\n")
|
||||||
writeOptions()
|
writeOptions()
|
||||||
@ -27,6 +28,7 @@ class IRFileWriter(private val irProgram: IRProgram) {
|
|||||||
writeBlocks()
|
writeBlocks()
|
||||||
out.write("</PROGRAM>\n")
|
out.write("</PROGRAM>\n")
|
||||||
out.close()
|
out.close()
|
||||||
|
return outfile
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun writeBlocks() {
|
private fun writeBlocks() {
|
||||||
@ -68,7 +70,7 @@ class IRFileWriter(private val irProgram: IRProgram) {
|
|||||||
}
|
}
|
||||||
out.write("</PARAMS>\n")
|
out.write("</PARAMS>\n")
|
||||||
out.write("<INLINEASM POS=${it.position}>\n")
|
out.write("<INLINEASM POS=${it.position}>\n")
|
||||||
out.write(it.assembly.trimStart('\n').trimEnd(' ', '\n'))
|
out.write(it.assembly.trimStart('\r', '\n').trimEnd(' ', '\r', '\n'))
|
||||||
out.write("\n</INLINEASM>\n</ASMSUB>\n")
|
out.write("\n</INLINEASM>\n</ASMSUB>\n")
|
||||||
}
|
}
|
||||||
out.write("</BLOCK>\n")
|
out.write("</BLOCK>\n")
|
||||||
@ -77,7 +79,7 @@ class IRFileWriter(private val irProgram: IRProgram) {
|
|||||||
|
|
||||||
private fun writeInlineAsm(chunk: IRInlineAsmChunk) {
|
private fun writeInlineAsm(chunk: IRInlineAsmChunk) {
|
||||||
out.write("<INLINEASM POS=${chunk.position}>\n")
|
out.write("<INLINEASM POS=${chunk.position}>\n")
|
||||||
out.write(chunk.assembly.trimStart('\n').trimEnd(' ', '\n'))
|
out.write(chunk.assembly.trimStart('\r', '\n').trimEnd(' ', '\r', '\n'))
|
||||||
out.write("\n</INLINEASM>\n")
|
out.write("\n</INLINEASM>\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,9 +152,7 @@ class IRFileWriter(private val irProgram: IRProgram) {
|
|||||||
private fun BufferedWriter.writeLine(line: IRCodeLine) {
|
private fun BufferedWriter.writeLine(line: IRCodeLine) {
|
||||||
when(line) {
|
when(line) {
|
||||||
is IRCodeComment -> write("; ${line.comment}\n")
|
is IRCodeComment -> write("; ${line.comment}\n")
|
||||||
is IRCodeInstruction -> {
|
is IRInstruction -> write(line.toString() + "\n")
|
||||||
write(line.ins.toString() + "\n")
|
|
||||||
}
|
|
||||||
is IRCodeLabel -> write("_${line.name}:\n")
|
is IRCodeLabel -> write("_${line.name}:\n")
|
||||||
is IRCodeInlineBinary -> {
|
is IRCodeInlineBinary -> {
|
||||||
write("<BYTES>\n")
|
write("<BYTES>\n")
|
||||||
|
@ -14,9 +14,10 @@ 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!!!
|
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!
|
logical or arithmetic operations DO NOT AFFECT THE STATUS FLAGS UNLESS EXPLICITLY NOTED!
|
||||||
|
|
||||||
Most instructions have an associated data type 'b','w','f'. (omitting it means 'b'/byte).
|
Instruction set is mostly a load/store architecture, there are few instructions operating on memory directly.
|
||||||
|
Most instructions have an associated data type 'b','w','f'. (omitting it defaults to 'b' - byte).
|
||||||
Currently NO support for 24 or 32 bits integers.
|
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
|
Floating point operations are just 'f' typed regular instructions, however there are a few unique fp conversion instructions.
|
||||||
|
|
||||||
|
|
||||||
LOAD/STORE
|
LOAD/STORE
|
||||||
@ -60,24 +61,24 @@ BRANCHING
|
|||||||
---------
|
---------
|
||||||
All have type b or w except the branches that only check status bits.
|
All have type b or w except the branches that only check status bits.
|
||||||
|
|
||||||
bstcc location - branch to location if Status bit Carry is Clear
|
bstcc address - branch to location if Status bit Carry is Clear
|
||||||
bstcs location - branch to location if Status bit Carry is Set
|
bstcs address - branch to location if Status bit Carry is Set
|
||||||
bsteq location - branch to location if Status bit Zero is set
|
bsteq address - branch to location if Status bit Zero is set
|
||||||
bstne location - branch to location if Status bit Zero is not set
|
bstne address - branch to location if Status bit Zero is not set
|
||||||
bstneg location - branch to location if Status bit Negative is not set
|
bstneg address - branch to location if Status bit Negative is not set
|
||||||
bstpos location - branch to location if Status bit Negative is not set
|
bstpos address - branch to location if Status bit Negative is not set
|
||||||
bz reg1, location - branch to location if reg1 is zero
|
bz reg1, address - branch to location if reg1 is zero
|
||||||
bnz reg1, location - branch to location if reg1 is not zero
|
bnz reg1, address - branch to location if reg1 is not zero
|
||||||
beq reg1, reg2, location - jump to location in program given by location, if reg1 == reg2
|
beq reg1, reg2, address - jump to location in program given by location, if reg1 == reg2
|
||||||
bne reg1, reg2, location - jump to location in program given by location, if reg1 != reg2
|
bne reg1, reg2, address - jump to location in program given by location, if reg1 != reg2
|
||||||
blt reg1, reg2, location - jump to location in program given by location, if reg1 < reg2 (unsigned)
|
blt reg1, reg2, address - jump to location in program given by location, if reg1 < reg2 (unsigned)
|
||||||
blts reg1, reg2, location - jump to location in program given by location, if reg1 < reg2 (signed)
|
blts reg1, reg2, address - jump to location in program given by location, if reg1 < reg2 (signed)
|
||||||
ble reg1, reg2, location - jump to location in program given by location, if reg1 <= reg2 (unsigned)
|
ble reg1, reg2, address - jump to location in program given by location, if reg1 <= reg2 (unsigned)
|
||||||
bles reg1, reg2, location - jump to location in program given by location, if reg1 <= reg2 (signed)
|
bles reg1, reg2, address - jump to location in program given by location, if reg1 <= reg2 (signed)
|
||||||
bgt reg1, reg2, location - jump to location in program given by location, if reg1 > reg2 (unsigned)
|
bgt reg1, reg2, address - jump to location in program given by location, if reg1 > reg2 (unsigned)
|
||||||
bgts reg1, reg2, location - jump to location in program given by location, if reg1 > reg2 (signed)
|
bgts reg1, reg2, address - jump to location in program given by location, if reg1 > reg2 (signed)
|
||||||
bge reg1, reg2, location - jump to location in program given by location, if reg1 >= reg2 (unsigned)
|
bge reg1, reg2, address - jump to location in program given by location, if reg1 >= reg2 (unsigned)
|
||||||
bges reg1, reg2, location - jump to location in program given by location, if reg1 >= reg2 (signed)
|
bges reg1, reg2, address - jump to location in program given by location, if reg1 >= reg2 (signed)
|
||||||
seq reg1, reg2 - set reg=1 if reg1 == reg2, otherwise set reg1=0
|
seq reg1, reg2 - set reg=1 if reg1 == reg2, otherwise set reg1=0
|
||||||
sne reg1, reg2 - set reg=1 if reg1 != reg2, otherwise set reg1=0
|
sne reg1, reg2 - set reg=1 if reg1 != reg2, otherwise set reg1=0
|
||||||
slt reg1, reg2 - set reg=1 if reg1 < reg2 (unsigned), otherwise set reg1=0
|
slt reg1, reg2 - set reg=1 if reg1 < reg2 (unsigned), otherwise set reg1=0
|
||||||
@ -380,7 +381,25 @@ val OpcodesWithAddress = setOf(
|
|||||||
Opcode.ROLM,
|
Opcode.ROLM,
|
||||||
Opcode.RORM,
|
Opcode.RORM,
|
||||||
Opcode.ROXLM,
|
Opcode.ROXLM,
|
||||||
Opcode.ROXRM
|
Opcode.ROXRM,
|
||||||
|
Opcode.BSTCC,
|
||||||
|
Opcode.BSTCS,
|
||||||
|
Opcode.BSTEQ,
|
||||||
|
Opcode.BSTNE,
|
||||||
|
Opcode.BSTNEG,
|
||||||
|
Opcode.BSTPOS,
|
||||||
|
Opcode.BZ,
|
||||||
|
Opcode.BNZ,
|
||||||
|
Opcode.BEQ,
|
||||||
|
Opcode.BNE,
|
||||||
|
Opcode.BLT,
|
||||||
|
Opcode.BLTS,
|
||||||
|
Opcode.BLE,
|
||||||
|
Opcode.BLES,
|
||||||
|
Opcode.BGT,
|
||||||
|
Opcode.BGTS,
|
||||||
|
Opcode.BGE,
|
||||||
|
Opcode.BGES
|
||||||
)
|
)
|
||||||
|
|
||||||
val OpcodesForCpuRegisters = setOf(
|
val OpcodesForCpuRegisters = setOf(
|
||||||
@ -397,7 +416,7 @@ enum class VmDataType {
|
|||||||
// TODO add INT (32-bit)? INT24 (24-bit)?
|
// TODO add INT (32-bit)? INT24 (24-bit)?
|
||||||
}
|
}
|
||||||
|
|
||||||
data class Instruction(
|
data class IRInstruction(
|
||||||
val opcode: Opcode,
|
val opcode: Opcode,
|
||||||
val type: VmDataType?=null,
|
val type: VmDataType?=null,
|
||||||
val reg1: Int?=null, // 0-$ffff
|
val reg1: Int?=null, // 0-$ffff
|
||||||
@ -406,43 +425,50 @@ data class Instruction(
|
|||||||
val fpReg2: Int?=null, // 0-$ffff
|
val fpReg2: Int?=null, // 0-$ffff
|
||||||
val value: Int?=null, // 0-$ffff
|
val value: Int?=null, // 0-$ffff
|
||||||
val fpValue: Float?=null,
|
val fpValue: Float?=null,
|
||||||
val labelSymbol: List<String>?=null, // symbolic label name as alternative to value (so only for Branch/jump/call Instructions!)
|
val labelSymbol: String?=null, // symbolic label name as alternative to value (so only for Branch/jump/call Instructions!)
|
||||||
val binaryData: ByteArray?=null
|
val binaryData: Collection<UByte>?=null
|
||||||
) {
|
): IRCodeLine() {
|
||||||
// reg1 and fpreg1 can be IN/OUT/INOUT (all others are readonly INPUT)
|
// reg1 and fpreg1 can be IN/OUT/INOUT (all others are readonly INPUT)
|
||||||
// This knowledge is useful in IL assembly optimizers to see how registers are used.
|
// This knowledge is useful in IL assembly optimizers to see how registers are used.
|
||||||
val reg1direction: OperandDirection
|
val reg1direction: OperandDirection
|
||||||
val fpReg1direction: OperandDirection
|
val fpReg1direction: OperandDirection
|
||||||
|
|
||||||
init {
|
init {
|
||||||
if(opcode==Opcode.BINARYDATA && binaryData==null || binaryData!=null && opcode!=Opcode.BINARYDATA)
|
require(labelSymbol?.first()!='_') {"label/symbol should not start with underscore $labelSymbol"}
|
||||||
throw IllegalArgumentException("binarydata inconsistency")
|
require(reg1==null || reg1 in 0..65536) {"reg1 out of bounds"}
|
||||||
|
require(reg2==null || reg2 in 0..65536) {"reg2 out of bounds"}
|
||||||
|
require(fpReg1==null || fpReg1 in 0..65536) {"fpReg1 out of bounds"}
|
||||||
|
require(fpReg2==null || fpReg2 in 0..65536) {"fpReg2 out of bounds"}
|
||||||
|
if(value!=null && opcode !in OpcodesWithAddress) {
|
||||||
|
when (type) {
|
||||||
|
VmDataType.BYTE -> require(value in -128..255) {"value out of range for byte: $value"}
|
||||||
|
VmDataType.WORD -> require(value in -32768..65535) {"value out of range for word: $value"}
|
||||||
|
VmDataType.FLOAT, null -> {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
require((opcode==Opcode.BINARYDATA && binaryData!=null) || (opcode!=Opcode.BINARYDATA && binaryData==null)) {
|
||||||
|
"binarydata inconsistency"
|
||||||
|
}
|
||||||
|
|
||||||
val formats = instructionFormats.getValue(opcode)
|
val formats = instructionFormats.getValue(opcode)
|
||||||
if(type==null && !formats.containsKey(null))
|
require (type != null || formats.containsKey(null)) { "missing type" }
|
||||||
throw IllegalArgumentException("missing type")
|
|
||||||
|
|
||||||
val format = formats.getValue(type)
|
val format = formats.getValue(type)
|
||||||
if(format.reg1 && reg1==null || format.reg2 && reg2==null)
|
if(format.reg1) require(reg1!=null) { "missing reg1" }
|
||||||
throw IllegalArgumentException("missing a register (int)")
|
if(format.reg2) require(reg2!=null) { "missing reg2" }
|
||||||
|
if(format.fpReg1) require(fpReg1!=null) { "missing fpReg1" }
|
||||||
if(format.fpReg1 && fpReg1==null || format.fpReg2 && fpReg2==null)
|
if(format.fpReg2) require(fpReg2!=null) { "missing fpReg2" }
|
||||||
throw IllegalArgumentException("missing a register (float)")
|
if(!format.reg1) require(reg1==null) { "invalid reg1" }
|
||||||
|
if(!format.reg2) require(reg2==null) { "invalid reg2" }
|
||||||
if(!format.reg1 && reg1!=null || !format.reg2 && reg2!=null)
|
if(!format.fpReg1) require(fpReg1==null) { "invalid fpReg1" }
|
||||||
throw IllegalArgumentException("too many registers (int)")
|
if(!format.fpReg2) require(fpReg2==null) { "invalid fpReg2" }
|
||||||
|
|
||||||
if(!format.fpReg1 && fpReg1!=null || !format.fpReg2 && fpReg2!=null)
|
|
||||||
throw IllegalArgumentException("too many registers (float)")
|
|
||||||
|
|
||||||
if (type==VmDataType.FLOAT) {
|
if (type==VmDataType.FLOAT) {
|
||||||
if(format.fpValue && (fpValue==null && labelSymbol==null))
|
if(format.fpValue) require(fpValue!=null || labelSymbol!=null) {"missing a fp-value or labelsymbol"}
|
||||||
throw IllegalArgumentException("$opcode: missing a fp-value or labelsymbol")
|
|
||||||
} else {
|
} else {
|
||||||
if(format.value && (value==null && labelSymbol==null))
|
if(format.value) require(value!=null || labelSymbol!=null) {"missing a value or labelsymbol"}
|
||||||
throw IllegalArgumentException("$opcode: missing a value or labelsymbol")
|
require(fpReg1==null && fpReg2==null) {"integer point instruction can't use floating point registers"}
|
||||||
if (fpReg1 != null || fpReg2 != null)
|
|
||||||
throw IllegalArgumentException("$opcode: integer point instruction can't use floating point registers")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
reg1direction = format.reg1direction
|
reg1direction = format.reg1direction
|
||||||
@ -454,9 +480,10 @@ data class Instruction(
|
|||||||
Opcode.SEQ, Opcode.SNE, Opcode.SLT, Opcode.SLTS,
|
Opcode.SEQ, Opcode.SNE, Opcode.SLT, Opcode.SLTS,
|
||||||
Opcode.SGT, Opcode.SGTS, Opcode.SLE, Opcode.SLES,
|
Opcode.SGT, Opcode.SGTS, Opcode.SLE, Opcode.SLES,
|
||||||
Opcode.SGE, Opcode.SGES)) {
|
Opcode.SGE, Opcode.SGES)) {
|
||||||
if((type==VmDataType.FLOAT && fpReg1==fpReg2) || reg1==reg2) {
|
if(type==VmDataType.FLOAT)
|
||||||
throw IllegalArgumentException("$opcode: reg1 and reg2 should be different")
|
require(fpReg1!=fpReg2) {"$opcode: fpReg1 and fpReg2 should be different"}
|
||||||
}
|
else
|
||||||
|
require(reg1!=reg2) {"$opcode: reg1 and reg2 should be different"}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -494,10 +521,10 @@ data class Instruction(
|
|||||||
result.add(",")
|
result.add(",")
|
||||||
}
|
}
|
||||||
labelSymbol?.let {
|
labelSymbol?.let {
|
||||||
if(labelSymbol[0].startsWith('&'))
|
if(it.startsWith('&'))
|
||||||
result.add(it.joinToString(".")) // address-of something
|
result.add(it) // address-of something
|
||||||
else
|
else
|
||||||
result.add("_" + it.joinToString("."))
|
result.add("_$it")
|
||||||
}
|
}
|
||||||
if(result.last() == ",")
|
if(result.last() == ",")
|
||||||
result.removeLast()
|
result.removeLast()
|
@ -55,8 +55,7 @@ class IRProgram(val name: String,
|
|||||||
|
|
||||||
fun addGlobalInits(chunk: IRCodeChunk) = globalInits.addAll(chunk.lines)
|
fun addGlobalInits(chunk: IRCodeChunk) = globalInits.addAll(chunk.lines)
|
||||||
fun addBlock(block: IRBlock) {
|
fun addBlock(block: IRBlock) {
|
||||||
if(blocks.any { it.name==block.name })
|
require(blocks.all { it.name != block.name}) { "duplicate block ${block.name} ${block.position}" }
|
||||||
throw IllegalArgumentException("duplicate block ${block.name} ${block.position}")
|
|
||||||
blocks.add(block)
|
blocks.add(block)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -94,16 +93,12 @@ class IRSubroutine(val name: String,
|
|||||||
val chunks = mutableListOf<IRCodeChunkBase>()
|
val chunks = mutableListOf<IRCodeChunkBase>()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
if(!name.contains('.'))
|
require('.' in name) {"subroutine name is not scoped: $name"}
|
||||||
throw IllegalArgumentException("subroutine name is not scoped: $name")
|
require(!name.startsWith("main.main.")) {"subroutine name invalid main prefix: $name"}
|
||||||
if(name.startsWith("main.main."))
|
|
||||||
throw IllegalArgumentException("subroutine name invalid main prefix: $name")
|
|
||||||
|
|
||||||
// params and return value should not be str
|
// params and return value should not be str
|
||||||
if(parameters.any{ it.dt !in NumericDatatypes })
|
require(parameters.all{ it.dt in NumericDatatypes }) {"non-numeric parameter"}
|
||||||
throw IllegalArgumentException("non-numeric parameter")
|
require(returnType==null || returnType in NumericDatatypes) {"non-numeric returntype $returnType"}
|
||||||
if(returnType!=null && returnType !in NumericDatatypes)
|
|
||||||
throw IllegalArgumentException("non-numeric returntype $returnType")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
operator fun plusAssign(chunk: IRCodeChunkBase) { chunks+= chunk }
|
operator fun plusAssign(chunk: IRCodeChunkBase) { chunks+= chunk }
|
||||||
@ -117,63 +112,18 @@ class IRAsmSubroutine(val name: String,
|
|||||||
val returns: List<Pair<DataType, RegisterOrStatusflag>>,
|
val returns: List<Pair<DataType, RegisterOrStatusflag>>,
|
||||||
val assembly: String) {
|
val assembly: String) {
|
||||||
init {
|
init {
|
||||||
if(!name.contains('.'))
|
require('.' in name) { "subroutine name is not scoped: $name" }
|
||||||
throw IllegalArgumentException("subroutine name is not scoped: $name")
|
require(!name.startsWith("main.main.")) { "subroutine name invalid main prefix: $name" }
|
||||||
if(name.startsWith("main.main."))
|
|
||||||
throw IllegalArgumentException("subroutine name invalid main prefix: $name")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed class IRCodeLine
|
sealed class IRCodeLine
|
||||||
|
|
||||||
class IRCodeInstruction(
|
|
||||||
opcode: Opcode,
|
|
||||||
type: VmDataType?=null,
|
|
||||||
reg1: Int?=null, // 0-$ffff
|
|
||||||
reg2: Int?=null, // 0-$ffff
|
|
||||||
fpReg1: Int?=null, // 0-$ffff
|
|
||||||
fpReg2: Int?=null, // 0-$ffff
|
|
||||||
value: Int?=null, // 0-$ffff
|
|
||||||
fpValue: Float?=null,
|
|
||||||
labelSymbol: String?=null // alternative to value
|
|
||||||
): IRCodeLine() {
|
|
||||||
val ins = Instruction(opcode, type, reg1, reg2, fpReg1, fpReg2, value, fpValue, if(labelSymbol==null) null else listOf(labelSymbol))
|
|
||||||
|
|
||||||
init {
|
|
||||||
if(reg1!=null && (reg1<0 || reg1>65536))
|
|
||||||
throw IllegalArgumentException("reg1 out of bounds")
|
|
||||||
if(reg2!=null && (reg2<0 || reg2>65536))
|
|
||||||
throw IllegalArgumentException("reg2 out of bounds")
|
|
||||||
if(fpReg1!=null && (fpReg1<0 || fpReg1>65536))
|
|
||||||
throw IllegalArgumentException("fpReg1 out of bounds")
|
|
||||||
if(fpReg2!=null && (fpReg2<0 || fpReg2>65536))
|
|
||||||
throw IllegalArgumentException("fpReg2 out of bounds")
|
|
||||||
|
|
||||||
if(value!=null && opcode !in OpcodesWithAddress) {
|
|
||||||
when (type) {
|
|
||||||
VmDataType.BYTE -> {
|
|
||||||
if (value < -128 || value > 255)
|
|
||||||
throw IllegalArgumentException("value out of range for byte: $value")
|
|
||||||
}
|
|
||||||
VmDataType.WORD -> {
|
|
||||||
if (value < -32768 || value > 65535)
|
|
||||||
throw IllegalArgumentException("value out of range for word: $value")
|
|
||||||
}
|
|
||||||
VmDataType.FLOAT, null -> {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(labelSymbol?.startsWith('_')==true) {
|
|
||||||
throw IllegalArgumentException("label/symbol should not start with underscore $labelSymbol")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class IRCodeLabel(val name: String): IRCodeLine()
|
class IRCodeLabel(val name: String): IRCodeLine()
|
||||||
|
|
||||||
class IRCodeComment(val comment: String): IRCodeLine()
|
class IRCodeComment(val comment: String): IRCodeLine()
|
||||||
|
|
||||||
class IRCodeInlineBinary(val data: ByteArray): IRCodeLine()
|
class IRCodeInlineBinary(val data: Collection<UByte>): IRCodeLine()
|
||||||
|
|
||||||
abstract class IRCodeChunkBase(val position: Position) {
|
abstract class IRCodeChunkBase(val position: Position) {
|
||||||
val lines = mutableListOf<IRCodeLine>()
|
val lines = mutableListOf<IRCodeLine>()
|
||||||
|
@ -97,15 +97,10 @@ class IRSymbolTable(sourceSt: SymbolTable?) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun add(variable: StMemorySlab) {
|
fun add(variable: StMemorySlab) {
|
||||||
val scopedName: String
|
val varToadd = if('.' in variable.name)
|
||||||
val varToadd: StMemorySlab
|
variable
|
||||||
if('.' in variable.name) {
|
else
|
||||||
scopedName = variable.name
|
StMemorySlab("prog8_slabs.${variable.name}", variable.size, variable.align, variable.position)
|
||||||
varToadd = variable
|
table[varToadd.name] = varToadd
|
||||||
} else {
|
|
||||||
scopedName = variable.scopedName.joinToString(".")
|
|
||||||
varToadd = StMemorySlab(scopedName, variable.size, variable.align, variable.position)
|
|
||||||
}
|
|
||||||
table[scopedName] = varToadd
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,3 +53,195 @@ fun getTypeString(variable : StStaticVariable): String {
|
|||||||
else -> throw InternalCompilerException("weird dt")
|
else -> throw InternalCompilerException("weird dt")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun convertIRType(typestr: String): VmDataType? {
|
||||||
|
return when(typestr.lowercase()) {
|
||||||
|
"" -> null
|
||||||
|
".b" -> VmDataType.BYTE
|
||||||
|
".w" -> VmDataType.WORD
|
||||||
|
".f" -> VmDataType.FLOAT
|
||||||
|
else -> throw IRParseException("invalid type $typestr")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun parseIRValue(value: String): Float {
|
||||||
|
return if(value.startsWith("-"))
|
||||||
|
-parseIRValue(value.substring(1))
|
||||||
|
else if(value.startsWith('$'))
|
||||||
|
value.substring(1).toInt(16).toFloat()
|
||||||
|
else if(value.startsWith('%'))
|
||||||
|
value.substring(1).toInt(2).toFloat()
|
||||||
|
else if(value.startsWith("0x"))
|
||||||
|
value.substring(2).toInt(16).toFloat()
|
||||||
|
else if(value.startsWith('_'))
|
||||||
|
throw IRParseException("attempt to parse a label as numeric value")
|
||||||
|
else if(value.startsWith('&'))
|
||||||
|
throw IRParseException("address-of should be done with normal LOAD <symbol>")
|
||||||
|
else
|
||||||
|
return value.toFloat()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private val instructionPattern = Regex("""([a-z]+)(\.b|\.w|\.f)?(.*)""", RegexOption.IGNORE_CASE)
|
||||||
|
private val labelPattern = Regex("""_([a-zA-Z\d\._]+):""")
|
||||||
|
|
||||||
|
fun parseIRCodeLine(line: String, pc: Int, placeholders: MutableMap<Int, String>): IRCodeLine {
|
||||||
|
// Note: this function is used from multiple places:
|
||||||
|
// the IR File Reader but also the VirtualMachine itself to make sense of any inline vmasm blocks.
|
||||||
|
val labelmatch = labelPattern.matchEntire(line.trim())
|
||||||
|
if(labelmatch!=null)
|
||||||
|
return IRCodeLabel(labelmatch.groupValues[1])
|
||||||
|
|
||||||
|
val match = instructionPattern.matchEntire(line)
|
||||||
|
?: throw IRParseException("invalid IR instruction: $line")
|
||||||
|
val (instr, typestr, rest) = match.destructured
|
||||||
|
val opcode = try {
|
||||||
|
Opcode.valueOf(instr.uppercase())
|
||||||
|
} catch (ax: IllegalArgumentException) {
|
||||||
|
throw IRParseException("invalid vmasm instruction: $instr")
|
||||||
|
}
|
||||||
|
var type: VmDataType? = convertIRType(typestr)
|
||||||
|
val formats = instructionFormats.getValue(opcode)
|
||||||
|
val format: InstructionFormat
|
||||||
|
if(type !in formats) {
|
||||||
|
type = VmDataType.BYTE
|
||||||
|
format = if(type !in formats)
|
||||||
|
formats.getValue(null)
|
||||||
|
else
|
||||||
|
formats.getValue(type)
|
||||||
|
} else {
|
||||||
|
format = formats.getValue(type)
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse the operands
|
||||||
|
val operands = rest.lowercase().split(",").toMutableList()
|
||||||
|
var reg1: Int? = null
|
||||||
|
var reg2: Int? = null
|
||||||
|
var reg3: Int? = null
|
||||||
|
var fpReg1: Int? = null
|
||||||
|
var fpReg2: Int? = null
|
||||||
|
var fpReg3: Int? = null
|
||||||
|
var value: Float? = null
|
||||||
|
var operand: String?
|
||||||
|
var labelSymbol: String? = null
|
||||||
|
|
||||||
|
fun parseValueOrPlaceholder(operand: String, pc: Int, rest: String, restIndex: Int): Float? {
|
||||||
|
return if(operand.startsWith('_')) {
|
||||||
|
labelSymbol = rest.split(",")[restIndex].trim().drop(1)
|
||||||
|
placeholders[pc] = labelSymbol!!
|
||||||
|
null
|
||||||
|
} else if(operand[0].isLetter()) {
|
||||||
|
labelSymbol = rest.split(",")[restIndex].trim()
|
||||||
|
placeholders[pc] = labelSymbol!!
|
||||||
|
null
|
||||||
|
} else {
|
||||||
|
parseIRValue(operand)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(operands.isNotEmpty() && operands[0].isNotEmpty()) {
|
||||||
|
operand = operands.removeFirst().trim()
|
||||||
|
if(operand[0]=='r')
|
||||||
|
reg1 = operand.substring(1).toInt()
|
||||||
|
else if(operand[0]=='f' && operand[1]=='r')
|
||||||
|
fpReg1 = operand.substring(2).toInt()
|
||||||
|
else {
|
||||||
|
value = parseValueOrPlaceholder(operand, pc, rest, 0)
|
||||||
|
operands.clear()
|
||||||
|
}
|
||||||
|
if(operands.isNotEmpty()) {
|
||||||
|
operand = operands.removeFirst().trim()
|
||||||
|
if(operand[0]=='r')
|
||||||
|
reg2 = operand.substring(1).toInt()
|
||||||
|
else if(operand[0]=='f' && operand[1]=='r')
|
||||||
|
fpReg2 = operand.substring(2).toInt()
|
||||||
|
else {
|
||||||
|
value = parseValueOrPlaceholder(operand, pc, rest, 1)
|
||||||
|
operands.clear()
|
||||||
|
}
|
||||||
|
if(operands.isNotEmpty()) {
|
||||||
|
operand = operands.removeFirst().trim()
|
||||||
|
if(operand[0]=='r')
|
||||||
|
reg3 = operand.substring(1).toInt()
|
||||||
|
else if(operand[0]=='f' && operand[1]=='r')
|
||||||
|
fpReg3 = operand.substring(2).toInt()
|
||||||
|
else {
|
||||||
|
value = parseValueOrPlaceholder(operand, pc, rest, 2)
|
||||||
|
operands.clear()
|
||||||
|
}
|
||||||
|
if(operands.isNotEmpty()) {
|
||||||
|
TODO("placeholder symbol? $operands rest=$rest'")
|
||||||
|
// operands.clear()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// shift the operands back into place
|
||||||
|
while(reg1==null && reg2!=null) {
|
||||||
|
reg1 = reg2
|
||||||
|
reg2 = reg3
|
||||||
|
reg3 = null
|
||||||
|
}
|
||||||
|
while(fpReg1==null && fpReg2!=null) {
|
||||||
|
fpReg1 = fpReg2
|
||||||
|
fpReg2 = fpReg3
|
||||||
|
fpReg3 = null
|
||||||
|
}
|
||||||
|
if(reg3!=null)
|
||||||
|
throw IRParseException("too many reg arguments $line")
|
||||||
|
if(fpReg3!=null)
|
||||||
|
throw IRParseException("too many fpreg arguments $line")
|
||||||
|
|
||||||
|
if(type!=null && type !in formats)
|
||||||
|
throw IRParseException("invalid type code for $line")
|
||||||
|
if(format.reg1 && reg1==null)
|
||||||
|
throw IRParseException("needs reg1 for $line")
|
||||||
|
if(format.reg2 && reg2==null)
|
||||||
|
throw IRParseException("needs reg2 for $line")
|
||||||
|
if(format.value && value==null && labelSymbol==null)
|
||||||
|
throw IRParseException("needs value or symbol for $line")
|
||||||
|
if(!format.reg1 && reg1!=null)
|
||||||
|
throw IRParseException("invalid reg1 for $line")
|
||||||
|
if(!format.reg2 && reg2!=null)
|
||||||
|
throw IRParseException("invalid reg2 for $line")
|
||||||
|
if(value!=null && opcode !in OpcodesWithAddress) {
|
||||||
|
when (type) {
|
||||||
|
VmDataType.BYTE -> {
|
||||||
|
if (value < -128 || value > 255)
|
||||||
|
throw IRParseException("value out of range for byte: $value")
|
||||||
|
}
|
||||||
|
VmDataType.WORD -> {
|
||||||
|
if (value < -32768 || value > 65535)
|
||||||
|
throw IRParseException("value out of range for word: $value")
|
||||||
|
}
|
||||||
|
VmDataType.FLOAT -> {}
|
||||||
|
null -> {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var floatValue: Float? = null
|
||||||
|
var intValue: Int? = null
|
||||||
|
|
||||||
|
if(format.value && value!=null)
|
||||||
|
intValue = value.toInt()
|
||||||
|
if(format.fpValue && value!=null)
|
||||||
|
floatValue = value
|
||||||
|
|
||||||
|
if(opcode in OpcodesForCpuRegisters) {
|
||||||
|
val regStr = rest.split(',').last().lowercase().trim()
|
||||||
|
val reg = if(regStr.startsWith('_')) regStr.substring(1) else regStr
|
||||||
|
if(reg !in setOf(
|
||||||
|
"a", "x", "y",
|
||||||
|
"ax", "ay", "xy",
|
||||||
|
"r0", "r1", "r2", "r3",
|
||||||
|
"r4", "r5", "r6", "r7",
|
||||||
|
"r8", "r9", "r10","r11",
|
||||||
|
"r12", "r13", "r14", "r15",
|
||||||
|
"pc", "pz", "pv","pn"))
|
||||||
|
throw IRParseException("invalid cpu reg: $reg")
|
||||||
|
|
||||||
|
return IRInstruction(opcode, type, reg1, labelSymbol = reg)
|
||||||
|
}
|
||||||
|
|
||||||
|
return IRInstruction(opcode, type, reg1, reg2, fpReg1, fpReg2, intValue, floatValue, labelSymbol = labelSymbol)
|
||||||
|
}
|
||||||
|
@ -30,9 +30,8 @@ class TestIRFileInOut: FunSpec({
|
|||||||
outputDir = tempdir
|
outputDir = tempdir
|
||||||
)
|
)
|
||||||
val program = IRProgram("unittest-irwriter", IRSymbolTable(null), options, target)
|
val program = IRProgram("unittest-irwriter", IRSymbolTable(null), options, target)
|
||||||
val writer = IRFileWriter(program)
|
val writer = IRFileWriter(program, null)
|
||||||
writer.writeFile()
|
val generatedFile = writer.write()
|
||||||
val generatedFile = tempdir.resolve("unittest-irwriter.p8ir")
|
|
||||||
val lines = generatedFile.readLines()
|
val lines = generatedFile.readLines()
|
||||||
lines.first() shouldBe "<PROGRAM NAME=unittest-irwriter>"
|
lines.first() shouldBe "<PROGRAM NAME=unittest-irwriter>"
|
||||||
lines.last() shouldBe "</PROGRAM>"
|
lines.last() shouldBe "</PROGRAM>"
|
||||||
@ -97,9 +96,7 @@ return
|
|||||||
"""
|
"""
|
||||||
val tempfile = createTempFile(suffix = ".p8ir")
|
val tempfile = createTempFile(suffix = ".p8ir")
|
||||||
tempfile.writeText(source)
|
tempfile.writeText(source)
|
||||||
val filepart = tempfile.name.dropLast(5)
|
val program = IRFileReader().read(tempfile)
|
||||||
val reader = IRFileReader(tempfile.parent, filepart)
|
|
||||||
val program = reader.readFile()
|
|
||||||
tempfile.deleteExisting()
|
tempfile.deleteExisting()
|
||||||
program.name shouldBe "test-ir-reader"
|
program.name shouldBe "test-ir-reader"
|
||||||
program.blocks.size shouldBe 2
|
program.blocks.size shouldBe 2
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import io.kotest.assertions.throwables.shouldThrow
|
import io.kotest.assertions.throwables.shouldThrow
|
||||||
|
import io.kotest.assertions.throwables.shouldThrowWithMessage
|
||||||
import io.kotest.core.spec.style.FunSpec
|
import io.kotest.core.spec.style.FunSpec
|
||||||
import io.kotest.matchers.shouldBe
|
import io.kotest.matchers.shouldBe
|
||||||
import io.kotest.matchers.shouldNotBe
|
import io.kotest.matchers.shouldNotBe
|
||||||
@ -8,7 +9,7 @@ import prog8.intermediate.*
|
|||||||
class TestInstructions: FunSpec({
|
class TestInstructions: FunSpec({
|
||||||
|
|
||||||
test("simple") {
|
test("simple") {
|
||||||
val ins = Instruction(Opcode.NOP)
|
val ins = IRInstruction(Opcode.NOP)
|
||||||
ins.opcode shouldBe Opcode.NOP
|
ins.opcode shouldBe Opcode.NOP
|
||||||
ins.type shouldBe null
|
ins.type shouldBe null
|
||||||
ins.reg1 shouldBe null
|
ins.reg1 shouldBe null
|
||||||
@ -21,33 +22,33 @@ class TestInstructions: FunSpec({
|
|||||||
}
|
}
|
||||||
|
|
||||||
test("with value") {
|
test("with value") {
|
||||||
val ins = Instruction(Opcode.BZ, VmDataType.BYTE, reg1=42, value = 9999)
|
val ins = IRInstruction(Opcode.BZ, VmDataType.BYTE, reg1=42, value = 99)
|
||||||
ins.opcode shouldBe Opcode.BZ
|
ins.opcode shouldBe Opcode.BZ
|
||||||
ins.type shouldBe VmDataType.BYTE
|
ins.type shouldBe VmDataType.BYTE
|
||||||
ins.reg1 shouldBe 42
|
ins.reg1 shouldBe 42
|
||||||
ins.reg2 shouldBe null
|
ins.reg2 shouldBe null
|
||||||
ins.value shouldBe 9999
|
ins.value shouldBe 99
|
||||||
ins.labelSymbol shouldBe null
|
ins.labelSymbol shouldBe null
|
||||||
ins.reg1direction shouldBe OperandDirection.INPUT
|
ins.reg1direction shouldBe OperandDirection.INPUT
|
||||||
ins.fpReg1direction shouldBe OperandDirection.INPUT
|
ins.fpReg1direction shouldBe OperandDirection.INPUT
|
||||||
ins.toString() shouldBe "bz.b r42,9999"
|
ins.toString() shouldBe "bz.b r42,99"
|
||||||
}
|
}
|
||||||
|
|
||||||
test("with label") {
|
test("with label") {
|
||||||
val ins = Instruction(Opcode.BZ, VmDataType.WORD, reg1=11, labelSymbol = listOf("a","b","c"))
|
val ins = IRInstruction(Opcode.BZ, VmDataType.WORD, reg1=11, labelSymbol = "a.b.c")
|
||||||
ins.opcode shouldBe Opcode.BZ
|
ins.opcode shouldBe Opcode.BZ
|
||||||
ins.type shouldBe VmDataType.WORD
|
ins.type shouldBe VmDataType.WORD
|
||||||
ins.reg1 shouldBe 11
|
ins.reg1 shouldBe 11
|
||||||
ins.reg2 shouldBe null
|
ins.reg2 shouldBe null
|
||||||
ins.value shouldBe null
|
ins.value shouldBe null
|
||||||
ins.labelSymbol shouldBe listOf("a","b","c")
|
ins.labelSymbol shouldBe "a.b.c"
|
||||||
ins.reg1direction shouldBe OperandDirection.INPUT
|
ins.reg1direction shouldBe OperandDirection.INPUT
|
||||||
ins.fpReg1direction shouldBe OperandDirection.INPUT
|
ins.fpReg1direction shouldBe OperandDirection.INPUT
|
||||||
ins.toString() shouldBe "bz.w r11,_a.b.c"
|
ins.toString() shouldBe "bz.w r11,_a.b.c"
|
||||||
}
|
}
|
||||||
|
|
||||||
test("with output registers") {
|
test("with output registers") {
|
||||||
val ins = Instruction(Opcode.ADDR, VmDataType.WORD, reg1=11, reg2=22)
|
val ins = IRInstruction(Opcode.ADDR, VmDataType.WORD, reg1=11, reg2=22)
|
||||||
ins.opcode shouldBe Opcode.ADDR
|
ins.opcode shouldBe Opcode.ADDR
|
||||||
ins.type shouldBe VmDataType.WORD
|
ins.type shouldBe VmDataType.WORD
|
||||||
ins.reg1 shouldBe 11
|
ins.reg1 shouldBe 11
|
||||||
@ -58,7 +59,7 @@ class TestInstructions: FunSpec({
|
|||||||
ins.fpReg1direction shouldBe OperandDirection.INPUT
|
ins.fpReg1direction shouldBe OperandDirection.INPUT
|
||||||
ins.toString() shouldBe "addr.w r11,r22"
|
ins.toString() shouldBe "addr.w r11,r22"
|
||||||
|
|
||||||
val ins2 = Instruction(Opcode.SQRT, VmDataType.BYTE, reg1=11, reg2=22)
|
val ins2 = IRInstruction(Opcode.SQRT, VmDataType.BYTE, reg1=11, reg2=22)
|
||||||
ins2.opcode shouldBe Opcode.SQRT
|
ins2.opcode shouldBe Opcode.SQRT
|
||||||
ins2.type shouldBe VmDataType.BYTE
|
ins2.type shouldBe VmDataType.BYTE
|
||||||
ins2.reg1 shouldBe 11
|
ins2.reg1 shouldBe 11
|
||||||
@ -73,25 +74,26 @@ class TestInstructions: FunSpec({
|
|||||||
|
|
||||||
test("missing type should fail") {
|
test("missing type should fail") {
|
||||||
shouldThrow<IllegalArgumentException> {
|
shouldThrow<IllegalArgumentException> {
|
||||||
Instruction(Opcode.BZ, reg1=42, value=9999)
|
IRInstruction(Opcode.BZ, reg1=42, value=99)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
test("missing registers should fail") {
|
test("missing registers should fail") {
|
||||||
shouldThrow<IllegalArgumentException> {
|
shouldThrowWithMessage<IllegalArgumentException>("missing reg1") {
|
||||||
Instruction(Opcode.BZ, VmDataType.BYTE, value=9999)
|
IRInstruction(Opcode.BZ, VmDataType.BYTE, value=99)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
test("missing value should fail") {
|
test("missing value should fail") {
|
||||||
shouldThrow<IllegalArgumentException> {
|
shouldThrowWithMessage<IllegalArgumentException>("missing a value or labelsymbol") {
|
||||||
Instruction(Opcode.BZ, VmDataType.BYTE, reg1=42)
|
IRInstruction(Opcode.BZ, VmDataType.BYTE, reg1=42)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
test("all instructionformats") {
|
test("all instructionformats") {
|
||||||
|
instructionFormats.size shouldBe Opcode.values().size
|
||||||
Opcode.values().forEach {
|
Opcode.values().forEach {
|
||||||
instructionFormats[it] shouldNotBe null
|
instructionFormats[it] shouldNotBe null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#!/usr/bin/env sh
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
rm -f *.bin *.xex *.jar *.asm *.prg *.vm.txt *.vice-mon-list *.list *.p8virt a.out imgui.ini
|
rm -f *.bin *.xex *.jar *.asm *.prg *.vm.txt *.vice-mon-list *.list *.p8ir a.out imgui.ini
|
||||||
rm -rf build out
|
rm -rf build out
|
||||||
rm -rf compiler/build codeGenCpu6502/build codeGenExperimental/build codeOptimizers/build compilerAst/build dbusCompilerService/build httpCompilerService/build parser/build parser/src/prog8/parser
|
rm -rf compiler/build codeGenCpu6502/build codeGenExperimental/build codeOptimizers/build compilerAst/build dbusCompilerService/build httpCompilerService/build parser/build parser/src/prog8/parser
|
||||||
|
|
||||||
|
@ -6,7 +6,6 @@ include(
|
|||||||
':codeOptimizers',
|
':codeOptimizers',
|
||||||
':virtualmachine',
|
':virtualmachine',
|
||||||
':codeGenIntermediate',
|
':codeGenIntermediate',
|
||||||
':codeGenVirtual',
|
|
||||||
':codeGenCpu6502',
|
':codeGenCpu6502',
|
||||||
':codeGenExperimental',
|
':codeGenExperimental',
|
||||||
':compiler',
|
':compiler',
|
||||||
|
@ -27,6 +27,7 @@ compileTestKotlin {
|
|||||||
dependencies {
|
dependencies {
|
||||||
implementation project(':codeCore')
|
implementation project(':codeCore')
|
||||||
implementation project(':intermediate')
|
implementation project(':intermediate')
|
||||||
|
implementation project(':codeGenIntermediate')
|
||||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
|
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
|
||||||
implementation "com.michael-bull.kotlin-result:kotlin-result-jvm:1.1.16"
|
implementation "com.michael-bull.kotlin-result:kotlin-result-jvm:1.1.16"
|
||||||
testImplementation 'io.kotest:kotest-runner-junit5-jvm:5.3.2'
|
testImplementation 'io.kotest:kotest-runner-junit5-jvm:5.3.2'
|
||||||
|
@ -1,349 +0,0 @@
|
|||||||
package prog8.vm
|
|
||||||
|
|
||||||
import prog8.code.core.unescape
|
|
||||||
import prog8.intermediate.*
|
|
||||||
|
|
||||||
|
|
||||||
class Assembler {
|
|
||||||
private val symbolAddresses = mutableMapOf<String, Int>()
|
|
||||||
private val placeholders = mutableMapOf<Int, String>()
|
|
||||||
var cx16virtualregBaseAdress = 0xff02
|
|
||||||
|
|
||||||
init {
|
|
||||||
require(instructionFormats.size== Opcode.values().size) {
|
|
||||||
"missing " + (Opcode.values().toSet() - instructionFormats.keys)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun initializeMemory(memsrc: String, memory: Memory) {
|
|
||||||
symbolAddresses.clear()
|
|
||||||
val arrayValuePlaceholders = mutableListOf<Pair<Int, String>>()
|
|
||||||
|
|
||||||
val instrPattern = Regex("""var (.+) @([0-9]+) ([a-z]+)(\[[0-9]+\])? (.+)""", RegexOption.IGNORE_CASE)
|
|
||||||
for(line in memsrc.lines()) {
|
|
||||||
if(line.isBlank() || line.startsWith(';'))
|
|
||||||
continue
|
|
||||||
val match = instrPattern.matchEntire(line.trim())
|
|
||||||
if(match==null)
|
|
||||||
throw IllegalArgumentException("invalid line $line")
|
|
||||||
else {
|
|
||||||
val (name, addrStr, datatype, arrayspec, values) = match.destructured
|
|
||||||
if(name=="cx16.r0") {
|
|
||||||
cx16virtualregBaseAdress = addrStr.toInt()
|
|
||||||
}
|
|
||||||
val numArrayElts = if(arrayspec.isBlank()) 1 else arrayspec.substring(1, arrayspec.length-1).toInt()
|
|
||||||
var address = parseValue(Opcode.LOADCPU, addrStr, 0).toInt()
|
|
||||||
symbolAddresses[name] = address
|
|
||||||
when(datatype) {
|
|
||||||
"str" -> {
|
|
||||||
val string = values.trim('"').unescape()
|
|
||||||
memory.setString(address, string, false)
|
|
||||||
}
|
|
||||||
"strz" -> {
|
|
||||||
val string = values.trim('"').unescape()
|
|
||||||
memory.setString(address, string, true)
|
|
||||||
}
|
|
||||||
"ubyte", "byte" -> {
|
|
||||||
val array = values.split(',').map { parseValue(Opcode.LOADCPU, it.trim(), 0).toInt() }
|
|
||||||
require(array.size==numArrayElts || array.size==1)
|
|
||||||
if(numArrayElts > array.size) {
|
|
||||||
val value = array.single().toUByte()
|
|
||||||
repeat(numArrayElts) {
|
|
||||||
memory.setUB(address, value)
|
|
||||||
address++
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (value in array) {
|
|
||||||
memory.setUB(address, value.toUByte())
|
|
||||||
address++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"uword", "word" -> {
|
|
||||||
if(arrayspec.isBlank()) {
|
|
||||||
// single value
|
|
||||||
val value = parseValue(Opcode.LOADCPU, values.trim(), 0).toInt()
|
|
||||||
memory.setUW(address, value.toUShort())
|
|
||||||
address += 2
|
|
||||||
} else {
|
|
||||||
// array initializer
|
|
||||||
val array = values.split(',').withIndex().map {(index, value) ->
|
|
||||||
val tv = value.trim()
|
|
||||||
if(tv.startsWith('&')) {
|
|
||||||
arrayValuePlaceholders += Pair(address+index*2, tv.drop(1))
|
|
||||||
9999 // will be replaced with correct value at the end.
|
|
||||||
} else
|
|
||||||
parseValue(Opcode.LOADCPU, tv, 0).toInt()
|
|
||||||
}
|
|
||||||
require(array.size==numArrayElts || array.size==1)
|
|
||||||
if(numArrayElts>array.size) {
|
|
||||||
val value = array.single().toUShort()
|
|
||||||
repeat(numArrayElts) {
|
|
||||||
memory.setUW(address, value)
|
|
||||||
address += 2
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (value in array) {
|
|
||||||
memory.setUW(address, value.toUShort())
|
|
||||||
address += 2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"float" -> {
|
|
||||||
val array = values.split(',').map { it.toFloat() }
|
|
||||||
require(array.size==numArrayElts || array.size==1)
|
|
||||||
if(numArrayElts>array.size) {
|
|
||||||
val value = array.single()
|
|
||||||
repeat(numArrayElts) {
|
|
||||||
memory.setFloat(address, value)
|
|
||||||
address += 4 // 32-bits floats
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (value in array) {
|
|
||||||
memory.setFloat(address, value)
|
|
||||||
address += 4 // 32-bits floats
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else -> throw IllegalArgumentException("invalid datatype $datatype")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// correct the addres-of values in array initializers
|
|
||||||
arrayValuePlaceholders.forEach { (address, symbol) ->
|
|
||||||
val addr = this.symbolAddresses.getValue(symbol)
|
|
||||||
memory.setUW(address, addr.toUShort())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun assembleProgram(source: CharSequence): List<Instruction> {
|
|
||||||
placeholders.clear()
|
|
||||||
val program = mutableListOf<Instruction>()
|
|
||||||
val instructionPattern = Regex("""([a-z]+)(\.b|\.w|\.f)?(.*)""", RegexOption.IGNORE_CASE)
|
|
||||||
val labelPattern = Regex("""_([a-zA-Z\d\._]+):""")
|
|
||||||
val binaryPattern = Regex("""!binary (.+)""")
|
|
||||||
for (line in source.lines()) {
|
|
||||||
if(line.isBlank() || line.startsWith(';'))
|
|
||||||
continue
|
|
||||||
val match = instructionPattern.matchEntire(line.trim())
|
|
||||||
if(match==null) {
|
|
||||||
val binarymatch = binaryPattern.matchEntire(line.trim())
|
|
||||||
if(binarymatch!=null) {
|
|
||||||
val hex = binarymatch.groups[1]!!.value
|
|
||||||
val binary = hex.windowed(size=2, step=2).map {
|
|
||||||
it.toByte(16)
|
|
||||||
}.toByteArray()
|
|
||||||
program.add(Instruction(Opcode.BINARYDATA, binaryData = binary))
|
|
||||||
} else {
|
|
||||||
val labelmatch = labelPattern.matchEntire(line.trim())
|
|
||||||
if (labelmatch == null)
|
|
||||||
throw IllegalArgumentException("invalid line $line at line ${program.size + 1}")
|
|
||||||
else {
|
|
||||||
val label = labelmatch.groupValues[1]
|
|
||||||
if (label in symbolAddresses)
|
|
||||||
throw IllegalArgumentException("label redefined $label")
|
|
||||||
symbolAddresses[label] = program.size
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
val (_, instr, typestr, rest) = match.groupValues
|
|
||||||
if(instr=="incbin") {
|
|
||||||
println("warning: ignoring incbin command: $rest")
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
val opcode = try {
|
|
||||||
Opcode.valueOf(instr.uppercase())
|
|
||||||
} catch (ax: IllegalArgumentException) {
|
|
||||||
throw IllegalArgumentException("invalid vmasm instruction: $instr", ax)
|
|
||||||
}
|
|
||||||
var type: VmDataType? = convertType(typestr)
|
|
||||||
val formats = instructionFormats.getValue(opcode)
|
|
||||||
val format: InstructionFormat
|
|
||||||
if(type !in formats) {
|
|
||||||
type = VmDataType.BYTE
|
|
||||||
format = if(type !in formats)
|
|
||||||
formats.getValue(null)
|
|
||||||
else
|
|
||||||
formats.getValue(type)
|
|
||||||
} else {
|
|
||||||
format = formats.getValue(type)
|
|
||||||
}
|
|
||||||
// parse the operands
|
|
||||||
val operands = rest.lowercase().split(",").toMutableList()
|
|
||||||
var reg1: Int? = null
|
|
||||||
var reg2: Int? = null
|
|
||||||
var reg3: Int? = null
|
|
||||||
var fpReg1: Int? = null
|
|
||||||
var fpReg2: Int? = null
|
|
||||||
var fpReg3: Int? = null
|
|
||||||
var value: Float? = null
|
|
||||||
var operand: String?
|
|
||||||
|
|
||||||
fun parseValueOrPlaceholder(operand: String, pc: Int, rest: String, restIndex: Int, opcode: Opcode): Float {
|
|
||||||
return if(operand.startsWith('_')) {
|
|
||||||
placeholders[pc] = rest.split(",")[restIndex].trim().drop(1)
|
|
||||||
0f
|
|
||||||
} else if(operand[0].isLetter()) {
|
|
||||||
placeholders[pc] = rest.split(",")[restIndex].trim()
|
|
||||||
0f
|
|
||||||
} else
|
|
||||||
parseValue(opcode, operand, pc)
|
|
||||||
}
|
|
||||||
|
|
||||||
if(operands.isNotEmpty() && operands[0].isNotEmpty()) {
|
|
||||||
operand = operands.removeFirst().trim()
|
|
||||||
if(operand[0]=='r')
|
|
||||||
reg1 = operand.substring(1).toInt()
|
|
||||||
else if(operand[0]=='f' && operand[1]=='r')
|
|
||||||
fpReg1 = operand.substring(2).toInt()
|
|
||||||
else {
|
|
||||||
value = parseValueOrPlaceholder(operand, program.size, rest, 0, opcode)
|
|
||||||
operands.clear()
|
|
||||||
}
|
|
||||||
if(operands.isNotEmpty()) {
|
|
||||||
operand = operands.removeFirst().trim()
|
|
||||||
if(operand[0]=='r')
|
|
||||||
reg2 = operand.substring(1).toInt()
|
|
||||||
else if(operand[0]=='f' && operand[1]=='r')
|
|
||||||
fpReg2 = operand.substring(2).toInt()
|
|
||||||
else {
|
|
||||||
value = parseValueOrPlaceholder(operand, program.size, rest, 1, opcode)
|
|
||||||
operands.clear()
|
|
||||||
}
|
|
||||||
if(operands.isNotEmpty()) {
|
|
||||||
operand = operands.removeFirst().trim()
|
|
||||||
if(operand[0]=='r')
|
|
||||||
reg3 = operand.substring(1).toInt()
|
|
||||||
else if(operand[0]=='f' && operand[1]=='r')
|
|
||||||
fpReg3 = operand.substring(2).toInt()
|
|
||||||
else {
|
|
||||||
value = parseValueOrPlaceholder(operand, program.size, rest, 2, opcode)
|
|
||||||
operands.clear()
|
|
||||||
}
|
|
||||||
if(operands.isNotEmpty()) {
|
|
||||||
TODO("placeholder symbol? $operands rest=$rest'")
|
|
||||||
operands.clear()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// shift the operands back into place
|
|
||||||
while(reg1==null && reg2!=null) {
|
|
||||||
reg1 = reg2
|
|
||||||
reg2 = reg3
|
|
||||||
reg3 = null
|
|
||||||
}
|
|
||||||
while(fpReg1==null && fpReg2!=null) {
|
|
||||||
fpReg1 = fpReg2
|
|
||||||
fpReg2 = fpReg3
|
|
||||||
fpReg3 = null
|
|
||||||
}
|
|
||||||
if(reg3!=null)
|
|
||||||
throw IllegalArgumentException("too many reg arguments $line")
|
|
||||||
if(fpReg3!=null)
|
|
||||||
throw IllegalArgumentException("too many fpreg arguments $line")
|
|
||||||
|
|
||||||
if(type!=null && type !in formats)
|
|
||||||
throw IllegalArgumentException("invalid type code for $line")
|
|
||||||
if(format.reg1 && reg1==null)
|
|
||||||
throw IllegalArgumentException("needs reg1 for $line")
|
|
||||||
if(format.reg2 && reg2==null)
|
|
||||||
throw IllegalArgumentException("needs reg2 for $line")
|
|
||||||
if(format.value && value==null)
|
|
||||||
throw IllegalArgumentException("needs value for $line")
|
|
||||||
if(!format.reg1 && reg1!=null)
|
|
||||||
throw IllegalArgumentException("invalid reg1 for $line")
|
|
||||||
if(!format.reg2 && reg2!=null)
|
|
||||||
throw IllegalArgumentException("invalid reg2 for $line")
|
|
||||||
if(value!=null && opcode !in OpcodesWithAddress) {
|
|
||||||
when (type) {
|
|
||||||
VmDataType.BYTE -> {
|
|
||||||
if (value < -128 || value > 255)
|
|
||||||
throw IllegalArgumentException("value out of range for byte: $value")
|
|
||||||
}
|
|
||||||
VmDataType.WORD -> {
|
|
||||||
if (value < -32768 || value > 65535)
|
|
||||||
throw IllegalArgumentException("value out of range for word: $value")
|
|
||||||
}
|
|
||||||
VmDataType.FLOAT -> {}
|
|
||||||
null -> {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var floatValue: Float? = null
|
|
||||||
var intValue: Int? = null
|
|
||||||
|
|
||||||
if(format.value)
|
|
||||||
intValue = value!!.toInt()
|
|
||||||
if(format.fpValue)
|
|
||||||
floatValue = value!!
|
|
||||||
|
|
||||||
if(opcode in OpcodesForCpuRegisters) {
|
|
||||||
val regStr = rest.split(',').last().lowercase().trim()
|
|
||||||
val reg = if(regStr.startsWith('_')) regStr.substring(1) else regStr
|
|
||||||
if(reg !in setOf(
|
|
||||||
"a", "x", "y",
|
|
||||||
"ax", "ay", "xy",
|
|
||||||
"r0", "r1", "r2", "r3",
|
|
||||||
"r4", "r5", "r6", "r7",
|
|
||||||
"r8", "r9", "r10","r11",
|
|
||||||
"r12", "r13", "r14", "r15",
|
|
||||||
"pc", "pz", "pv","pn"))
|
|
||||||
throw IllegalArgumentException("invalid cpu reg: $reg")
|
|
||||||
program.add(Instruction(opcode, type, reg1, labelSymbol = listOf(reg)))
|
|
||||||
} else {
|
|
||||||
program.add(Instruction(opcode, type, reg1, reg2, fpReg1, fpReg2, intValue, floatValue))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pass2replaceLabels(program)
|
|
||||||
return program
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun pass2replaceLabels(program: MutableList<Instruction>) {
|
|
||||||
for((line, label) in placeholders) {
|
|
||||||
val replacement = symbolAddresses[label]
|
|
||||||
if(replacement==null) {
|
|
||||||
// it could be an address + index: symbol+42
|
|
||||||
if('+' in label) {
|
|
||||||
val (symbol, indexStr) = label.split('+')
|
|
||||||
val index = indexStr.toInt()
|
|
||||||
val address = symbolAddresses.getValue(symbol) + index
|
|
||||||
program[line] = program[line].copy(value = address)
|
|
||||||
} else {
|
|
||||||
throw IllegalArgumentException("placeholder not found in labels: $label")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
program[line] = program[line].copy(value = replacement)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun parseValue(opcode: Opcode, value: String, pc: Int): Float {
|
|
||||||
return if(value.startsWith("-"))
|
|
||||||
-parseValue(opcode, value.substring(1), pc)
|
|
||||||
else if(value.startsWith('$'))
|
|
||||||
value.substring(1).toInt(16).toFloat()
|
|
||||||
else if(value.startsWith('%'))
|
|
||||||
value.substring(1).toInt(2).toFloat()
|
|
||||||
else if(value.startsWith("0x"))
|
|
||||||
value.substring(2).toInt(16).toFloat()
|
|
||||||
else if(value.startsWith('_') || value[0].isLetter())
|
|
||||||
throw IllegalArgumentException("attempt to parse non-numeric value $value")
|
|
||||||
else
|
|
||||||
value.toFloat()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun convertType(typestr: String): VmDataType? {
|
|
||||||
return when(typestr.lowercase()) {
|
|
||||||
"" -> null
|
|
||||||
".b" -> VmDataType.BYTE
|
|
||||||
".w" -> VmDataType.WORD
|
|
||||||
".f" -> VmDataType.FLOAT
|
|
||||||
else -> throw IllegalArgumentException("invalid type $typestr")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,43 +0,0 @@
|
|||||||
package prog8.vm
|
|
||||||
|
|
||||||
fun main(args: Array<String>) {
|
|
||||||
val memsrc = """
|
|
||||||
$4000 strz "Hello from program! "derp" bye.\n"
|
|
||||||
$2000 ubyte 65,66,67,68,0
|
|
||||||
$2100 uword $1111,$2222,$3333,$4444
|
|
||||||
"""
|
|
||||||
val src = """
|
|
||||||
; enable lores gfx screen
|
|
||||||
load r0, 0
|
|
||||||
syscall 8
|
|
||||||
load.w r10, 320
|
|
||||||
load.w r11, 240
|
|
||||||
load.b r12, 0
|
|
||||||
|
|
||||||
_forever:
|
|
||||||
load.w r1, 0
|
|
||||||
_yloop:
|
|
||||||
load.w r0, 0
|
|
||||||
_xloop:
|
|
||||||
mul.b r2,r0,r1
|
|
||||||
add.b r2,r2,r12
|
|
||||||
syscall 10
|
|
||||||
addi.w r0,r0,1
|
|
||||||
blt.w r0, r10, _xloop
|
|
||||||
addi.w r1,r1,1
|
|
||||||
blt.w r1, r11,_yloop
|
|
||||||
addi.b r12,r12,1
|
|
||||||
jump _forever
|
|
||||||
|
|
||||||
load.w r0, 2000
|
|
||||||
syscall 7
|
|
||||||
load.w r0,0
|
|
||||||
return"""
|
|
||||||
val memory = Memory()
|
|
||||||
val assembler = Assembler()
|
|
||||||
assembler.initializeMemory(memsrc, memory)
|
|
||||||
val program = assembler.assembleProgram(src)
|
|
||||||
|
|
||||||
val vm = VirtualMachine(memory, program, assembler.cx16virtualregBaseAdress)
|
|
||||||
vm.run()
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
234
virtualmachine/src/prog8/vm/VmProgramLoader.kt
Normal file
234
virtualmachine/src/prog8/vm/VmProgramLoader.kt
Normal file
@ -0,0 +1,234 @@
|
|||||||
|
package prog8.vm
|
||||||
|
|
||||||
|
import prog8.code.core.DataType
|
||||||
|
import prog8.intermediate.*
|
||||||
|
|
||||||
|
class VmProgramLoader {
|
||||||
|
|
||||||
|
private val placeholders = mutableMapOf<Int, String>() // program index to symbolname
|
||||||
|
|
||||||
|
fun load(irProgram: IRProgram, memory: Memory): List<IRInstruction> {
|
||||||
|
|
||||||
|
// at long last, allocate the variables in memory.
|
||||||
|
placeholders.clear()
|
||||||
|
val allocations = VmVariableAllocator(irProgram.st, irProgram.encoding, irProgram.options.compTarget)
|
||||||
|
val symbolAddresses = allocations.allocations.toMutableMap()
|
||||||
|
val program = mutableListOf<IRInstruction>()
|
||||||
|
|
||||||
|
varsToMemory(irProgram, allocations, symbolAddresses, memory)
|
||||||
|
|
||||||
|
if(!irProgram.options.dontReinitGlobals)
|
||||||
|
addToProgram(irProgram.globalInits, program, symbolAddresses)
|
||||||
|
|
||||||
|
// make sure that if there is a "main.start" entrypoint, we jump to it
|
||||||
|
irProgram.blocks.firstOrNull()?.let {
|
||||||
|
if(it.subroutines.any { sub -> sub.name=="main.start" }) {
|
||||||
|
placeholders[program.size] = "main.start"
|
||||||
|
program += IRInstruction(Opcode.JUMP, labelSymbol = "main.start")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
irProgram.blocks.forEach { block ->
|
||||||
|
if(block.address!=null)
|
||||||
|
throw IRParseException("blocks cannot have a load address for vm: ${block.name}")
|
||||||
|
|
||||||
|
block.inlineAssembly.forEach { addAssemblyToProgram(it, program, symbolAddresses) }
|
||||||
|
block.subroutines.forEach {
|
||||||
|
symbolAddresses[it.name] = program.size
|
||||||
|
it.chunks.forEach { chunk ->
|
||||||
|
if(chunk is IRInlineAsmChunk)
|
||||||
|
addAssemblyToProgram(chunk, program, symbolAddresses)
|
||||||
|
else
|
||||||
|
addToProgram(chunk.lines, program, symbolAddresses)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(block.asmSubroutines.any())
|
||||||
|
throw IRParseException("vm currently does not support asmsubs: ${block.asmSubroutines.first().name}")
|
||||||
|
}
|
||||||
|
|
||||||
|
pass2replaceLabelsByProgIndex(program, symbolAddresses)
|
||||||
|
|
||||||
|
program.forEach {
|
||||||
|
if(it.opcode in OpcodesWithAddress && it.value==null) {
|
||||||
|
throw IRParseException("instruction missing numeric value, label not replaced? $it")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return program
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun varsToMemory(
|
||||||
|
program: IRProgram,
|
||||||
|
allocations: VmVariableAllocator,
|
||||||
|
symbolAddresses: MutableMap<String, Int>,
|
||||||
|
memory: Memory
|
||||||
|
) {
|
||||||
|
program.st.allVariables().forEach { variable ->
|
||||||
|
var addr = allocations.allocations.getValue(variable.name)
|
||||||
|
variable.onetimeInitializationNumericValue?.let {
|
||||||
|
when(variable.dt) {
|
||||||
|
DataType.UBYTE -> memory.setUB(addr, it.toInt().toUByte())
|
||||||
|
DataType.BYTE -> memory.setSB(addr, it.toInt().toByte())
|
||||||
|
DataType.UWORD -> memory.setUW(addr, it.toInt().toUShort())
|
||||||
|
DataType.WORD -> memory.setSW(addr, it.toInt().toShort())
|
||||||
|
DataType.FLOAT -> memory.setFloat(addr, it.toFloat())
|
||||||
|
else -> throw IRParseException("invalid dt")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
variable.onetimeInitializationArrayValue?.let {
|
||||||
|
require(variable.length==it.size || it.size==1)
|
||||||
|
if(it.size==1) {
|
||||||
|
val value = it[0].number!!
|
||||||
|
when(variable.dt) {
|
||||||
|
DataType.STR, DataType.ARRAY_UB -> {
|
||||||
|
repeat(variable.length!!) {
|
||||||
|
memory.setUB(addr, value.toInt().toUByte())
|
||||||
|
addr++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DataType.ARRAY_B -> {
|
||||||
|
repeat(variable.length!!) {
|
||||||
|
memory.setSB(addr, value.toInt().toByte())
|
||||||
|
addr++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DataType.ARRAY_UW -> {
|
||||||
|
repeat(variable.length!!) {
|
||||||
|
memory.setUW(addr, value.toInt().toUShort())
|
||||||
|
addr+=2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DataType.ARRAY_W -> {
|
||||||
|
repeat(variable.length!!) {
|
||||||
|
memory.setSW(addr, value.toInt().toShort())
|
||||||
|
addr+=2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DataType.ARRAY_F -> {
|
||||||
|
repeat(variable.length!!) {
|
||||||
|
memory.setFloat(addr, value.toFloat())
|
||||||
|
addr += program.options.compTarget.machine.FLOAT_MEM_SIZE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> throw IRParseException("invalid dt")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
when(variable.dt) {
|
||||||
|
DataType.STR, DataType.ARRAY_UB -> {
|
||||||
|
for(elt in it) {
|
||||||
|
memory.setUB(addr, elt.number!!.toInt().toUByte())
|
||||||
|
addr++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DataType.ARRAY_B -> {
|
||||||
|
for(elt in it) {
|
||||||
|
memory.setSB(addr, elt.number!!.toInt().toByte())
|
||||||
|
addr++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DataType.ARRAY_UW -> {
|
||||||
|
for(elt in it) {
|
||||||
|
if(elt.addressOf!=null) {
|
||||||
|
val symbolAddress = symbolAddresses.getValue(elt.addressOf!!.joinToString("."))
|
||||||
|
memory.setUW(addr, symbolAddress.toUShort())
|
||||||
|
} else {
|
||||||
|
memory.setUW(addr, elt.number!!.toInt().toUShort())
|
||||||
|
}
|
||||||
|
addr+=2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DataType.ARRAY_W -> {
|
||||||
|
for(elt in it) {
|
||||||
|
memory.setSW(addr, elt.number!!.toInt().toShort())
|
||||||
|
addr+=2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DataType.ARRAY_F -> {
|
||||||
|
for(elt in it) {
|
||||||
|
memory.setSW(addr, elt.number!!.toInt().toShort())
|
||||||
|
addr+=program.options.compTarget.machine.FLOAT_MEM_SIZE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> throw IRParseException("invalid dt")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
require(variable.onetimeInitializationStringValue==null) { "in vm/ir, strings should have been converted into bytearrays." }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun pass2replaceLabelsByProgIndex(
|
||||||
|
program: MutableList<IRInstruction>,
|
||||||
|
symbolAddresses: MutableMap<String, Int>
|
||||||
|
) {
|
||||||
|
for((line, label) in placeholders) {
|
||||||
|
val replacement = symbolAddresses[label]
|
||||||
|
if(replacement==null) {
|
||||||
|
// it could be an address + index: symbol+42
|
||||||
|
if('+' in label) {
|
||||||
|
val (symbol, indexStr) = label.split('+')
|
||||||
|
val index = indexStr.toInt()
|
||||||
|
val address = symbolAddresses.getValue(symbol) + index
|
||||||
|
program[line] = program[line].copy(value = address)
|
||||||
|
} else {
|
||||||
|
throw IRParseException("placeholder not found in labels: $label")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
program[line] = program[line].copy(value = replacement)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun addToProgram(
|
||||||
|
lines: Iterable<IRCodeLine>,
|
||||||
|
program: MutableList<IRInstruction>,
|
||||||
|
symbolAddresses: MutableMap<String, Int>
|
||||||
|
) {
|
||||||
|
lines.map {
|
||||||
|
when(it) {
|
||||||
|
is IRInstruction -> {
|
||||||
|
it.labelSymbol?.let { symbol -> placeholders[program.size]=symbol }
|
||||||
|
if(it.opcode==Opcode.SYSCALL) {
|
||||||
|
// convert IR Syscall to VM Syscall
|
||||||
|
val vmSyscall = when(it.value!!) {
|
||||||
|
IMSyscall.SORT_UBYTE.ordinal -> Syscall.SORT_UBYTE
|
||||||
|
IMSyscall.SORT_BYTE.ordinal -> Syscall.SORT_BYTE
|
||||||
|
IMSyscall.SORT_UWORD.ordinal -> Syscall.SORT_UWORD
|
||||||
|
IMSyscall.SORT_WORD.ordinal -> Syscall.SORT_WORD
|
||||||
|
IMSyscall.ANY_BYTE.ordinal -> Syscall.ANY_BYTE
|
||||||
|
IMSyscall.ANY_WORD.ordinal -> Syscall.ANY_WORD
|
||||||
|
IMSyscall.ANY_FLOAT.ordinal -> Syscall.ANY_FLOAT
|
||||||
|
IMSyscall.ALL_BYTE.ordinal -> Syscall.ALL_BYTE
|
||||||
|
IMSyscall.ALL_WORD.ordinal -> Syscall.ALL_WORD
|
||||||
|
IMSyscall.ALL_FLOAT.ordinal -> Syscall.ALL_FLOAT
|
||||||
|
IMSyscall.REVERSE_BYTES.ordinal -> Syscall.REVERSE_BYTES
|
||||||
|
IMSyscall.REVERSE_WORDS.ordinal -> Syscall.REVERSE_WORDS
|
||||||
|
IMSyscall.REVERSE_FLOATS.ordinal -> Syscall.REVERSE_FLOATS
|
||||||
|
else -> throw IRParseException("invalid IM syscall number $it")
|
||||||
|
}
|
||||||
|
program += it.copy(value=vmSyscall.ordinal)
|
||||||
|
} else {
|
||||||
|
program += it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is IRCodeInlineBinary -> program += IRInstruction(Opcode.BINARYDATA, binaryData = it.data)
|
||||||
|
is IRCodeComment -> { /* just ignore */ }
|
||||||
|
is IRCodeLabel -> { symbolAddresses[it.name] = program.size }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun addAssemblyToProgram(
|
||||||
|
asmChunk: IRInlineAsmChunk,
|
||||||
|
program: MutableList<IRInstruction>,
|
||||||
|
symbolAddresses: MutableMap<String, Int>,
|
||||||
|
) {
|
||||||
|
asmChunk.assembly.lineSequence().forEach {
|
||||||
|
val parsed = parseIRCodeLine(it.trim(), program.size, placeholders)
|
||||||
|
if(parsed is IRInstruction)
|
||||||
|
program += parsed
|
||||||
|
else if(parsed is IRCodeLabel)
|
||||||
|
symbolAddresses[parsed.name] = program.size
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
37
virtualmachine/src/prog8/vm/VmVariableAllocator.kt
Normal file
37
virtualmachine/src/prog8/vm/VmVariableAllocator.kt
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
package prog8.vm
|
||||||
|
|
||||||
|
import prog8.code.core.*
|
||||||
|
import prog8.intermediate.IRSymbolTable
|
||||||
|
|
||||||
|
internal class VmVariableAllocator(val st: IRSymbolTable, val encoding: IStringEncoding, memsizer: IMemSizer) {
|
||||||
|
|
||||||
|
internal val allocations = mutableMapOf<String, Int>()
|
||||||
|
private var freeMemoryStart: Int
|
||||||
|
|
||||||
|
val freeMem: Int
|
||||||
|
get() = freeMemoryStart
|
||||||
|
|
||||||
|
|
||||||
|
init {
|
||||||
|
var nextLocation = 0
|
||||||
|
for (variable in st.allVariables()) {
|
||||||
|
val memsize =
|
||||||
|
when (variable.dt) {
|
||||||
|
DataType.STR -> variable.onetimeInitializationStringValue!!.first.length + 1 // include the zero byte
|
||||||
|
in NumericDatatypes -> memsizer.memorySize(variable.dt)
|
||||||
|
in ArrayDatatypes -> memsizer.memorySize(variable.dt, variable.length!!)
|
||||||
|
else -> throw InternalCompilerException("weird dt")
|
||||||
|
}
|
||||||
|
|
||||||
|
allocations[variable.name] = nextLocation
|
||||||
|
nextLocation += memsize
|
||||||
|
}
|
||||||
|
for(slab in st.allMemorySlabs()) {
|
||||||
|
// we ignore the alignment for the VM.
|
||||||
|
allocations[slab.name] = nextLocation
|
||||||
|
nextLocation += slab.size.toInt()
|
||||||
|
}
|
||||||
|
|
||||||
|
freeMemoryStart = nextLocation
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package prog8.codegen.virtual
|
package prog8.vm.codegen
|
||||||
|
|
||||||
import prog8.code.SymbolTable
|
import prog8.code.SymbolTable
|
||||||
import prog8.code.ast.PtProgram
|
import prog8.code.ast.PtProgram
|
||||||
@ -9,7 +9,8 @@ import prog8.code.core.IErrorReporter
|
|||||||
import prog8.codegen.intermediate.IRCodeGen
|
import prog8.codegen.intermediate.IRCodeGen
|
||||||
import prog8.intermediate.IRFileReader
|
import prog8.intermediate.IRFileReader
|
||||||
import prog8.intermediate.IRFileWriter
|
import prog8.intermediate.IRFileWriter
|
||||||
import kotlin.io.path.Path
|
import prog8.intermediate.IRProgram
|
||||||
|
import java.nio.file.Path
|
||||||
|
|
||||||
class VmCodeGen(private val program: PtProgram,
|
class VmCodeGen(private val program: PtProgram,
|
||||||
private val symbolTable: SymbolTable,
|
private val symbolTable: SymbolTable,
|
||||||
@ -21,20 +22,24 @@ class VmCodeGen(private val program: PtProgram,
|
|||||||
val irCodeGen = IRCodeGen(program, symbolTable, options, errors)
|
val irCodeGen = IRCodeGen(program, symbolTable, options, errors)
|
||||||
val irProgram = irCodeGen.generate()
|
val irProgram = irCodeGen.generate()
|
||||||
|
|
||||||
return if(options.keepIR) {
|
// no need to check options.keepIR, as the VM file format *is* the IR file.
|
||||||
//create IR file on disk and read it back.
|
return VmAssemblyProgram(irProgram.name, irProgram)
|
||||||
IRFileWriter(irProgram).writeFile()
|
|
||||||
val irProgram2 = IRFileReader(options.outputDir, irProgram.name).readFile()
|
|
||||||
VmAssemblyProgram(irProgram2.name, irProgram2)
|
|
||||||
} else {
|
|
||||||
VmAssemblyProgram(irProgram.name, irProgram)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun compileIR(listingFilename: String): IAssemblyProgram {
|
fun compileIR(irFile: Path): IAssemblyProgram {
|
||||||
val irProgram = IRFileReader(Path(""), listingFilename).readFile()
|
val irProgram = IRFileReader().read(irFile)
|
||||||
return VmAssemblyProgram(irProgram.name, irProgram)
|
return VmAssemblyProgram(irProgram.name, irProgram)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
internal class VmAssemblyProgram(override val name: String, private val irProgram: IRProgram): IAssemblyProgram {
|
||||||
|
|
||||||
|
override fun assemble(options: CompilationOptions): Boolean {
|
||||||
|
// the VM reads the IR file from disk.
|
||||||
|
IRFileWriter(irProgram, null).write()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
@ -1,17 +1,32 @@
|
|||||||
|
import io.kotest.assertions.throwables.shouldThrowWithMessage
|
||||||
import io.kotest.core.spec.style.FunSpec
|
import io.kotest.core.spec.style.FunSpec
|
||||||
import io.kotest.matchers.collections.shouldBeEmpty
|
import io.kotest.matchers.collections.shouldBeEmpty
|
||||||
import io.kotest.matchers.shouldBe
|
import io.kotest.matchers.shouldBe
|
||||||
import prog8.intermediate.Instruction
|
import prog8.code.core.*
|
||||||
import prog8.intermediate.Opcode
|
import prog8.code.target.VMTarget
|
||||||
import prog8.intermediate.VmDataType
|
import prog8.intermediate.*
|
||||||
import prog8.vm.Memory
|
|
||||||
import prog8.vm.VirtualMachine
|
import prog8.vm.VirtualMachine
|
||||||
import prog8.vm.VmRunner
|
import prog8.vm.VmRunner
|
||||||
|
|
||||||
class TestVm: FunSpec( {
|
class TestVm: FunSpec( {
|
||||||
|
|
||||||
|
fun getTestOptions(): CompilationOptions {
|
||||||
|
val target = VMTarget()
|
||||||
|
return CompilationOptions(
|
||||||
|
OutputType.RAW,
|
||||||
|
CbmPrgLauncherType.NONE,
|
||||||
|
ZeropageType.DONTUSE,
|
||||||
|
zpReserved = emptyList(),
|
||||||
|
floats = true,
|
||||||
|
noSysInit = false,
|
||||||
|
compTarget = target,
|
||||||
|
loadAddress = target.machine.PROGRAM_LOAD_ADDRESS
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
test("vm execution: empty program") {
|
test("vm execution: empty program") {
|
||||||
val memory = Memory()
|
val program = IRProgram("test", IRSymbolTable(null), getTestOptions(), VMTarget())
|
||||||
val vm = VirtualMachine(memory, emptyList(), 0xff00)
|
val vm = VirtualMachine(program)
|
||||||
vm.callStack.shouldBeEmpty()
|
vm.callStack.shouldBeEmpty()
|
||||||
vm.valueStack.shouldBeEmpty()
|
vm.valueStack.shouldBeEmpty()
|
||||||
vm.pc shouldBe 0
|
vm.pc shouldBe 0
|
||||||
@ -24,29 +39,81 @@ class TestVm: FunSpec( {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test("vm execution: modify memory") {
|
test("vm execution: modify memory") {
|
||||||
val memory = Memory()
|
val program = IRProgram("test", IRSymbolTable(null), getTestOptions(), VMTarget())
|
||||||
val program = listOf(
|
val block = IRBlock("testmain", null, IRBlock.BlockAlignment.NONE, Position.DUMMY)
|
||||||
Instruction(Opcode.LOAD, VmDataType.WORD, reg1=1, value=12345),
|
val startSub = IRSubroutine("testmain.testsub", emptyList(), null, Position.DUMMY)
|
||||||
Instruction(Opcode.STOREM, VmDataType.WORD, reg1=1, value=1000),
|
val code = IRCodeChunk(Position.DUMMY)
|
||||||
Instruction(Opcode.RETURN)
|
code += IRInstruction(Opcode.NOP)
|
||||||
)
|
code += IRInstruction(Opcode.LOAD, VmDataType.WORD, reg1=1, value=12345)
|
||||||
val vm = VirtualMachine(memory, program, 0xff00)
|
code += IRInstruction(Opcode.STOREM, VmDataType.WORD, reg1=1, value=1000)
|
||||||
|
code += IRInstruction(Opcode.RETURN)
|
||||||
|
startSub += code
|
||||||
|
block += startSub
|
||||||
|
program.addBlock(block)
|
||||||
|
val vm = VirtualMachine(program)
|
||||||
|
|
||||||
memory.getUW(1000) shouldBe 0u
|
vm.memory.getUW(1000) shouldBe 0u
|
||||||
vm.callStack.shouldBeEmpty()
|
vm.callStack.shouldBeEmpty()
|
||||||
vm.valueStack.shouldBeEmpty()
|
vm.valueStack.shouldBeEmpty()
|
||||||
vm.pc shouldBe 0
|
vm.pc shouldBe 0
|
||||||
vm.stepCount shouldBe 0
|
vm.stepCount shouldBe 0
|
||||||
vm.run()
|
vm.run()
|
||||||
memory.getUW(1000) shouldBe 12345u
|
vm.memory.getUW(1000) shouldBe 12345u
|
||||||
vm.callStack.shouldBeEmpty()
|
vm.callStack.shouldBeEmpty()
|
||||||
vm.valueStack.shouldBeEmpty()
|
vm.valueStack.shouldBeEmpty()
|
||||||
vm.pc shouldBe 2
|
vm.pc shouldBe code.lines.size-1
|
||||||
vm.stepCount shouldBe 3
|
vm.stepCount shouldBe code.lines.size
|
||||||
|
}
|
||||||
|
|
||||||
|
test("vm asmsub not supported") {
|
||||||
|
val program = IRProgram("test", IRSymbolTable(null), getTestOptions(), VMTarget())
|
||||||
|
val block = IRBlock("testmain", null, IRBlock.BlockAlignment.NONE, Position.DUMMY)
|
||||||
|
val startSub = IRSubroutine("testmain.testsub", emptyList(), null, Position.DUMMY)
|
||||||
|
val code = IRCodeChunk(Position.DUMMY)
|
||||||
|
code += IRInstruction(Opcode.BINARYDATA, binaryData = listOf(1u,2u,3u))
|
||||||
|
code += IRInstruction(Opcode.RETURN)
|
||||||
|
startSub += code
|
||||||
|
block += startSub
|
||||||
|
program.addBlock(block)
|
||||||
|
val vm = VirtualMachine(program)
|
||||||
|
shouldThrowWithMessage<NotImplementedError>("An operation is not implemented: BINARYDATA not yet supported in VM") {
|
||||||
|
vm.run()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test("vm asmbinary not supported") {
|
||||||
|
val program = IRProgram("test", IRSymbolTable(null), getTestOptions(), VMTarget())
|
||||||
|
val block = IRBlock("main", null, IRBlock.BlockAlignment.NONE, Position.DUMMY)
|
||||||
|
val startSub = IRAsmSubroutine("main.asmstart", Position.DUMMY, 0x2000u, emptySet(), emptyList(), emptyList(), "inlined asm here")
|
||||||
|
block += startSub
|
||||||
|
program.addBlock(block)
|
||||||
|
shouldThrowWithMessage<IRParseException>("vm currently does not support asmsubs: main.asmstart") {
|
||||||
|
VirtualMachine(program)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
test("vmrunner") {
|
test("vmrunner") {
|
||||||
val runner = VmRunner()
|
val runner = VmRunner()
|
||||||
runner.runProgram(";comment\n------PROGRAM------\n;comment\n")
|
val irSource="""<PROGRAM NAME=test>
|
||||||
|
<OPTIONS>
|
||||||
|
</OPTIONS>
|
||||||
|
|
||||||
|
<VARIABLES>
|
||||||
|
</VARIABLES>
|
||||||
|
|
||||||
|
<MEMORYMAPPEDVARIABLES>
|
||||||
|
</MEMORYMAPPEDVARIABLES>
|
||||||
|
|
||||||
|
<MEMORYSLABS>
|
||||||
|
</MEMORYSLABS>
|
||||||
|
|
||||||
|
<INITGLOBALS>
|
||||||
|
</INITGLOBALS>
|
||||||
|
|
||||||
|
<BLOCK NAME=main ADDRESS=null ALIGN=NONE POS=[unittest: line 42 col 1-9]>
|
||||||
|
</BLOCK>
|
||||||
|
</PROGRAM>
|
||||||
|
"""
|
||||||
|
runner.runProgram(irSource)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -14,5 +14,6 @@
|
|||||||
<orderEntry type="library" name="io.kotest.runner.junit5.jvm" level="project" />
|
<orderEntry type="library" name="io.kotest.runner.junit5.jvm" level="project" />
|
||||||
<orderEntry type="module" module-name="codeCore" />
|
<orderEntry type="module" module-name="codeCore" />
|
||||||
<orderEntry type="module" module-name="intermediate" />
|
<orderEntry type="module" module-name="intermediate" />
|
||||||
|
<orderEntry type="module" module-name="codeGenIntermediate" />
|
||||||
</component>
|
</component>
|
||||||
</module>
|
</module>
|
Reference in New Issue
Block a user