mirror of
https://github.com/irmen/prog8.git
synced 2024-12-22 18:30:01 +00:00
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:
parent
03e486c082
commit
2e37f5dee3
@ -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 {
|
||||
|
@ -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(
|
||||
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,9 @@
|
||||
TODO
|
||||
====
|
||||
|
||||
6502 codegen: make multi return value asmsub calls work.
|
||||
|
||||
|
||||
...
|
||||
|
||||
|
||||
|
@ -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 {
|
||||
|
||||
|
@ -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)
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user