From 278cbcec6325b9584a324d3d0e4f02ecc7b41616 Mon Sep 17 00:00:00 2001 From: Karol Stasiak Date: Sun, 10 Jun 2018 01:56:04 +0200 Subject: [PATCH] Fixed return dispatch returns on LUnix. Added non-relocated address constants. --- docs/api/target-platforms.md | 11 ++++ include/lunix.mfk | 2 + .../millfork/compiler/ReturnDispatch.scala | 57 ++++++++++++------- src/main/scala/millfork/env/Environment.scala | 19 +++++++ src/main/scala/millfork/node/Node.scala | 4 ++ 5 files changed, 72 insertions(+), 21 deletions(-) diff --git a/docs/api/target-platforms.md b/docs/api/target-platforms.md index b7fb4ab2..1f1a0fb4 100644 --- a/docs/api/target-platforms.md +++ b/docs/api/target-platforms.md @@ -81,6 +81,17 @@ After putting it on a disk, the file can be run with: Currently, multipart BBC Micro programs are not supported. +### A note about LUnix + +LUnix uses relocatable code, which means that object addresses (`.addr`) are not constants. +To help with this problem, new constants are defined, with a `.rawaddr` suffix. +They are not relocated, so to use them, you need to manually relocate them +by adding `relocation_offset` to their high bytes: + + pointer p + p = variable.rawaddr + p.hi += relocation_offset + ## Adding a custom platform Every platform is defined in an `.ini` file with an appropriate name. diff --git a/include/lunix.mfk b/include/lunix.mfk index 165faeeb..d6765d11 100644 --- a/include/lunix.mfk +++ b/include/lunix.mfk @@ -1,5 +1,7 @@ const word lkf_jumptab = $200 +byte relocation_offset @$1001 + inline asm byte get_ipid() { ? lda 2 ? rts diff --git a/src/main/scala/millfork/compiler/ReturnDispatch.scala b/src/main/scala/millfork/compiler/ReturnDispatch.scala index fc3f8e90..0474946d 100644 --- a/src/main/scala/millfork/compiler/ReturnDispatch.scala +++ b/src/main/scala/millfork/compiler/ReturnDispatch.scala @@ -52,11 +52,12 @@ object ReturnDispatch { case _ => () } + var env = ctx.env val returnType = ctx.function.returnType - val map: mutable.Map[Int, (String, List[Expression])] = mutable.Map() + val map: mutable.Map[Int, (Option[ThingInMemory], List[Expression])] = mutable.Map() var min = Option.empty[Int] var max = Option.empty[Int] - var default = Option.empty[(String, List[Expression])] + var default = Option.empty[(Option[ThingInMemory], List[Expression])] stmt.branches.foreach { branch => val function: String = ctx.env.evalForAsm(branch.function) match { case Some(MemoryAddressConstant(f: FunctionInMemory)) => @@ -80,14 +81,14 @@ object ReturnDispatch { } min = start.map(toInt) max = end.map(toInt) - default = Some(function -> params) + default = Some(Some(env.get[FunctionInMemory](function)) -> params) case StandardReturnDispatchLabel(labels) => labels.foreach { label => val i = toInt(label) if (map.contains(i)) { ErrorReporting.error(s"Duplicate dispatch label: $label = $i", label.position) } - map(i) = function -> params + map(i) = Some(env.get[FunctionInMemory](function)) -> params } } } @@ -100,7 +101,7 @@ object ReturnDispatch { } val actualMin = defaultMin min nonDefaultMin.getOrElse(defaultMin) val actualMax = defaultMax max nonDefaultMax.getOrElse(defaultMax) - val zeroes = "" -> List[Expression]() + val zeroes = None -> List[Expression]() for (i <- actualMin to actualMax) { if (!map.contains(i)) map(i) = default.getOrElse { // TODO: warning? @@ -118,7 +119,6 @@ object ReturnDispatch { else actualMax } - var env = ctx.env while (env.parent.isDefined) env = env.parent.get val label = MfCompiler.nextLabel("di") val paramArrays = stmt.params.indices.map { ix => @@ -130,7 +130,7 @@ object ReturnDispatch { a } - val useJmpaix = ctx.options.flag(CompilationFlag.EmitCmosOpcodes) && (actualMax - actualMin) <= 127 + val useJmpaix = ctx.options.flag(CompilationFlag.EmitCmosOpcodes) && !ctx.options.flag(CompilationFlag.LUnixRelocatableCode) && (actualMax - actualMin) <= 127 val b = ctx.env.get[Type]("byte") import millfork.assembly.AddrMode._ @@ -164,28 +164,43 @@ object ReturnDispatch { val jumpTableHi = InitializedArray(label + "$jh.array", None, (actualMin to actualMax).map(i => hibyte1(map(i)._1)).toList, ctx.function.declaredBank) env.registerUnnamedArray(jumpTableLo) env.registerUnnamedArray(jumpTableHi) - loadIndex ++ copyParams ++ List( - AssemblyLine.absoluteX(LDA, jumpTableHi.toAddress - actualMin), - AssemblyLine.implied(PHA), - AssemblyLine.absoluteX(LDA, jumpTableLo.toAddress - actualMin), - AssemblyLine.implied(PHA), - AssemblyLine.implied(RTS)) + val actualJump = if (ctx.options.flag(CompilationFlag.LUnixRelocatableCode)) { + List( + AssemblyLine.absoluteX(LDA, jumpTableHi.toAddress - actualMin), + AssemblyLine.implied(CLC), + AssemblyLine.absolute(ADC, env.get[ThingInMemory]("relocation_offset")), + AssemblyLine.implied(PHA), + AssemblyLine.absoluteX(LDA, jumpTableLo.toAddress - actualMin), + AssemblyLine.implied(PHA), + AssemblyLine.implied(RTS)) + }else { + List( + AssemblyLine.absoluteX(LDA, jumpTableHi.toAddress - actualMin), + AssemblyLine.implied(PHA), + AssemblyLine.absoluteX(LDA, jumpTableLo.toAddress - actualMin), + AssemblyLine.implied(PHA), + AssemblyLine.implied(RTS)) + } + loadIndex ++ copyParams ++ actualJump } } - private def lobyte0(fname: String): Expression = if (fname == "") LiteralExpression(0, 1) else { - FunctionCallExpression("lo",List(VariableExpression(fname + ".addr"))) + private def zeroOr(function: Option[ThingInMemory])(F: ThingInMemory => Constant): Expression = + function.fold[Expression](LiteralExpression(0, 1))(F andThen ConstantArrayElementExpression) + + private def lobyte0(function: Option[ThingInMemory]): Expression = { + zeroOr(function)(f => MemoryAddressConstant(f).loByte) } - private def hibyte0(fname: String): Expression = if (fname == "") LiteralExpression(0, 1) else { - FunctionCallExpression("hi",List(VariableExpression(fname + ".addr"))) + private def hibyte0(function: Option[ThingInMemory]): Expression = { + zeroOr(function)(f => MemoryAddressConstant(f).hiByte) } - private def lobyte1(fname: String): Expression = if (fname == "") LiteralExpression(0, 1) else { - FunctionCallExpression("lo", List(SumExpression(List(false -> VariableExpression(fname + ".addr"), true -> LiteralExpression(1, 1)), decimal = false))) + private def lobyte1(function: Option[ThingInMemory]): Expression = { + zeroOr(function)(f => MemoryAddressConstant(f).-(1).loByte) } - private def hibyte1(fname: String): Expression = if (fname == "") LiteralExpression(0, 1) else { - FunctionCallExpression("hi", List(SumExpression(List(false -> VariableExpression(fname + ".addr"), true -> LiteralExpression(1, 1)), decimal = false))) + private def hibyte1(function: Option[ThingInMemory]): Expression = { + zeroOr(function)(f => MemoryAddressConstant(f).-(1).hiByte) } } diff --git a/src/main/scala/millfork/env/Environment.scala b/src/main/scala/millfork/env/Environment.scala index 6fcd76cf..58906e76 100644 --- a/src/main/scala/millfork/env/Environment.scala +++ b/src/main/scala/millfork/env/Environment.scala @@ -174,14 +174,23 @@ class Environment(val parent: Option[Environment], val prefix: String) { removedThings += str + ".addr" removedThings += str + ".addr.lo" removedThings += str + ".addr.hi" + removedThings += str + ".rawaddr" + removedThings += str + ".rawaddr.lo" + removedThings += str + ".rawaddr.hi" things -= str things -= str + ".addr" things -= str + ".addr.lo" things -= str + ".addr.hi" + things -= str + ".rawaddr" + things -= str + ".rawaddr.lo" + things -= str + ".rawaddr.hi" things -= str.stripPrefix(prefix) things -= str.stripPrefix(prefix) + ".addr" things -= str.stripPrefix(prefix) + ".addr.lo" things -= str.stripPrefix(prefix) + ".addr.hi" + things -= str.stripPrefix(prefix) + ".rawaddr" + things -= str.stripPrefix(prefix) + ".rawaddr.lo" + things -= str.stripPrefix(prefix) + ".rawaddr.hi" parent.foreach(_ removeVariableImpl str) } @@ -334,6 +343,7 @@ class Environment(val parent: Option[Environment], val prefix: String) { def eval(e: Expression): Option[Constant] = { e match { case LiteralExpression(value, size) => Some(NumericConstant(value, size)) + case ConstantArrayElementExpression(c) => Some(c) case VariableExpression(name) => maybeGet[ConstantThing](name).map(_.value) case IndexedExpression(_, _) => None @@ -429,6 +439,7 @@ class Environment(val parent: Option[Environment], val prefix: String) { def evalForAsm(e: Expression): Option[Constant] = { e match { case LiteralExpression(value, size) => Some(NumericConstant(value, size)) + case ConstantArrayElementExpression(c) => Some(c) case VariableExpression(name) => maybeGet[ConstantThing](name).map(_.value).orElse(maybeGet[ThingInMemory](name).map(_.toAddress)) case IndexedExpression(name, index) => (evalForAsm(VariableExpression(name)), evalForAsm(index)) match { @@ -602,11 +613,18 @@ class Environment(val parent: Option[Environment], val prefix: String) { addThing(relocatable, position) addThing(RelativeVariable(thing.name + ".addr.hi", addr + 1, b, zeropage = false, None), position) addThing(RelativeVariable(thing.name + ".addr.lo", addr, b, zeropage = false, None), position) + val rawaddr = thing.toAddress + addThing(ConstantThing(thing.name + ".rawaddr", rawaddr, get[Type]("pointer")), position) + addThing(ConstantThing(thing.name + ".rawaddr.hi", rawaddr.hiByte, get[Type]("byte")), position) + addThing(ConstantThing(thing.name + ".rawaddr.lo", rawaddr.loByte, get[Type]("byte")), position) } else { val addr = thing.toAddress addThing(ConstantThing(thing.name + ".addr", addr, get[Type]("pointer")), position) addThing(ConstantThing(thing.name + ".addr.hi", addr.hiByte, get[Type]("byte")), position) addThing(ConstantThing(thing.name + ".addr.lo", addr.loByte, get[Type]("byte")), position) + addThing(ConstantThing(thing.name + ".rawaddr", addr, get[Type]("pointer")), position) + addThing(ConstantThing(thing.name + ".rawaddr.hi", addr.hiByte, get[Type]("byte")), position) + addThing(ConstantThing(thing.name + ".rawaddr.lo", addr.loByte, get[Type]("byte")), position) } } @@ -661,6 +679,7 @@ class Environment(val parent: Option[Environment], val prefix: String) { val pointerName = array.name.stripSuffix(".array") addThing(ConstantThing(pointerName, array.toAddress, p), None) addThing(ConstantThing(pointerName + ".addr", array.toAddress, p), None) + addThing(ConstantThing(pointerName + ".rawaddr", array.toAddress, p), None) addThing(array, None) } diff --git a/src/main/scala/millfork/node/Node.scala b/src/main/scala/millfork/node/Node.scala index 9b246cb3..d58fb639 100644 --- a/src/main/scala/millfork/node/Node.scala +++ b/src/main/scala/millfork/node/Node.scala @@ -22,6 +22,10 @@ sealed trait Expression extends Node { def replaceVariable(variable: String, actualParam: Expression): Expression } +case class ConstantArrayElementExpression(constant: Constant) extends Expression { + override def replaceVariable(variable: String, actualParam: Expression): Expression = this +} + case class LiteralExpression(value: Long, requiredSize: Int) extends Expression { override def replaceVariable(variable: String, actualParam: Expression): Expression = this }