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())
TODO("deal with (multiple?) FP return registers")
TODO("add to result multi return regs from expression")
// addToResult(result, funcCall, funcCall.resultReg, funcCall.resultFpReg)
// sub.returns.zip(assignment.children).forEach { (returns, target) ->
// result += assignCpuRegister(returns, funcCall, target as PtAssignTarget)
// }
// result.filterIsInstance<IRCodeChunk>().firstOrNull()?.appendSrcPosition(assignment.position)
// return result
// because we can only handle integer results right now we can just zip() it all up
addToResult(result, funcCall, funcCall.resultReg, funcCall.resultFpReg)
sub.returns.zip(assignment.children).zip(funcCall.multipleResultRegs).forEach {
val regNumber = it.second
val returns = it.first.first
val target = it.first.second as PtAssignTarget
result += assignCpuRegister(returns, regNumber, target)
}
result.filterIsInstance<IRCodeChunk>().firstOrNull()?.appendSrcPosition(assignment.position)
return result
} else {
if (assignment.target.children.single() is PtIrRegister)
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 {
val targetIdentifier = target.identifier
val chunk = IRCodeChunk(null, null)
if(targetIdentifier!=null) {
TODO()
val regNum = 4242 // TODO??
when(returns.register.registerOrPair) {
RegisterOrPair.A -> chunk += IRInstruction(Opcode.LOADHA, IRDataType.BYTE, reg1=regNum)
RegisterOrPair.X -> chunk += IRInstruction(Opcode.LOADHX, IRDataType.BYTE, reg1=regNum)
RegisterOrPair.Y -> chunk += IRInstruction(Opcode.LOADHY, IRDataType.BYTE, reg1=regNum)
RegisterOrPair.AX -> chunk += IRInstruction(Opcode.LOADHAX, IRDataType.WORD, reg1=regNum)
RegisterOrPair.AY -> chunk += IRInstruction(Opcode.LOADHAY, IRDataType.WORD, reg1=regNum)
RegisterOrPair.XY -> chunk += IRInstruction(Opcode.LOADHXY, IRDataType.WORD, reg1=regNum)
null -> {
when(returns.register.statusflag) {
Statusflag.Pc -> chunk += IRInstruction(Opcode.LOADHA, IRDataType.BYTE, reg1=regNum)
else -> throw AssemblyError("weird statusflag as returnvalue")
}
private fun assignCpuRegister(returns: StRomSubParameter, regNum: Int, target: PtAssignTarget): IRCodeChunks {
val result = mutableListOf<IRCodeChunkBase>()
val loadCpuRegInstr = when(returns.register.registerOrPair) {
RegisterOrPair.A -> IRInstruction(Opcode.LOADHA, IRDataType.BYTE, reg1=regNum)
RegisterOrPair.X -> IRInstruction(Opcode.LOADHX, IRDataType.BYTE, reg1=regNum)
RegisterOrPair.Y -> IRInstruction(Opcode.LOADHY, IRDataType.BYTE, reg1=regNum)
RegisterOrPair.AX -> IRInstruction(Opcode.LOADHAX, IRDataType.WORD, reg1=regNum)
RegisterOrPair.AY -> IRInstruction(Opcode.LOADHAY, IRDataType.WORD, reg1=regNum)
RegisterOrPair.XY -> IRInstruction(Opcode.LOADHXY, IRDataType.WORD, reg1=regNum)
null -> {
when(returns.register.statusflag) {
Statusflag.Pc -> 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)
return chunk
else -> throw AssemblyError("cannot load register")
}
val targetMem = target.memory
if(targetMem!=null) {
TODO("assign $returns to $targetMem")
return chunk
}
val targetArray = target.array
if(targetArray!=null) {
TODO("assign $returns to $targetArray")
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)
addInstr(result, loadCpuRegInstr, null)
// build an assignment to store the value in the actual target.
val assign = PtAssignment(target.position)
assign.add(target)
assign.add(PtIrRegister(regNum, target.type, target.position))
result += translate(assign)
return result
}
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)))
result += tr.chunks
}
// return value
// return value (always singular for normal Subs)
val returnRegSpec = if(fcall.void) null else {
val returnIrType = irType(callTarget.returnType!!)
if(returnIrType==IRDataType.FLOAT)
@ -475,7 +475,8 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
FunctionCallArgs.RegSpec(returnIrType, codeGen.registers.nextFree(), null)
}
// 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)
ExpressionCodeResult(result, IRDataType.BYTE, -1, -1)
else if(fcall.type==DataType.FLOAT)
@ -516,34 +517,37 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
}
if(callTarget.returns.size>1)
return callWithMultipleReturnValues()
return callRomSubWithMultipleReturnValues(callTarget, fcall, argRegisters, result)
// return a single value
var statusFlagResult: Statusflag? = null
// return a single value (or nothing)
val returnRegSpec = if(fcall.void) null else {
if(callTarget.returns.isEmpty())
null
val returns = callTarget.returns[0]
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)
val returns = callTarget.returns[0]
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
val returnRegs = if(returnRegSpec==null) emptyList() else listOf(returnRegSpec)
val call =
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
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)
var finalReturnRegister = returnRegSpec?.registerNum ?: -1
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)
if(statusFlagResult!=null && returnRegSpec!=null) {
val statusFlagResult = returnRegSpec?.cpuRegister?.statusflag
if(statusFlagResult!=null) {
// assign status flag bit to the return value register
finalReturnRegister = returnRegSpec.registerNum
if(finalReturnRegister<0)
@ -586,8 +590,27 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
}
}
private fun callWithMultipleReturnValues(): ExpressionCodeResult {
TODO("call with multiple return values")
private fun callRomSubWithMultipleReturnValues(
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(

View File

@ -1650,7 +1650,8 @@ class IRCodeGen(
val args = params.map { (dt, reg)->
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))
}
}

View File

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

View File

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

View File

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

View File

@ -216,7 +216,7 @@ object SysCalls {
if(maxlenvalue>0)
input = input.substring(0, min(input.length, maxlenvalue))
vm.memory.setString((address as UShort).toInt(), input, true)
returnValue(callspec.returns!!, input.length, vm)
returnValue(callspec.returns.single(), input.length, vm)
}
Syscall.SLEEP -> {
val duration = getArgValues(callspec.arguments, vm).single() as UShort
@ -237,7 +237,7 @@ object SysCalls {
Syscall.GFX_GETPIXEL -> {
val (x,y) = getArgValues(callspec.arguments, vm)
val color = vm.gfx_getpixel(x as UShort, y as UShort)
returnValue(callspec.returns!!, color, vm)
returnValue(callspec.returns.single(), color, vm)
}
Syscall.WAIT -> {
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 addresses = IntProgression.fromClosedRange(address, endAddressExcl-1, 1)
if(addresses.any { vm.memory.getUB(it).toInt()!=0 })
returnValue(callspec.returns!!, 1, vm)
returnValue(callspec.returns.single(), 1, vm)
else
returnValue(callspec.returns!!, 0, vm)
returnValue(callspec.returns.single(), 0, vm)
}
Syscall.ANY_WORD -> {
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 addresses = IntProgression.fromClosedRange(address, endAddressExcl-2, 2)
if(addresses.any { vm.memory.getUW(it).toInt()!=0 })
returnValue(callspec.returns!!, 1, vm)
returnValue(callspec.returns.single(), 1, vm)
else
returnValue(callspec.returns!!, 0, vm)
returnValue(callspec.returns.single(), 0, vm)
}
Syscall.ANY_FLOAT -> {
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 addresses = IntProgression.fromClosedRange(address, endAddressExcl-vm.machinedef.FLOAT_MEM_SIZE, 4)
if(addresses.any { vm.memory.getFloat(it).toInt()!=0 })
returnValue(callspec.returns!!, 1, vm)
returnValue(callspec.returns.single(), 1, vm)
else
returnValue(callspec.returns!!, 0, vm)
returnValue(callspec.returns.single(), 0, vm)
}
Syscall.ALL_BYTE -> {
val (addressV, lengthV) = getArgValues(callspec.arguments, vm)
@ -361,9 +361,9 @@ object SysCalls {
val endAddressExcl = address + if(length==0) 256 else length
val addresses = IntProgression.fromClosedRange(address, endAddressExcl-1, 1)
if(addresses.all { vm.memory.getUB(it).toInt()!=0 })
returnValue(callspec.returns!!, 1, vm)
returnValue(callspec.returns.single(), 1, vm)
else
returnValue(callspec.returns!!, 0, vm)
returnValue(callspec.returns.single(), 0, vm)
}
Syscall.ALL_WORD -> {
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 addresses = IntProgression.fromClosedRange(address, endAddressExcl-2, 2)
if(addresses.all { vm.memory.getUW(it).toInt()!=0 })
returnValue(callspec.returns!!, 1, vm)
returnValue(callspec.returns.single(), 1, vm)
else
returnValue(callspec.returns!!, 0, vm)
returnValue(callspec.returns.single(), 0, vm)
}
Syscall.ALL_FLOAT -> {
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 addresses = IntProgression.fromClosedRange(address, endAddressExcl-vm.machinedef.FLOAT_MEM_SIZE, 4)
if(addresses.all { vm.memory.getFloat(it).toInt()!=0 })
returnValue(callspec.returns!!, 1, vm)
returnValue(callspec.returns.single(), 1, vm)
else
returnValue(callspec.returns!!, 0, vm)
returnValue(callspec.returns.single(), 0, vm)
}
Syscall.PRINT_F -> {
val value = getArgValues(callspec.arguments, vm).single() as Double
@ -402,18 +402,18 @@ object SysCalls {
} catch(_: NumberFormatException) {
0u
}
returnValue(callspec.returns!!, value, vm)
returnValue(callspec.returns.single(), value, vm)
}
Syscall.STR_TO_WORD -> {
val stringAddr = getArgValues(callspec.arguments, vm).single() as UShort
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 {
match.value.toShort()
} catch(_: NumberFormatException) {
0
}
return returnValue(callspec.returns!!, value, vm)
return returnValue(callspec.returns.single(), value, vm)
}
Syscall.STR_TO_FLOAT -> {
val stringAddr = getArgValues(callspec.arguments, vm).single() as UShort
@ -428,7 +428,7 @@ object SysCalls {
0.0
}
}
returnValue(callspec.returns!!, result, vm)
returnValue(callspec.returns.single(), result, vm)
}
Syscall.COMPARE_STRINGS -> {
val (firstV, secondV) = getArgValues(callspec.arguments, vm)
@ -438,11 +438,11 @@ object SysCalls {
val second = vm.memory.getString(secondAddr.toInt())
val comparison = first.compareTo(second)
if(comparison==0)
returnValue(callspec.returns!!, 0, vm)
returnValue(callspec.returns.single(), 0, vm)
else if(comparison<0)
returnValue(callspec.returns!!, -1, vm)
returnValue(callspec.returns.single(), -1, vm)
else
returnValue(callspec.returns!!, 1, vm)
returnValue(callspec.returns.single(), 1, vm)
}
Syscall.RNDFSEED -> {
val seed = getArgValues(callspec.arguments, vm).single() as Double
@ -456,20 +456,20 @@ object SysCalls {
vm.randomSeed(seed1 as UShort, seed2 as UShort)
}
Syscall.RND -> {
returnValue(callspec.returns!!, vm.randomGenerator.nextInt().toUByte(), vm)
returnValue(callspec.returns.single(), vm.randomGenerator.nextInt().toUByte(), vm)
}
Syscall.RNDW -> {
returnValue(callspec.returns!!, vm.randomGenerator.nextInt().toUShort(), vm)
returnValue(callspec.returns.single(), vm.randomGenerator.nextInt().toUShort(), vm)
}
Syscall.RNDF -> {
returnValue(callspec.returns!!, vm.randomGeneratorFloats.nextFloat(), vm)
returnValue(callspec.returns.single(), vm.randomGeneratorFloats.nextFloat(), vm)
}
Syscall.STRING_CONTAINS -> {
val (charV, addr) = getArgValues(callspec.arguments, vm)
val stringAddr = addr as UShort
val char = (charV as UByte).toInt().toChar()
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 -> {
val (value, arrayV, lengthV) = getArgValues(callspec.arguments, vm)
@ -477,11 +477,11 @@ object SysCalls {
var array = (arrayV as UShort).toInt()
while(length>0u) {
if(vm.memory.getUB(array)==value)
return returnValue(callspec.returns!!, 1u, vm)
return returnValue(callspec.returns.single(), 1u, vm)
array++
length--
}
returnValue(callspec.returns!!, 0u, vm)
returnValue(callspec.returns.single(), 0u, vm)
}
Syscall.WORDARRAY_CONTAINS -> {
val (value, arrayV, lengthV) = getArgValues(callspec.arguments, vm)
@ -489,11 +489,11 @@ object SysCalls {
var array = (arrayV as UShort).toInt()
while(length>0u) {
if(vm.memory.getUW(array)==value)
return returnValue(callspec.returns!!, 1u, vm)
return returnValue(callspec.returns.single(), 1u, vm)
array += 2
length--
}
returnValue(callspec.returns!!, 0u, vm)
returnValue(callspec.returns.single(), 0u, vm)
}
Syscall.FLOATARRAY_CONTAINS -> {
val (value, arrayV, lengthV) = getArgValues(callspec.arguments, vm)
@ -501,11 +501,11 @@ object SysCalls {
var array = (arrayV as UShort).toInt()
while(length>0u) {
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
length--
}
returnValue(callspec.returns!!, 0u, vm)
returnValue(callspec.returns.single(), 0u, vm)
}
Syscall.CLAMP_BYTE -> {
val (valueU, minimumU, maximumU) = getArgValues(callspec.arguments, vm)
@ -513,7 +513,7 @@ object SysCalls {
val minimum = (minimumU as UByte).toByte().toInt()
val maximum = (maximumU as UByte).toByte().toInt()
val result = min(max(value, minimum), maximum)
returnValue(callspec.returns!!, result, vm)
returnValue(callspec.returns.single(), result, vm)
}
Syscall.CLAMP_UBYTE -> {
val (valueU, minimumU, maximumU) = getArgValues(callspec.arguments, vm)
@ -521,7 +521,7 @@ object SysCalls {
val minimum = (minimumU as UByte).toInt()
val maximum = (maximumU as UByte).toInt()
val result = min(max(value, minimum), maximum)
returnValue(callspec.returns!!, result, vm)
returnValue(callspec.returns.single(), result, vm)
}
Syscall.CLAMP_WORD -> {
val (valueU, minimumU, maximumU) = getArgValues(callspec.arguments, vm)
@ -529,7 +529,7 @@ object SysCalls {
val minimum = (minimumU as UShort).toShort().toInt()
val maximum = (maximumU as UShort).toShort().toInt()
val result = min(max(value, minimum), maximum)
returnValue(callspec.returns!!, result, vm)
returnValue(callspec.returns.single(), result, vm)
}
Syscall.CLAMP_UWORD -> {
val (valueU, minimumU, maximumU) = getArgValues(callspec.arguments, vm)
@ -537,7 +537,7 @@ object SysCalls {
val minimum = (minimumU as UShort).toInt()
val maximum = (maximumU as UShort).toInt()
val result = min(max(value, minimum), maximum)
returnValue(callspec.returns!!, result, vm)
returnValue(callspec.returns.single(), result, vm)
}
Syscall.CLAMP_FLOAT -> {
val (valueU, minimumU, maximumU) = getArgValues(callspec.arguments, vm)
@ -545,7 +545,7 @@ object SysCalls {
val minimum = minimumU as Double
val maximum = maximumU as Double
val result = min(max(value, minimum), maximum)
returnValue(callspec.returns!!, result, vm)
returnValue(callspec.returns.single(), result, vm)
}
Syscall.ATAN -> {
val (x1, y1, x2, y2) = getArgValues(callspec.arguments, vm)
@ -557,10 +557,10 @@ object SysCalls {
if(radians<0)
radians+=2*PI
val result = floor(radians/2.0/PI*256.0)
returnValue(callspec.returns!!, result, vm)
returnValue(callspec.returns.single(), result, vm)
}
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 -> {
val (buffer, number) = getArgValues(callspec.arguments, vm)
@ -612,7 +612,7 @@ object SysCalls {
val target = (targetA as UShort).toInt()
val string = vm.memory.getString(source)
vm.memory.setString(target, string, true)
returnValue(callspec.returns!!, string.length, vm)
returnValue(callspec.returns.single(), string.length, vm)
}
Syscall.ARRAYCOPY_SPLITW_TO_NORMAL -> {
val (fromLsbA, fromMsbA, targetA, bytecountA) = getArgValues(callspec.arguments, vm)
@ -646,9 +646,9 @@ object SysCalls {
for (i in 0..<data.size - 2) {
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 {
returnValue(callspec.returns!!, 0u, vm)
returnValue(callspec.returns.single(), 0u, vm)
}
}
Syscall.LOAD_RAW -> {
@ -660,9 +660,9 @@ object SysCalls {
for (i in 0..<data.size) {
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 {
returnValue(callspec.returns!!, 0u, vm)
returnValue(callspec.returns.single(), 0u, vm)
}
}
Syscall.SAVE -> {
@ -688,10 +688,10 @@ object SysCalls {
}
val filename = vm.memory.getString((filenamePtr as UShort).toInt())
if (File(filename).exists())
returnValue(callspec.returns!!, 0u, vm)
returnValue(callspec.returns.single(), 0u, vm)
else {
File(filename).writeBytes(data)
returnValue(callspec.returns!!, 1u, vm)
returnValue(callspec.returns.single(), 1u, vm)
}
}
Syscall.DELETE -> {
@ -712,12 +712,12 @@ object SysCalls {
directory.listDirectoryEntries().sorted().forEach {
println("${it.toFile().length()}\t${it.normalize()}")
}
returnValue(callspec.returns!!, 1u, vm)
returnValue(callspec.returns.single(), 1u, vm)
}
Syscall.GETGONSOLESIZE -> {
// no arguments
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")
@ -725,7 +725,7 @@ object SysCalls {
if(linesS!=null && columnsS!=null) {
val lines = linesS.toInt()
val columns = columnsS.toInt()
return returnValue(callspec.returns!!, lines*256 + columns, vm)
return returnValue(callspec.returns.single(), lines*256 + columns, vm)
}
try {
@ -735,12 +735,12 @@ object SysCalls {
val response = process.inputStream.bufferedReader().lineSequence().iterator()
val width = 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) {
// 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
when (i.type!!) {
IRDataType.BYTE -> {
if(returns!=null)
registers.setUB(returns.registerNum, registers.getUB(i.reg1!!))
if(returns.isNotEmpty())
registers.setUB(returns.single().registerNum, registers.getUB(i.reg1!!))
else {
val callInstr = context.returnChunk.instructions[context.returnIndex-1]
if(callInstr.opcode!=Opcode.CALL)
@ -664,8 +664,8 @@ class VirtualMachine(irProgram: IRProgram) {
}
}
IRDataType.WORD -> {
if(returns!=null)
registers.setUW(returns.registerNum, registers.getUW(i.reg1!!))
if(returns.isNotEmpty())
registers.setUW(returns.single().registerNum, registers.getUW(i.reg1!!))
else {
val callInstr = context.returnChunk.instructions[context.returnIndex-1]
if(callInstr.opcode!=Opcode.CALL)
@ -673,8 +673,8 @@ class VirtualMachine(irProgram: IRProgram) {
}
}
IRDataType.FLOAT -> {
if(returns!=null)
registers.setFloat(returns.registerNum, registers.getFloat(i.fpReg1!!))
if(returns.isNotEmpty())
registers.setFloat(returns.single().registerNum, registers.getFloat(i.fpReg1!!))
else {
val callInstr = context.returnChunk.instructions[context.returnIndex-1]
if(callInstr.opcode!=Opcode.CALL)