mirror of
https://github.com/irmen/prog8.git
synced 2025-01-03 06:29:54 +00:00
call convention for @Rx parameters, also use cpu registers if possible, like normal parameters
This commit is contained in:
parent
d58f9f56c4
commit
2eed75f602
@ -15,7 +15,7 @@ data class Position(val file: String, val line: Int, val startCol: Int, val endC
|
|||||||
return try {
|
return try {
|
||||||
val path = Path(file).absolute().normalize().toString()
|
val path = Path(file).absolute().normalize().toString()
|
||||||
"file://$path:$line:$startCol:"
|
"file://$path:$line:$startCol:"
|
||||||
} catch(x: InvalidPathException) {
|
} catch(_: InvalidPathException) {
|
||||||
// this can occur on Windows when the source origin contains "invalid" characters such as ':'
|
// this can occur on Windows when the source origin contains "invalid" characters such as ':'
|
||||||
"file://$file:$line:$startCol:"
|
"file://$file:$line:$startCol:"
|
||||||
}
|
}
|
||||||
|
@ -55,7 +55,7 @@ class C64MachineDefinition: IMachineDefinition {
|
|||||||
val process: Process
|
val process: Process
|
||||||
try {
|
try {
|
||||||
process=processb.start()
|
process=processb.start()
|
||||||
} catch(x: IOException) {
|
} catch(_: IOException) {
|
||||||
continue // try the next emulator executable
|
continue // try the next emulator executable
|
||||||
}
|
}
|
||||||
process.waitFor()
|
process.waitFor()
|
||||||
|
@ -15,16 +15,7 @@ internal class FunctionCallAsmGen(private val program: PtProgram, private val as
|
|||||||
// just ignore any result values from the function call.
|
// just ignore any result values from the function call.
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmName("optimizeIntArgsViaRegisters")
|
internal fun optimizeIntArgsViaCpuRegisters(params: List<PtSubroutineParameter>) =
|
||||||
internal fun optimizeIntArgsViaRegisters(params: List<IndexedValue<PtSubroutineParameter>>) =
|
|
||||||
when(params.size) {
|
|
||||||
1 -> params[0].value.type in IntegerDatatypesWithBoolean
|
|
||||||
2 -> params[0].value.type in ByteDatatypesWithBoolean && params[1].value.type in ByteDatatypesWithBoolean
|
|
||||||
else -> false
|
|
||||||
}
|
|
||||||
|
|
||||||
@JvmName("optimizeIntArgsViaRegistersNotIndexed")
|
|
||||||
internal fun optimizeIntArgsViaRegisters(params: List<PtSubroutineParameter>) =
|
|
||||||
when(params.size) {
|
when(params.size) {
|
||||||
1 -> params[0].type in IntegerDatatypesWithBoolean
|
1 -> params[0].type in IntegerDatatypesWithBoolean
|
||||||
2 -> params[0].type in ByteDatatypesWithBoolean && params[1].type in ByteDatatypesWithBoolean
|
2 -> params[0].type in ByteDatatypesWithBoolean && params[1].type in ByteDatatypesWithBoolean
|
||||||
@ -133,39 +124,23 @@ internal class FunctionCallAsmGen(private val program: PtProgram, private val as
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(sub is PtSub) {
|
else if(sub is PtSub) {
|
||||||
val (paramsViaRegisters, normalParams) = sub.parameters.withIndex().partition { it.value.register!=null }
|
if(optimizeIntArgsViaCpuRegisters(sub.parameters)) {
|
||||||
if(normalParams.isNotEmpty()) {
|
// Note that if the args fit into cpu registers, we don't concern ourselves here
|
||||||
if(optimizeIntArgsViaRegisters(normalParams)) {
|
// if they should be put into regular subroutine parameter variables, or the R0-R15 register variables.
|
||||||
when(normalParams.size) {
|
// That is now up to the subroutine itself.
|
||||||
1 -> {
|
useCpuRegistersForArgs(call.args, sub)
|
||||||
val register = if (normalParams[0].value.type in ByteDatatypesWithBoolean) RegisterOrPair.A else RegisterOrPair.AY
|
} else {
|
||||||
argumentViaRegister(sub, IndexedValue(0, normalParams[0].value), call.args[0], register)
|
// arguments via variables
|
||||||
}
|
val (normalParams, registerParams) = sub.parameters.withIndex().partition { it.value.register == null }
|
||||||
2 -> {
|
if (normalParams.isNotEmpty()) {
|
||||||
if(normalParams[0].value.type in ByteDatatypesWithBoolean && normalParams[1].value.type in ByteDatatypesWithBoolean) {
|
for (arg in normalParams.zip(call.args))
|
||||||
// 2 byte params, second in Y, first in A
|
argumentViaVariable(sub, arg.first.value, arg.second)
|
||||||
argumentViaRegister(sub, IndexedValue(0, normalParams[0].value), call.args[0], RegisterOrPair.A)
|
}
|
||||||
if(asmgen.needAsaveForExpr(call.args[1]))
|
if (registerParams.isNotEmpty()) {
|
||||||
asmgen.out(" pha")
|
// the R0-R15 'registers' are not really registers. They're just special variables.
|
||||||
argumentViaRegister(sub, IndexedValue(1, normalParams[1].value), call.args[1], RegisterOrPair.Y)
|
for (arg in registerParams.zip(call.args))
|
||||||
if(asmgen.needAsaveForExpr(call.args[1]))
|
|
||||||
asmgen.out(" pla")
|
|
||||||
} else {
|
|
||||||
throw AssemblyError("cannot use registers for word+byte")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else -> throw AssemblyError("cannot use registers for >2 arguments")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// arguments via variables
|
|
||||||
for(arg in normalParams.zip(call.args))
|
|
||||||
argumentViaVariable(sub, arg.first.value, arg.second)
|
argumentViaVariable(sub, arg.first.value, arg.second)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if(paramsViaRegisters.isNotEmpty()) {
|
|
||||||
// the R0-R15 'registers' are not really registers. They're just special variables.
|
|
||||||
for(arg in paramsViaRegisters.zip(call.args))
|
|
||||||
argumentViaVariable(sub, arg.first.value, arg.second)
|
|
||||||
}
|
}
|
||||||
asmgen.out(" jsr $subAsmName")
|
asmgen.out(" jsr $subAsmName")
|
||||||
}
|
}
|
||||||
@ -174,6 +149,30 @@ internal class FunctionCallAsmGen(private val program: PtProgram, private val as
|
|||||||
// remember: dealing with the X register and/or dealing with return values is the responsibility of the caller
|
// remember: dealing with the X register and/or dealing with return values is the responsibility of the caller
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun useCpuRegistersForArgs(args: List<PtExpression>, sub: PtSub) {
|
||||||
|
val params = sub.parameters
|
||||||
|
when(params.size) {
|
||||||
|
1 -> {
|
||||||
|
val register = if (params[0].type in ByteDatatypesWithBoolean) RegisterOrPair.A else RegisterOrPair.AY
|
||||||
|
argumentViaRegister(sub, IndexedValue(0, params[0]), args[0], register)
|
||||||
|
}
|
||||||
|
2 -> {
|
||||||
|
if(params[0].type in ByteDatatypesWithBoolean && params[1].type in ByteDatatypesWithBoolean) {
|
||||||
|
// 2 byte params, second in Y, first in A
|
||||||
|
argumentViaRegister(sub, IndexedValue(0, params[0]), args[0], RegisterOrPair.A)
|
||||||
|
if(asmgen.needAsaveForExpr(args[1]))
|
||||||
|
asmgen.out(" pha")
|
||||||
|
argumentViaRegister(sub, IndexedValue(1, params[1]), args[1], RegisterOrPair.Y)
|
||||||
|
if(asmgen.needAsaveForExpr(args[1]))
|
||||||
|
asmgen.out(" pla")
|
||||||
|
} else {
|
||||||
|
throw AssemblyError("cannot use registers for word+byte")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> throw AssemblyError("cannot use cpu registers for >2 arguments")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun usesOtherRegistersWhileEvaluating(arg: PtExpression): Boolean {
|
private fun usesOtherRegistersWhileEvaluating(arg: PtExpression): Boolean {
|
||||||
return when(arg) {
|
return when(arg) {
|
||||||
|
@ -421,28 +421,35 @@ internal class ProgramAndVarsGen(
|
|||||||
if((sub.name=="start" || sub.name=="p8s_start") && (sub.definingBlock()!!.name=="main" || sub.definingBlock()!!.name=="p8b_main"))
|
if((sub.name=="start" || sub.name=="p8s_start") && (sub.definingBlock()!!.name=="main" || sub.definingBlock()!!.name=="p8b_main"))
|
||||||
entrypointInitialization()
|
entrypointInitialization()
|
||||||
|
|
||||||
val normalParams = sub.parameters.filter { it.register==null }
|
val params = sub.parameters
|
||||||
if(functioncallAsmGen.optimizeIntArgsViaRegisters(normalParams)) {
|
if(functioncallAsmGen.optimizeIntArgsViaCpuRegisters(params)) {
|
||||||
asmgen.out("; simple int arg(s) passed via register(s)")
|
asmgen.out("; simple int arg(s) passed via cpu register(s)")
|
||||||
when(normalParams.size) {
|
|
||||||
|
fun varname(param: PtSubroutineParameter): String =
|
||||||
|
if(param.register==null)
|
||||||
|
param.name
|
||||||
|
else
|
||||||
|
param.register!!.asScopedNameVirtualReg(param.type).joinToString(".")
|
||||||
|
|
||||||
|
when(params.size) {
|
||||||
1 -> {
|
1 -> {
|
||||||
val dt = normalParams[0].type
|
val dt = params[0].type
|
||||||
val target = AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, dt, sub, normalParams[0].position, variableAsmName = normalParams[0].name)
|
val target = AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, dt, sub, params[0].position, variableAsmName = varname(params[0]))
|
||||||
if(dt in ByteDatatypesWithBoolean)
|
if(dt in ByteDatatypesWithBoolean)
|
||||||
asmgen.assignRegister(RegisterOrPair.A, target)
|
asmgen.assignRegister(RegisterOrPair.A, target) // single byte in A
|
||||||
else
|
else
|
||||||
asmgen.assignRegister(RegisterOrPair.AY, target)
|
asmgen.assignRegister(RegisterOrPair.AY, target) // word in AY
|
||||||
}
|
}
|
||||||
2 -> {
|
2 -> {
|
||||||
val target1 = AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, normalParams[0].type, sub, normalParams[0].position, variableAsmName = normalParams[0].name)
|
val target1 = AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, params[0].type, sub, params[0].position, variableAsmName = varname(params[0]))
|
||||||
val target2 = AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, normalParams[1].type, sub, normalParams[1].position, variableAsmName = normalParams[1].name)
|
val target2 = AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, params[1].type, sub, params[1].position, variableAsmName = varname(params[1]))
|
||||||
if(normalParams[0].type in ByteDatatypesWithBoolean && normalParams[1].type in ByteDatatypesWithBoolean) {
|
if(params[0].type in ByteDatatypesWithBoolean && params[1].type in ByteDatatypesWithBoolean) {
|
||||||
// 2 byte args, first in A, second in Y
|
// 2 byte args, first in A, second in Y
|
||||||
asmgen.assignRegister(RegisterOrPair.A, target1)
|
asmgen.assignRegister(RegisterOrPair.A, target1)
|
||||||
asmgen.assignRegister(RegisterOrPair.Y, target2)
|
asmgen.assignRegister(RegisterOrPair.Y, target2)
|
||||||
} else throw AssemblyError("cannot use registers for word+byte")
|
} else throw AssemblyError("cannot use registers for word+byte args")
|
||||||
}
|
}
|
||||||
else -> throw AssemblyError("cannot use registers for >2 arguments")
|
else -> throw AssemblyError("cannot use registers for >2 args")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -286,10 +286,10 @@ private class BuiltinFunctionsFacade(functions: Map<String, FSignature>): IBuilt
|
|||||||
if(exprfunc!=null) {
|
if(exprfunc!=null) {
|
||||||
return try {
|
return try {
|
||||||
exprfunc(args, position, program)
|
exprfunc(args, position, program)
|
||||||
} catch(x: NotConstArgumentException) {
|
} catch(_: NotConstArgumentException) {
|
||||||
// const-evaluating the builtin function call failed.
|
// const-evaluating the builtin function call failed.
|
||||||
null
|
null
|
||||||
} catch(x: CannotEvaluateException) {
|
} catch(_: CannotEvaluateException) {
|
||||||
// const-evaluating the builtin function call failed.
|
// const-evaluating the builtin function call failed.
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
@ -354,7 +354,7 @@ fun determineCompilationOptions(program: Program, compTarget: ICompilationTarget
|
|||||||
else
|
else
|
||||||
try {
|
try {
|
||||||
ZeropageType.valueOf(zpoption)
|
ZeropageType.valueOf(zpoption)
|
||||||
} catch (x: IllegalArgumentException) {
|
} catch (_: IllegalArgumentException) {
|
||||||
ZeropageType.KERNALSAFE
|
ZeropageType.KERNALSAFE
|
||||||
// error will be printed by the astchecker
|
// error will be printed by the astchecker
|
||||||
}
|
}
|
||||||
@ -383,7 +383,7 @@ fun determineCompilationOptions(program: Program, compTarget: ICompilationTarget
|
|||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
OutputType.valueOf(outputTypeStr)
|
OutputType.valueOf(outputTypeStr)
|
||||||
} catch (x: IllegalArgumentException) {
|
} catch (_: IllegalArgumentException) {
|
||||||
// set default value; actual check and error handling of invalid option is handled in the AstChecker later
|
// set default value; actual check and error handling of invalid option is handled in the AstChecker later
|
||||||
OutputType.PRG
|
OutputType.PRG
|
||||||
}
|
}
|
||||||
@ -396,7 +396,7 @@ fun determineCompilationOptions(program: Program, compTarget: ICompilationTarget
|
|||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
CbmPrgLauncherType.valueOf(launcherTypeStr)
|
CbmPrgLauncherType.valueOf(launcherTypeStr)
|
||||||
} catch (x: IllegalArgumentException) {
|
} catch (_: IllegalArgumentException) {
|
||||||
// set default value; actual check and error handling of invalid option is handled in the AstChecker later
|
// set default value; actual check and error handling of invalid option is handled in the AstChecker later
|
||||||
CbmPrgLauncherType.BASIC
|
CbmPrgLauncherType.BASIC
|
||||||
}
|
}
|
||||||
|
@ -516,7 +516,7 @@ internal class AstChecker(private val program: Program,
|
|||||||
if (!subroutine.isAsmSubroutine && p.registerOrPair!=null) {
|
if (!subroutine.isAsmSubroutine && p.registerOrPair!=null) {
|
||||||
if (p.registerOrPair !in Cx16VirtualRegisters) errors.err("can only use R0-R15 as register param for normal subroutines", p.position)
|
if (p.registerOrPair !in Cx16VirtualRegisters) errors.err("can only use R0-R15 as register param for normal subroutines", p.position)
|
||||||
else {
|
else {
|
||||||
errors.warn("\uD83D\uDCA3 footgun: reusing R0-R15 as parameters risks overwriting due to no callstack or clobbering", subroutine.position)
|
errors.warn("\uD83D\uDCA3 footgun: reusing R0-R15 as parameters risks overwriting due to clobbering or no callstack", subroutine.position)
|
||||||
if(p.type !in WordDatatypes && p.type !in ByteDatatypesWithBoolean) {
|
if(p.type !in WordDatatypes && p.type !in ByteDatatypesWithBoolean) {
|
||||||
errors.err("can only use register param when type is boolean, byte or word", p.position)
|
errors.err("can only use register param when type is boolean, byte or word", p.position)
|
||||||
}
|
}
|
||||||
|
@ -219,8 +219,8 @@ class AstPreprocessor(val program: Program,
|
|||||||
val namesInSub = symbolsInSub.map{ it.first }.toSet()
|
val namesInSub = symbolsInSub.map{ it.first }.toSet()
|
||||||
if(subroutine.asmAddress==null) {
|
if(subroutine.asmAddress==null) {
|
||||||
if(!subroutine.isAsmSubroutine && subroutine.parameters.isNotEmpty()) {
|
if(!subroutine.isAsmSubroutine && subroutine.parameters.isNotEmpty()) {
|
||||||
var mods = mutableListOf<IAstModification>()
|
val mods = mutableListOf<IAstModification>()
|
||||||
var (normalParams, registerParams) = subroutine.parameters.partition { it.registerOrPair==null }
|
val (normalParams, registerParams) = subroutine.parameters.partition { it.registerOrPair==null }
|
||||||
if(normalParams.isNotEmpty()) {
|
if(normalParams.isNotEmpty()) {
|
||||||
val existingVars = subroutine.statements.asSequence().filterIsInstance<VarDecl>().map { it.name }.toSet()
|
val existingVars = subroutine.statements.asSequence().filterIsInstance<VarDecl>().map { it.name }.toSet()
|
||||||
normalParams
|
normalParams
|
||||||
|
@ -1050,7 +1050,7 @@ main {
|
|||||||
val src="""
|
val src="""
|
||||||
main { sub start() { cx16.r0++ cx16.r1++ } }
|
main { sub start() { cx16.r0++ cx16.r1++ } }
|
||||||
other { asmsub thing() { %asm {{ inx }} } }
|
other { asmsub thing() { %asm {{ inx }} } }
|
||||||
""";
|
"""
|
||||||
val result = compileText(VMTarget(), false, src, writeAssembly = false)!!
|
val result = compileText(VMTarget(), false, src, writeAssembly = false)!!
|
||||||
val st = result.compilerAst.entrypoint.statements
|
val st = result.compilerAst.entrypoint.statements
|
||||||
st.size shouldBe 2
|
st.size shouldBe 2
|
||||||
|
@ -58,7 +58,9 @@ Variables
|
|||||||
|
|
||||||
Subroutines
|
Subroutines
|
||||||
-----------
|
-----------
|
||||||
- There is no call stack. Subroutine parameters are overwritten when called again (recursion is not easily possible, but you can do it with manual stack manipulations).
|
- Subroutines can be nested. Inner subroutines can directly access variables from their parent.
|
||||||
|
- Subroutine parameters are just local variables in the subroutine. (you can access them directly as such via their scoped name, if you want)
|
||||||
|
- There is no call stack. So subroutine parameters are overwritten when called again. Thus recursion is not easily possible, but you can do it with manual stack manipulations.
|
||||||
- There is no function overloading (except for a couple of builtin functions).
|
- There is no function overloading (except for a couple of builtin functions).
|
||||||
- Some subroutine types can return multiple return values, and you can multi-assign those in a single statement.
|
- Some subroutine types can return multiple return values, and you can multi-assign those in a single statement.
|
||||||
- Because every declared variable allocates some memory, it might be beneficial to share the same variables over different subroutines
|
- Because every declared variable allocates some memory, it might be beneficial to share the same variables over different subroutines
|
||||||
|
@ -1,29 +1,43 @@
|
|||||||
|
%import textio
|
||||||
|
%zeropage basicsafe
|
||||||
|
|
||||||
main {
|
main {
|
||||||
sub start() {
|
sub start() {
|
||||||
foo(42)
|
foo(42)
|
||||||
bar(9999,55)
|
foo(42)
|
||||||
; faulty1(false)
|
foo(42)
|
||||||
faulty2(42)
|
bar(9999)
|
||||||
faulty3(9999,55)
|
bar(9999)
|
||||||
|
bar(9999)
|
||||||
|
baz(42, 123)
|
||||||
|
baz(42, 123)
|
||||||
|
baz(42, 123)
|
||||||
|
meh(42, 9999)
|
||||||
|
meh(42, 9999)
|
||||||
|
meh(42, 9999)
|
||||||
}
|
}
|
||||||
|
|
||||||
sub foo(ubyte arg @R2) {
|
sub foo(ubyte arg @R0) {
|
||||||
arg++
|
txt.print_ub(arg)
|
||||||
|
txt.nl()
|
||||||
}
|
}
|
||||||
|
|
||||||
sub bar(uword arg @R0, ubyte arg2 @R1) {
|
sub bar(uword arg @R0) {
|
||||||
arg += arg2
|
txt.print_uw(arg)
|
||||||
|
txt.nl()
|
||||||
}
|
}
|
||||||
|
|
||||||
; sub faulty1(bool flag @Pc) {
|
sub baz(ubyte arg1 @R0, ubyte arg2 @R1) {
|
||||||
; cx16.r0++
|
txt.print_ub(arg1)
|
||||||
; }
|
txt.spc()
|
||||||
|
txt.print_ub(arg2)
|
||||||
sub faulty2(byte arg @Y) {
|
txt.nl()
|
||||||
arg++
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sub faulty3(uword arg @R1, ubyte arg2 @R1) {
|
sub meh(ubyte arg1 @R0, uword arg2 @R1) {
|
||||||
arg += arg2
|
txt.print_ub(arg1)
|
||||||
|
txt.spc()
|
||||||
|
txt.print_uw(arg2)
|
||||||
|
txt.nl()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -72,7 +72,7 @@ fun parseIRCodeLine(line: String): Either<IRInstruction, String> {
|
|||||||
val (instr, typestr, rest) = match.destructured
|
val (instr, typestr, rest) = match.destructured
|
||||||
val opcode = try {
|
val opcode = try {
|
||||||
Opcode.valueOf(instr.uppercase())
|
Opcode.valueOf(instr.uppercase())
|
||||||
} catch (ax: IllegalArgumentException) {
|
} catch (_: IllegalArgumentException) {
|
||||||
throw IRParseException("invalid vmasm instruction: $instr")
|
throw IRParseException("invalid vmasm instruction: $instr")
|
||||||
}
|
}
|
||||||
var type: IRDataType? = convertIRType(typestr)
|
var type: IRDataType? = convertIRType(typestr)
|
||||||
@ -181,11 +181,11 @@ fun parseIRCodeLine(line: String): Either<IRInstruction, String> {
|
|||||||
throw IRParseException("needs value or symbol for $line")
|
throw IRParseException("needs value or symbol for $line")
|
||||||
when (type) {
|
when (type) {
|
||||||
IRDataType.BYTE -> {
|
IRDataType.BYTE -> {
|
||||||
if (immediateInt!=null && (immediateInt!! < -128 || immediateInt!! > 255))
|
if (immediateInt!=null && (immediateInt < -128 || immediateInt > 255))
|
||||||
throw IRParseException("immediate value out of range for byte: $immediateInt")
|
throw IRParseException("immediate value out of range for byte: $immediateInt")
|
||||||
}
|
}
|
||||||
IRDataType.WORD -> {
|
IRDataType.WORD -> {
|
||||||
if (immediateInt!=null && (immediateInt!! < -32768 || immediateInt!! > 65535))
|
if (immediateInt!=null && (immediateInt < -32768 || immediateInt > 65535))
|
||||||
throw IRParseException("immediate value out of range for word: $immediateInt")
|
throw IRParseException("immediate value out of range for word: $immediateInt")
|
||||||
}
|
}
|
||||||
IRDataType.FLOAT -> {}
|
IRDataType.FLOAT -> {}
|
||||||
@ -198,13 +198,13 @@ fun parseIRCodeLine(line: String): Either<IRInstruction, String> {
|
|||||||
|
|
||||||
var offset: Int? = null
|
var offset: Int? = null
|
||||||
if(labelSymbol!=null) {
|
if(labelSymbol!=null) {
|
||||||
if (labelSymbol!![0] == 'r' && labelSymbol!![1].isDigit())
|
if (labelSymbol[0] == 'r' && labelSymbol[1].isDigit())
|
||||||
throw IRParseException("labelsymbol confused with register?: $labelSymbol")
|
throw IRParseException("labelsymbol confused with register?: $labelSymbol")
|
||||||
if('+' in labelSymbol!!) {
|
if('+' in labelSymbol) {
|
||||||
val offsetStr = labelSymbol!!.substringAfterLast('+')
|
val offsetStr = labelSymbol.substringAfterLast('+')
|
||||||
if (offsetStr.isNotEmpty()) {
|
if (offsetStr.isNotEmpty()) {
|
||||||
offset = offsetStr.toInt()
|
offset = offsetStr.toInt()
|
||||||
labelSymbol = labelSymbol!!.substringBeforeLast('+')
|
labelSymbol = labelSymbol.substringBeforeLast('+')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -320,10 +320,10 @@ internal fun parseRegisterOrStatusflag(sourceregs: String): RegisterOrStatusflag
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
reg = RegisterOrPair.valueOf(regs)
|
reg = RegisterOrPair.valueOf(regs)
|
||||||
} catch (x: IllegalArgumentException) {
|
} catch (_: IllegalArgumentException) {
|
||||||
try {
|
try {
|
||||||
sf = Statusflag.valueOf(regs)
|
sf = Statusflag.valueOf(regs)
|
||||||
} catch(x: IllegalArgumentException) {
|
} catch(_: IllegalArgumentException) {
|
||||||
throw IRParseException("invalid IR register or statusflag: $regs")
|
throw IRParseException("invalid IR register or statusflag: $regs")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -270,7 +270,7 @@ object SysCalls {
|
|||||||
val trimmed = memstring.takeWhile { it in " +-0123456789.eE" }
|
val trimmed = memstring.takeWhile { it in " +-0123456789.eE" }
|
||||||
try {
|
try {
|
||||||
trimmed.toDouble()
|
trimmed.toDouble()
|
||||||
} catch(x: NumberFormatException) {
|
} catch(_: NumberFormatException) {
|
||||||
0.0
|
0.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -567,7 +567,7 @@ object SysCalls {
|
|||||||
val height = response.next().toInt()
|
val height = response.next().toInt()
|
||||||
return returnValue(callspec.returns.single(), height*256 + width, vm)
|
return returnValue(callspec.returns.single(), height*256 + width, vm)
|
||||||
}
|
}
|
||||||
} catch (x: Exception) {
|
} catch (_: Exception) {
|
||||||
// don't know what happened...
|
// don't know what happened...
|
||||||
}
|
}
|
||||||
return returnValue(callspec.returns.single(), 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
|
||||||
|
Loading…
Reference in New Issue
Block a user