mirror of
https://github.com/irmen/prog8.git
synced 2025-02-19 11:31:07 +00:00
refactor
This commit is contained in:
parent
dff4518608
commit
b7d8f026f4
@ -2,6 +2,7 @@ package prog8
|
||||
|
||||
import prog8.ast.*
|
||||
import prog8.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
|
||||
|
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
|
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)
|
||||
|
||||
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)
|
||||
}
|
@ -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)
|
||||
|
@ -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.*
|
||||
|
||||
|
@ -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