IR: support for multi-returnvalue function calls (asmsubs)

note: the VM can't execute these though as it has no CPU hardware registers
This commit is contained in:
Irmen de Jong 2024-03-23 00:20:12 +01:00
parent 03e486c082
commit 2e37f5dee3
8 changed files with 168 additions and 146 deletions

View File

@ -23,13 +23,16 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
if(funcCall.multipleResultFpRegs.isNotEmpty()) if(funcCall.multipleResultFpRegs.isNotEmpty())
TODO("deal with (multiple?) FP return registers") TODO("deal with (multiple?) FP return registers")
TODO("add to result multi return regs from expression") // because we can only handle integer results right now we can just zip() it all up
// addToResult(result, funcCall, funcCall.resultReg, funcCall.resultFpReg) addToResult(result, funcCall, funcCall.resultReg, funcCall.resultFpReg)
// sub.returns.zip(assignment.children).forEach { (returns, target) -> sub.returns.zip(assignment.children).zip(funcCall.multipleResultRegs).forEach {
// result += assignCpuRegister(returns, funcCall, target as PtAssignTarget) val regNumber = it.second
// } val returns = it.first.first
// result.filterIsInstance<IRCodeChunk>().firstOrNull()?.appendSrcPosition(assignment.position) val target = it.first.second as PtAssignTarget
// return result result += assignCpuRegister(returns, regNumber, target)
}
result.filterIsInstance<IRCodeChunk>().firstOrNull()?.appendSrcPosition(assignment.position)
return result
} else { } else {
if (assignment.target.children.single() is PtIrRegister) if (assignment.target.children.single() is PtIrRegister)
throw AssemblyError("assigning to a register should be done by just evaluating the expression into resultregister") throw AssemblyError("assigning to a register should be done by just evaluating the expression into resultregister")
@ -40,46 +43,31 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
} }
} }
private fun assignCpuRegister(returns: StRomSubParameter, target: PtAssignTarget): IRCodeChunk { private fun assignCpuRegister(returns: StRomSubParameter, regNum: Int, target: PtAssignTarget): IRCodeChunks {
val targetIdentifier = target.identifier val result = mutableListOf<IRCodeChunkBase>()
val chunk = IRCodeChunk(null, null) val loadCpuRegInstr = when(returns.register.registerOrPair) {
if(targetIdentifier!=null) { RegisterOrPair.A -> IRInstruction(Opcode.LOADHA, IRDataType.BYTE, reg1=regNum)
TODO() RegisterOrPair.X -> IRInstruction(Opcode.LOADHX, IRDataType.BYTE, reg1=regNum)
val regNum = 4242 // TODO?? RegisterOrPair.Y -> IRInstruction(Opcode.LOADHY, IRDataType.BYTE, reg1=regNum)
when(returns.register.registerOrPair) { RegisterOrPair.AX -> IRInstruction(Opcode.LOADHAX, IRDataType.WORD, reg1=regNum)
RegisterOrPair.A -> chunk += IRInstruction(Opcode.LOADHA, IRDataType.BYTE, reg1=regNum) RegisterOrPair.AY -> IRInstruction(Opcode.LOADHAY, IRDataType.WORD, reg1=regNum)
RegisterOrPair.X -> chunk += IRInstruction(Opcode.LOADHX, IRDataType.BYTE, reg1=regNum) RegisterOrPair.XY -> IRInstruction(Opcode.LOADHXY, IRDataType.WORD, reg1=regNum)
RegisterOrPair.Y -> chunk += IRInstruction(Opcode.LOADHY, IRDataType.BYTE, reg1=regNum) null -> {
RegisterOrPair.AX -> chunk += IRInstruction(Opcode.LOADHAX, IRDataType.WORD, reg1=regNum) when(returns.register.statusflag) {
RegisterOrPair.AY -> chunk += IRInstruction(Opcode.LOADHAY, IRDataType.WORD, reg1=regNum) Statusflag.Pc -> IRInstruction(Opcode.LOADHA, IRDataType.BYTE, reg1=regNum)
RegisterOrPair.XY -> chunk += IRInstruction(Opcode.LOADHXY, IRDataType.WORD, reg1=regNum) else -> throw AssemblyError("weird statusflag as returnvalue")
null -> {
when(returns.register.statusflag) {
Statusflag.Pc -> chunk += IRInstruction(Opcode.LOADHA, IRDataType.BYTE, reg1=regNum)
else -> throw AssemblyError("weird statusflag as returnvalue")
}
} }
else -> throw AssemblyError("cannot load register")
} }
chunk += IRInstruction(Opcode.STOREM, irType(target.type), reg1=regNum, labelSymbol = targetIdentifier.name) else -> throw AssemblyError("cannot load register")
return chunk
} }
val targetMem = target.memory addInstr(result, loadCpuRegInstr, null)
if(targetMem!=null) {
TODO("assign $returns to $targetMem") // build an assignment to store the value in the actual target.
return chunk val assign = PtAssignment(target.position)
} assign.add(target)
val targetArray = target.array assign.add(PtIrRegister(regNum, target.type, target.position))
if(targetArray!=null) { result += translate(assign)
TODO("assign $returns to $targetArray") return result
return chunk
}
throw AssemblyError("weird target")
// val singleAssign = PtAssignment(target.position)
// singleAssign.children.add(target)
// TODO("use the new IR instructions to store machine regs STOREHxx ${target.position}")
// singleAssign.children.add(PtMachineRegister(4242, returns.type, assignment.position))
// result += translateRegularAssign(singleAssign)
} }
internal fun translate(augAssign: PtAugmentedAssign): IRCodeChunks { internal fun translate(augAssign: PtAugmentedAssign): IRCodeChunks {

View File

@ -466,7 +466,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
argRegisters.add(FunctionCallArgs.ArgumentSpec(parameter.name, null, FunctionCallArgs.RegSpec(paramDt, tr.resultReg, null))) argRegisters.add(FunctionCallArgs.ArgumentSpec(parameter.name, null, FunctionCallArgs.RegSpec(paramDt, tr.resultReg, null)))
result += tr.chunks result += tr.chunks
} }
// return value // return value (always singular for normal Subs)
val returnRegSpec = if(fcall.void) null else { val returnRegSpec = if(fcall.void) null else {
val returnIrType = irType(callTarget.returnType!!) val returnIrType = irType(callTarget.returnType!!)
if(returnIrType==IRDataType.FLOAT) if(returnIrType==IRDataType.FLOAT)
@ -475,7 +475,8 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
FunctionCallArgs.RegSpec(returnIrType, codeGen.registers.nextFree(), null) FunctionCallArgs.RegSpec(returnIrType, codeGen.registers.nextFree(), null)
} }
// create the call // create the call
addInstr(result, IRInstruction(Opcode.CALL, labelSymbol = fcall.name, fcallArgs = FunctionCallArgs(argRegisters, returnRegSpec)), null) addInstr(result, IRInstruction(Opcode.CALL, labelSymbol = fcall.name,
fcallArgs = FunctionCallArgs(argRegisters, if(returnRegSpec==null) emptyList() else listOf(returnRegSpec))), null)
return if(fcall.void) return if(fcall.void)
ExpressionCodeResult(result, IRDataType.BYTE, -1, -1) ExpressionCodeResult(result, IRDataType.BYTE, -1, -1)
else if(fcall.type==DataType.FLOAT) else if(fcall.type==DataType.FLOAT)
@ -516,34 +517,37 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
} }
if(callTarget.returns.size>1) if(callTarget.returns.size>1)
return callWithMultipleReturnValues() return callRomSubWithMultipleReturnValues(callTarget, fcall, argRegisters, result)
// return a single value // return a single value (or nothing)
var statusFlagResult: Statusflag? = null
val returnRegSpec = if(fcall.void) null else { val returnRegSpec = if(fcall.void) null else {
if(callTarget.returns.isEmpty()) if(callTarget.returns.isEmpty())
null null
val returns = callTarget.returns[0]
val returnIrType = irType(returns.type)
if(returnIrType==IRDataType.FLOAT)
FunctionCallArgs.RegSpec(returnIrType, codeGen.registers.nextFreeFloat(), returns.register)
else { else {
val returnRegister = codeGen.registers.nextFree() val returns = callTarget.returns[0]
FunctionCallArgs.RegSpec(returnIrType, returnRegister, returns.register) val returnIrType = irType(returns.type)
if (returnIrType == IRDataType.FLOAT)
FunctionCallArgs.RegSpec(returnIrType, codeGen.registers.nextFreeFloat(), returns.register)
else {
val returnRegister = codeGen.registers.nextFree()
FunctionCallArgs.RegSpec(returnIrType, returnRegister, returns.register)
}
} }
} }
// create the call // create the call
val returnRegs = if(returnRegSpec==null) emptyList() else listOf(returnRegSpec)
val call = val call =
if(callTarget.address==null) if(callTarget.address==null)
IRInstruction(Opcode.CALL, labelSymbol = fcall.name, fcallArgs = FunctionCallArgs(argRegisters, returnRegSpec)) IRInstruction(Opcode.CALL, labelSymbol = fcall.name, fcallArgs = FunctionCallArgs(argRegisters, returnRegs))
else else
IRInstruction(Opcode.CALL, address = callTarget.address!!.toInt(), fcallArgs = FunctionCallArgs(argRegisters, returnRegSpec)) IRInstruction(Opcode.CALL, address = callTarget.address!!.toInt(), fcallArgs = FunctionCallArgs(argRegisters, returnRegs))
addInstr(result, call, null) addInstr(result, call, null)
var finalReturnRegister = returnRegSpec?.registerNum ?: -1 var finalReturnRegister = returnRegSpec?.registerNum ?: -1
if(fcall.parent is PtAssignment || fcall.parent is PtTypeCast) { if(fcall.parent is PtAssignment || fcall.parent is PtTypeCast) {
// look if the status flag bit should actually be returned as a 0/1 byte value in a result register (so it can be assigned) // look if the status flag bit should actually be returned as a 0/1 byte value in a result register (so it can be assigned)
if(statusFlagResult!=null && returnRegSpec!=null) { val statusFlagResult = returnRegSpec?.cpuRegister?.statusflag
if(statusFlagResult!=null) {
// assign status flag bit to the return value register // assign status flag bit to the return value register
finalReturnRegister = returnRegSpec.registerNum finalReturnRegister = returnRegSpec.registerNum
if(finalReturnRegister<0) if(finalReturnRegister<0)
@ -586,8 +590,27 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
} }
} }
private fun callWithMultipleReturnValues(): ExpressionCodeResult { private fun callRomSubWithMultipleReturnValues(
TODO("call with multiple return values") callTarget: StRomSub,
fcall: PtFunctionCall,
argRegisters: MutableList<FunctionCallArgs.ArgumentSpec>,
result: MutableList<IRCodeChunkBase>
): ExpressionCodeResult {
// return multiple values
val returnRegisters = callTarget.returns.map {
val regnum = if(it.type==DataType.FLOAT) codeGen.registers.nextFreeFloat() else codeGen.registers.nextFree()
FunctionCallArgs.RegSpec(irType(it.type), regnum, it.register)
}
// create the call
val call =
if(callTarget.address==null)
IRInstruction(Opcode.CALL, labelSymbol = fcall.name, fcallArgs = FunctionCallArgs(argRegisters, returnRegisters))
else
IRInstruction(Opcode.CALL, address = callTarget.address!!.toInt(), fcallArgs = FunctionCallArgs(argRegisters, returnRegisters))
addInstr(result, call, null)
val resultRegs = returnRegisters.filter{it.dt!=IRDataType.FLOAT}.map{it.registerNum}
val resultFpRegs = returnRegisters.filter{it.dt==IRDataType.FLOAT}.map{it.registerNum}
return ExpressionCodeResult(result, IRDataType.BYTE, -1, -1, resultRegs, resultFpRegs)
} }
private fun operatorGreaterThan( private fun operatorGreaterThan(

View File

@ -1650,7 +1650,8 @@ class IRCodeGen(
val args = params.map { (dt, reg)-> val args = params.map { (dt, reg)->
FunctionCallArgs.ArgumentSpec("", null, FunctionCallArgs.RegSpec(dt, reg, null)) FunctionCallArgs.ArgumentSpec("", null, FunctionCallArgs.RegSpec(dt, reg, null))
} }
val returnSpec = if(returns==null) null else FunctionCallArgs.RegSpec(returns.first, returns.second, null) // for now, syscalls have 0 or 1 return value
val returnSpec = if(returns==null) emptyList() else listOf(FunctionCallArgs.RegSpec(returns.first, returns.second, null))
it += IRInstruction(Opcode.SYSCALL, immediate = syscall.number, fcallArgs = FunctionCallArgs(args, returnSpec)) it += IRInstruction(Opcode.SYSCALL, immediate = syscall.number, fcallArgs = FunctionCallArgs(args, returnSpec))
} }
} }

