mirror of
https://github.com/irmen/prog8.git
synced 2025-01-27 10:31:40 +00:00
more asm
This commit is contained in:
parent
85f6c5350c
commit
263b197fec
@ -11,43 +11,44 @@ sub start() {
|
||||
memory byte mb = $c000
|
||||
memory word mw = $c002
|
||||
|
||||
byte b
|
||||
|
||||
byte b = -100
|
||||
ubyte ub = $c4
|
||||
ubyte ub2 = $c4
|
||||
uword uw = $c500
|
||||
uword uw2 = $c502
|
||||
word ww
|
||||
word ww = -30000
|
||||
|
||||
float f1 = 1.23456
|
||||
float f2 = -999.999e22
|
||||
float f3 = -999.999e22
|
||||
float f4 = -999.999e22
|
||||
|
||||
mub=5
|
||||
muw=4444
|
||||
mb=-100
|
||||
mw=-23333
|
||||
str s1 = "hallo"
|
||||
str_p s2 = "hallo p"
|
||||
str_s s3 = "hallo s"
|
||||
str_ps s4 = "hallo ps"
|
||||
|
||||
|
||||
; b++
|
||||
; A++
|
||||
; XY++
|
||||
; mub++
|
||||
; ub++
|
||||
; uw++
|
||||
; ww++
|
||||
; mb++
|
||||
; mw++
|
||||
;
|
||||
; b--
|
||||
; A--
|
||||
; XY--
|
||||
; mub--
|
||||
; ub--
|
||||
; uw--
|
||||
; ww--
|
||||
; mb--
|
||||
; mw--
|
||||
byte[4] array1 = -99
|
||||
ubyte[4] array2 = 244
|
||||
word[4] array3 = -999
|
||||
uword[4] array4 = 44444
|
||||
float[4] array5 = [11.11, 22.22, 33.33, 44.44]
|
||||
byte[3,7] matrix1 = [1,-2,3,-4,5,-6,1,-2,3,-4,5,-6,1,-2,3,-4,5,-6,22,33,44]
|
||||
ubyte[3,7] matrix2 = [11,22,33,44,55,66, 11,22,33,44,55,66, 11,22,33,44,55,66, 55,66,77]
|
||||
|
||||
|
||||
return
|
||||
|
||||
sub nested () {
|
||||
byte b
|
||||
uword uw
|
||||
}
|
||||
}
|
||||
|
||||
sub second() {
|
||||
byte b
|
||||
uword uw
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -106,7 +106,7 @@ fun main(args: Array<String>) {
|
||||
stackvmFile.close()
|
||||
println("StackVM program code written to '$stackVmFilename'")
|
||||
|
||||
val assembly = AsmGen(compilerOptions).compileToAssembly(intermediate)
|
||||
val assembly = AsmGen(compilerOptions, intermediate, heap).compileToAssembly()
|
||||
assembly.assemble(compilerOptions)
|
||||
|
||||
val endTime = System.currentTimeMillis()
|
||||
|
@ -866,20 +866,24 @@ class AstChecker(private val namespace: INameScope,
|
||||
}
|
||||
DataType.MATRIX_UB, DataType.MATRIX_B -> {
|
||||
// value can only be a single byte, or a byte array (which represents the matrix)
|
||||
if(value.type==targetDt) {
|
||||
if(value.type==targetDt ||
|
||||
(targetDt==DataType.MATRIX_UB && value.type==DataType.ARRAY_UB) ||
|
||||
(targetDt==DataType.MATRIX_B && value.type==DataType.ARRAY_B)) {
|
||||
val arraySpecSize = arrayspec.size()
|
||||
if(arraySpecSize!=null && arraySpecSize>0) {
|
||||
val constX = arrayspec.x.constValue(namespace, heap)
|
||||
val constY = arrayspec.y!!.constValue(namespace, heap)
|
||||
if (constX?.asIntegerValue == null || constY?.asIntegerValue == null)
|
||||
val constY = arrayspec.y?.constValue(namespace, heap)
|
||||
if (constX?.asIntegerValue == null || (constY!=null && constY?.asIntegerValue == null))
|
||||
return err("matrix size specifiers must be constant integer values")
|
||||
val matrix = heap.get(value.heapId!!).array!!
|
||||
val expectedSize = constX.asIntegerValue * constY.asIntegerValue
|
||||
val expectedSize =
|
||||
if(constY==null) constX.asIntegerValue else constX.asIntegerValue * constY.asIntegerValue!!
|
||||
if (matrix.size != expectedSize)
|
||||
return err("initializer matrix size mismatch (expecting $expectedSize, got ${matrix.size} elements)")
|
||||
return true
|
||||
}
|
||||
}
|
||||
return err("invalid matrix initialization value $value")
|
||||
return err("invalid matrix initialization value of type ${value.type} - expecting byte array")
|
||||
}
|
||||
}
|
||||
return true
|
||||
|
@ -1111,6 +1111,7 @@ private class StatementTranslator(private val prog: IntermediateProgram,
|
||||
private fun translate(stmt: VariableInitializationAssignment) {
|
||||
// this is an assignment to initialize a variable's value in the scope.
|
||||
// the compiler can perhaps optimize this phase.
|
||||
// todo: optimize variable init by keeping track of the block of init values so it can be copied as a whole
|
||||
translate(stmt as Assignment)
|
||||
}
|
||||
|
||||
|
@ -8,11 +8,13 @@ import java.io.PrintStream
|
||||
|
||||
class IntermediateProgram(val name: String, var loadAddress: Int, val heap: HeapValues) {
|
||||
|
||||
class ProgramBlock(val scopedname: String, val shortname: String, var address: Int?) {
|
||||
val instructions = mutableListOf<Instruction>()
|
||||
val variables = mutableMapOf<String, Value>()
|
||||
val labels = mutableMapOf<String, Instruction>()
|
||||
|
||||
class ProgramBlock(val scopedname: String,
|
||||
val shortname: String,
|
||||
var address: Int?,
|
||||
val instructions: MutableList<Instruction> = mutableListOf(),
|
||||
val variables: MutableMap<String, Value> = mutableMapOf(),
|
||||
val labels: MutableMap<String, Instruction> = mutableMapOf())
|
||||
{
|
||||
val numVariables: Int
|
||||
get() { return variables.size }
|
||||
val numInstructions: Int
|
||||
|
@ -1,32 +1,92 @@
|
||||
package prog8.compiler.target.c64
|
||||
|
||||
import prog8.ast.DataType
|
||||
import prog8.compiler.*
|
||||
import prog8.compiler.intermediate.Instruction
|
||||
import prog8.compiler.intermediate.IntermediateProgram
|
||||
import prog8.compiler.intermediate.LabelInstr
|
||||
import prog8.compiler.intermediate.Opcode
|
||||
import prog8.compiler.intermediate.*
|
||||
import java.io.File
|
||||
import java.io.PrintWriter
|
||||
import java.util.*
|
||||
import kotlin.math.abs
|
||||
|
||||
|
||||
class AssemblyError(msg: String) : RuntimeException(msg)
|
||||
|
||||
|
||||
class AsmGen(val options: CompilationOptions) {
|
||||
fun compileToAssembly(program: IntermediateProgram): AssemblyProgram {
|
||||
class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, val heap: HeapValues) {
|
||||
private val globalFloatConsts = mutableMapOf<Double, String>()
|
||||
private lateinit var output: PrintWriter
|
||||
|
||||
init {
|
||||
// because 64tass understands scoped names via .proc / .block,
|
||||
// we'll strip the block prefix from all scoped names in the program.
|
||||
val newblocks = mutableListOf<IntermediateProgram.ProgramBlock>()
|
||||
for(block in program.blocks) {
|
||||
val newvars = block.variables.map { symname(it.key, block) to it.value }.toMap().toMutableMap()
|
||||
val newlabels = block.labels.map { symname(it.key, block) to it.value}.toMap().toMutableMap()
|
||||
val newinstructions = block.instructions.asSequence().map {
|
||||
it as? LabelInstr ?: Instruction(it.opcode, it.arg,
|
||||
if(it.callLabel!=null) symname(it.callLabel, block) else null,
|
||||
if(it.callLabel2!=null) symname(it.callLabel2, block) else null)
|
||||
}.toMutableList()
|
||||
newblocks.add(IntermediateProgram.ProgramBlock(
|
||||
block.scopedname,
|
||||
block.shortname,
|
||||
block.address,
|
||||
newinstructions,
|
||||
newvars,
|
||||
newlabels))
|
||||
}
|
||||
program.blocks.clear()
|
||||
program.blocks.addAll(newblocks)
|
||||
|
||||
// make a list of all const floats that are used
|
||||
for(block in program.blocks) {
|
||||
for(ins in block.instructions.filter{it.arg?.type==DataType.FLOAT}) {
|
||||
val float = ins.arg!!.numericValue().toDouble()
|
||||
if(float !in globalFloatConsts)
|
||||
globalFloatConsts[float] = "prog8_const_float_${globalFloatConsts.size}"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun out(str: String) = output.println(str)
|
||||
|
||||
fun compileToAssembly(): AssemblyProgram {
|
||||
println("\nGenerating assembly code from intermediate code... ")
|
||||
|
||||
// todo generate 6502 assembly
|
||||
val out = File("${program.name}.asm").printWriter()
|
||||
out.use {
|
||||
header(out::println, program)
|
||||
output = File("${program.name}.asm").printWriter()
|
||||
output.use {
|
||||
header()
|
||||
for(block in program.blocks)
|
||||
block2asm(out::println, block)
|
||||
block2asm(block)
|
||||
}
|
||||
|
||||
return AssemblyProgram(program.name)
|
||||
}
|
||||
|
||||
private fun header(out: (String)->Unit, program: IntermediateProgram) {
|
||||
private fun symname(scoped: String, block: IntermediateProgram.ProgramBlock) =
|
||||
if (scoped.startsWith("${block.shortname}.")) scoped.substring(block.shortname.length+1) else scoped
|
||||
|
||||
private fun copyFloat(source: String, target: String) {
|
||||
// todo: optimize this to bulk copy all floats in the same loop
|
||||
out("\tldy #4")
|
||||
out("-\tlda $source,y")
|
||||
out("\tsta $target,y")
|
||||
out("\tdey")
|
||||
out("\tbpl -")
|
||||
}
|
||||
|
||||
private fun makeFloatFill(flt: Mflpt5): String {
|
||||
val b0 = "$"+flt.b0.toString(16).padStart(2, '0')
|
||||
val b1 = "$"+flt.b1.toString(16).padStart(2, '0')
|
||||
val b2 = "$"+flt.b2.toString(16).padStart(2, '0')
|
||||
val b3 = "$"+flt.b3.toString(16).padStart(2, '0')
|
||||
val b4 = "$"+flt.b4.toString(16).padStart(2, '0')
|
||||
return "$b0, $b1, $b2, $b3, $b4"
|
||||
}
|
||||
|
||||
private fun header() {
|
||||
val ourName = this.javaClass.name
|
||||
out("; 6502 assembly code for '${program.name}'")
|
||||
out("; generated by $ourName on ${Date()}")
|
||||
@ -59,66 +119,187 @@ class AsmGen(val options: CompilationOptions) {
|
||||
}
|
||||
}
|
||||
|
||||
// call the init methods of each block and then jump to the main.start entrypoint
|
||||
out("\t; initialize all blocks(reset vars)")
|
||||
// todo zeropage if it's there
|
||||
for(block in program.blocks)
|
||||
out("\tjsr ${block.scopedname}._prog8_init")
|
||||
out("\tlda #0")
|
||||
out("\ttay")
|
||||
out("\ttax")
|
||||
out("\tdex\t; init estack pointer to \$ff")
|
||||
out("\tclc")
|
||||
out("\tjmp main.start\t; jump to program entrypoint")
|
||||
out("")
|
||||
|
||||
// the global list of all floating point constants for the whole program
|
||||
for(flt in globalFloatConsts) {
|
||||
val floatFill = makeFloatFill(Mflpt5.fromNumber(flt.key))
|
||||
out("${flt.value}\t.byte $floatFill ; float ${flt.key}")
|
||||
}
|
||||
}
|
||||
|
||||
private fun block2asm(out: (String)->Unit, block: IntermediateProgram.ProgramBlock) {
|
||||
private fun block2asm(block: IntermediateProgram.ProgramBlock) {
|
||||
out("\n; ---- block: '${block.shortname}' ----")
|
||||
if(block.address!=null) {
|
||||
out(".cerror * > ${block.address?.toHex()}, 'block address overlaps by ', *-${block.address?.toHex()},' bytes'")
|
||||
out("* = ${block.address?.toHex()}")
|
||||
}
|
||||
out("${block.shortname}\t.proc\n")
|
||||
|
||||
// init the variables
|
||||
out("_prog8_init\t; (re)set vars to initial values")
|
||||
// todo init vars
|
||||
out("\n; variables")
|
||||
vardecls2asm(block)
|
||||
out("")
|
||||
|
||||
var skip = 0
|
||||
for(ins in block.instructions.withIndex()) {
|
||||
if(skip==0)
|
||||
skip = ins2asm(out, ins.index, ins.value, block)
|
||||
skip = instr2asm(ins.index, ins.value, block)
|
||||
else
|
||||
skip--
|
||||
}
|
||||
out("\n\t.pend\n")
|
||||
}
|
||||
|
||||
private fun vardecls2asm(block: IntermediateProgram.ProgramBlock) {
|
||||
val sortedVars = block.variables.toList().sortedBy { it.second.type }
|
||||
for (v in sortedVars) {
|
||||
when (v.second.type) {
|
||||
DataType.UBYTE -> out("${v.first}\t.byte 0")
|
||||
DataType.BYTE -> out("${v.first}\t.char 0")
|
||||
DataType.UWORD -> out("${v.first}\t.word 0")
|
||||
DataType.WORD -> out("${v.first}\t.sint 0")
|
||||
DataType.FLOAT -> out("${v.first}\t.fill 5 ; float")
|
||||
DataType.STR,
|
||||
DataType.STR_P,
|
||||
DataType.STR_S,
|
||||
DataType.STR_PS -> {
|
||||
val rawStr = heap.get(v.second.heapId).str!!
|
||||
val bytes = encodeStr(rawStr, v.second.type).map { "$" + it.toString(16).padStart(2, '0') }
|
||||
out("${v.first}\t; ${v.second.type} \"$rawStr\"")
|
||||
for (chunk in bytes.chunked(16))
|
||||
out("\t.byte " + chunk.joinToString())
|
||||
}
|
||||
DataType.ARRAY_UB, DataType.MATRIX_UB -> {
|
||||
// unsigned integer byte array
|
||||
val data = makeArrayFillDataUnsigned(v.second)
|
||||
if (data.size <= 16)
|
||||
out("${v.first}\t.byte ${data.joinToString()}")
|
||||
else {
|
||||
out(v.first)
|
||||
for (chunk in data.chunked(16))
|
||||
out("\t.byte " + chunk.joinToString())
|
||||
}
|
||||
}
|
||||
DataType.ARRAY_B, DataType.MATRIX_B -> {
|
||||
// signed integer byte array
|
||||
val data = makeArrayFillDataSigned(v.second)
|
||||
if (data.size <= 16)
|
||||
out("${v.first}\t.char ${data.joinToString()}")
|
||||
else {
|
||||
out(v.first)
|
||||
for (chunk in data.chunked(16))
|
||||
out("\t.char " + chunk.joinToString())
|
||||
}
|
||||
}
|
||||
DataType.ARRAY_UW -> {
|
||||
// unsigned word array
|
||||
val data = makeArrayFillDataUnsigned(v.second)
|
||||
if (data.size <= 16)
|
||||
out("${v.first}\t.word ${data.joinToString()}")
|
||||
else {
|
||||
out(v.first)
|
||||
for (chunk in data.chunked(16))
|
||||
out("\t.word " + chunk.joinToString())
|
||||
}
|
||||
}
|
||||
DataType.ARRAY_W -> {
|
||||
// signed word array
|
||||
val data = makeArrayFillDataSigned(v.second)
|
||||
if (data.size <= 16)
|
||||
out("${v.first}\t.sint ${data.joinToString()}")
|
||||
else {
|
||||
out(v.first)
|
||||
for (chunk in data.chunked(16))
|
||||
out("\t.sint " + chunk.joinToString())
|
||||
}
|
||||
}
|
||||
DataType.ARRAY_F -> {
|
||||
// float array
|
||||
val array = heap.get(v.second.heapId).doubleArray!!
|
||||
val floatFills = array.map { makeFloatFill(Mflpt5.fromNumber(it)) }
|
||||
out(v.first)
|
||||
for(f in array.zip(floatFills))
|
||||
out("\t.byte ${f.second} ; float ${f.first}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun encodeStr(str: String, dt: DataType): List<Short> {
|
||||
when(dt) {
|
||||
DataType.STR -> {
|
||||
val bytes = Petscii.encodePetscii(str, true)
|
||||
return bytes.plus(0)
|
||||
}
|
||||
DataType.STR_P -> {
|
||||
val result = listOf(str.length.toShort())
|
||||
val bytes = Petscii.encodePetscii(str, true)
|
||||
return result.plus(bytes)
|
||||
}
|
||||
DataType.STR_S -> {
|
||||
val bytes = Petscii.encodeScreencode(str, true)
|
||||
return bytes.plus(0)
|
||||
}
|
||||
DataType.STR_PS -> {
|
||||
val result = listOf(str.length.toShort())
|
||||
val bytes = Petscii.encodeScreencode(str, true)
|
||||
return result.plus(bytes)
|
||||
}
|
||||
else -> throw AssemblyError("invalid str type")
|
||||
}
|
||||
}
|
||||
|
||||
private fun makeArrayFillDataUnsigned(value: Value): List<String> {
|
||||
val array = heap.get(value.heapId).array!!
|
||||
return if (value.type == DataType.ARRAY_UB || value.type == DataType.ARRAY_UW || value.type == DataType.MATRIX_UB)
|
||||
array.map { "$"+it.toString(16).padStart(2, '0') }
|
||||
else
|
||||
throw AssemblyError("invalid array type")
|
||||
}
|
||||
|
||||
private fun makeArrayFillDataSigned(value: Value): List<String> {
|
||||
val array = heap.get(value.heapId).array!!
|
||||
return if (value.type == DataType.ARRAY_B || value.type == DataType.ARRAY_W || value.type == DataType.MATRIX_B) {
|
||||
array.map {
|
||||
if(it>=0)
|
||||
"$"+it.toString(16).padStart(2, '0')
|
||||
else
|
||||
"-$"+abs(it).toString(16).padStart(2, '0')
|
||||
}
|
||||
}
|
||||
else throw AssemblyError("invalid array type")
|
||||
}
|
||||
|
||||
private val registerStrings = setOf("A", "X", "Y", "AX", "AY", "XY")
|
||||
|
||||
|
||||
// note: to put stuff on the stack, we use Absolute,X addressing mode which is 3 bytes / 4 cycles
|
||||
// possible space optimization is to use zeropage (indirect),Y which is 2 bytes, but 5 cycles
|
||||
|
||||
private fun pushByte(byte: Int, out: (String) -> Unit) {
|
||||
private fun pushByte(byte: Int) {
|
||||
out("\tlda #${byte.toHex()}")
|
||||
out("\tsta ${ESTACK_LO.toHex()},x")
|
||||
out("\tdex")
|
||||
}
|
||||
|
||||
private fun pushMemByte(address: Int, out: (String) -> Unit) {
|
||||
private fun pushMemByte(address: Int) {
|
||||
out("\tlda ${address.toHex()}")
|
||||
out("\tsta ${ESTACK_LO.toHex()},x")
|
||||
out("\tdex")
|
||||
}
|
||||
|
||||
private fun pushVarByte(name: String, out: (String) -> Unit) {
|
||||
private fun pushVarByte(name: String) {
|
||||
out("\tlda $name")
|
||||
out("\tsta ${ESTACK_LO.toHex()},x")
|
||||
out("\tdex")
|
||||
}
|
||||
|
||||
private fun pushWord(word: Int, out: (String) -> Unit) {
|
||||
private fun pushWord(word: Int) {
|
||||
out("\tlda #<${word.toHex()}")
|
||||
out("\tsta ${ESTACK_LO.toHex()},x")
|
||||
out("\tlda #>${word.toHex()}")
|
||||
@ -126,7 +307,7 @@ class AsmGen(val options: CompilationOptions) {
|
||||
out("\tdex")
|
||||
}
|
||||
|
||||
private fun pushMemWord(address: Int, out: (String) -> Unit) {
|
||||
private fun pushMemWord(address: Int) {
|
||||
out("\tlda ${address.toHex()}")
|
||||
out("\tsta ${ESTACK_LO.toHex()},x")
|
||||
out("\tlda ${(address+1).toHex()}")
|
||||
@ -134,7 +315,7 @@ class AsmGen(val options: CompilationOptions) {
|
||||
out("\tdex")
|
||||
}
|
||||
|
||||
private fun pushVarWord(name: String, out: (String) -> Unit) {
|
||||
private fun pushVarWord(name: String) {
|
||||
out("\tlda $name")
|
||||
out("\tsta ${ESTACK_LO.toHex()},x")
|
||||
out("\tlda $name+1")
|
||||
@ -142,18 +323,25 @@ class AsmGen(val options: CompilationOptions) {
|
||||
out("\tdex")
|
||||
}
|
||||
|
||||
private fun popByteA(out: (String) -> Unit) {
|
||||
out("\tinx")
|
||||
out("\tlda ${ESTACK_LO.toHex()},x")
|
||||
private fun pushFloat(label: String) {
|
||||
// todo this is too large for inline, make a subroutine
|
||||
out("\tlda $label")
|
||||
out("\tsta ${ESTACK_LO.toHex()},x")
|
||||
out("\tlda $label+1")
|
||||
out("\tsta ${ESTACK_HI.toHex()},x")
|
||||
out("\tdex")
|
||||
out("\tlda $label+2")
|
||||
out("\tsta ${ESTACK_LO.toHex()},x")
|
||||
out("\tlda $label+3")
|
||||
out("\tsta ${ESTACK_HI.toHex()},x")
|
||||
out("\tdex")
|
||||
out("\tlda $label+4")
|
||||
out("\tsta ${ESTACK_LO.toHex()},x")
|
||||
// 6th byte is not used for floats
|
||||
out("\tdex")
|
||||
}
|
||||
|
||||
private fun popWordAY(out: (String) -> Unit) {
|
||||
out("\tinx")
|
||||
out("\tlda ${ESTACK_LO.toHex()},x")
|
||||
out("\tldy ${ESTACK_HI.toHex()},x")
|
||||
}
|
||||
|
||||
private fun ins2asm(out: (String) -> Unit, insIdx: Int, ins: Instruction, block: IntermediateProgram.ProgramBlock): Int {
|
||||
private fun instr2asm(insIdx: Int, ins: Instruction, block: IntermediateProgram.ProgramBlock): Int {
|
||||
if(ins is LabelInstr) {
|
||||
if(ins.name==block.shortname)
|
||||
return 0
|
||||
@ -271,7 +459,7 @@ class AsmGen(val options: CompilationOptions) {
|
||||
return 1 // skip 1
|
||||
}
|
||||
// byte onto stack
|
||||
pushByte(ins.arg!!.integerValue(), out)
|
||||
pushByte(ins.arg!!.integerValue())
|
||||
}
|
||||
Opcode.PUSH_MEM_UB, Opcode.PUSH_MEM_B -> {
|
||||
val nextIns = block.getIns(insIdx+1)
|
||||
@ -293,7 +481,7 @@ class AsmGen(val options: CompilationOptions) {
|
||||
return 1 // skip 1
|
||||
}
|
||||
// byte from memory onto stack
|
||||
pushMemByte(ins.arg!!.integerValue(), out)
|
||||
pushMemByte(ins.arg!!.integerValue())
|
||||
}
|
||||
Opcode.PUSH_VAR_BYTE -> {
|
||||
val nextIns = block.getIns(insIdx+1)
|
||||
@ -307,7 +495,7 @@ class AsmGen(val options: CompilationOptions) {
|
||||
return 1 // skip 1
|
||||
}
|
||||
// byte from variable onto stack
|
||||
pushVarByte(ins.callLabel!!, out)
|
||||
pushVarByte(ins.callLabel!!)
|
||||
}
|
||||
Opcode.PUSH_WORD -> {
|
||||
val nextIns = block.getIns(insIdx+1)
|
||||
@ -337,7 +525,7 @@ class AsmGen(val options: CompilationOptions) {
|
||||
out("\tsta ${(nextIns.arg.integerValue()+1).toHex()}")
|
||||
return 1 // skip 1
|
||||
}
|
||||
pushWord(ins.arg!!.integerValue(), out)
|
||||
pushWord(ins.arg!!.integerValue())
|
||||
}
|
||||
Opcode.PUSH_MEM_UW, Opcode.PUSH_MEM_W -> {
|
||||
val nextIns = block.getIns(insIdx+1)
|
||||
@ -368,7 +556,7 @@ class AsmGen(val options: CompilationOptions) {
|
||||
return 1 // skip 1
|
||||
}
|
||||
// word from memory onto stack
|
||||
pushMemWord(ins.arg!!.integerValue(), out)
|
||||
pushMemWord(ins.arg!!.integerValue())
|
||||
}
|
||||
Opcode.PUSH_VAR_WORD -> {
|
||||
val nextIns = block.getIns(insIdx+1)
|
||||
@ -382,7 +570,7 @@ class AsmGen(val options: CompilationOptions) {
|
||||
return 1 // skip 1
|
||||
}
|
||||
// word from memory onto stack
|
||||
pushVarWord(ins.callLabel!!, out)
|
||||
pushVarWord(ins.callLabel!!)
|
||||
}
|
||||
Opcode.PUSH_FLOAT -> {
|
||||
val nextIns = block.getIns(insIdx+1)
|
||||
@ -390,7 +578,18 @@ class AsmGen(val options: CompilationOptions) {
|
||||
throw CompilerException("discard after push should have been removed")
|
||||
if(!options.floats)
|
||||
throw CompilerException("floats not enabled")
|
||||
TODO("push float")
|
||||
val float = ins.arg!!.numericValue().toDouble()
|
||||
val label = globalFloatConsts[float]!!
|
||||
if(nextIns.opcode==Opcode.POP_MEM_FLOAT) {
|
||||
// set a float in memory to a constant float value
|
||||
copyFloat(label, nextIns.arg!!.integerValue().toHex())
|
||||
return 1
|
||||
} else if(nextIns.opcode==Opcode.POP_VAR_FLOAT) {
|
||||
// set a variable to a constant float value
|
||||
copyFloat(label, nextIns.callLabel!!)
|
||||
return 1
|
||||
}
|
||||
pushFloat(label)
|
||||
}
|
||||
Opcode.PUSH_VAR_FLOAT -> {
|
||||
val nextIns = block.getIns(insIdx+1)
|
||||
@ -400,7 +599,11 @@ class AsmGen(val options: CompilationOptions) {
|
||||
throw CompilerException("push var+pop var should have been replaced by copy var")
|
||||
if(!options.floats)
|
||||
throw CompilerException("floats not enabled")
|
||||
TODO("push var float")
|
||||
if(nextIns.opcode==Opcode.POP_MEM_FLOAT) {
|
||||
copyFloat(ins.callLabel!!, nextIns.arg!!.integerValue().toHex()) // copy var float to memory
|
||||
return 1
|
||||
}
|
||||
pushFloat(ins.callLabel!!)
|
||||
}
|
||||
Opcode.PUSH_MEM_FLOAT -> {
|
||||
val nextIns = block.getIns(insIdx+1)
|
||||
@ -408,7 +611,15 @@ class AsmGen(val options: CompilationOptions) {
|
||||
throw CompilerException("discard after push should have been removed")
|
||||
if(!options.floats)
|
||||
throw CompilerException("floats not enabled")
|
||||
TODO("push mem float")
|
||||
if(nextIns.opcode==Opcode.POP_VAR_FLOAT) {
|
||||
copyFloat(ins.arg!!.integerValue().toHex(), nextIns.callLabel!!) // copy memory float to var
|
||||
return 1
|
||||
}
|
||||
if(nextIns.opcode==Opcode.POP_MEM_FLOAT) {
|
||||
copyFloat(ins.arg!!.integerValue().toHex(), nextIns.arg!!.integerValue().toHex()) // copy memory float to memory float
|
||||
return 1
|
||||
}
|
||||
pushFloat(ins.arg!!.integerValue().toHex())
|
||||
}
|
||||
else-> TODO("asm for $ins")
|
||||
// Opcode.POP_MEM_B -> TODO()
|
||||
|
Loading…
x
Reference in New Issue
Block a user