mirror of
https://github.com/irmen/prog8.git
synced 2025-02-16 22:30:46 +00:00
refactor
This commit is contained in:
parent
dff4518608
commit
b7d8f026f4
@ -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)
|
||||
|
@ -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
|
||||
@ -1394,7 +1397,7 @@ private class StatementTranslator(private val prog: IntermediateProgram,
|
||||
continueStmtLabelStack.push(continueLabel)
|
||||
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(opcodePopvar(zero.type), callLabel = indexVar)
|
||||
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.
|
||||
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(opcodeSub(varDt))
|
||||
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.LiteralValue
|
||||
import prog8.ast.Position
|
||||
import prog8.ast.VarDecl
|
||||
import prog8.stackvm.*
|
||||
import prog8.compiler.CompilerException
|
||||
import prog8.compiler.HeapValues
|
||||
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.IterableDatatypes
|
||||
import prog8.ast.NumericDatatypes
|
||||
import prog8.stackvm.VmExecutionException
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.floor
|
||||
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
|
||||
val number = abs(result.toDouble().toInt())
|
||||
if(leftDt==DataType.UBYTE)
|
||||
Value(DataType.UBYTE, (number xor 255) +1)
|
||||
Value(DataType.UBYTE, (number xor 255) + 1)
|
||||
else
|
||||
Value(DataType.UBYTE, (number xor 65535) +1)
|
||||
Value(DataType.UBYTE, (number xor 65535) + 1)
|
||||
}
|
||||
DataType.BYTE -> Value(DataType.BYTE, 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
|
||||
|
||||
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)
|
||||
|
||||
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.compiler.HeapValues
|
||||
import prog8.compiler.intermediate.*
|
||||
import prog8.compiler.unescape
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
|
@ -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)
|
||||
@ -1307,157 +1035,157 @@ class StackVm(private var traceOutputFile: String?) {
|
||||
val (top, second) = evalstack.pop2()
|
||||
checkDt(top, 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 -> {
|
||||
val (top, second) = evalstack.pop2()
|
||||
checkDt(top, 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 -> {
|
||||
val (top, second) = evalstack.pop2()
|
||||
checkDt(top, 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 -> {
|
||||
val (top, second) = evalstack.pop2()
|
||||
checkDt(top, 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 -> {
|
||||
val (top, second) = evalstack.pop2()
|
||||
checkDt(top, 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 -> {
|
||||
val (top, second) = evalstack.pop2()
|
||||
checkDt(top, 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 -> {
|
||||
val (top, second) = evalstack.pop2()
|
||||
checkDt(top, 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 -> {
|
||||
val (top, second) = evalstack.pop2()
|
||||
checkDt(top, 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 -> {
|
||||
val (top, second) = evalstack.pop2()
|
||||
checkDt(top, 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 -> {
|
||||
val (top, second) = evalstack.pop2()
|
||||
checkDt(top, 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 -> {
|
||||
val (top, second) = evalstack.pop2()
|
||||
checkDt(top, 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 -> {
|
||||
val (top, second) = evalstack.pop2()
|
||||
checkDt(top, 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 -> {
|
||||
val (top, second) = evalstack.pop2()
|
||||
checkDt(top, 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 -> {
|
||||
val (top, second) = evalstack.pop2()
|
||||
checkDt(top, 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 -> {
|
||||
val (top, second) = evalstack.pop2()
|
||||
checkDt(top, 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 -> {
|
||||
val (top, second) = evalstack.pop2()
|
||||
checkDt(top, 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 -> {
|
||||
val (top, second) = evalstack.pop2()
|
||||
checkDt(top, 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 -> {
|
||||
val (top, second) = evalstack.pop2()
|
||||
checkDt(top, 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 -> {
|
||||
val (top, second) = evalstack.pop2()
|
||||
checkDt(top, 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 -> {
|
||||
val (top, second) = evalstack.pop2()
|
||||
checkDt(top, 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 -> {
|
||||
val (top, second) = evalstack.pop2()
|
||||
checkDt(top, 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 -> {
|
||||
val (top, second) = evalstack.pop2()
|
||||
checkDt(top, 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 -> {
|
||||
val (top, second) = evalstack.pop2()
|
||||
checkDt(top, 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 -> {
|
||||
val (top, second) = evalstack.pop2()
|
||||
checkDt(top, 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 -> {
|
||||
val (top, second) = evalstack.pop2()
|
||||
checkDt(top, 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 -> {
|
||||
val (top, second) = evalstack.pop2()
|
||||
checkDt(top, 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 -> {
|
||||
val byte = evalstack.pop()
|
||||
@ -1793,7 +1521,7 @@ class StackVm(private var traceOutputFile: String?) {
|
||||
if (value.str != null)
|
||||
evalstack.push(Value(DataType.UBYTE, if (Petscii.encodePetscii(value.str, true).any { c -> c != 0.toShort() }) 1 else 0))
|
||||
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 -> {
|
||||
val iterable = evalstack.pop()
|
||||
@ -1801,7 +1529,7 @@ class StackVm(private var traceOutputFile: String?) {
|
||||
if (value.str != null)
|
||||
evalstack.push(Value(DataType.UBYTE, if (Petscii.encodePetscii(value.str, true).all { c -> c != 0.toShort() }) 1 else 0))
|
||||
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 -> {
|
||||
val strvar = evalstack.pop()
|
||||
@ -1845,7 +1573,7 @@ class StackVm(private var traceOutputFile: String?) {
|
||||
if(value.integerValue() <= 32767)
|
||||
Value(DataType.WORD, value.integerValue())
|
||||
else
|
||||
Value(DataType.WORD, -((value.integerValue() xor 65535)+1))
|
||||
Value(DataType.WORD, -((value.integerValue() xor 65535) + 1))
|
||||
evalstack.push(v2)
|
||||
}
|
||||
DataType.WORD -> evalstack.push(value)
|
||||
@ -1863,7 +1591,7 @@ class StackVm(private var traceOutputFile: String?) {
|
||||
if(value.integerValue()>=0)
|
||||
Value(DataType.UWORD, value.integerValue())
|
||||
else
|
||||
Value(DataType.UWORD, (abs(value.integerValue()) xor 65535)+1)
|
||||
Value(DataType.UWORD, (abs(value.integerValue()) xor 65535) + 1)
|
||||
evalstack.push(v2)
|
||||
}
|
||||
else -> {}
|
||||
|
@ -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.*
|
||||
|
||||
@ -317,7 +320,7 @@ class TestStackVmOpcodes {
|
||||
@Test
|
||||
fun testSub() {
|
||||
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))
|
||||
assertFailsWith<VmExecutionException> {
|
||||
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
|
||||
fun testMul() {
|
||||
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))
|
||||
assertFailsWith<VmExecutionException> {
|
||||
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() {
|
||||
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.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> {
|
||||
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
|
||||
fun testIncVar() {
|
||||
val ins = mutableListOf(
|
||||
Instruction(Opcode.INC_VAR_UW, callLabel ="var1"),
|
||||
Instruction(Opcode.INC_VAR_UB, callLabel ="var2"),
|
||||
Instruction(Opcode.INC_VAR_F, callLabel ="var3"),
|
||||
Instruction(Opcode.INC_VAR_UW, callLabel ="var1"),
|
||||
Instruction(Opcode.INC_VAR_UB, callLabel ="var2"),
|
||||
Instruction(Opcode.INC_VAR_F, callLabel ="var3")
|
||||
Instruction(Opcode.INC_VAR_UW, callLabel = "var1"),
|
||||
Instruction(Opcode.INC_VAR_UB, callLabel = "var2"),
|
||||
Instruction(Opcode.INC_VAR_F, callLabel = "var3"),
|
||||
Instruction(Opcode.INC_VAR_UW, callLabel = "var1"),
|
||||
Instruction(Opcode.INC_VAR_UB, callLabel = "var2"),
|
||||
Instruction(Opcode.INC_VAR_F, callLabel = "var3")
|
||||
)
|
||||
val vars = mapOf("var1" to Value(DataType.UWORD, 65534),
|
||||
"var2" to Value(DataType.UBYTE, 254),
|
||||
@ -675,7 +678,7 @@ class TestStackVmOpcodes {
|
||||
Instruction(Opcode.DEC_VAR_UB, callLabel = "var2"),
|
||||
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),
|
||||
"var3" to Value(DataType.FLOAT, 1.5)
|
||||
)
|
||||
|
@ -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
|
||||
|
@ -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.*
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user