mirror of
https://github.com/irmen/prog8.git
synced 2024-09-07 19:54:26 +00:00
vm: add sorting and reverse functions, fix value arg out of range errors
This commit is contained in:
parent
d78bfcc35c
commit
8e4c0f7c22
@ -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)
|
||||||
|
@ -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))
|
||||||
|
@ -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
|
||||||
|
@ -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.
|
||||||
|
@ -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('%'))
|
||||||
|
@ -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
|
||||||
|
@ -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}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user