mirror of
https://github.com/irmen/prog8.git
synced 2024-10-25 00:24:16 +00:00
vm: fix instruction type checks
This commit is contained in:
parent
0fab806f36
commit
f4993d6e5d
@ -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")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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()) {
|
||||||
|
Loading…
Reference in New Issue
Block a user