vm: add sorting and reverse functions, fix value arg out of range errors

This commit is contained in:
Irmen de Jong 2022-04-05 17:48:49 +02:00
parent d78bfcc35c
commit 8e4c0f7c22
7 changed files with 125 additions and 4 deletions

View File

@ -4,6 +4,7 @@ import prog8.code.core.CompilationOptions
import prog8.code.core.IAssemblyProgram import prog8.code.core.IAssemblyProgram
import prog8.vm.Instruction import prog8.vm.Instruction
import prog8.vm.Opcode import prog8.vm.Opcode
import prog8.vm.OpcodesWithAddress
import prog8.vm.VmDataType import prog8.vm.VmDataType
import java.io.BufferedWriter import java.io.BufferedWriter
import kotlin.io.path.bufferedWriter import kotlin.io.path.bufferedWriter
@ -66,7 +67,7 @@ internal class VmCodeInstruction(
val ins = Instruction(opcode, type, reg1, reg2, reg3, value, symbol) val ins = Instruction(opcode, type, reg1, reg2, reg3, value, symbol)
init { init {
if(value!=null) { if(value!=null && opcode !in OpcodesWithAddress) {
when (type) { when (type) {
VmDataType.BYTE -> { VmDataType.BYTE -> {
if (value < -128 || value > 255) if (value < -128 || value > 255)

View File

@ -1,8 +1,12 @@
package prog8.codegen.virtual package prog8.codegen.virtual
import prog8.code.StArray
import prog8.code.StStaticVariable
import prog8.code.ast.PtBuiltinFunctionCall import prog8.code.ast.PtBuiltinFunctionCall
import prog8.code.ast.PtIdentifier
import prog8.code.ast.PtNumber import prog8.code.ast.PtNumber
import prog8.code.ast.PtString import prog8.code.ast.PtString
import prog8.code.core.DataType
import prog8.code.core.WordDatatypes import prog8.code.core.WordDatatypes
import prog8.vm.Opcode import prog8.vm.Opcode
import prog8.vm.Syscall import prog8.vm.Syscall
@ -127,6 +131,37 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
if(resultRegister!=0) if(resultRegister!=0)
code += VmCodeInstruction(Opcode.LOADR, VmDataType.BYTE, reg1=resultRegister, reg2=0) code += VmCodeInstruction(Opcode.LOADR, VmDataType.BYTE, reg1=resultRegister, reg2=0)
} }
"sort" -> {
val arrayName = call.args[0] as PtIdentifier
val array = codeGen.symbolTable.flat.getValue(arrayName.targetName) as StStaticVariable
val sortSyscall =
when(array.dt) {
DataType.ARRAY_UB -> Syscall.SORT_UBYTE
DataType.ARRAY_B -> Syscall.SORT_BYTE
DataType.ARRAY_UW -> Syscall.SORT_UWORD
DataType.ARRAY_W -> Syscall.SORT_WORD
DataType.FLOAT -> TODO("float sort")
DataType.STR -> Syscall.SORT_UBYTE
else -> throw IllegalArgumentException("weird type to sort")
}
code += exprGen.translateExpression(call.args[0], 0)
code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=1, value=array.length)
code += VmCodeInstruction(Opcode.SYSCALL, value=sortSyscall.ordinal)
}
"reverse" -> {
val arrayName = call.args[0] as PtIdentifier
val array = codeGen.symbolTable.flat.getValue(arrayName.targetName) as StStaticVariable
val sortSyscall =
when(array.dt) {
DataType.ARRAY_UB, DataType.ARRAY_B, DataType.STR -> Syscall.REVERSE_BYTES
DataType.ARRAY_UW, DataType.ARRAY_W -> Syscall.REVERSE_WORDS
DataType.FLOAT -> TODO("reverse floats")
else -> throw IllegalArgumentException("weird type to reverse")
}
code += exprGen.translateExpression(call.args[0], 0)
code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=1, value=array.length)
code += VmCodeInstruction(Opcode.SYSCALL, value=sortSyscall.ordinal)
}
else -> { else -> {
TODO("builtinfunc ${call.name}") TODO("builtinfunc ${call.name}")
// code += VmCodeInstruction(Opcode.NOP)) // code += VmCodeInstruction(Opcode.NOP))

View File

@ -3,6 +3,7 @@ TODO
For next release For next release
^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^
- add -vm option to load an existing p8virt file directly in the virtual machine
- pipe operator: allow non-unary function calls in the pipe that specify the other argument(s) in the calls. - pipe operator: allow non-unary function calls in the pipe that specify the other argument(s) in the calls.
- writeAssembly(): make it possible to actually get rid of the VarDecl nodes by fixing the rest of the code mentioned there. - writeAssembly(): make it possible to actually get rid of the VarDecl nodes by fixing the rest of the code mentioned there.
- allow "xxx" * constexpr (where constexpr is not a number literal), now gives expression error not same type - allow "xxx" * constexpr (where constexpr is not a number literal), now gives expression error not same type

View File

@ -1,5 +1,4 @@
%import textio %import textio
%import test_stack
%zeropage basicsafe %zeropage basicsafe
; Note: this program is compatible with C64 and CX16. ; Note: this program is compatible with C64 and CX16.

View File

@ -132,7 +132,7 @@ class Assembler {
throw IllegalArgumentException("invalid reg3 for $line") throw IllegalArgumentException("invalid reg3 for $line")
if(!format.value && value!=null) if(!format.value && value!=null)
throw IllegalArgumentException("invalid value for $line") throw IllegalArgumentException("invalid value for $line")
if(value!=null) { if(value!=null && opcode !in OpcodesWithAddress) {
when (type) { when (type) {
VmDataType.BYTE -> { VmDataType.BYTE -> {
if (value < -128 || value > 255) if (value < -128 || value > 255)
@ -161,6 +161,9 @@ class Assembler {
} }
private fun parseValue(value: String, pc: Int): Int { private fun parseValue(value: String, pc: Int): Int {
if(value.startsWith("-")) {
return -parseValue(value.substring(1), pc)
}
if(value.startsWith('$')) if(value.startsWith('$'))
return value.substring(1).toInt(16) return value.substring(1).toInt(16)
if(value.startsWith('%')) if(value.startsWith('%'))

View File

@ -214,6 +214,16 @@ enum class Opcode {
BREAKPOINT BREAKPOINT
} }
val OpcodesWithAddress = setOf(
Opcode.LOADM,
Opcode.LOADX,
Opcode.STOREM,
Opcode.STOREX,
Opcode.STOREZ,
Opcode.STOREZX
)
enum class VmDataType { enum class VmDataType {
BYTE, BYTE,
WORD WORD

View File

@ -22,6 +22,12 @@ SYSCALLS:
13 = waitvsync ; wait on vsync 13 = waitvsync ; wait on vsync
14 = sin8u 14 = sin8u
15 = cos8u 15 = cos8u
16 = sort_ubyte array
17 = sort_byte array
18 = sort_uword array
19 = sort_word array
20 = reverse_bytes array
21 = reverse_words array
*/ */
enum class Syscall { enum class Syscall {
@ -40,7 +46,13 @@ enum class Syscall {
WAIT, WAIT,
WAITVSYNC, WAITVSYNC,
SIN8U, SIN8U,
COS8U COS8U,
SORT_UBYTE,
SORT_BYTE,
SORT_UWORD,
SORT_WORD,
REVERSE_BYTES,
REVERSE_WORDS
} }
object SysCalls { object SysCalls {
@ -107,6 +119,66 @@ object SysCalls {
val answer = truncate(128.0 + 127.5 * cos(rad)) val answer = truncate(128.0 + 127.5 * cos(rad))
vm.registers.setUB(0, answer.toUInt().toUByte()) vm.registers.setUB(0, answer.toUInt().toUByte())
} }
Syscall.SORT_UBYTE -> {
val address = vm.registers.getUW(0).toInt()
val length = vm.registers.getUB(1).toInt()
val array = IntProgression.fromClosedRange(address, address+length-1, 1).map {
vm.memory.getUB(it)
}.sorted()
array.withIndex().forEach { (index, value)->
vm.memory.setUB(address+index, value)
}
}
Syscall.SORT_BYTE -> {
val address = vm.registers.getUW(0).toInt()
val length = vm.registers.getUB(1).toInt()
val array = IntProgression.fromClosedRange(address, address+length-1, 1).map {
vm.memory.getSB(it)
}.sorted()
array.withIndex().forEach { (index, value)->
vm.memory.setSB(address+index, value)
}
}
Syscall.SORT_UWORD -> {
val address = vm.registers.getUW(0).toInt()
val length = vm.registers.getUB(1).toInt()
val array = IntProgression.fromClosedRange(address, address+length*2-2, 2).map {
vm.memory.getUW(it)
}.sorted()
array.withIndex().forEach { (index, value)->
vm.memory.setUW(address+index*2, value)
}
}
Syscall.SORT_WORD -> {
val address = vm.registers.getUW(0).toInt()
val length = vm.registers.getUB(1).toInt()
val array = IntProgression.fromClosedRange(address, address+length*2-2, 2).map {
vm.memory.getSW(it)
}.sorted()
array.withIndex().forEach { (index, value)->
vm.memory.setSW(address+index*2, value)
}
}
Syscall.REVERSE_BYTES -> {
val address = vm.registers.getUW(0).toInt()
val length = vm.registers.getUB(1).toInt()
val array = IntProgression.fromClosedRange(address, address+length-1, 1).map {
vm.memory.getUB(it)
}.reversed()
array.withIndex().forEach { (index, value)->
vm.memory.setUB(address+index, value)
}
}
Syscall.REVERSE_WORDS -> {
val address = vm.registers.getUW(0).toInt()
val length = vm.registers.getUB(1).toInt()
val array = IntProgression.fromClosedRange(address, address+length*2-2, 2).map {
vm.memory.getUW(it)
}.reversed()
array.withIndex().forEach { (index, value)->
vm.memory.setUW(address+index*2, value)
}
}
else -> TODO("syscall ${call.name}") else -> TODO("syscall ${call.name}")
} }
} }