This commit is contained in:
Irmen de Jong 2018-10-13 18:15:09 +02:00
parent dff4518608
commit b7d8f026f4
15 changed files with 450 additions and 425 deletions

View File

@ -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)

View File

@ -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)

View 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:"
}
}

View File

@ -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

View 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
)

View File

@ -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())

View 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)
}
}

View 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"))
}
}

View File

@ -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)
}

View File

@ -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"
}
}

View File

@ -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.*

View File

@ -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 -> {}

View File

@ -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)
) )

View File

@ -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

View File

@ -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.*