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.compiler.*
import prog8.compiler.target.c64.AsmGen
import prog8.optimizing.constantFold
import prog8.optimizing.optimizeStatements
import prog8.optimizing.simplifyExpressions
@ -103,15 +104,13 @@ fun main(args: Array<String>) {
stackvmFile.close()
println("StackVM program code written to '$stackVmFilename'")
// val assembly = stackvmProg.compileToAssembly()
//
// assembly.assemble(compilerOptions, "input", "output")
// val monitorfile = assembly.generateBreakpointList()
val assembly = AsmGen(compilerOptions).compileToAssembly(intermediate)
assembly.assemble(compilerOptions)
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 cmdline = listOf("x64", "-moncommands", monitorfile,
// "-autostartprgmode", "1", "-autostart-warp", "-autostart", program)

View File

@ -1,6 +1,9 @@
package prog8.compiler
import prog8.ast.*
import prog8.compiler.intermediate.IntermediateProgram
import prog8.compiler.intermediate.Opcode
import prog8.compiler.intermediate.Value
import prog8.stackvm.*
import java.util.*
import kotlin.math.abs

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.LiteralValue
import prog8.ast.Position
import prog8.ast.VarDecl
import prog8.stackvm.*
import prog8.compiler.CompilerException
import prog8.compiler.HeapValues
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.IterableDatatypes
import prog8.ast.NumericDatatypes
import prog8.stackvm.VmExecutionException
import kotlin.math.abs
import kotlin.math.floor
import kotlin.math.pow

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
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.pow
import kotlin.system.exitProcess
// 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
class C64Zeropage(options: CompilationOptions) : Zeropage(options) {
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 {
println("\nGenerating assembly code from stackvmProg code... ")
// todo generate 6502 assembly
return AssemblyResult(program.name)
}
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)
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 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 proc = ProcessBuilder(command).inheritIO().start()
val result = proc.waitFor()
if(result!=0) {
System.err.println("assembler failed with returncode $result")
exitProcess(result)
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()
}
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"
}
val normalChars = scanChars(normalImg)
val shiftedChars = scanChars(shiftedImg)
}

View File

@ -2,6 +2,7 @@ package prog8.stackvm
import prog8.ast.DataType
import prog8.compiler.HeapValues
import prog8.compiler.intermediate.*
import prog8.compiler.unescape
import java.io.File
import java.util.*

View File

@ -4,251 +4,15 @@ import prog8.ast.DataType
import prog8.ast.IterableDatatypes
import prog8.ast.NumericDatatypes
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 java.io.File
import java.io.PrintStream
import java.util.*
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) {
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 VmTerminationException(msg: String?) : Exception(msg)

View File

@ -6,6 +6,9 @@ import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestInstance
import prog8.ast.DataType
import prog8.compiler.HeapValues
import prog8.compiler.intermediate.Instruction
import prog8.compiler.intermediate.Opcode
import prog8.compiler.intermediate.Value
import prog8.stackvm.*
import kotlin.test.*

View File

@ -8,7 +8,7 @@ import org.junit.jupiter.api.TestInstance
import prog8.ast.*
import prog8.compiler.*
import prog8.compiler.target.c64.*
import prog8.stackvm.Value
import prog8.compiler.intermediate.Value
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
import kotlin.test.assertFalse

View File

@ -6,7 +6,7 @@ import prog8.ast.DataType
import prog8.ast.ExpressionError
import prog8.ast.LiteralValue
import prog8.ast.Position
import prog8.stackvm.Value
import prog8.compiler.intermediate.Value
import prog8.stackvm.VmExecutionException
import kotlin.test.*