View File

@ -1,6 +1,9 @@
TODO TODO
==== ====
6502 codegen: make multi return value asmsub calls work.
... ...

View File

@ -777,7 +777,7 @@ val instructionFormats = mutableMapOf(
class FunctionCallArgs( class FunctionCallArgs(
var arguments: List<ArgumentSpec>, var arguments: List<ArgumentSpec>,
val returns: RegSpec? val returns: List<RegSpec>
) { ) {
class RegSpec(val dt: IRDataType, val registerNum: Int, val cpuRegister: RegisterOrStatusflag?) class RegSpec(val dt: IRDataType, val registerNum: Int, val cpuRegister: RegisterOrStatusflag?)
class ArgumentSpec(val name: String, val address: Int?, val reg: RegSpec) { class ArgumentSpec(val name: String, val address: Int?, val reg: RegSpec) {
@ -975,13 +975,13 @@ data class IRInstruction(
} }
if(fcallArgs!=null) { if(fcallArgs!=null) {
fcallArgs.returns?.let { fcallArgs.returns.forEach {
if(it.dt==IRDataType.FLOAT) if (it.dt == IRDataType.FLOAT)
writeFpRegsCounts[it.registerNum] = writeFpRegsCounts.getValue(it.registerNum)+1 writeFpRegsCounts[it.registerNum] = writeFpRegsCounts.getValue(it.registerNum) + 1
else { else {
writeRegsCounts[it.registerNum] = writeRegsCounts.getValue(it.registerNum) + 1 writeRegsCounts[it.registerNum] = writeRegsCounts.getValue(it.registerNum) + 1
val types = regsTypes[it.registerNum] val types = regsTypes[it.registerNum]
if(types==null) { if (types == null) {
regsTypes[it.registerNum] = mutableSetOf(it.dt) regsTypes[it.registerNum] = mutableSetOf(it.dt)
} else { } else {
types += it.dt types += it.dt
@ -1049,27 +1049,30 @@ data class IRInstruction(
} }
result.add(")") result.add(")")
val returns = fcallArgs.returns val returns = fcallArgs.returns
if(returns!=null) { if(returns.isNotEmpty()) {
result.add(":") result.add(":")
val cpuReg = if(returns.cpuRegister==null) "" else { val resultParts = returns.map { returnspec ->
if(returns.cpuRegister.registerOrPair!=null) val cpuReg = if (returnspec.cpuRegister == null) "" else {
returns.cpuRegister.registerOrPair.toString() if (returnspec.cpuRegister.registerOrPair != null)
else returnspec.cpuRegister.registerOrPair.toString()
returns.cpuRegister.statusflag.toString() else
} returnspec.cpuRegister.statusflag.toString()
if(cpuReg.isEmpty()) {
when (returns.dt) {
IRDataType.BYTE -> result.add("r${returns.registerNum}.b")
IRDataType.WORD -> result.add("r${returns.registerNum}.w")
IRDataType.FLOAT -> result.add("fr${returns.registerNum}.f")
} }
} else { if (cpuReg.isEmpty()) {
when(returns.dt) { when (returnspec.dt) {
IRDataType.BYTE -> result.add("r${returns.registerNum}.b@" + cpuReg) IRDataType.BYTE -> "r${returnspec.registerNum}.b"
IRDataType.WORD -> result.add("r${returns.registerNum}.w@" + cpuReg) IRDataType.WORD -> "r${returnspec.registerNum}.w"
IRDataType.FLOAT -> result.add("r${returns.registerNum}.f@" + cpuReg) IRDataType.FLOAT -> "fr${returnspec.registerNum}.f"
}
} else {
when (returnspec.dt) {
IRDataType.BYTE -> "r${returnspec.registerNum}.b@" + cpuReg
IRDataType.WORD -> "r${returnspec.registerNum}.w@" + cpuReg
IRDataType.FLOAT -> "r${returnspec.registerNum}.f@" + cpuReg
}
} }
} }
result.add(resultParts.joinToString(","))
} }
} else { } else {

View File

@ -216,7 +216,7 @@ private class ParsedCall(
val target: String?, val target: String?,
val address: Int?, val address: Int?,
val args: List<FunctionCallArgs.ArgumentSpec>, val args: List<FunctionCallArgs.ArgumentSpec>,
val returns: FunctionCallArgs.RegSpec? val returns: List<FunctionCallArgs.RegSpec>
) )
private fun parseCall(rest: String): ParsedCall { private fun parseCall(rest: String): ParsedCall {
@ -239,11 +239,15 @@ private fun parseCall(rest: String): ParsedCall {
return FunctionCallArgs.RegSpec(type, num, cpuRegister) return FunctionCallArgs.RegSpec(type, num, cpuRegister)
} }
fun parseReturnRegspec(reg: String): FunctionCallArgs.RegSpec { fun parseReturnRegspec(regs: String?): List<FunctionCallArgs.RegSpec> {
return if(reg.startsWith('@')) { if(regs==null)
FunctionCallArgs.RegSpec(IRDataType.BYTE, -1, parseRegisterOrStatusflag(reg.drop(1))) return emptyList()
} else { return regs.split(',').map { reg->
parseRegspec(reg) if (reg.startsWith('@')) {
FunctionCallArgs.RegSpec(IRDataType.BYTE, -1, parseRegisterOrStatusflag(reg.drop(1)))
} else {
parseRegspec(reg)
}
} }
} }
@ -278,7 +282,7 @@ private fun parseCall(rest: String): ParsedCall {
actualTarget, actualTarget,
address, address,
arguments, arguments,
if(returns==null) null else parseReturnRegspec(returns) parseReturnRegspec(returns)
) )
} }

View File

@ -216,7 +216,7 @@ object SysCalls {
if(maxlenvalue>0) if(maxlenvalue>0)
input = input.substring(0, min(input.length, maxlenvalue)) input = input.substring(0, min(input.length, maxlenvalue))
vm.memory.setString((address as UShort).toInt(), input, true) vm.memory.setString((address as UShort).toInt(), input, true)
returnValue(callspec.returns!!, input.length, vm) returnValue(callspec.returns.single(), input.length, vm)
} }
Syscall.SLEEP -> { Syscall.SLEEP -> {
val duration = getArgValues(callspec.arguments, vm).single() as UShort val duration = getArgValues(callspec.arguments, vm).single() as UShort
@ -237,7 +237,7 @@ object SysCalls {
Syscall.GFX_GETPIXEL -> { Syscall.GFX_GETPIXEL -> {
val (x,y) = getArgValues(callspec.arguments, vm) val (x,y) = getArgValues(callspec.arguments, vm)
val color = vm.gfx_getpixel(x as UShort, y as UShort) val color = vm.gfx_getpixel(x as UShort, y as UShort)
returnValue(callspec.returns!!, color, vm) returnValue(callspec.returns.single(), color, vm)
} }
Syscall.WAIT -> { Syscall.WAIT -> {
val time = getArgValues(callspec.arguments, vm).single() as UShort val time = getArgValues(callspec.arguments, vm).single() as UShort
@ -328,9 +328,9 @@ object SysCalls {
val endAddressExcl = address + if(length==0) 256 else length val endAddressExcl = address + if(length==0) 256 else length
val addresses = IntProgression.fromClosedRange(address, endAddressExcl-1, 1) val addresses = IntProgression.fromClosedRange(address, endAddressExcl-1, 1)
if(addresses.any { vm.memory.getUB(it).toInt()!=0 }) if(addresses.any { vm.memory.getUB(it).toInt()!=0 })
returnValue(callspec.returns!!, 1, vm) returnValue(callspec.returns.single(), 1, vm)
else else
returnValue(callspec.returns!!, 0, vm) returnValue(callspec.returns.single(), 0, vm)
} }
Syscall.ANY_WORD -> { Syscall.ANY_WORD -> {
val (addressV, lengthV) = getArgValues(callspec.arguments, vm) val (addressV, lengthV) = getArgValues(callspec.arguments, vm)
@ -339,9 +339,9 @@ object SysCalls {
val endAddressExcl = address + if(length==0) 256*2 else length*2 val endAddressExcl = address + if(length==0) 256*2 else length*2
val addresses = IntProgression.fromClosedRange(address, endAddressExcl-2, 2) val addresses = IntProgression.fromClosedRange(address, endAddressExcl-2, 2)
if(addresses.any { vm.memory.getUW(it).toInt()!=0 }) if(addresses.any { vm.memory.getUW(it).toInt()!=0 })
returnValue(callspec.returns!!, 1, vm) returnValue(callspec.returns.single(), 1, vm)
else else
returnValue(callspec.returns!!, 0, vm) returnValue(callspec.returns.single(), 0, vm)
} }
Syscall.ANY_FLOAT -> { Syscall.ANY_FLOAT -> {
val (addressV, lengthV) = getArgValues(callspec.arguments, vm) val (addressV, lengthV) = getArgValues(callspec.arguments, vm)
@ -350,9 +350,9 @@ object SysCalls {
val endAddressExcl = address + (if(length==0) 256*vm.machinedef.FLOAT_MEM_SIZE else length*vm.machinedef.FLOAT_MEM_SIZE) val endAddressExcl = address + (if(length==0) 256*vm.machinedef.FLOAT_MEM_SIZE else length*vm.machinedef.FLOAT_MEM_SIZE)
val addresses = IntProgression.fromClosedRange(address, endAddressExcl-vm.machinedef.FLOAT_MEM_SIZE, 4) val addresses = IntProgression.fromClosedRange(address, endAddressExcl-vm.machinedef.FLOAT_MEM_SIZE, 4)
if(addresses.any { vm.memory.getFloat(it).toInt()!=0 }) if(addresses.any { vm.memory.getFloat(it).toInt()!=0 })
returnValue(callspec.returns!!, 1, vm) returnValue(callspec.returns.single(), 1, vm)
else else
returnValue(callspec.returns!!, 0, vm) returnValue(callspec.returns.single(), 0, vm)
} }
Syscall.ALL_BYTE -> { Syscall.ALL_BYTE -> {
val (addressV, lengthV) = getArgValues(callspec.arguments, vm) val (addressV, lengthV) = getArgValues(callspec.arguments, vm)
@ -361,9 +361,9 @@ object SysCalls {
val endAddressExcl = address + if(length==0) 256 else length val endAddressExcl = address + if(length==0) 256 else length
val addresses = IntProgression.fromClosedRange(address, endAddressExcl-1, 1) val addresses = IntProgression.fromClosedRange(address, endAddressExcl-1, 1)
if(addresses.all { vm.memory.getUB(it).toInt()!=0 }) if(addresses.all { vm.memory.getUB(it).toInt()!=0 })
returnValue(callspec.returns!!, 1, vm) returnValue(callspec.returns.single(), 1, vm)
else else
returnValue(callspec.returns!!, 0, vm) returnValue(callspec.returns.single(), 0, vm)
} }
Syscall.ALL_WORD -> { Syscall.ALL_WORD -> {
val (addressV, lengthV) = getArgValues(callspec.arguments, vm) val (addressV, lengthV) = getArgValues(callspec.arguments, vm)
@ -372,9 +372,9 @@ object SysCalls {
val endAddressExcl = address + if(length==0) 256*2 else length*2 val endAddressExcl = address + if(length==0) 256*2 else length*2
val addresses = IntProgression.fromClosedRange(address, endAddressExcl-2, 2) val addresses = IntProgression.fromClosedRange(address, endAddressExcl-2, 2)
if(addresses.all { vm.memory.getUW(it).toInt()!=0 }) if(addresses.all { vm.memory.getUW(it).toInt()!=0 })
returnValue(callspec.returns!!, 1, vm) returnValue(callspec.returns.single(), 1, vm)
else else
returnValue(callspec.returns!!, 0, vm) returnValue(callspec.returns.single(), 0, vm)
} }
Syscall.ALL_FLOAT -> { Syscall.ALL_FLOAT -> {
val (addressV, lengthV) = getArgValues(callspec.arguments, vm) val (addressV, lengthV) = getArgValues(callspec.arguments, vm)
@ -383,9 +383,9 @@ object SysCalls {
val endAddressExcl = address + (if(length==0) 256*vm.machinedef.FLOAT_MEM_SIZE else length*vm.machinedef.FLOAT_MEM_SIZE) val endAddressExcl = address + (if(length==0) 256*vm.machinedef.FLOAT_MEM_SIZE else length*vm.machinedef.FLOAT_MEM_SIZE)
val addresses = IntProgression.fromClosedRange(address, endAddressExcl-vm.machinedef.FLOAT_MEM_SIZE, 4) val addresses = IntProgression.fromClosedRange(address, endAddressExcl-vm.machinedef.FLOAT_MEM_SIZE, 4)
if(addresses.all { vm.memory.getFloat(it).toInt()!=0 }) if(addresses.all { vm.memory.getFloat(it).toInt()!=0 })
returnValue(callspec.returns!!, 1, vm) returnValue(callspec.returns.single(), 1, vm)
else else
returnValue(callspec.returns!!, 0, vm) returnValue(callspec.returns.single(), 0, vm)
} }
Syscall.PRINT_F -> { Syscall.PRINT_F -> {
val value = getArgValues(callspec.arguments, vm).single() as Double val value = getArgValues(callspec.arguments, vm).single() as Double
@ -402,18 +402,18 @@ object SysCalls {
} catch(_: NumberFormatException) { } catch(_: NumberFormatException) {
0u 0u
} }
returnValue(callspec.returns!!, value, vm) returnValue(callspec.returns.single(), value, vm)
} }
Syscall.STR_TO_WORD -> { Syscall.STR_TO_WORD -> {
val stringAddr = getArgValues(callspec.arguments, vm).single() as UShort val stringAddr = getArgValues(callspec.arguments, vm).single() as UShort
val memstring = vm.memory.getString(stringAddr.toInt()) val memstring = vm.memory.getString(stringAddr.toInt())
val match = Regex("^[+-]?\\d+").find(memstring) ?: return returnValue(callspec.returns!!, 0, vm) val match = Regex("^[+-]?\\d+").find(memstring) ?: return returnValue(callspec.returns.single(), 0, vm)
val value = try { val value = try {
match.value.toShort() match.value.toShort()
} catch(_: NumberFormatException) { } catch(_: NumberFormatException) {
0 0
} }
return returnValue(callspec.returns!!, value, vm) return returnValue(callspec.returns.single(), value, vm)
} }
Syscall.STR_TO_FLOAT -> { Syscall.STR_TO_FLOAT -> {
val stringAddr = getArgValues(callspec.arguments, vm).single() as UShort val stringAddr = getArgValues(callspec.arguments, vm).single() as UShort
@ -428,7 +428,7 @@ object SysCalls {
0.0 0.0
} }
} }
returnValue(callspec.returns!!, result, vm) returnValue(callspec.returns.single(), result, vm)
} }
Syscall.COMPARE_STRINGS -> { Syscall.COMPARE_STRINGS -> {
val (firstV, secondV) = getArgValues(callspec.arguments, vm) val (firstV, secondV) = getArgValues(callspec.arguments, vm)
@ -438,11 +438,11 @@ object SysCalls {
val second = vm.memory.getString(secondAddr.toInt()) val second = vm.memory.getString(secondAddr.toInt())
val comparison = first.compareTo(second) val comparison = first.compareTo(second)
if(comparison==0) if(comparison==0)
returnValue(callspec.returns!!, 0, vm) returnValue(callspec.returns.single(), 0, vm)
else if(comparison<0) else if(comparison<0)
returnValue(callspec.returns!!, -1, vm) returnValue(callspec.returns.single(), -1, vm)
else else
returnValue(callspec.returns!!, 1, vm) returnValue(callspec.returns.single(), 1, vm)
} }
Syscall.RNDFSEED -> { Syscall.RNDFSEED -> {
val seed = getArgValues(callspec.arguments, vm).single() as Double val seed = getArgValues(callspec.arguments, vm).single() as Double
@ -456,20 +456,20 @@ object SysCalls {
vm.randomSeed(seed1 as UShort, seed2 as UShort) vm.randomSeed(seed1 as UShort, seed2 as UShort)
} }
Syscall.RND -> { Syscall.RND -> {
returnValue(callspec.returns!!, vm.randomGenerator.nextInt().toUByte(), vm) returnValue(callspec.returns.single(), vm.randomGenerator.nextInt().toUByte(), vm)
} }
Syscall.RNDW -> { Syscall.RNDW -> {
returnValue(callspec.returns!!, vm.randomGenerator.nextInt().toUShort(), vm) returnValue(callspec.returns.single(), vm.randomGenerator.nextInt().toUShort(), vm)
} }
Syscall.RNDF -> { Syscall.RNDF -> {
returnValue(callspec.returns!!, vm.randomGeneratorFloats.nextFloat(), vm) returnValue(callspec.returns.single(), vm.randomGeneratorFloats.nextFloat(), vm)
} }
Syscall.STRING_CONTAINS -> { Syscall.STRING_CONTAINS -> {
val (charV, addr) = getArgValues(callspec.arguments, vm) val (charV, addr) = getArgValues(callspec.arguments, vm)
val stringAddr = addr as UShort val stringAddr = addr as UShort
val char = (charV as UByte).toInt().toChar() val char = (charV as UByte).toInt().toChar()
val string = vm.memory.getString(stringAddr.toInt()) val string = vm.memory.getString(stringAddr.toInt())
returnValue(callspec.returns!!, if(char in string) 1u else 0u, vm) returnValue(callspec.returns.single(), if(char in string) 1u else 0u, vm)
} }
Syscall.BYTEARRAY_CONTAINS -> { Syscall.BYTEARRAY_CONTAINS -> {
val (value, arrayV, lengthV) = getArgValues(callspec.arguments, vm) val (value, arrayV, lengthV) = getArgValues(callspec.arguments, vm)
@ -477,11 +477,11 @@ object SysCalls {
var array = (arrayV as UShort).toInt() var array = (arrayV as UShort).toInt()
while(length>0u) { while(length>0u) {
if(vm.memory.getUB(array)==value) if(vm.memory.getUB(array)==value)
return returnValue(callspec.returns!!, 1u, vm) return returnValue(callspec.returns.single(), 1u, vm)
array++ array++
length-- length--
} }
returnValue(callspec.returns!!, 0u, vm) returnValue(callspec.returns.single(), 0u, vm)
} }
Syscall.WORDARRAY_CONTAINS -> { Syscall.WORDARRAY_CONTAINS -> {
val (value, arrayV, lengthV) = getArgValues(callspec.arguments, vm) val (value, arrayV, lengthV) = getArgValues(callspec.arguments, vm)
@ -489,11 +489,11 @@ object SysCalls {
var array = (arrayV as UShort).toInt() var array = (arrayV as UShort).toInt()
while(length>0u) { while(length>0u) {
if(vm.memory.getUW(array)==value) if(vm.memory.getUW(array)==value)
return returnValue(callspec.returns!!, 1u, vm) return returnValue(callspec.returns.single(), 1u, vm)
array += 2 array += 2
length-- length--
} }
returnValue(callspec.returns!!, 0u, vm) returnValue(callspec.returns.single(), 0u, vm)
} }
Syscall.FLOATARRAY_CONTAINS -> { Syscall.FLOATARRAY_CONTAINS -> {
val (value, arrayV, lengthV) = getArgValues(callspec.arguments, vm) val (value, arrayV, lengthV) = getArgValues(callspec.arguments, vm)
@ -501,11 +501,11 @@ object SysCalls {
var array = (arrayV as UShort).toInt() var array = (arrayV as UShort).toInt()
while(length>0u) { while(length>0u) {
if(vm.memory.getFloat(array)==value) if(vm.memory.getFloat(array)==value)
return returnValue(callspec.returns!!, 1u, vm) return returnValue(callspec.returns.single(), 1u, vm)
array += vm.machinedef.FLOAT_MEM_SIZE array += vm.machinedef.FLOAT_MEM_SIZE
length-- length--
} }
returnValue(callspec.returns!!, 0u, vm) returnValue(callspec.returns.single(), 0u, vm)
} }
Syscall.CLAMP_BYTE -> { Syscall.CLAMP_BYTE -> {
val (valueU, minimumU, maximumU) = getArgValues(callspec.arguments, vm) val (valueU, minimumU, maximumU) = getArgValues(callspec.arguments, vm)
@ -513,7 +513,7 @@ object SysCalls {
val minimum = (minimumU as UByte).toByte().toInt() val minimum = (minimumU as UByte).toByte().toInt()
val maximum = (maximumU as UByte).toByte().toInt() val maximum = (maximumU as UByte).toByte().toInt()
val result = min(max(value, minimum), maximum) val result = min(max(value, minimum), maximum)
returnValue(callspec.returns!!, result, vm) returnValue(callspec.returns.single(), result, vm)
} }
Syscall.CLAMP_UBYTE -> { Syscall.CLAMP_UBYTE -> {
val (valueU, minimumU, maximumU) = getArgValues(callspec.arguments, vm) val (valueU, minimumU, maximumU) = getArgValues(callspec.arguments, vm)
@ -521,7 +521,7 @@ object SysCalls {
val minimum = (minimumU as UByte).toInt() val minimum = (minimumU as UByte).toInt()
val maximum = (maximumU as UByte).toInt() val maximum = (maximumU as UByte).toInt()
val result = min(max(value, minimum), maximum) val result = min(max(value, minimum), maximum)
returnValue(callspec.returns!!, result, vm) returnValue(callspec.returns.single(), result, vm)
} }
Syscall.CLAMP_WORD -> { Syscall.CLAMP_WORD -> {
val (valueU, minimumU, maximumU) = getArgValues(callspec.arguments, vm) val (valueU, minimumU, maximumU) = getArgValues(callspec.arguments, vm)
@ -529,7 +529,7 @@ object SysCalls {
val minimum = (minimumU as UShort).toShort().toInt() val minimum = (minimumU as UShort).toShort().toInt()
val maximum = (maximumU as UShort).toShort().toInt() val maximum = (maximumU as UShort).toShort().toInt()
val result = min(max(value, minimum), maximum) val result = min(max(value, minimum), maximum)
returnValue(callspec.returns!!, result, vm) returnValue(callspec.returns.single(), result, vm)
} }
Syscall.CLAMP_UWORD -> { Syscall.CLAMP_UWORD -> {
val (valueU, minimumU, maximumU) = getArgValues(callspec.arguments, vm) val (valueU, minimumU, maximumU) = getArgValues(callspec.arguments, vm)
@ -537,7 +537,7 @@ object SysCalls {
val minimum = (minimumU as UShort).toInt() val minimum = (minimumU as UShort).toInt()
val maximum = (maximumU as UShort).toInt() val maximum = (maximumU as UShort).toInt()
val result = min(max(value, minimum), maximum) val result = min(max(value, minimum), maximum)
returnValue(callspec.returns!!, result, vm) returnValue(callspec.returns.single(), result, vm)
} }
Syscall.CLAMP_FLOAT -> { Syscall.CLAMP_FLOAT -> {
val (valueU, minimumU, maximumU) = getArgValues(callspec.arguments, vm) val (valueU, minimumU, maximumU) = getArgValues(callspec.arguments, vm)
@ -545,7 +545,7 @@ object SysCalls {
val minimum = minimumU as Double val minimum = minimumU as Double
val maximum = maximumU as Double val maximum = maximumU as Double
val result = min(max(value, minimum), maximum) val result = min(max(value, minimum), maximum)
returnValue(callspec.returns!!, result, vm) returnValue(callspec.returns.single(), result, vm)
} }
Syscall.ATAN -> { Syscall.ATAN -> {
val (x1, y1, x2, y2) = getArgValues(callspec.arguments, vm) val (x1, y1, x2, y2) = getArgValues(callspec.arguments, vm)
@ -557,10 +557,10 @@ object SysCalls {
if(radians<0) if(radians<0)
radians+=2*PI radians+=2*PI
val result = floor(radians/2.0/PI*256.0) val result = floor(radians/2.0/PI*256.0)
returnValue(callspec.returns!!, result, vm) returnValue(callspec.returns.single(), result, vm)
} }
Syscall.MUL16_LAST_UPPER -> { Syscall.MUL16_LAST_UPPER -> {
returnValue(callspec.returns!!, vm.mul16_last_upper, vm) returnValue(callspec.returns.single(), vm.mul16_last_upper, vm)
} }
Syscall.FLOAT_TO_STR -> { Syscall.FLOAT_TO_STR -> {
val (buffer, number) = getArgValues(callspec.arguments, vm) val (buffer, number) = getArgValues(callspec.arguments, vm)
@ -612,7 +612,7 @@ object SysCalls {
val target = (targetA as UShort).toInt() val target = (targetA as UShort).toInt()
val string = vm.memory.getString(source) val string = vm.memory.getString(source)
vm.memory.setString(target, string, true) vm.memory.setString(target, string, true)
returnValue(callspec.returns!!, string.length, vm) returnValue(callspec.returns.single(), string.length, vm)
} }
Syscall.ARRAYCOPY_SPLITW_TO_NORMAL -> { Syscall.ARRAYCOPY_SPLITW_TO_NORMAL -> {
val (fromLsbA, fromMsbA, targetA, bytecountA) = getArgValues(callspec.arguments, vm) val (fromLsbA, fromMsbA, targetA, bytecountA) = getArgValues(callspec.arguments, vm)
@ -646,9 +646,9 @@ object SysCalls {
for (i in 0..<data.size - 2) { for (i in 0..<data.size - 2) {
vm.memory.setUB(addr + i, data[i + 2].toUByte()) vm.memory.setUB(addr + i, data[i + 2].toUByte())
} }
returnValue(callspec.returns!!, (addr + data.size - 2).toUShort(), vm) returnValue(callspec.returns.single(), (addr + data.size - 2).toUShort(), vm)
} else { } else {
returnValue(callspec.returns!!, 0u, vm) returnValue(callspec.returns.single(), 0u, vm)
} }
} }
Syscall.LOAD_RAW -> { Syscall.LOAD_RAW -> {
@ -660,9 +660,9 @@ object SysCalls {
for (i in 0..<data.size) { for (i in 0..<data.size) {
vm.memory.setUB(addr + i, data[i].toUByte()) vm.memory.setUB(addr + i, data[i].toUByte())
} }
returnValue(callspec.returns!!, (addr + data.size).toUShort(), vm) returnValue(callspec.returns.single(), (addr + data.size).toUShort(), vm)
} else { } else {
returnValue(callspec.returns!!, 0u, vm) returnValue(callspec.returns.single(), 0u, vm)
} }
} }
Syscall.SAVE -> { Syscall.SAVE -> {
@ -688,10 +688,10 @@ object SysCalls {
} }
val filename = vm.memory.getString((filenamePtr as UShort).toInt()) val filename = vm.memory.getString((filenamePtr as UShort).toInt())
if (File(filename).exists()) if (File(filename).exists())
returnValue(callspec.returns!!, 0u, vm) returnValue(callspec.returns.single(), 0u, vm)
else { else {
File(filename).writeBytes(data) File(filename).writeBytes(data)
returnValue(callspec.returns!!, 1u, vm) returnValue(callspec.returns.single(), 1u, vm)
} }
} }
Syscall.DELETE -> { Syscall.DELETE -> {
@ -712,12 +712,12 @@ object SysCalls {
directory.listDirectoryEntries().sorted().forEach { directory.listDirectoryEntries().sorted().forEach {
println("${it.toFile().length()}\t${it.normalize()}") println("${it.toFile().length()}\t${it.normalize()}")
} }
returnValue(callspec.returns!!, 1u, vm) returnValue(callspec.returns.single(), 1u, vm)
} }
Syscall.GETGONSOLESIZE -> { Syscall.GETGONSOLESIZE -> {
// no arguments // no arguments
if(System.console()==null) { if(System.console()==null) {
return returnValue(callspec.returns!!, 30*256 + 80, vm) // just return some defaults in this case 80*30 return returnValue(callspec.returns.single(), 30*256 + 80, vm) // just return some defaults in this case 80*30
} }
val linesS = System.getenv("LINES") val linesS = System.getenv("LINES")
@ -725,7 +725,7 @@ object SysCalls {
if(linesS!=null && columnsS!=null) { if(linesS!=null && columnsS!=null) {
val lines = linesS.toInt() val lines = linesS.toInt()
val columns = columnsS.toInt() val columns = columnsS.toInt()
return returnValue(callspec.returns!!, lines*256 + columns, vm) return returnValue(callspec.returns.single(), lines*256 + columns, vm)
} }
try { try {
@ -735,12 +735,12 @@ object SysCalls {
val response = process.inputStream.bufferedReader().lineSequence().iterator() val response = process.inputStream.bufferedReader().lineSequence().iterator()
val width = response.next().toInt() val width = response.next().toInt()
val height = response.next().toInt() val height = response.next().toInt()
return returnValue(callspec.returns!!, height*256 + width, vm) return returnValue(callspec.returns.single(), height*256 + width, vm)
} }
} catch (x: Exception) { } catch (x: Exception) {
// dunno what happened... // dunno what happened...
} }
return returnValue(callspec.returns!!, 30*256 + 80, vm) // just return some defaults in this case 80*30 return returnValue(callspec.returns.single(), 30*256 + 80, vm) // just return some defaults in this case 80*30
} }
} }
} }

View File

@ -655,8 +655,8 @@ class VirtualMachine(irProgram: IRProgram) {
val returns = context.fcallSpec.returns val returns = context.fcallSpec.returns
when (i.type!!) { when (i.type!!) {
IRDataType.BYTE -> { IRDataType.BYTE -> {
if(returns!=null) if(returns.isNotEmpty())
registers.setUB(returns.registerNum, registers.getUB(i.reg1!!)) registers.setUB(returns.single().registerNum, registers.getUB(i.reg1!!))
else { else {
val callInstr = context.returnChunk.instructions[context.returnIndex-1] val callInstr = context.returnChunk.instructions[context.returnIndex-1]
if(callInstr.opcode!=Opcode.CALL) if(callInstr.opcode!=Opcode.CALL)
@ -664,8 +664,8 @@ class VirtualMachine(irProgram: IRProgram) {
} }
} }
IRDataType.WORD -> { IRDataType.WORD -> {
if(returns!=null) if(returns.isNotEmpty())
registers.setUW(returns.registerNum, registers.getUW(i.reg1!!)) registers.setUW(returns.single().registerNum, registers.getUW(i.reg1!!))
else { else {
val callInstr = context.returnChunk.instructions[context.returnIndex-1] val callInstr = context.returnChunk.instructions[context.returnIndex-1]
if(callInstr.opcode!=Opcode.CALL) if(callInstr.opcode!=Opcode.CALL)
@ -673,8 +673,8 @@ class VirtualMachine(irProgram: IRProgram) {
} }
} }
IRDataType.FLOAT -> { IRDataType.FLOAT -> {
if(returns!=null) if(returns.isNotEmpty())
registers.setFloat(returns.registerNum, registers.getFloat(i.fpReg1!!)) registers.setFloat(returns.single().registerNum, registers.getFloat(i.fpReg1!!))
else { else {
val callInstr = context.returnChunk.instructions[context.returnIndex-1] val callInstr = context.returnChunk.instructions[context.returnIndex-1]
if(callInstr.opcode!=Opcode.CALL) if(callInstr.opcode!=Opcode.CALL)