mirror of
https://github.com/irmen/prog8.git
synced 2024-11-20 03:32:05 +00:00
vm: fix symbols to be case sensitive properly in p8virt assembler
This commit is contained in:
parent
ca41669f4f
commit
dda19c29fe
@ -3,18 +3,16 @@ package prog8tests
|
||||
import io.kotest.core.spec.style.FunSpec
|
||||
import io.kotest.matchers.shouldNotBe
|
||||
import prog8.code.core.ICompilationTarget
|
||||
import prog8.code.target.C64Target
|
||||
import prog8.code.target.Cx16Target
|
||||
import prog8.code.target.*
|
||||
import prog8.compiler.CompilationResult
|
||||
import prog8.compiler.CompilerArguments
|
||||
import prog8.compiler.compileProgram
|
||||
import prog8tests.helpers.assumeDirectory
|
||||
import prog8tests.helpers.cartesianProduct
|
||||
import prog8tests.helpers.outputDir
|
||||
import prog8tests.helpers.workingDir
|
||||
import prog8tests.helpers.*
|
||||
import prog8tests.helpers.compileText
|
||||
import java.nio.file.Path
|
||||
import kotlin.io.path.absolute
|
||||
import kotlin.io.path.exists
|
||||
import kotlin.io.path.readText
|
||||
|
||||
|
||||
/**
|
||||
@ -47,8 +45,11 @@ private fun compileTheThing(filepath: Path, optimize: Boolean, target: ICompilat
|
||||
|
||||
private fun prepareTestFiles(source: String, optimize: Boolean, target: ICompilationTarget): Pair<String, Path> {
|
||||
val searchIn = mutableListOf(examplesDir)
|
||||
if (target is Cx16Target) {
|
||||
searchIn.add(0, assumeDirectory(examplesDir, "cx16"))
|
||||
when (target) {
|
||||
is Cx16Target -> searchIn.add(0, assumeDirectory(examplesDir, "cx16"))
|
||||
is VMTarget -> searchIn.add(0, assumeDirectory(examplesDir, "vm"))
|
||||
is C128Target -> searchIn.add(0, assumeDirectory(examplesDir, "c128"))
|
||||
is AtariTarget -> searchIn.add(0, assumeDirectory(examplesDir, "atari"))
|
||||
}
|
||||
val filepath = searchIn.asSequence()
|
||||
.map { it.resolve("$source.p8") }
|
||||
@ -168,3 +169,24 @@ class TestCompilerOnExamplesBothC64andCx16: FunSpec({
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
class TestCompilerOnExamplesVirtual: FunSpec({
|
||||
|
||||
val onlyVirtual = listOf(
|
||||
"bouncegfx",
|
||||
"bsieve",
|
||||
"pixelshader",
|
||||
"sincos",
|
||||
"textelite"
|
||||
)
|
||||
|
||||
onlyVirtual.forEach {
|
||||
val target = VMTarget()
|
||||
val (displayName, filepath) = prepareTestFiles(it, false, target)
|
||||
test(displayName) {
|
||||
val src = filepath.readText()
|
||||
compileText(target, false, src, writeAssembly = true, keepIR=false) shouldNotBe null
|
||||
compileText(target, false, src, writeAssembly = true, keepIR=true) shouldNotBe null
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@ -28,6 +28,9 @@ main {
|
||||
val result = compileText(target, true, src, writeAssembly = true, keepIR=true)!!
|
||||
val virtfile = result.compilationOptions.outputDir.resolve(result.program.name + ".p8virt")
|
||||
VmRunner().runProgram(virtfile.readText())
|
||||
val result2 = compileText(target, true, src, writeAssembly = true, keepIR=false)!!
|
||||
val virtfile2 = result2.compilationOptions.outputDir.resolve(result2.program.name + ".p8virt")
|
||||
VmRunner().runProgram(virtfile2.readText())
|
||||
}
|
||||
|
||||
test("compile virtual: array with pointers") {
|
||||
@ -50,6 +53,9 @@ main {
|
||||
val result = compileText(target, true, src, writeAssembly = true, keepIR=true)!!
|
||||
val virtfile = result.compilationOptions.outputDir.resolve(result.program.name + ".p8virt")
|
||||
VmRunner().runProgram(virtfile.readText())
|
||||
val result2 = compileText(target, true, src, writeAssembly = true, keepIR=false)!!
|
||||
val virtfile2 = result2.compilationOptions.outputDir.resolve(result2.program.name + ".p8virt")
|
||||
VmRunner().runProgram(virtfile2.readText())
|
||||
}
|
||||
|
||||
test("compile virtual: str args and return type") {
|
||||
@ -68,6 +74,9 @@ main {
|
||||
val result = compileText(target, true, src, writeAssembly = true, keepIR=true)!!
|
||||
val virtfile = result.compilationOptions.outputDir.resolve(result.program.name + ".p8virt")
|
||||
VmRunner().runProgram(virtfile.readText())
|
||||
val result2 = compileText(target, true, src, writeAssembly = true, keepIR=false)!!
|
||||
val virtfile2 = result2.compilationOptions.outputDir.resolve(result2.program.name + ".p8virt")
|
||||
VmRunner().runProgram(virtfile2.readText())
|
||||
}
|
||||
|
||||
test("compile virtual: nested labels") {
|
||||
@ -108,6 +117,9 @@ mylabel_inside:
|
||||
val result = compileText(target, true, src, writeAssembly = true, keepIR=true)!!
|
||||
val virtfile = result.compilationOptions.outputDir.resolve(result.program.name + ".p8virt")
|
||||
VmRunner().runProgram(virtfile.readText())
|
||||
val result2 = compileText(target, true, src, writeAssembly = true, keepIR=false)!!
|
||||
val virtfile2 = result2.compilationOptions.outputDir.resolve(result2.program.name + ".p8virt")
|
||||
VmRunner().runProgram(virtfile2.readText())
|
||||
}
|
||||
|
||||
test("case sensitive symbols") {
|
||||
@ -136,5 +148,12 @@ skipLABEL:
|
||||
vm.memory.getUB(0) shouldBe 42u
|
||||
vm.memory.getUB(3) shouldBe 66u
|
||||
}
|
||||
|
||||
val result2 = compileText(target, true, src, writeAssembly = true, keepIR=false)!!
|
||||
val virtfile2 = result2.compilationOptions.outputDir.resolve(result2.program.name + ".p8virt")
|
||||
VmRunner().runAndTestProgram(virtfile2.readText()) { vm ->
|
||||
vm.memory.getUB(0) shouldBe 42u
|
||||
vm.memory.getUB(3) shouldBe 66u
|
||||
}
|
||||
}
|
||||
})
|
@ -3,9 +3,8 @@ TODO
|
||||
|
||||
For next release
|
||||
^^^^^^^^^^^^^^^^
|
||||
- fix vm symbol case insensitivity (TestCompilerVirtual)
|
||||
- fix vm crash in TestCompilerVirtual: array with pointers
|
||||
- fix vm crash (parseValue error) in examples/vm/textelite.p8 (Assembler, caused by above?)
|
||||
- fix vm assembler bug in TestCompilerVirtual when no IR code is written (IRWriter.writeVariableAllocations TODO)
|
||||
- fix examples/vm/textelite.p8 having wrong randomization? (starts with wrong planet)
|
||||
|
||||
...
|
||||
|
||||
@ -21,6 +20,7 @@ Future Things and Ideas
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Compiler:
|
||||
|
||||
- vm: get rid of p8virt format and Assembler, run p8ir directly
|
||||
- vm/ir: put variables and arrays in BSS section (unless -noreinit is specified)
|
||||
- vm: Jumps go to a code block rather than a specific address(label) -> also helps future dead code elimination?
|
||||
- vm: the above means that every label introduces a new code block. This eliminates the use of actual labels altogether.
|
||||
|
@ -14,7 +14,7 @@ main {
|
||||
|
||||
sub start() {
|
||||
txt.lowercase()
|
||||
txt.print("\u000c\n --- TextElite v1.2 ---\n")
|
||||
txt.print("--- TextElite v1.2 ---\n")
|
||||
txt.print("VirtualMachine edition: no disk saving, bad text layout!\n")
|
||||
|
||||
galaxy.travel_to(1, numforLave)
|
||||
|
@ -122,6 +122,7 @@ class IRFileWriter(private val irProgram: IRProgram) {
|
||||
if(it.number!=null)
|
||||
it.number!!.toInt().toString()
|
||||
else {
|
||||
// TODO : don't do a lookup; addressOf should be scoped properly already!
|
||||
val target = variable.lookup(it.addressOf!!)
|
||||
?: throw InternalCompilerException("symbol not found: ${it.addressOf} in ${variable.scopedName}")
|
||||
"&${target.scopedName.joinToString(".")}"
|
||||
|
@ -180,6 +180,18 @@ class Assembler {
|
||||
var fpReg3: Int? = null
|
||||
var value: Float? = null
|
||||
var operand: String?
|
||||
|
||||
fun parseValueOrPlaceholder(operand: String, pc: Int, rest: String, restIndex: Int, opcode: Opcode): Float {
|
||||
return if(operand.startsWith('_')) {
|
||||
placeholders[pc] = rest.split(",")[restIndex].trim().drop(1)
|
||||
0f
|
||||
} else if(operand[0].isLetter()) {
|
||||
placeholders[pc] = rest.split(",")[restIndex].trim()
|
||||
0f
|
||||
} else
|
||||
parseValue(opcode, operand, pc)
|
||||
}
|
||||
|
||||
if(operands.isNotEmpty() && operands[0].isNotEmpty()) {
|
||||
operand = operands.removeFirst().trim()
|
||||
if(operand[0]=='r')
|
||||
@ -187,13 +199,7 @@ class Assembler {
|
||||
else if(operand[0]=='f' && operand[1]=='r')
|
||||
fpReg1 = operand.substring(2).toInt()
|
||||
else {
|
||||
value = if(operand.startsWith('_')) {
|
||||
// it's a label, keep the original case!
|
||||
val labelname = rest.split(",").first().trim()
|
||||
parseValue(opcode, labelname, program.size)
|
||||
} else {
|
||||
parseValue(opcode, operand, program.size)
|
||||
}
|
||||
value = parseValueOrPlaceholder(operand, program.size, rest, 0, opcode)
|
||||
operands.clear()
|
||||
}
|
||||
if(operands.isNotEmpty()) {
|
||||
@ -203,7 +209,7 @@ class Assembler {
|
||||
else if(operand[0]=='f' && operand[1]=='r')
|
||||
fpReg2 = operand.substring(2).toInt()
|
||||
else {
|
||||
value = parseValue(opcode, operand, program.size)
|
||||
value = parseValueOrPlaceholder(operand, program.size, rest, 1, opcode)
|
||||
operands.clear()
|
||||
}
|
||||
if(operands.isNotEmpty()) {
|
||||
@ -213,13 +219,11 @@ class Assembler {
|
||||
else if(operand[0]=='f' && operand[1]=='r')
|
||||
fpReg3 = operand.substring(2).toInt()
|
||||
else {
|
||||
val symbol=rest.split(',').last()
|
||||
value = parseValue(opcode, symbol, program.size)
|
||||
value = parseValueOrPlaceholder(operand, program.size, rest, 2, opcode)
|
||||
operands.clear()
|
||||
}
|
||||
if(operands.isNotEmpty()) {
|
||||
val symbol=rest.split(',').last()
|
||||
value = parseValue(opcode, symbol, program.size)
|
||||
TODO("placeholder symbol? $operands rest=$rest'")
|
||||
operands.clear()
|
||||
}
|
||||
}
|
||||
@ -319,26 +323,18 @@ class Assembler {
|
||||
}
|
||||
|
||||
private fun parseValue(opcode: Opcode, value: String, pc: Int): Float {
|
||||
if(value.startsWith("-")) {
|
||||
return -parseValue(opcode, value.substring(1), pc)
|
||||
}
|
||||
if(value.startsWith('$'))
|
||||
return value.substring(1).toInt(16).toFloat()
|
||||
if(value.startsWith('%'))
|
||||
return value.substring(1).toInt(2).toFloat()
|
||||
if(value.startsWith("0x"))
|
||||
return value.substring(2).toInt(16).toFloat()
|
||||
if(value.startsWith('_')) {
|
||||
if(opcode !in OpcodesForCpuRegisters)
|
||||
placeholders[pc] = value.substring(1)
|
||||
return 0f
|
||||
}
|
||||
if(value[0].isLetter()) {
|
||||
if(opcode !in OpcodesForCpuRegisters)
|
||||
placeholders[pc] = value
|
||||
return 0f
|
||||
}
|
||||
return value.toFloat()
|
||||
return if(value.startsWith("-"))
|
||||
-parseValue(opcode, value.substring(1), pc)
|
||||
else if(value.startsWith('$'))
|
||||
value.substring(1).toInt(16).toFloat()
|
||||
else if(value.startsWith('%'))
|
||||
value.substring(1).toInt(2).toFloat()
|
||||
else if(value.startsWith("0x"))
|
||||
value.substring(2).toInt(16).toFloat()
|
||||
else if(value.startsWith('_') || value[0].isLetter())
|
||||
throw IllegalArgumentException("attempt to parse non-numeric value $value")
|
||||
else
|
||||
value.toFloat()
|
||||
}
|
||||
|
||||
private fun convertType(typestr: String): VmDataType? {
|
||||
|
@ -1,6 +1,7 @@
|
||||
package prog8.vm
|
||||
|
||||
import prog8.code.core.AssemblyError
|
||||
import java.lang.NumberFormatException
|
||||
import kotlin.math.min
|
||||
|
||||
/*
|
||||
@ -253,13 +254,23 @@ object SysCalls {
|
||||
}
|
||||
Syscall.STR_TO_UWORD -> {
|
||||
val stringAddr = vm.registers.getUW(0)
|
||||
val string = vm.memory.getString(stringAddr.toInt())
|
||||
vm.registers.setUW(0, string.toUShort())
|
||||
val string = vm.memory.getString(stringAddr.toInt()).takeWhile { it.isDigit() }
|
||||
val value = try {
|
||||
string.toUShort()
|
||||
} catch(_: NumberFormatException) {
|
||||
0u
|
||||
}
|
||||
vm.registers.setUW(0, value)
|
||||
}
|
||||
Syscall.STR_TO_WORD -> {
|
||||
val stringAddr = vm.registers.getUW(0)
|
||||
val string = vm.memory.getString(stringAddr.toInt())
|
||||
vm.registers.setSW(0, string.toShort())
|
||||
val string = vm.memory.getString(stringAddr.toInt()).takeWhile { it.isDigit() }
|
||||
val value = try {
|
||||
string.toShort()
|
||||
} catch(_: NumberFormatException) {
|
||||
0
|
||||
}
|
||||
vm.registers.setSW(0, value)
|
||||
}
|
||||
Syscall.COMPARE_STRINGS -> {
|
||||
val firstAddr = vm.registers.getUW(0)
|
||||
|
Loading…
Reference in New Issue
Block a user