vm: fix instruction type checks

This commit is contained in:
Irmen de Jong 2022-04-28 21:46:24 +02:00
parent 0fab806f36
commit f4993d6e5d
2 changed files with 54 additions and 25 deletions

View File

@ -21,7 +21,7 @@ class Assembler {
throw IllegalArgumentException("invalid line $line") throw IllegalArgumentException("invalid line $line")
else { else {
val (_, addr, what, values) = match.groupValues val (_, addr, what, values) = match.groupValues
var address = parseValue(addr, 0) var address = parseValue(addr, 0).toInt()
when(what) { when(what) {
"str" -> { "str" -> {
val string = values.trim('"').unescape() val string = values.trim('"').unescape()
@ -32,14 +32,14 @@ class Assembler {
memory.setString(address, string, true) memory.setString(address, string, true)
} }
"ubyte", "byte" -> { "ubyte", "byte" -> {
val array = values.split(',').map { parseValue(it.trim(), 0) } val array = values.split(',').map { parseValue(it.trim(), 0).toInt() }
for (value in array) { for (value in array) {
memory.setUB(address, value.toUByte()) memory.setUB(address, value.toUByte())
address++ address++
} }
} }
"uword", "word" -> { "uword", "word" -> {
val array = values.split(',').map { parseValue(it.trim(), 0) } val array = values.split(',').map { parseValue(it.trim(), 0).toInt() }
for (value in array) { for (value in array) {
memory.setUW(address, value.toUShort()) memory.setUW(address, value.toUShort())
address += 2 address += 2
@ -62,7 +62,7 @@ class Assembler {
labels.clear() labels.clear()
placeholders.clear() placeholders.clear()
val program = mutableListOf<Instruction>() val program = mutableListOf<Instruction>()
val instructionPattern = Regex("""([a-z]+)(\.b|\.w)?(.*)""", RegexOption.IGNORE_CASE) val instructionPattern = Regex("""([a-z]+)(\.b|\.w|\.f)?(.*)""", RegexOption.IGNORE_CASE)
val labelPattern = Regex("""_([a-z0-9\._]+):""") val labelPattern = Regex("""_([a-z0-9\._]+):""")
for (line in source.lines()) { for (line in source.lines()) {
if(line.isBlank() || line.startsWith(';')) if(line.isBlank() || line.startsWith(';'))
@ -86,12 +86,17 @@ class Assembler {
var reg1: Int? = null var reg1: Int? = null
var reg2: Int? = null var reg2: Int? = null
var reg3: Int? = null var reg3: Int? = null
var value: Int? = null var fpReg1: Int? = null
var fpReg2: Int? = null
var fpReg3: Int? = null
var value: Float? = null
var operand: String? var operand: String?
if(operands.isNotEmpty() && operands[0].isNotEmpty()) { if(operands.isNotEmpty() && operands[0].isNotEmpty()) {
operand = operands.removeFirst().trim() operand = operands.removeFirst().trim()
if(operand[0]=='r') if(operand[0]=='r')
reg1 = operand.substring(1).toInt() reg1 = operand.substring(1).toInt()
else if(operand[0]=='f' && operand[1]=='r')
fpReg1 = operand.substring(2).toInt()
else { else {
value = parseValue(operand, program.size) value = parseValue(operand, program.size)
operands.clear() operands.clear()
@ -100,6 +105,8 @@ class Assembler {
operand = operands.removeFirst().trim() operand = operands.removeFirst().trim()
if(operand[0]=='r') if(operand[0]=='r')
reg2 = operand.substring(1).toInt() reg2 = operand.substring(1).toInt()
else if(operand[0]=='f' && operand[1]=='r')
fpReg2 = operand.substring(2).toInt()
else { else {
value = parseValue(operand, program.size) value = parseValue(operand, program.size)
operands.clear() operands.clear()
@ -108,6 +115,8 @@ class Assembler {
operand = operands.removeFirst().trim() operand = operands.removeFirst().trim()
if(operand[0]=='r') if(operand[0]=='r')
reg3 = operand.substring(1).toInt() reg3 = operand.substring(1).toInt()
else if(operand[0]=='f' && operand[1]=='r')
fpReg3 = operand.substring(2).toInt()
else { else {
value = parseValue(operand, program.size) value = parseValue(operand, program.size)
operands.clear() operands.clear()
@ -147,8 +156,6 @@ class Assembler {
throw IllegalArgumentException("invalid reg2 for $line") throw IllegalArgumentException("invalid reg2 for $line")
if(!format.reg3 && reg3!=null) if(!format.reg3 && reg3!=null)
throw IllegalArgumentException("invalid reg3 for $line") throw IllegalArgumentException("invalid reg3 for $line")
if(!format.value && value!=null)
throw IllegalArgumentException("invalid value for $line")
if(value!=null && opcode !in OpcodesWithAddress) { if(value!=null && opcode !in OpcodesWithAddress) {
when (type) { when (type) {
VmDataType.BYTE -> { VmDataType.BYTE -> {
@ -165,7 +172,18 @@ class Assembler {
null -> {} null -> {}
} }
} }
program.add(Instruction(opcode, type, reg1, reg2, reg3, value=value)) var floatValue: Float? = null
var intValue: Int? = null
if(type==VmDataType.FLOAT)
floatValue = value // TODO NOT ALWAYS CORRECT, SOMETIMES IT IS THE INT VALUE
else
intValue = value?.toInt()
if(!format.value && intValue!=null)
throw IllegalArgumentException("invalid int value for $line")
if(!format.fpValue && floatValue!=null)
throw IllegalArgumentException("invalid float value for $line")
program.add(Instruction(opcode, type, reg1, reg2, reg3, fpReg1, fpReg2, fpReg3, value = intValue, fpValue = floatValue))
} }
} }
@ -180,21 +198,21 @@ class Assembler {
} }
} }
private fun parseValue(value: String, pc: Int): Int { private fun parseValue(value: String, pc: Int): Float {
if(value.startsWith("-")) { if(value.startsWith("-")) {
return -parseValue(value.substring(1), pc) return -parseValue(value.substring(1), pc)
} }
if(value.startsWith('$')) if(value.startsWith('$'))
return value.substring(1).toInt(16) return value.substring(1).toInt(16).toFloat()
if(value.startsWith('%')) if(value.startsWith('%'))
return value.substring(1).toInt(2) return value.substring(1).toInt(2).toFloat()
if(value.startsWith("0x")) if(value.startsWith("0x"))
return value.substring(2).toInt(16) return value.substring(2).toInt(16).toFloat()
if(value.startsWith('_')) { if(value.startsWith('_')) {
placeholders[pc] = value.substring(1) placeholders[pc] = value.substring(1)
return 0 return 0f
} }
return value.toInt() return value.toFloat()
} }
private fun convertType(typestr: String): VmDataType? { private fun convertType(typestr: String): VmDataType? {
@ -202,6 +220,7 @@ class Assembler {
"" -> null "" -> null
".b" -> VmDataType.BYTE ".b" -> VmDataType.BYTE
".w" -> VmDataType.WORD ".w" -> VmDataType.WORD
".f" -> VmDataType.FLOAT
else -> throw IllegalArgumentException("invalid type $typestr") else -> throw IllegalArgumentException("invalid type $typestr")
} }
} }

View File

@ -298,16 +298,25 @@ data class Instruction(
if(format.reg1 && reg1==null || if(format.reg1 && reg1==null ||
format.reg2 && reg2==null || format.reg2 && reg2==null ||
format.reg3 && reg3==null) format.reg3 && reg3==null)
throw IllegalArgumentException("missing a register") throw IllegalArgumentException("missing a register (int)")
if(format.fpReg1 && fpReg1==null ||
format.fpReg2 && fpReg2==null ||
format.fpReg3 && fpReg3==null)
throw IllegalArgumentException("missing a register (float)")
if(!format.reg1 && reg1!=null || if(!format.reg1 && reg1!=null ||
!format.reg2 && reg2!=null || !format.reg2 && reg2!=null ||
!format.reg3 && reg3!=null) !format.reg3 && reg3!=null)
throw IllegalArgumentException("too many registers") throw IllegalArgumentException("too many registers (int)")
if(!format.fpReg1 && fpReg1!=null ||
!format.fpReg2 && fpReg2!=null ||
!format.fpReg3 && fpReg3!=null)
throw IllegalArgumentException("too many registers (float)")
if (type==VmDataType.FLOAT) { if (type==VmDataType.FLOAT) {
if(format.value && (fpValue==null && symbol==null)) if(format.fpValue && (fpValue==null && symbol==null))
throw IllegalArgumentException("$opcode: missing a fp-value or symbol") throw IllegalArgumentException("$opcode: missing a fp-value or symbol")
if (reg1 != null || reg2 != null || reg3 != null) if (reg1 != null || reg2 != null || reg3 != null)
throw java.lang.IllegalArgumentException("$opcode: floating point instruction can't use integer registers") throw java.lang.IllegalArgumentException("$opcode: floating point instruction can't use integer registers")
@ -325,6 +334,7 @@ data class Instruction(
when(type) { when(type) {
VmDataType.BYTE -> result.add(".b ") VmDataType.BYTE -> result.add(".b ")
VmDataType.WORD -> result.add(".w ") VmDataType.WORD -> result.add(".w ")
VmDataType.FLOAT -> result.add(".f ")
else -> result.add(" ") else -> result.add(" ")
} }
reg1?.let { reg1?.let {
@ -376,15 +386,15 @@ data class InstructionFormat(val datatype: VmDataType?,
companion object { companion object {
fun from(spec: String): Map<VmDataType?, InstructionFormat> { fun from(spec: String): Map<VmDataType?, InstructionFormat> {
val result = mutableMapOf<VmDataType?, InstructionFormat>() val result = mutableMapOf<VmDataType?, InstructionFormat>()
var reg1 = false
var reg2 = false
var reg3 = false
var fpreg1 = false
var fpreg2 = false
var fpreg3 = false
var value = false
var fpvalue = false
for(part in spec.split('|').map{ it.trim() }) { for(part in spec.split('|').map{ it.trim() }) {
var reg1 = false
var reg2 = false
var reg3 = false
var fpreg1 = false
var fpreg2 = false
var fpreg3 = false
var value = false
var fpvalue = false
val splits = part.splitToSequence(',').iterator() val splits = part.splitToSequence(',').iterator()
val typespec = splits.next() val typespec = splits.next()
while(splits.hasNext()) { while(splits.hasNext()) {