mirror of
https://github.com/irmen/prog8.git
synced 2025-02-19 11:31:07 +00:00
refactor
This commit is contained in:
parent
dff4518608
commit
b7d8f026f4
@ -2,6 +2,7 @@ package prog8
|
|||||||
|
|
||||||
import prog8.ast.*
|
import prog8.ast.*
|
||||||
import prog8.compiler.*
|
import prog8.compiler.*
|
||||||
|
import prog8.compiler.target.c64.AsmGen
|
||||||
import prog8.optimizing.constantFold
|
import prog8.optimizing.constantFold
|
||||||
import prog8.optimizing.optimizeStatements
|
import prog8.optimizing.optimizeStatements
|
||||||
import prog8.optimizing.simplifyExpressions
|
import prog8.optimizing.simplifyExpressions
|
||||||
@ -103,15 +104,13 @@ fun main(args: Array<String>) {
|
|||||||
stackvmFile.close()
|
stackvmFile.close()
|
||||||
println("StackVM program code written to '$stackVmFilename'")
|
println("StackVM program code written to '$stackVmFilename'")
|
||||||
|
|
||||||
// val assembly = stackvmProg.compileToAssembly()
|
val assembly = AsmGen(compilerOptions).compileToAssembly(intermediate)
|
||||||
//
|
assembly.assemble(compilerOptions)
|
||||||
// assembly.assemble(compilerOptions, "input", "output")
|
|
||||||
// val monitorfile = assembly.generateBreakpointList()
|
|
||||||
|
|
||||||
val endTime = System.currentTimeMillis()
|
val endTime = System.currentTimeMillis()
|
||||||
println("\nTotal compilation time: ${(endTime-startTime)/1000.0} sec.")
|
println("\nTotal compilation+assemble time: ${(endTime-startTime)/1000.0} sec.")
|
||||||
|
|
||||||
// // start the vice emulator
|
// // todo start the vice emulator
|
||||||
// val program = "foo"
|
// val program = "foo"
|
||||||
// val cmdline = listOf("x64", "-moncommands", monitorfile,
|
// val cmdline = listOf("x64", "-moncommands", monitorfile,
|
||||||
// "-autostartprgmode", "1", "-autostart-warp", "-autostart", program)
|
// "-autostartprgmode", "1", "-autostart-warp", "-autostart", program)
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
package prog8.compiler
|
package prog8.compiler
|
||||||
|
|
||||||
import prog8.ast.*
|
import prog8.ast.*
|
||||||
|
import prog8.compiler.intermediate.IntermediateProgram
|
||||||
|
import prog8.compiler.intermediate.Opcode
|
||||||
|
import prog8.compiler.intermediate.Value
|
||||||
import prog8.stackvm.*
|
import prog8.stackvm.*
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
@ -1394,7 +1397,7 @@ private class StatementTranslator(private val prog: IntermediateProgram,
|
|||||||
continueStmtLabelStack.push(continueLabel)
|
continueStmtLabelStack.push(continueLabel)
|
||||||
breakStmtLabelStack.push(breakLabel)
|
breakStmtLabelStack.push(breakLabel)
|
||||||
|
|
||||||
val zero = Value(if(numElements<=255) DataType.UBYTE else DataType.UWORD, 0)
|
val zero = Value(if (numElements <= 255) DataType.UBYTE else DataType.UWORD, 0)
|
||||||
prog.instr(opcodePush(zero.type), zero)
|
prog.instr(opcodePush(zero.type), zero)
|
||||||
prog.instr(opcodePopvar(zero.type), callLabel = indexVar)
|
prog.instr(opcodePopvar(zero.type), callLabel = indexVar)
|
||||||
prog.label(loopLabel)
|
prog.label(loopLabel)
|
||||||
@ -1473,7 +1476,7 @@ private class StatementTranslator(private val prog: IntermediateProgram,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: optimize edge cases if last value = 255 or 0 (for bytes) etc. to avoid PUSH_BYTE / SUB opcodes and make use of the wrapping around of the value.
|
// TODO: optimize edge cases if last value = 255 or 0 (for bytes) etc. to avoid PUSH_BYTE / SUB opcodes and make use of the wrapping around of the value.
|
||||||
prog.instr(opcodePush(varDt), Value(varDt, range.last+range.step))
|
prog.instr(opcodePush(varDt), Value(varDt, range.last + range.step))
|
||||||
prog.instr(opcodePushvar(varDt), callLabel = varname)
|
prog.instr(opcodePushvar(varDt), callLabel = varname)
|
||||||
prog.instr(opcodeSub(varDt))
|
prog.instr(opcodeSub(varDt))
|
||||||
prog.instr(Opcode.BNZ, callLabel = loopLabel)
|
prog.instr(Opcode.BNZ, callLabel = loopLabel)
|
||||||
|
39
compiler/src/prog8/compiler/intermediate/Instruction.kt
Normal file
39
compiler/src/prog8/compiler/intermediate/Instruction.kt
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
package prog8.compiler.intermediate
|
||||||
|
|
||||||
|
import prog8.stackvm.Syscall
|
||||||
|
|
||||||
|
open class Instruction(val opcode: Opcode,
|
||||||
|
val arg: Value? = null,
|
||||||
|
val callLabel: String? = null,
|
||||||
|
val callLabel2: String? = null)
|
||||||
|
{
|
||||||
|
lateinit var next: Instruction
|
||||||
|
var nextAlt: Instruction? = null
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
val argStr = arg?.toString() ?: ""
|
||||||
|
val result =
|
||||||
|
when {
|
||||||
|
opcode== Opcode.LINE -> "_line $callLabel"
|
||||||
|
opcode== Opcode.SYSCALL -> {
|
||||||
|
val syscall = Syscall.values().find { it.callNr==arg!!.numericValue() }
|
||||||
|
"syscall $syscall"
|
||||||
|
}
|
||||||
|
opcode in opcodesWithVarArgument -> {
|
||||||
|
// opcodes that manipulate a variable
|
||||||
|
"${opcode.toString().toLowerCase()} ${callLabel?:""} ${callLabel2?:""}".trimEnd()
|
||||||
|
}
|
||||||
|
callLabel==null -> "${opcode.toString().toLowerCase()} $argStr"
|
||||||
|
else -> "${opcode.toString().toLowerCase()} $callLabel $argStr"
|
||||||
|
}
|
||||||
|
.trimEnd()
|
||||||
|
|
||||||
|
return " $result"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class LabelInstr(val name: String) : Instruction(opcode = Opcode.NOP) {
|
||||||
|
override fun toString(): String {
|
||||||
|
return "\n$name:"
|
||||||
|
}
|
||||||
|
}
|
@ -1,10 +1,11 @@
|
|||||||
package prog8.compiler
|
package prog8.compiler.intermediate
|
||||||
|
|
||||||
import prog8.ast.DataType
|
import prog8.ast.DataType
|
||||||
import prog8.ast.LiteralValue
|
import prog8.ast.LiteralValue
|
||||||
import prog8.ast.Position
|
import prog8.ast.Position
|
||||||
import prog8.ast.VarDecl
|
import prog8.ast.VarDecl
|
||||||
import prog8.stackvm.*
|
import prog8.compiler.CompilerException
|
||||||
|
import prog8.compiler.HeapValues
|
||||||
import java.io.PrintStream
|
import java.io.PrintStream
|
||||||
|
|
||||||
|
|
241
compiler/src/prog8/compiler/intermediate/Opcode.kt
Normal file
241
compiler/src/prog8/compiler/intermediate/Opcode.kt
Normal file
@ -0,0 +1,241 @@
|
|||||||
|
package prog8.compiler.intermediate
|
||||||
|
|
||||||
|
enum class Opcode {
|
||||||
|
|
||||||
|
// pushing values on the (evaluation) stack
|
||||||
|
PUSH_BYTE, // push byte value
|
||||||
|
PUSH_WORD, // push word value (or 'address' of string / array / matrix)
|
||||||
|
PUSH_FLOAT, // push float value
|
||||||
|
PUSH_MEM_B, // push byte value from memory to stack
|
||||||
|
PUSH_MEM_UB, // push byte value from memory to stack
|
||||||
|
PUSH_MEM_W, // push word value from memory to stack
|
||||||
|
PUSH_MEM_UW, // push word value from memory to stack
|
||||||
|
PUSH_MEM_FLOAT, // push float value from memory to stack
|
||||||
|
PUSH_VAR_BYTE, // push byte variable (ubyte, byte)
|
||||||
|
PUSH_VAR_WORD, // push word variable (uword, word)
|
||||||
|
PUSH_VAR_FLOAT, // push float variable
|
||||||
|
|
||||||
|
// popping values off the (evaluation) stack, possibly storing them in another location
|
||||||
|
DISCARD_BYTE, // discard top byte value
|
||||||
|
DISCARD_WORD, // discard top word value
|
||||||
|
DISCARD_FLOAT, // discard top float value
|
||||||
|
POP_MEM_B, // pop byte value into destination memory address
|
||||||
|
POP_MEM_UB, // pop byte value into destination memory address
|
||||||
|
POP_MEM_W, // pop word value into destination memory address
|
||||||
|
POP_MEM_UW, // pop word value into destination memory address
|
||||||
|
POP_MEM_FLOAT, // pop float value into destination memory address
|
||||||
|
POP_VAR_BYTE, // pop byte value into variable (byte, ubyte)
|
||||||
|
POP_VAR_WORD, // pop word value into variable (word, uword)
|
||||||
|
POP_VAR_FLOAT, // pop float value into variable
|
||||||
|
|
||||||
|
// optimized copying of one var to another (replaces push+pop)
|
||||||
|
COPY_VAR_BYTE,
|
||||||
|
COPY_VAR_WORD,
|
||||||
|
COPY_VAR_FLOAT,
|
||||||
|
|
||||||
|
// numeric arithmetic
|
||||||
|
ADD_UB,
|
||||||
|
ADD_B,
|
||||||
|
ADD_UW,
|
||||||
|
ADD_W,
|
||||||
|
ADD_F,
|
||||||
|
SUB_UB,
|
||||||
|
SUB_B,
|
||||||
|
SUB_UW,
|
||||||
|
SUB_W,
|
||||||
|
SUB_F,
|
||||||
|
MUL_UB,
|
||||||
|
MUL_B,
|
||||||
|
MUL_UW,
|
||||||
|
MUL_W,
|
||||||
|
MUL_F,
|
||||||
|
DIV_UB,
|
||||||
|
DIV_B,
|
||||||
|
DIV_UW,
|
||||||
|
DIV_W,
|
||||||
|
DIV_F,
|
||||||
|
FLOORDIV_UB,
|
||||||
|
FLOORDIV_B,
|
||||||
|
FLOORDIV_UW,
|
||||||
|
FLOORDIV_W,
|
||||||
|
FLOORDIV_F,
|
||||||
|
REMAINDER_UB,
|
||||||
|
REMAINDER_B,
|
||||||
|
REMAINDER_UW,
|
||||||
|
REMAINDER_W,
|
||||||
|
REMAINDER_F,
|
||||||
|
POW_UB,
|
||||||
|
POW_B,
|
||||||
|
POW_UW,
|
||||||
|
POW_W,
|
||||||
|
POW_F,
|
||||||
|
NEG_B,
|
||||||
|
NEG_W,
|
||||||
|
NEG_F,
|
||||||
|
|
||||||
|
// bit shifts and bitwise arithmetic
|
||||||
|
SHL_BYTE,
|
||||||
|
SHL_WORD,
|
||||||
|
SHL_MEM_BYTE,
|
||||||
|
SHL_MEM_WORD,
|
||||||
|
SHL_VAR_BYTE,
|
||||||
|
SHL_VAR_WORD,
|
||||||
|
SHR_BYTE,
|
||||||
|
SHR_WORD,
|
||||||
|
SHR_MEM_BYTE,
|
||||||
|
SHR_MEM_WORD,
|
||||||
|
SHR_VAR_BYTE,
|
||||||
|
SHR_VAR_WORD,
|
||||||
|
ROL_BYTE,
|
||||||
|
ROL_WORD,
|
||||||
|
ROL_MEM_BYTE,
|
||||||
|
ROL_MEM_WORD,
|
||||||
|
ROL_VAR_BYTE,
|
||||||
|
ROL_VAR_WORD,
|
||||||
|
ROR_BYTE,
|
||||||
|
ROR_WORD,
|
||||||
|
ROR_MEM_BYTE,
|
||||||
|
ROR_MEM_WORD,
|
||||||
|
ROR_VAR_BYTE,
|
||||||
|
ROR_VAR_WORD,
|
||||||
|
ROL2_BYTE,
|
||||||
|
ROL2_WORD,
|
||||||
|
ROL2_MEM_BYTE,
|
||||||
|
ROL2_MEM_WORD,
|
||||||
|
ROL2_VAR_BYTE,
|
||||||
|
ROL2_VAR_WORD,
|
||||||
|
ROR2_BYTE,
|
||||||
|
ROR2_WORD,
|
||||||
|
ROR2_MEM_BYTE,
|
||||||
|
ROR2_MEM_WORD,
|
||||||
|
ROR2_VAR_BYTE,
|
||||||
|
ROR2_VAR_WORD,
|
||||||
|
BITAND_BYTE,
|
||||||
|
BITAND_WORD,
|
||||||
|
BITOR_BYTE,
|
||||||
|
BITOR_WORD,
|
||||||
|
BITXOR_BYTE,
|
||||||
|
BITXOR_WORD,
|
||||||
|
INV_BYTE,
|
||||||
|
INV_WORD,
|
||||||
|
|
||||||
|
// numeric type conversions
|
||||||
|
LSB,
|
||||||
|
MSB,
|
||||||
|
B2UB,
|
||||||
|
UB2B,
|
||||||
|
B2WORD, // convert a byte into a word where it is the lower eight bits $ssxx with sign extension
|
||||||
|
UB2UWORD, // convert a byte into a word where it is the lower eight bits $00xx
|
||||||
|
MSB2WORD, // convert a byte into a word where it is the upper eight bits $xx00
|
||||||
|
B2FLOAT, // convert byte into floating point
|
||||||
|
UB2FLOAT, // convert unsigned byte into floating point
|
||||||
|
W2FLOAT, // convert word into floating point
|
||||||
|
UW2FLOAT, // convert unsigned word into floating point
|
||||||
|
|
||||||
|
// logical operations
|
||||||
|
AND_BYTE,
|
||||||
|
AND_WORD,
|
||||||
|
OR_BYTE,
|
||||||
|
OR_WORD,
|
||||||
|
XOR_BYTE,
|
||||||
|
XOR_WORD,
|
||||||
|
NOT_BYTE,
|
||||||
|
NOT_WORD,
|
||||||
|
|
||||||
|
// increment, decrement
|
||||||
|
INC_B,
|
||||||
|
INC_UB,
|
||||||
|
INC_W,
|
||||||
|
INC_UW,
|
||||||
|
INC_F,
|
||||||
|
INC_VAR_B,
|
||||||
|
INC_VAR_UB,
|
||||||
|
INC_VAR_W,
|
||||||
|
INC_VAR_UW,
|
||||||
|
INC_VAR_F,
|
||||||
|
DEC_B,
|
||||||
|
DEC_UB,
|
||||||
|
DEC_W,
|
||||||
|
DEC_UW,
|
||||||
|
DEC_F,
|
||||||
|
DEC_VAR_B,
|
||||||
|
DEC_VAR_UB,
|
||||||
|
DEC_VAR_W,
|
||||||
|
DEC_VAR_UW,
|
||||||
|
DEC_VAR_F,
|
||||||
|
|
||||||
|
// comparisons
|
||||||
|
LESS_B,
|
||||||
|
LESS_UB,
|
||||||
|
LESS_W,
|
||||||
|
LESS_UW,
|
||||||
|
LESS_F,
|
||||||
|
GREATER_B,
|
||||||
|
GREATER_UB,
|
||||||
|
GREATER_W,
|
||||||
|
GREATER_UW,
|
||||||
|
GREATER_F,
|
||||||
|
LESSEQ_B,
|
||||||
|
LESSEQ_UB,
|
||||||
|
LESSEQ_W,
|
||||||
|
LESSEQ_UW,
|
||||||
|
LESSEQ_F,
|
||||||
|
GREATEREQ_B,
|
||||||
|
GREATEREQ_UB,
|
||||||
|
GREATEREQ_W,
|
||||||
|
GREATEREQ_UW,
|
||||||
|
GREATEREQ_F,
|
||||||
|
EQUAL_BYTE,
|
||||||
|
EQUAL_WORD,
|
||||||
|
EQUAL_F,
|
||||||
|
NOTEQUAL_BYTE,
|
||||||
|
NOTEQUAL_WORD,
|
||||||
|
NOTEQUAL_F,
|
||||||
|
|
||||||
|
// array access
|
||||||
|
READ_INDEXED_VAR_BYTE,
|
||||||
|
READ_INDEXED_VAR_WORD,
|
||||||
|
READ_INDEXED_VAR_FLOAT,
|
||||||
|
WRITE_INDEXED_VAR_BYTE,
|
||||||
|
WRITE_INDEXED_VAR_WORD,
|
||||||
|
WRITE_INDEXED_VAR_FLOAT,
|
||||||
|
|
||||||
|
// branching
|
||||||
|
JUMP,
|
||||||
|
BCS,
|
||||||
|
BCC,
|
||||||
|
BZ, // branch if value on top of stack is zero
|
||||||
|
BNZ, // branch if value on top of stack is not zero
|
||||||
|
BNEG, // branch if value on top of stack < 0
|
||||||
|
BPOS, // branch if value on top of stack >= 0
|
||||||
|
// BVS, // status flag V (overflow) not implemented
|
||||||
|
// BVC, // status flag V (overflow) not implemented
|
||||||
|
|
||||||
|
// subroutine calling
|
||||||
|
CALL,
|
||||||
|
RETURN,
|
||||||
|
SYSCALL,
|
||||||
|
|
||||||
|
// misc
|
||||||
|
SEC, // set carry status flag NOTE: is mostly fake, carry flag is not affected by any numeric operations
|
||||||
|
CLC, // clear carry status flag NOTE: is mostly fake, carry flag is not affected by any numeric operations
|
||||||
|
SEI, // set irq-disable status flag
|
||||||
|
CLI, // clear irq-disable status flag
|
||||||
|
NOP, // do nothing
|
||||||
|
BREAKPOINT, // breakpoint
|
||||||
|
TERMINATE, // end the program
|
||||||
|
LINE // track source file line number
|
||||||
|
}
|
||||||
|
|
||||||
|
val opcodesWithVarArgument = setOf(
|
||||||
|
Opcode.INC_VAR_B, Opcode.INC_VAR_W, Opcode.DEC_VAR_B, Opcode.DEC_VAR_W,
|
||||||
|
Opcode.INC_VAR_UB, Opcode.INC_VAR_UW, Opcode.DEC_VAR_UB, Opcode.DEC_VAR_UW,
|
||||||
|
Opcode.SHR_VAR_BYTE, Opcode.SHR_VAR_WORD, Opcode.SHL_VAR_BYTE, Opcode.SHL_VAR_WORD,
|
||||||
|
Opcode.ROL_VAR_BYTE, Opcode.ROL_VAR_WORD, Opcode.ROR_VAR_BYTE, Opcode.ROR_VAR_WORD,
|
||||||
|
Opcode.ROL2_VAR_BYTE, Opcode.ROL2_VAR_WORD, Opcode.ROR2_VAR_BYTE, Opcode.ROR2_VAR_WORD,
|
||||||
|
Opcode.POP_VAR_BYTE, Opcode.POP_VAR_WORD, Opcode.POP_VAR_FLOAT,
|
||||||
|
Opcode.PUSH_VAR_BYTE, Opcode.PUSH_VAR_WORD, Opcode.PUSH_VAR_FLOAT,
|
||||||
|
Opcode.COPY_VAR_BYTE, Opcode.COPY_VAR_WORD, Opcode.COPY_VAR_FLOAT,
|
||||||
|
Opcode.READ_INDEXED_VAR_BYTE, Opcode.READ_INDEXED_VAR_WORD, Opcode.READ_INDEXED_VAR_FLOAT,
|
||||||
|
Opcode.WRITE_INDEXED_VAR_BYTE, Opcode.WRITE_INDEXED_VAR_WORD, Opcode.WRITE_INDEXED_VAR_FLOAT
|
||||||
|
)
|
@ -1,8 +1,9 @@
|
|||||||
package prog8.stackvm
|
package prog8.compiler.intermediate
|
||||||
|
|
||||||
import prog8.ast.DataType
|
import prog8.ast.DataType
|
||||||
import prog8.ast.IterableDatatypes
|
import prog8.ast.IterableDatatypes
|
||||||
import prog8.ast.NumericDatatypes
|
import prog8.ast.NumericDatatypes
|
||||||
|
import prog8.stackvm.VmExecutionException
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
import kotlin.math.floor
|
import kotlin.math.floor
|
||||||
import kotlin.math.pow
|
import kotlin.math.pow
|
||||||
@ -123,9 +124,9 @@ class Value(val type: DataType, numericvalueOrHeapId: Number) {
|
|||||||
// storing a negative number in an unsigned one is done by storing the 2's complement instead
|
// storing a negative number in an unsigned one is done by storing the 2's complement instead
|
||||||
val number = abs(result.toDouble().toInt())
|
val number = abs(result.toDouble().toInt())
|
||||||
if(leftDt==DataType.UBYTE)
|
if(leftDt==DataType.UBYTE)
|
||||||
Value(DataType.UBYTE, (number xor 255) +1)
|
Value(DataType.UBYTE, (number xor 255) + 1)
|
||||||
else
|
else
|
||||||
Value(DataType.UBYTE, (number xor 65535) +1)
|
Value(DataType.UBYTE, (number xor 65535) + 1)
|
||||||
}
|
}
|
||||||
DataType.BYTE -> Value(DataType.BYTE, result.toInt())
|
DataType.BYTE -> Value(DataType.BYTE, result.toInt())
|
||||||
DataType.WORD -> Value(DataType.WORD, result.toInt())
|
DataType.WORD -> Value(DataType.WORD, result.toInt())
|
15
compiler/src/prog8/compiler/target/c64/AsmGen.kt
Normal file
15
compiler/src/prog8/compiler/target/c64/AsmGen.kt
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package prog8.compiler.target.c64
|
||||||
|
|
||||||
|
import prog8.compiler.CompilationOptions
|
||||||
|
import prog8.compiler.intermediate.IntermediateProgram
|
||||||
|
|
||||||
|
|
||||||
|
class AsmGen(val options: CompilationOptions) {
|
||||||
|
fun compileToAssembly(program: IntermediateProgram): AssemblyProgram {
|
||||||
|
println("\nGenerating assembly code from intermediate code... ")
|
||||||
|
// todo generate 6502 assembly
|
||||||
|
return AssemblyProgram(program.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
57
compiler/src/prog8/compiler/target/c64/AssemblyProgram.kt
Normal file
57
compiler/src/prog8/compiler/target/c64/AssemblyProgram.kt
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
package prog8.compiler.target.c64
|
||||||
|
|
||||||
|
import prog8.compiler.CompilationOptions
|
||||||
|
import prog8.compiler.OutputType
|
||||||
|
import java.io.File
|
||||||
|
import kotlin.system.exitProcess
|
||||||
|
|
||||||
|
class AssemblyProgram(val name: String) {
|
||||||
|
private val assemblyFile = "$name.asm"
|
||||||
|
private val viceMonListFile = "$name.vice-mon-list"
|
||||||
|
|
||||||
|
fun assemble(options: CompilationOptions) {
|
||||||
|
println("Generating machine code program...")
|
||||||
|
|
||||||
|
val command = mutableListOf("64tass", "--ascii", "--case-sensitive", "-Wall", "-Wno-strict-bool",
|
||||||
|
"--dump-labels", "--vice-labels", "-l", viceMonListFile, "--no-monitor")
|
||||||
|
|
||||||
|
val outFile = when(options.output) {
|
||||||
|
OutputType.PRG -> {
|
||||||
|
command.add("--cbm-prg")
|
||||||
|
println("\nCreating C-64 prg.")
|
||||||
|
"$name.prg"
|
||||||
|
}
|
||||||
|
OutputType.RAW -> {
|
||||||
|
command.add("--nostart")
|
||||||
|
println("\nCreating raw binary.")
|
||||||
|
"$name.bin"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
command.addAll(listOf("--output", outFile, assemblyFile))
|
||||||
|
|
||||||
|
val proc = ProcessBuilder(command).inheritIO().start()
|
||||||
|
val result = proc.waitFor()
|
||||||
|
if(result!=0) {
|
||||||
|
System.err.println("assembler failed with returncode $result")
|
||||||
|
exitProcess(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
generateBreakpointList()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun generateBreakpointList() {
|
||||||
|
// builds list of breakpoints, appends to monitor list file
|
||||||
|
val breakpoints = mutableListOf<String>()
|
||||||
|
val pattern = Regex("""al (\w+) \S+_prog8_breakpoint_\d+.?""") // todo what's with the _prog8_breakpoint_? how to find breakpoint?
|
||||||
|
for(line in File(viceMonListFile).readLines()) {
|
||||||
|
val match = pattern.matchEntire(line)
|
||||||
|
if(match!=null)
|
||||||
|
breakpoints.add("break \$" + match.groupValues[0]) // todo check
|
||||||
|
}
|
||||||
|
val num = breakpoints.size
|
||||||
|
breakpoints.add(0, "; vice monitor breakpoint list now follows")
|
||||||
|
breakpoints.add(1, "; $num breakpoints have been defined")
|
||||||
|
breakpoints.add(2, "del")
|
||||||
|
File(viceMonListFile).appendText(breakpoints.joinToString("\n"))
|
||||||
|
}
|
||||||
|
}
|
@ -1,37 +0,0 @@
|
|||||||
package prog8.compiler.target.c64
|
|
||||||
|
|
||||||
import java.awt.Color
|
|
||||||
import java.awt.image.BufferedImage
|
|
||||||
import javax.imageio.ImageIO
|
|
||||||
|
|
||||||
object Charset {
|
|
||||||
private val normalImg = ImageIO.read(javaClass.getResource("/charset/c64/charset-normal.png"))
|
|
||||||
private val shiftedImg = ImageIO.read(javaClass.getResource("/charset/c64/charset-shifted.png"))
|
|
||||||
|
|
||||||
private fun scanChars(img: BufferedImage): Array<BufferedImage> {
|
|
||||||
|
|
||||||
val transparent = BufferedImage(img.width, img.height, BufferedImage.TYPE_INT_ARGB)
|
|
||||||
transparent.createGraphics().drawImage(img, 0, 0, null)
|
|
||||||
|
|
||||||
val black = Color(0,0,0).rgb
|
|
||||||
val nopixel = Color(0,0,0,0).rgb
|
|
||||||
for(y in 0 until transparent.height) {
|
|
||||||
for(x in 0 until transparent.width) {
|
|
||||||
val col = transparent.getRGB(x, y)
|
|
||||||
if(col==black)
|
|
||||||
transparent.setRGB(x, y, nopixel)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val numColumns = transparent.width / 8
|
|
||||||
val charImages = (0..255).map {
|
|
||||||
val charX = it % numColumns
|
|
||||||
val charY = it/ numColumns
|
|
||||||
transparent.getSubimage(charX*8, charY*8, 8, 8)
|
|
||||||
}
|
|
||||||
return charImages.toTypedArray()
|
|
||||||
}
|
|
||||||
|
|
||||||
val normalChars = scanChars(normalImg)
|
|
||||||
val shiftedChars = scanChars(shiftedImg)
|
|
||||||
}
|
|
@ -1,10 +1,11 @@
|
|||||||
package prog8.compiler.target.c64
|
package prog8.compiler.target.c64
|
||||||
|
|
||||||
import prog8.compiler.*
|
import prog8.compiler.*
|
||||||
import prog8.stackvm.Program
|
import java.awt.Color
|
||||||
|
import java.awt.image.BufferedImage
|
||||||
|
import javax.imageio.ImageIO
|
||||||
import kotlin.math.absoluteValue
|
import kotlin.math.absoluteValue
|
||||||
import kotlin.math.pow
|
import kotlin.math.pow
|
||||||
import kotlin.system.exitProcess
|
|
||||||
|
|
||||||
|
|
||||||
// 5-byte cbm MFLPT format limitations:
|
// 5-byte cbm MFLPT format limitations:
|
||||||
@ -12,7 +13,6 @@ const val FLOAT_MAX_POSITIVE = 1.7014118345e+38
|
|||||||
const val FLOAT_MAX_NEGATIVE = -1.7014118345e+38
|
const val FLOAT_MAX_NEGATIVE = -1.7014118345e+38
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class C64Zeropage(options: CompilationOptions) : Zeropage(options) {
|
class C64Zeropage(options: CompilationOptions) : Zeropage(options) {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@ -113,60 +113,34 @@ data class Mflpt5(val b0: Short, val b1: Short, val b2: Short, val b3: Short, va
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
object Charset {
|
||||||
|
private val normalImg = ImageIO.read(javaClass.getResource("/charset/c64/charset-normal.png"))
|
||||||
|
private val shiftedImg = ImageIO.read(javaClass.getResource("/charset/c64/charset-shifted.png"))
|
||||||
|
|
||||||
fun compileToAssembly(program: Program): AssemblyResult {
|
private fun scanChars(img: BufferedImage): Array<BufferedImage> {
|
||||||
println("\nGenerating assembly code from stackvmProg code... ")
|
|
||||||
// todo generate 6502 assembly
|
val transparent = BufferedImage(img.width, img.height, BufferedImage.TYPE_INT_ARGB)
|
||||||
return AssemblyResult(program.name)
|
transparent.createGraphics().drawImage(img, 0, 0, null)
|
||||||
|
|
||||||
|
val black = Color(0,0,0).rgb
|
||||||
|
val nopixel = Color(0,0,0,0).rgb
|
||||||
|
for(y in 0 until transparent.height) {
|
||||||
|
for(x in 0 until transparent.width) {
|
||||||
|
val col = transparent.getRGB(x, y)
|
||||||
|
if(col==black)
|
||||||
|
transparent.setRGB(x, y, nopixel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val numColumns = transparent.width / 8
|
||||||
|
val charImages = (0..255).map {
|
||||||
|
val charX = it % numColumns
|
||||||
|
val charY = it/ numColumns
|
||||||
|
transparent.getSubimage(charX*8, charY*8, 8, 8)
|
||||||
|
}
|
||||||
|
return charImages.toTypedArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
val normalChars = scanChars(normalImg)
|
||||||
|
val shiftedChars = scanChars(shiftedImg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class AssemblyResult(val name: String) {
|
|
||||||
fun assemble(options: CompilationOptions, inputfilename: String, outputfilename: String) {
|
|
||||||
println("\nGenerating machine code program...")
|
|
||||||
|
|
||||||
val command = mutableListOf("64tass", "--ascii", "--case-sensitive", "-Wall", "-Wno-strict-bool",
|
|
||||||
"--dump-labels", "--vice-labels", "-l", "$outputfilename.vice-mon-list",
|
|
||||||
"--no-monitor", "--output", outputfilename, inputfilename)
|
|
||||||
|
|
||||||
when(options.output) {
|
|
||||||
OutputType.PRG -> {
|
|
||||||
command.add("--cbm-prg")
|
|
||||||
println("\nCreating C-64 prg.")
|
|
||||||
}
|
|
||||||
OutputType.RAW -> {
|
|
||||||
command.add("--nostart")
|
|
||||||
println("\nCreating raw binary.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val proc = ProcessBuilder(command).inheritIO().start()
|
|
||||||
val result = proc.waitFor()
|
|
||||||
if(result!=0) {
|
|
||||||
System.err.println("assembler failed with returncode $result")
|
|
||||||
exitProcess(result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun generateBreakpointList(): String {
|
|
||||||
// todo build breakpoint list
|
|
||||||
/*
|
|
||||||
def generate_breakpoint_list(self, program_filename: str) -> str:
|
|
||||||
breakpoints = []
|
|
||||||
vice_mon_file = program_filename + ".vice-mon-list"
|
|
||||||
with open(vice_mon_file, "rU") as f:
|
|
||||||
for line in f:
|
|
||||||
match = re.fullmatch(r"al (?P<address>\w+) \S+_prog8_breakpoint_\d+.?", line, re.DOTALL)
|
|
||||||
if match:
|
|
||||||
breakpoints.append("$" + match.group("address"))
|
|
||||||
with open(vice_mon_file, "at") as f:
|
|
||||||
print("; vice monitor breakpoint list now follows", file=f)
|
|
||||||
print("; {:d} breakpoints have been defined here".format(len(breakpoints)), file=f)
|
|
||||||
print("del", file=f)
|
|
||||||
for b in breakpoints:
|
|
||||||
print("break", b, file=f)
|
|
||||||
return vice_mon_file
|
|
||||||
*/
|
|
||||||
return "monitorfile.txt"
|
|
||||||
}
|
|
||||||
}
|
|
@ -2,6 +2,7 @@ package prog8.stackvm
|
|||||||
|
|
||||||
import prog8.ast.DataType
|
import prog8.ast.DataType
|
||||||
import prog8.compiler.HeapValues
|
import prog8.compiler.HeapValues
|
||||||
|
import prog8.compiler.intermediate.*
|
||||||
import prog8.compiler.unescape
|
import prog8.compiler.unescape
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
@ -4,251 +4,15 @@ import prog8.ast.DataType
|
|||||||
import prog8.ast.IterableDatatypes
|
import prog8.ast.IterableDatatypes
|
||||||
import prog8.ast.NumericDatatypes
|
import prog8.ast.NumericDatatypes
|
||||||
import prog8.compiler.HeapValues
|
import prog8.compiler.HeapValues
|
||||||
|
import prog8.compiler.intermediate.Instruction
|
||||||
|
import prog8.compiler.intermediate.Opcode
|
||||||
|
import prog8.compiler.intermediate.Value
|
||||||
import prog8.compiler.target.c64.Petscii
|
import prog8.compiler.target.c64.Petscii
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.PrintStream
|
import java.io.PrintStream
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.math.*
|
import kotlin.math.*
|
||||||
|
|
||||||
enum class Opcode {
|
|
||||||
|
|
||||||
// pushing values on the (evaluation) stack
|
|
||||||
PUSH_BYTE, // push byte value
|
|
||||||
PUSH_WORD, // push word value (or 'address' of string / array / matrix)
|
|
||||||
PUSH_FLOAT, // push float value
|
|
||||||
PUSH_MEM_B, // push byte value from memory to stack
|
|
||||||
PUSH_MEM_UB, // push byte value from memory to stack
|
|
||||||
PUSH_MEM_W, // push word value from memory to stack
|
|
||||||
PUSH_MEM_UW, // push word value from memory to stack
|
|
||||||
PUSH_MEM_FLOAT, // push float value from memory to stack
|
|
||||||
PUSH_VAR_BYTE, // push byte variable (ubyte, byte)
|
|
||||||
PUSH_VAR_WORD, // push word variable (uword, word)
|
|
||||||
PUSH_VAR_FLOAT, // push float variable
|
|
||||||
|
|
||||||
// popping values off the (evaluation) stack, possibly storing them in another location
|
|
||||||
DISCARD_BYTE, // discard top byte value
|
|
||||||
DISCARD_WORD, // discard top word value
|
|
||||||
DISCARD_FLOAT, // discard top float value
|
|
||||||
POP_MEM_B, // pop byte value into destination memory address
|
|
||||||
POP_MEM_UB, // pop byte value into destination memory address
|
|
||||||
POP_MEM_W, // pop word value into destination memory address
|
|
||||||
POP_MEM_UW, // pop word value into destination memory address
|
|
||||||
POP_MEM_FLOAT, // pop float value into destination memory address
|
|
||||||
POP_VAR_BYTE, // pop byte value into variable (byte, ubyte)
|
|
||||||
POP_VAR_WORD, // pop word value into variable (word, uword)
|
|
||||||
POP_VAR_FLOAT, // pop float value into variable
|
|
||||||
|
|
||||||
// optimized copying of one var to another (replaces push+pop)
|
|
||||||
COPY_VAR_BYTE,
|
|
||||||
COPY_VAR_WORD,
|
|
||||||
COPY_VAR_FLOAT,
|
|
||||||
|
|
||||||
// numeric arithmetic
|
|
||||||
ADD_UB,
|
|
||||||
ADD_B,
|
|
||||||
ADD_UW,
|
|
||||||
ADD_W,
|
|
||||||
ADD_F,
|
|
||||||
SUB_UB,
|
|
||||||
SUB_B,
|
|
||||||
SUB_UW,
|
|
||||||
SUB_W,
|
|
||||||
SUB_F,
|
|
||||||
MUL_UB,
|
|
||||||
MUL_B,
|
|
||||||
MUL_UW,
|
|
||||||
MUL_W,
|
|
||||||
MUL_F,
|
|
||||||
DIV_UB,
|
|
||||||
DIV_B,
|
|
||||||
DIV_UW,
|
|
||||||
DIV_W,
|
|
||||||
DIV_F,
|
|
||||||
FLOORDIV_UB,
|
|
||||||
FLOORDIV_B,
|
|
||||||
FLOORDIV_UW,
|
|
||||||
FLOORDIV_W,
|
|
||||||
FLOORDIV_F,
|
|
||||||
REMAINDER_UB,
|
|
||||||
REMAINDER_B,
|
|
||||||
REMAINDER_UW,
|
|
||||||
REMAINDER_W,
|
|
||||||
REMAINDER_F,
|
|
||||||
POW_UB,
|
|
||||||
POW_B,
|
|
||||||
POW_UW,
|
|
||||||
POW_W,
|
|
||||||
POW_F,
|
|
||||||
NEG_B,
|
|
||||||
NEG_W,
|
|
||||||
NEG_F,
|
|
||||||
|
|
||||||
// bit shifts and bitwise arithmetic
|
|
||||||
SHL_BYTE,
|
|
||||||
SHL_WORD,
|
|
||||||
SHL_MEM_BYTE,
|
|
||||||
SHL_MEM_WORD,
|
|
||||||
SHL_VAR_BYTE,
|
|
||||||
SHL_VAR_WORD,
|
|
||||||
SHR_BYTE,
|
|
||||||
SHR_WORD,
|
|
||||||
SHR_MEM_BYTE,
|
|
||||||
SHR_MEM_WORD,
|
|
||||||
SHR_VAR_BYTE,
|
|
||||||
SHR_VAR_WORD,
|
|
||||||
ROL_BYTE,
|
|
||||||
ROL_WORD,
|
|
||||||
ROL_MEM_BYTE,
|
|
||||||
ROL_MEM_WORD,
|
|
||||||
ROL_VAR_BYTE,
|
|
||||||
ROL_VAR_WORD,
|
|
||||||
ROR_BYTE,
|
|
||||||
ROR_WORD,
|
|
||||||
ROR_MEM_BYTE,
|
|
||||||
ROR_MEM_WORD,
|
|
||||||
ROR_VAR_BYTE,
|
|
||||||
ROR_VAR_WORD,
|
|
||||||
ROL2_BYTE,
|
|
||||||
ROL2_WORD,
|
|
||||||
ROL2_MEM_BYTE,
|
|
||||||
ROL2_MEM_WORD,
|
|
||||||
ROL2_VAR_BYTE,
|
|
||||||
ROL2_VAR_WORD,
|
|
||||||
ROR2_BYTE,
|
|
||||||
ROR2_WORD,
|
|
||||||
ROR2_MEM_BYTE,
|
|
||||||
ROR2_MEM_WORD,
|
|
||||||
ROR2_VAR_BYTE,
|
|
||||||
ROR2_VAR_WORD,
|
|
||||||
BITAND_BYTE,
|
|
||||||
BITAND_WORD,
|
|
||||||
BITOR_BYTE,
|
|
||||||
BITOR_WORD,
|
|
||||||
BITXOR_BYTE,
|
|
||||||
BITXOR_WORD,
|
|
||||||
INV_BYTE,
|
|
||||||
INV_WORD,
|
|
||||||
|
|
||||||
// numeric type conversions
|
|
||||||
LSB,
|
|
||||||
MSB,
|
|
||||||
B2UB,
|
|
||||||
UB2B,
|
|
||||||
B2WORD, // convert a byte into a word where it is the lower eight bits $ssxx with sign extension
|
|
||||||
UB2UWORD, // convert a byte into a word where it is the lower eight bits $00xx
|
|
||||||
MSB2WORD, // convert a byte into a word where it is the upper eight bits $xx00
|
|
||||||
B2FLOAT, // convert byte into floating point
|
|
||||||
UB2FLOAT, // convert unsigned byte into floating point
|
|
||||||
W2FLOAT, // convert word into floating point
|
|
||||||
UW2FLOAT, // convert unsigned word into floating point
|
|
||||||
|
|
||||||
// logical operations
|
|
||||||
AND_BYTE,
|
|
||||||
AND_WORD,
|
|
||||||
OR_BYTE,
|
|
||||||
OR_WORD,
|
|
||||||
XOR_BYTE,
|
|
||||||
XOR_WORD,
|
|
||||||
NOT_BYTE,
|
|
||||||
NOT_WORD,
|
|
||||||
|
|
||||||
// increment, decrement
|
|
||||||
INC_B,
|
|
||||||
INC_UB,
|
|
||||||
INC_W,
|
|
||||||
INC_UW,
|
|
||||||
INC_F,
|
|
||||||
INC_VAR_B,
|
|
||||||
INC_VAR_UB,
|
|
||||||
INC_VAR_W,
|
|
||||||
INC_VAR_UW,
|
|
||||||
INC_VAR_F,
|
|
||||||
DEC_B,
|
|
||||||
DEC_UB,
|
|
||||||
DEC_W,
|
|
||||||
DEC_UW,
|
|
||||||
DEC_F,
|
|
||||||
DEC_VAR_B,
|
|
||||||
DEC_VAR_UB,
|
|
||||||
DEC_VAR_W,
|
|
||||||
DEC_VAR_UW,
|
|
||||||
DEC_VAR_F,
|
|
||||||
|
|
||||||
// comparisons
|
|
||||||
LESS_B,
|
|
||||||
LESS_UB,
|
|
||||||
LESS_W,
|
|
||||||
LESS_UW,
|
|
||||||
LESS_F,
|
|
||||||
GREATER_B,
|
|
||||||
GREATER_UB,
|
|
||||||
GREATER_W,
|
|
||||||
GREATER_UW,
|
|
||||||
GREATER_F,
|
|
||||||
LESSEQ_B,
|
|
||||||
LESSEQ_UB,
|
|
||||||
LESSEQ_W,
|
|
||||||
LESSEQ_UW,
|
|
||||||
LESSEQ_F,
|
|
||||||
GREATEREQ_B,
|
|
||||||
GREATEREQ_UB,
|
|
||||||
GREATEREQ_W,
|
|
||||||
GREATEREQ_UW,
|
|
||||||
GREATEREQ_F,
|
|
||||||
EQUAL_BYTE,
|
|
||||||
EQUAL_WORD,
|
|
||||||
EQUAL_F,
|
|
||||||
NOTEQUAL_BYTE,
|
|
||||||
NOTEQUAL_WORD,
|
|
||||||
NOTEQUAL_F,
|
|
||||||
|
|
||||||
// array access
|
|
||||||
READ_INDEXED_VAR_BYTE,
|
|
||||||
READ_INDEXED_VAR_WORD,
|
|
||||||
READ_INDEXED_VAR_FLOAT,
|
|
||||||
WRITE_INDEXED_VAR_BYTE,
|
|
||||||
WRITE_INDEXED_VAR_WORD,
|
|
||||||
WRITE_INDEXED_VAR_FLOAT,
|
|
||||||
|
|
||||||
// branching
|
|
||||||
JUMP,
|
|
||||||
BCS,
|
|
||||||
BCC,
|
|
||||||
BZ, // branch if value on top of stack is zero
|
|
||||||
BNZ, // branch if value on top of stack is not zero
|
|
||||||
BNEG, // branch if value on top of stack < 0
|
|
||||||
BPOS, // branch if value on top of stack >= 0
|
|
||||||
// BVS, // status flag V (overflow) not implemented
|
|
||||||
// BVC, // status flag V (overflow) not implemented
|
|
||||||
|
|
||||||
// subroutine calling
|
|
||||||
CALL,
|
|
||||||
RETURN,
|
|
||||||
SYSCALL,
|
|
||||||
|
|
||||||
// misc
|
|
||||||
SEC, // set carry status flag NOTE: is mostly fake, carry flag is not affected by any numeric operations
|
|
||||||
CLC, // clear carry status flag NOTE: is mostly fake, carry flag is not affected by any numeric operations
|
|
||||||
SEI, // set irq-disable status flag
|
|
||||||
CLI, // clear irq-disable status flag
|
|
||||||
NOP, // do nothing
|
|
||||||
BREAKPOINT, // breakpoint
|
|
||||||
TERMINATE, // end the program
|
|
||||||
LINE // track source file line number
|
|
||||||
}
|
|
||||||
|
|
||||||
val opcodesWithVarArgument = setOf(
|
|
||||||
Opcode.INC_VAR_B, Opcode.INC_VAR_W, Opcode.DEC_VAR_B, Opcode.DEC_VAR_W,
|
|
||||||
Opcode.INC_VAR_UB, Opcode.INC_VAR_UW, Opcode.DEC_VAR_UB, Opcode.DEC_VAR_UW,
|
|
||||||
Opcode.SHR_VAR_BYTE, Opcode.SHR_VAR_WORD, Opcode.SHL_VAR_BYTE, Opcode.SHL_VAR_WORD,
|
|
||||||
Opcode.ROL_VAR_BYTE, Opcode.ROL_VAR_WORD, Opcode.ROR_VAR_BYTE, Opcode.ROR_VAR_WORD,
|
|
||||||
Opcode.ROL2_VAR_BYTE, Opcode.ROL2_VAR_WORD, Opcode.ROR2_VAR_BYTE, Opcode.ROR2_VAR_WORD,
|
|
||||||
Opcode.POP_VAR_BYTE, Opcode.POP_VAR_WORD, Opcode.POP_VAR_FLOAT,
|
|
||||||
Opcode.PUSH_VAR_BYTE, Opcode.PUSH_VAR_WORD, Opcode.PUSH_VAR_FLOAT,
|
|
||||||
Opcode.COPY_VAR_BYTE, Opcode.COPY_VAR_WORD, Opcode.COPY_VAR_FLOAT,
|
|
||||||
Opcode.READ_INDEXED_VAR_BYTE, Opcode.READ_INDEXED_VAR_WORD, Opcode.READ_INDEXED_VAR_FLOAT,
|
|
||||||
Opcode.WRITE_INDEXED_VAR_BYTE, Opcode.WRITE_INDEXED_VAR_WORD, Opcode.WRITE_INDEXED_VAR_FLOAT
|
|
||||||
)
|
|
||||||
|
|
||||||
enum class Syscall(val callNr: Short) {
|
enum class Syscall(val callNr: Short) {
|
||||||
WRITE_MEMCHR(10), // print a single char from the memory address popped from stack
|
WRITE_MEMCHR(10), // print a single char from the memory address popped from stack
|
||||||
@ -301,42 +65,6 @@ enum class Syscall(val callNr: Short) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
open class Instruction(val opcode: Opcode,
|
|
||||||
val arg: Value? = null,
|
|
||||||
val callLabel: String? = null,
|
|
||||||
val callLabel2: String? = null)
|
|
||||||
{
|
|
||||||
lateinit var next: Instruction
|
|
||||||
var nextAlt: Instruction? = null
|
|
||||||
|
|
||||||
override fun toString(): String {
|
|
||||||
val argStr = arg?.toString() ?: ""
|
|
||||||
val result =
|
|
||||||
when {
|
|
||||||
opcode==Opcode.LINE -> "_line $callLabel"
|
|
||||||
opcode==Opcode.SYSCALL -> {
|
|
||||||
val syscall = Syscall.values().find { it.callNr==arg!!.numericValue() }
|
|
||||||
"syscall $syscall"
|
|
||||||
}
|
|
||||||
opcode in opcodesWithVarArgument -> {
|
|
||||||
// opcodes that manipulate a variable
|
|
||||||
"${opcode.toString().toLowerCase()} ${callLabel?:""} ${callLabel2?:""}".trimEnd()
|
|
||||||
}
|
|
||||||
callLabel==null -> "${opcode.toString().toLowerCase()} $argStr"
|
|
||||||
else -> "${opcode.toString().toLowerCase()} $callLabel $argStr"
|
|
||||||
}
|
|
||||||
.trimEnd()
|
|
||||||
|
|
||||||
return " $result"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class LabelInstr(val name: String) : Instruction(opcode = Opcode.NOP) {
|
|
||||||
override fun toString(): String {
|
|
||||||
return "\n$name:"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class VmExecutionException(msg: String?) : Exception(msg)
|
class VmExecutionException(msg: String?) : Exception(msg)
|
||||||
|
|
||||||
class VmTerminationException(msg: String?) : Exception(msg)
|
class VmTerminationException(msg: String?) : Exception(msg)
|
||||||
@ -1307,157 +1035,157 @@ class StackVm(private var traceOutputFile: String?) {
|
|||||||
val (top, second) = evalstack.pop2()
|
val (top, second) = evalstack.pop2()
|
||||||
checkDt(top, DataType.UBYTE)
|
checkDt(top, DataType.UBYTE)
|
||||||
checkDt(second, DataType.UBYTE)
|
checkDt(second, DataType.UBYTE)
|
||||||
evalstack.push(Value(DataType.UBYTE, if(second < top) 1 else 0))
|
evalstack.push(Value(DataType.UBYTE, if (second < top) 1 else 0))
|
||||||
}
|
}
|
||||||
Opcode.LESS_B -> {
|
Opcode.LESS_B -> {
|
||||||
val (top, second) = evalstack.pop2()
|
val (top, second) = evalstack.pop2()
|
||||||
checkDt(top, DataType.BYTE)
|
checkDt(top, DataType.BYTE)
|
||||||
checkDt(second, DataType.BYTE)
|
checkDt(second, DataType.BYTE)
|
||||||
evalstack.push(Value(DataType.UBYTE, if(second < top) 1 else 0))
|
evalstack.push(Value(DataType.UBYTE, if (second < top) 1 else 0))
|
||||||
}
|
}
|
||||||
Opcode.LESS_UW -> {
|
Opcode.LESS_UW -> {
|
||||||
val (top, second) = evalstack.pop2()
|
val (top, second) = evalstack.pop2()
|
||||||
checkDt(top, DataType.UWORD)
|
checkDt(top, DataType.UWORD)
|
||||||
checkDt(second, DataType.UWORD)
|
checkDt(second, DataType.UWORD)
|
||||||
evalstack.push(Value(DataType.UBYTE, if(second < top) 1 else 0))
|
evalstack.push(Value(DataType.UBYTE, if (second < top) 1 else 0))
|
||||||
}
|
}
|
||||||
Opcode.LESS_W -> {
|
Opcode.LESS_W -> {
|
||||||
val (top, second) = evalstack.pop2()
|
val (top, second) = evalstack.pop2()
|
||||||
checkDt(top, DataType.WORD)
|
checkDt(top, DataType.WORD)
|
||||||
checkDt(second, DataType.WORD)
|
checkDt(second, DataType.WORD)
|
||||||
evalstack.push(Value(DataType.UBYTE, if(second < top) 1 else 0))
|
evalstack.push(Value(DataType.UBYTE, if (second < top) 1 else 0))
|
||||||
}
|
}
|
||||||
Opcode.LESS_F -> {
|
Opcode.LESS_F -> {
|
||||||
val (top, second) = evalstack.pop2()
|
val (top, second) = evalstack.pop2()
|
||||||
checkDt(top, DataType.FLOAT)
|
checkDt(top, DataType.FLOAT)
|
||||||
checkDt(second, DataType.FLOAT)
|
checkDt(second, DataType.FLOAT)
|
||||||
evalstack.push(Value(DataType.UBYTE, if(second < top) 1 else 0))
|
evalstack.push(Value(DataType.UBYTE, if (second < top) 1 else 0))
|
||||||
}
|
}
|
||||||
Opcode.GREATER_UB -> {
|
Opcode.GREATER_UB -> {
|
||||||
val (top, second) = evalstack.pop2()
|
val (top, second) = evalstack.pop2()
|
||||||
checkDt(top, DataType.UBYTE)
|
checkDt(top, DataType.UBYTE)
|
||||||
checkDt(second, DataType.UBYTE)
|
checkDt(second, DataType.UBYTE)
|
||||||
evalstack.push(Value(DataType.UBYTE, if(second > top) 1 else 0))
|
evalstack.push(Value(DataType.UBYTE, if (second > top) 1 else 0))
|
||||||
}
|
}
|
||||||
Opcode.GREATER_B -> {
|
Opcode.GREATER_B -> {
|
||||||
val (top, second) = evalstack.pop2()
|
val (top, second) = evalstack.pop2()
|
||||||
checkDt(top, DataType.BYTE)
|
checkDt(top, DataType.BYTE)
|
||||||
checkDt(second, DataType.BYTE)
|
checkDt(second, DataType.BYTE)
|
||||||
evalstack.push(Value(DataType.UBYTE, if(second > top) 1 else 0))
|
evalstack.push(Value(DataType.UBYTE, if (second > top) 1 else 0))
|
||||||
}
|
}
|
||||||
Opcode.GREATER_UW -> {
|
Opcode.GREATER_UW -> {
|
||||||
val (top, second) = evalstack.pop2()
|
val (top, second) = evalstack.pop2()
|
||||||
checkDt(top, DataType.UWORD)
|
checkDt(top, DataType.UWORD)
|
||||||
checkDt(second, DataType.UWORD)
|
checkDt(second, DataType.UWORD)
|
||||||
evalstack.push(Value(DataType.UBYTE, if(second > top) 1 else 0))
|
evalstack.push(Value(DataType.UBYTE, if (second > top) 1 else 0))
|
||||||
}
|
}
|
||||||
Opcode.GREATER_W -> {
|
Opcode.GREATER_W -> {
|
||||||
val (top, second) = evalstack.pop2()
|
val (top, second) = evalstack.pop2()
|
||||||
checkDt(top, DataType.WORD)
|
checkDt(top, DataType.WORD)
|
||||||
checkDt(second, DataType.WORD)
|
checkDt(second, DataType.WORD)
|
||||||
evalstack.push(Value(DataType.UBYTE, if(second > top) 1 else 0))
|
evalstack.push(Value(DataType.UBYTE, if (second > top) 1 else 0))
|
||||||
}
|
}
|
||||||
Opcode.GREATER_F -> {
|
Opcode.GREATER_F -> {
|
||||||
val (top, second) = evalstack.pop2()
|
val (top, second) = evalstack.pop2()
|
||||||
checkDt(top, DataType.FLOAT)
|
checkDt(top, DataType.FLOAT)
|
||||||
checkDt(second, DataType.FLOAT)
|
checkDt(second, DataType.FLOAT)
|
||||||
evalstack.push(Value(DataType.UBYTE, if(second > top) 1 else 0))
|
evalstack.push(Value(DataType.UBYTE, if (second > top) 1 else 0))
|
||||||
}
|
}
|
||||||
Opcode.LESSEQ_UB -> {
|
Opcode.LESSEQ_UB -> {
|
||||||
val (top, second) = evalstack.pop2()
|
val (top, second) = evalstack.pop2()
|
||||||
checkDt(top, DataType.UBYTE)
|
checkDt(top, DataType.UBYTE)
|
||||||
checkDt(second, DataType.UBYTE)
|
checkDt(second, DataType.UBYTE)
|
||||||
evalstack.push(Value(DataType.UBYTE, if(second <= top) 1 else 0))
|
evalstack.push(Value(DataType.UBYTE, if (second <= top) 1 else 0))
|
||||||
}
|
}
|
||||||
Opcode.LESSEQ_B -> {
|
Opcode.LESSEQ_B -> {
|
||||||
val (top, second) = evalstack.pop2()
|
val (top, second) = evalstack.pop2()
|
||||||
checkDt(top, DataType.BYTE)
|
checkDt(top, DataType.BYTE)
|
||||||
checkDt(second, DataType.BYTE)
|
checkDt(second, DataType.BYTE)
|
||||||
evalstack.push(Value(DataType.UBYTE, if(second <= top) 1 else 0))
|
evalstack.push(Value(DataType.UBYTE, if (second <= top) 1 else 0))
|
||||||
}
|
}
|
||||||
Opcode.LESSEQ_UW -> {
|
Opcode.LESSEQ_UW -> {
|
||||||
val (top, second) = evalstack.pop2()
|
val (top, second) = evalstack.pop2()
|
||||||
checkDt(top, DataType.UWORD)
|
checkDt(top, DataType.UWORD)
|
||||||
checkDt(second, DataType.UWORD)
|
checkDt(second, DataType.UWORD)
|
||||||
evalstack.push(Value(DataType.UBYTE, if(second <= top) 1 else 0))
|
evalstack.push(Value(DataType.UBYTE, if (second <= top) 1 else 0))
|
||||||
}
|
}
|
||||||
Opcode.LESSEQ_W -> {
|
Opcode.LESSEQ_W -> {
|
||||||
val (top, second) = evalstack.pop2()
|
val (top, second) = evalstack.pop2()
|
||||||
checkDt(top, DataType.WORD)
|
checkDt(top, DataType.WORD)
|
||||||
checkDt(second, DataType.WORD)
|
checkDt(second, DataType.WORD)
|
||||||
evalstack.push(Value(DataType.UBYTE, if(second <= top) 1 else 0))
|
evalstack.push(Value(DataType.UBYTE, if (second <= top) 1 else 0))
|
||||||
}
|
}
|
||||||
Opcode.LESSEQ_F -> {
|
Opcode.LESSEQ_F -> {
|
||||||
val (top, second) = evalstack.pop2()
|
val (top, second) = evalstack.pop2()
|
||||||
checkDt(top, DataType.FLOAT)
|
checkDt(top, DataType.FLOAT)
|
||||||
checkDt(second, DataType.FLOAT)
|
checkDt(second, DataType.FLOAT)
|
||||||
evalstack.push(Value(DataType.UBYTE, if(second <= top) 1 else 0))
|
evalstack.push(Value(DataType.UBYTE, if (second <= top) 1 else 0))
|
||||||
}
|
}
|
||||||
Opcode.GREATEREQ_UB -> {
|
Opcode.GREATEREQ_UB -> {
|
||||||
val (top, second) = evalstack.pop2()
|
val (top, second) = evalstack.pop2()
|
||||||
checkDt(top, DataType.UBYTE)
|
checkDt(top, DataType.UBYTE)
|
||||||
checkDt(second, DataType.UBYTE)
|
checkDt(second, DataType.UBYTE)
|
||||||
evalstack.push(Value(DataType.UBYTE, if(second >= top) 1 else 0))
|
evalstack.push(Value(DataType.UBYTE, if (second >= top) 1 else 0))
|
||||||
}
|
}
|
||||||
Opcode.GREATEREQ_B -> {
|
Opcode.GREATEREQ_B -> {
|
||||||
val (top, second) = evalstack.pop2()
|
val (top, second) = evalstack.pop2()
|
||||||
checkDt(top, DataType.BYTE)
|
checkDt(top, DataType.BYTE)
|
||||||
checkDt(second, DataType.BYTE)
|
checkDt(second, DataType.BYTE)
|
||||||
evalstack.push(Value(DataType.UBYTE, if(second >= top) 1 else 0))
|
evalstack.push(Value(DataType.UBYTE, if (second >= top) 1 else 0))
|
||||||
}
|
}
|
||||||
Opcode.GREATEREQ_UW -> {
|
Opcode.GREATEREQ_UW -> {
|
||||||
val (top, second) = evalstack.pop2()
|
val (top, second) = evalstack.pop2()
|
||||||
checkDt(top, DataType.UWORD)
|
checkDt(top, DataType.UWORD)
|
||||||
checkDt(second, DataType.UWORD)
|
checkDt(second, DataType.UWORD)
|
||||||
evalstack.push(Value(DataType.UBYTE, if(second >= top) 1 else 0))
|
evalstack.push(Value(DataType.UBYTE, if (second >= top) 1 else 0))
|
||||||
}
|
}
|
||||||
Opcode.GREATEREQ_W -> {
|
Opcode.GREATEREQ_W -> {
|
||||||
val (top, second) = evalstack.pop2()
|
val (top, second) = evalstack.pop2()
|
||||||
checkDt(top, DataType.WORD)
|
checkDt(top, DataType.WORD)
|
||||||
checkDt(second, DataType.WORD)
|
checkDt(second, DataType.WORD)
|
||||||
evalstack.push(Value(DataType.UBYTE, if(second >= top) 1 else 0))
|
evalstack.push(Value(DataType.UBYTE, if (second >= top) 1 else 0))
|
||||||
}
|
}
|
||||||
Opcode.GREATEREQ_F -> {
|
Opcode.GREATEREQ_F -> {
|
||||||
val (top, second) = evalstack.pop2()
|
val (top, second) = evalstack.pop2()
|
||||||
checkDt(top, DataType.FLOAT)
|
checkDt(top, DataType.FLOAT)
|
||||||
checkDt(second, DataType.FLOAT)
|
checkDt(second, DataType.FLOAT)
|
||||||
evalstack.push(Value(DataType.UBYTE, if(second >= top) 1 else 0))
|
evalstack.push(Value(DataType.UBYTE, if (second >= top) 1 else 0))
|
||||||
}
|
}
|
||||||
Opcode.EQUAL_BYTE -> {
|
Opcode.EQUAL_BYTE -> {
|
||||||
val (top, second) = evalstack.pop2()
|
val (top, second) = evalstack.pop2()
|
||||||
checkDt(top, DataType.UBYTE)
|
checkDt(top, DataType.UBYTE)
|
||||||
checkDt(second, DataType.UBYTE)
|
checkDt(second, DataType.UBYTE)
|
||||||
evalstack.push(Value(DataType.UBYTE, if(second == top) 1 else 0))
|
evalstack.push(Value(DataType.UBYTE, if (second == top) 1 else 0))
|
||||||
}
|
}
|
||||||
Opcode.EQUAL_WORD -> {
|
Opcode.EQUAL_WORD -> {
|
||||||
val (top, second) = evalstack.pop2()
|
val (top, second) = evalstack.pop2()
|
||||||
checkDt(top, DataType.UWORD)
|
checkDt(top, DataType.UWORD)
|
||||||
checkDt(second, DataType.UWORD)
|
checkDt(second, DataType.UWORD)
|
||||||
evalstack.push(Value(DataType.UBYTE, if(second == top) 1 else 0))
|
evalstack.push(Value(DataType.UBYTE, if (second == top) 1 else 0))
|
||||||
}
|
}
|
||||||
Opcode.EQUAL_F -> {
|
Opcode.EQUAL_F -> {
|
||||||
val (top, second) = evalstack.pop2()
|
val (top, second) = evalstack.pop2()
|
||||||
checkDt(top, DataType.FLOAT)
|
checkDt(top, DataType.FLOAT)
|
||||||
checkDt(second, DataType.FLOAT)
|
checkDt(second, DataType.FLOAT)
|
||||||
evalstack.push(Value(DataType.UBYTE, if(second == top) 1 else 0))
|
evalstack.push(Value(DataType.UBYTE, if (second == top) 1 else 0))
|
||||||
}
|
}
|
||||||
Opcode.NOTEQUAL_BYTE -> {
|
Opcode.NOTEQUAL_BYTE -> {
|
||||||
val (top, second) = evalstack.pop2()
|
val (top, second) = evalstack.pop2()
|
||||||
checkDt(top, DataType.UBYTE)
|
checkDt(top, DataType.UBYTE)
|
||||||
checkDt(second, DataType.UBYTE)
|
checkDt(second, DataType.UBYTE)
|
||||||
evalstack.push(Value(DataType.UBYTE, if(second != top) 1 else 0))
|
evalstack.push(Value(DataType.UBYTE, if (second != top) 1 else 0))
|
||||||
}
|
}
|
||||||
Opcode.NOTEQUAL_WORD -> {
|
Opcode.NOTEQUAL_WORD -> {
|
||||||
val (top, second) = evalstack.pop2()
|
val (top, second) = evalstack.pop2()
|
||||||
checkDt(top, DataType.UWORD)
|
checkDt(top, DataType.UWORD)
|
||||||
checkDt(second, DataType.UWORD)
|
checkDt(second, DataType.UWORD)
|
||||||
evalstack.push(Value(DataType.UBYTE, if(second != top) 1 else 0))
|
evalstack.push(Value(DataType.UBYTE, if (second != top) 1 else 0))
|
||||||
}
|
}
|
||||||
Opcode.NOTEQUAL_F -> {
|
Opcode.NOTEQUAL_F -> {
|
||||||
val (top, second) = evalstack.pop2()
|
val (top, second) = evalstack.pop2()
|
||||||
checkDt(top, DataType.FLOAT)
|
checkDt(top, DataType.FLOAT)
|
||||||
checkDt(second, DataType.FLOAT)
|
checkDt(second, DataType.FLOAT)
|
||||||
evalstack.push(Value(DataType.UBYTE, if(second != top) 1 else 0))
|
evalstack.push(Value(DataType.UBYTE, if (second != top) 1 else 0))
|
||||||
}
|
}
|
||||||
Opcode.B2UB -> {
|
Opcode.B2UB -> {
|
||||||
val byte = evalstack.pop()
|
val byte = evalstack.pop()
|
||||||
@ -1793,7 +1521,7 @@ class StackVm(private var traceOutputFile: String?) {
|
|||||||
if (value.str != null)
|
if (value.str != null)
|
||||||
evalstack.push(Value(DataType.UBYTE, if (Petscii.encodePetscii(value.str, true).any { c -> c != 0.toShort() }) 1 else 0))
|
evalstack.push(Value(DataType.UBYTE, if (Petscii.encodePetscii(value.str, true).any { c -> c != 0.toShort() }) 1 else 0))
|
||||||
else
|
else
|
||||||
evalstack.push(Value(DataType.UBYTE, if (value.array!!.any{ v->v!=0}) 1 else 0))
|
evalstack.push(Value(DataType.UBYTE, if (value.array!!.any { v -> v != 0 }) 1 else 0))
|
||||||
}
|
}
|
||||||
Syscall.FUNC_ALL -> {
|
Syscall.FUNC_ALL -> {
|
||||||
val iterable = evalstack.pop()
|
val iterable = evalstack.pop()
|
||||||
@ -1801,7 +1529,7 @@ class StackVm(private var traceOutputFile: String?) {
|
|||||||
if (value.str != null)
|
if (value.str != null)
|
||||||
evalstack.push(Value(DataType.UBYTE, if (Petscii.encodePetscii(value.str, true).all { c -> c != 0.toShort() }) 1 else 0))
|
evalstack.push(Value(DataType.UBYTE, if (Petscii.encodePetscii(value.str, true).all { c -> c != 0.toShort() }) 1 else 0))
|
||||||
else
|
else
|
||||||
evalstack.push(Value(DataType.UBYTE, if (value.array!!.all{ v->v!=0}) 1 else 0))
|
evalstack.push(Value(DataType.UBYTE, if (value.array!!.all { v -> v != 0 }) 1 else 0))
|
||||||
}
|
}
|
||||||
Syscall.FUNC_STR2BYTE -> {
|
Syscall.FUNC_STR2BYTE -> {
|
||||||
val strvar = evalstack.pop()
|
val strvar = evalstack.pop()
|
||||||
@ -1845,7 +1573,7 @@ class StackVm(private var traceOutputFile: String?) {
|
|||||||
if(value.integerValue() <= 32767)
|
if(value.integerValue() <= 32767)
|
||||||
Value(DataType.WORD, value.integerValue())
|
Value(DataType.WORD, value.integerValue())
|
||||||
else
|
else
|
||||||
Value(DataType.WORD, -((value.integerValue() xor 65535)+1))
|
Value(DataType.WORD, -((value.integerValue() xor 65535) + 1))
|
||||||
evalstack.push(v2)
|
evalstack.push(v2)
|
||||||
}
|
}
|
||||||
DataType.WORD -> evalstack.push(value)
|
DataType.WORD -> evalstack.push(value)
|
||||||
@ -1863,7 +1591,7 @@ class StackVm(private var traceOutputFile: String?) {
|
|||||||
if(value.integerValue()>=0)
|
if(value.integerValue()>=0)
|
||||||
Value(DataType.UWORD, value.integerValue())
|
Value(DataType.UWORD, value.integerValue())
|
||||||
else
|
else
|
||||||
Value(DataType.UWORD, (abs(value.integerValue()) xor 65535)+1)
|
Value(DataType.UWORD, (abs(value.integerValue()) xor 65535) + 1)
|
||||||
evalstack.push(v2)
|
evalstack.push(v2)
|
||||||
}
|
}
|
||||||
else -> {}
|
else -> {}
|
||||||
|
@ -6,6 +6,9 @@ import org.junit.jupiter.api.Test
|
|||||||
import org.junit.jupiter.api.TestInstance
|
import org.junit.jupiter.api.TestInstance
|
||||||
import prog8.ast.DataType
|
import prog8.ast.DataType
|
||||||
import prog8.compiler.HeapValues
|
import prog8.compiler.HeapValues
|
||||||
|
import prog8.compiler.intermediate.Instruction
|
||||||
|
import prog8.compiler.intermediate.Opcode
|
||||||
|
import prog8.compiler.intermediate.Value
|
||||||
import prog8.stackvm.*
|
import prog8.stackvm.*
|
||||||
import kotlin.test.*
|
import kotlin.test.*
|
||||||
|
|
||||||
@ -317,7 +320,7 @@ class TestStackVmOpcodes {
|
|||||||
@Test
|
@Test
|
||||||
fun testSub() {
|
fun testSub() {
|
||||||
testBinaryOperator(Value(DataType.UBYTE, 250), Opcode.SUB_UB, Value(DataType.UBYTE, 70), Value(DataType.UBYTE, 180))
|
testBinaryOperator(Value(DataType.UBYTE, 250), Opcode.SUB_UB, Value(DataType.UBYTE, 70), Value(DataType.UBYTE, 180))
|
||||||
testBinaryOperator(Value(DataType.UWORD, 4000), Opcode.SUB_UW, Value(DataType.UWORD, 123), Value(DataType.UWORD, 4000-123))
|
testBinaryOperator(Value(DataType.UWORD, 4000), Opcode.SUB_UW, Value(DataType.UWORD, 123), Value(DataType.UWORD, 4000 - 123))
|
||||||
testBinaryOperator(Value(DataType.FLOAT, 123.44), Opcode.SUB_F, Value(DataType.FLOAT, 23.44), Value(DataType.FLOAT, 100.0))
|
testBinaryOperator(Value(DataType.FLOAT, 123.44), Opcode.SUB_F, Value(DataType.FLOAT, 23.44), Value(DataType.FLOAT, 100.0))
|
||||||
assertFailsWith<VmExecutionException> {
|
assertFailsWith<VmExecutionException> {
|
||||||
testBinaryOperator(Value(DataType.UWORD, 4000 - 40), Opcode.SUB_UW, Value(DataType.FLOAT, 42.25), Value(DataType.FLOAT, 42.25 - (4000 - 40)))
|
testBinaryOperator(Value(DataType.UWORD, 4000 - 40), Opcode.SUB_UW, Value(DataType.FLOAT, 42.25), Value(DataType.FLOAT, 42.25 - (4000 - 40)))
|
||||||
@ -327,7 +330,7 @@ class TestStackVmOpcodes {
|
|||||||
@Test
|
@Test
|
||||||
fun testMul() {
|
fun testMul() {
|
||||||
testBinaryOperator(Value(DataType.UBYTE, 41), Opcode.MUL_UB, Value(DataType.UBYTE, 4), Value(DataType.UBYTE, 164))
|
testBinaryOperator(Value(DataType.UBYTE, 41), Opcode.MUL_UB, Value(DataType.UBYTE, 4), Value(DataType.UBYTE, 164))
|
||||||
testBinaryOperator(Value(DataType.UWORD, 401), Opcode.MUL_UW, Value(DataType.UWORD, 4), Value(DataType.UWORD, 401*4))
|
testBinaryOperator(Value(DataType.UWORD, 401), Opcode.MUL_UW, Value(DataType.UWORD, 4), Value(DataType.UWORD, 401 * 4))
|
||||||
testBinaryOperator(Value(DataType.FLOAT, 40.1), Opcode.MUL_F, Value(DataType.FLOAT, 2.4), Value(DataType.FLOAT, 96.24))
|
testBinaryOperator(Value(DataType.FLOAT, 40.1), Opcode.MUL_F, Value(DataType.FLOAT, 2.4), Value(DataType.FLOAT, 96.24))
|
||||||
assertFailsWith<VmExecutionException> {
|
assertFailsWith<VmExecutionException> {
|
||||||
testBinaryOperator(Value(DataType.UWORD, 401 * 4), Opcode.MUL_UW, Value(DataType.FLOAT, 42.2533), Value(DataType.FLOAT, 42.2533 * (401 * 4)))
|
testBinaryOperator(Value(DataType.UWORD, 401 * 4), Opcode.MUL_UW, Value(DataType.FLOAT, 42.2533), Value(DataType.FLOAT, 42.2533 * (401 * 4)))
|
||||||
@ -338,7 +341,7 @@ class TestStackVmOpcodes {
|
|||||||
fun testDiv() {
|
fun testDiv() {
|
||||||
testBinaryOperator(Value(DataType.UBYTE, 250), Opcode.DIV_UB, Value(DataType.UBYTE, 12), Value(DataType.UBYTE, 20))
|
testBinaryOperator(Value(DataType.UBYTE, 250), Opcode.DIV_UB, Value(DataType.UBYTE, 12), Value(DataType.UBYTE, 20))
|
||||||
testBinaryOperator(Value(DataType.UWORD, 3999), Opcode.DIV_UW, Value(DataType.UWORD, 40), Value(DataType.UWORD, 99))
|
testBinaryOperator(Value(DataType.UWORD, 3999), Opcode.DIV_UW, Value(DataType.UWORD, 40), Value(DataType.UWORD, 99))
|
||||||
testBinaryOperator(Value(DataType.FLOAT, 42.25), Opcode.DIV_F, Value(DataType.FLOAT, 99.0), Value(DataType.FLOAT, 42.25/99.0))
|
testBinaryOperator(Value(DataType.FLOAT, 42.25), Opcode.DIV_F, Value(DataType.FLOAT, 99.0), Value(DataType.FLOAT, 42.25 / 99.0))
|
||||||
assertFailsWith<VmExecutionException> {
|
assertFailsWith<VmExecutionException> {
|
||||||
testBinaryOperator(Value(DataType.UWORD, 3333), Opcode.DIV_UW, Value(DataType.FLOAT, 2.22), Value(DataType.FLOAT, 3333 / 2.22))
|
testBinaryOperator(Value(DataType.UWORD, 3333), Opcode.DIV_UW, Value(DataType.FLOAT, 2.22), Value(DataType.FLOAT, 3333 / 2.22))
|
||||||
}
|
}
|
||||||
@ -643,12 +646,12 @@ class TestStackVmOpcodes {
|
|||||||
@Test
|
@Test
|
||||||
fun testIncVar() {
|
fun testIncVar() {
|
||||||
val ins = mutableListOf(
|
val ins = mutableListOf(
|
||||||
Instruction(Opcode.INC_VAR_UW, callLabel ="var1"),
|
Instruction(Opcode.INC_VAR_UW, callLabel = "var1"),
|
||||||
Instruction(Opcode.INC_VAR_UB, callLabel ="var2"),
|
Instruction(Opcode.INC_VAR_UB, callLabel = "var2"),
|
||||||
Instruction(Opcode.INC_VAR_F, callLabel ="var3"),
|
Instruction(Opcode.INC_VAR_F, callLabel = "var3"),
|
||||||
Instruction(Opcode.INC_VAR_UW, callLabel ="var1"),
|
Instruction(Opcode.INC_VAR_UW, callLabel = "var1"),
|
||||||
Instruction(Opcode.INC_VAR_UB, callLabel ="var2"),
|
Instruction(Opcode.INC_VAR_UB, callLabel = "var2"),
|
||||||
Instruction(Opcode.INC_VAR_F, callLabel ="var3")
|
Instruction(Opcode.INC_VAR_F, callLabel = "var3")
|
||||||
)
|
)
|
||||||
val vars = mapOf("var1" to Value(DataType.UWORD, 65534),
|
val vars = mapOf("var1" to Value(DataType.UWORD, 65534),
|
||||||
"var2" to Value(DataType.UBYTE, 254),
|
"var2" to Value(DataType.UBYTE, 254),
|
||||||
@ -675,7 +678,7 @@ class TestStackVmOpcodes {
|
|||||||
Instruction(Opcode.DEC_VAR_UB, callLabel = "var2"),
|
Instruction(Opcode.DEC_VAR_UB, callLabel = "var2"),
|
||||||
Instruction(Opcode.DEC_VAR_F, callLabel = "var3")
|
Instruction(Opcode.DEC_VAR_F, callLabel = "var3")
|
||||||
)
|
)
|
||||||
val vars = mapOf("var1" to Value(DataType.UWORD,1),
|
val vars = mapOf("var1" to Value(DataType.UWORD, 1),
|
||||||
"var2" to Value(DataType.UBYTE, 1),
|
"var2" to Value(DataType.UBYTE, 1),
|
||||||
"var3" to Value(DataType.FLOAT, 1.5)
|
"var3" to Value(DataType.FLOAT, 1.5)
|
||||||
)
|
)
|
||||||
|
@ -8,7 +8,7 @@ import org.junit.jupiter.api.TestInstance
|
|||||||
import prog8.ast.*
|
import prog8.ast.*
|
||||||
import prog8.compiler.*
|
import prog8.compiler.*
|
||||||
import prog8.compiler.target.c64.*
|
import prog8.compiler.target.c64.*
|
||||||
import prog8.stackvm.Value
|
import prog8.compiler.intermediate.Value
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
import kotlin.test.assertFailsWith
|
import kotlin.test.assertFailsWith
|
||||||
import kotlin.test.assertFalse
|
import kotlin.test.assertFalse
|
||||||
|
@ -6,7 +6,7 @@ import prog8.ast.DataType
|
|||||||
import prog8.ast.ExpressionError
|
import prog8.ast.ExpressionError
|
||||||
import prog8.ast.LiteralValue
|
import prog8.ast.LiteralValue
|
||||||
import prog8.ast.Position
|
import prog8.ast.Position
|
||||||
import prog8.stackvm.Value
|
import prog8.compiler.intermediate.Value
|
||||||
import prog8.stackvm.VmExecutionException
|
import prog8.stackvm.VmExecutionException
|
||||||
import kotlin.test.*
|
import kotlin.test.*
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user