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

View File

@ -1,8 +1,12 @@
package prog8.codegen.virtual
import prog8.code.StArray
import prog8.code.StStaticVariable
import prog8.code.ast.PtBuiltinFunctionCall
import prog8.code.ast.PtIdentifier
import prog8.code.ast.PtNumber
import prog8.code.ast.PtString
import prog8.code.core.DataType
import prog8.code.core.WordDatatypes
import prog8.vm.Opcode
import prog8.vm.Syscall
@ -127,6 +131,37 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
if(resultRegister!=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 -> {
TODO("builtinfunc ${call.name}")
// code += VmCodeInstruction(Opcode.NOP))

View File

@ -3,6 +3,7 @@ TODO
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.
- 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

View File

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

View File

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

View File

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

View File

@ -22,6 +22,12 @@ SYSCALLS:
13 = waitvsync ; wait on vsync
14 = sin8u
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 {
@ -40,7 +46,13 @@ enum class Syscall {
WAIT,
WAITVSYNC,
SIN8U,
COS8U
COS8U,
SORT_UBYTE,
SORT_BYTE,
SORT_UWORD,
SORT_WORD,
REVERSE_BYTES,
REVERSE_WORDS
}
object SysCalls {
@ -107,6 +119,66 @@ object SysCalls {
val answer = truncate(128.0 + 127.5 * cos(rad))
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}")
}
}