mirror of
https://github.com/KarolS/millfork.git
synced 2026-04-21 09:16:34 +00:00
Preliminary LUnix support
This commit is contained in:
@@ -104,6 +104,9 @@ object Cpu extends Enumeration {
|
||||
case "6502" => Mos
|
||||
case "6510" => Mos
|
||||
case "strict" => StrictMos
|
||||
case "strictnmos" => StrictMos
|
||||
case "strict6502" => StrictMos
|
||||
case "strict6510" => StrictMos
|
||||
case "cmos" => Cmos
|
||||
case "65sc02" => Cmos
|
||||
case "sc02" => Cmos
|
||||
@@ -135,7 +138,7 @@ object CompilationFlag extends Enumeration {
|
||||
// optimization options:
|
||||
DangerousOptimizations, InlineFunctions, OptimizeForSize, OptimizeForSpeed, OptimizeForSonicSpeed,
|
||||
// memory allocation options
|
||||
VariableOverlap, CompactReturnDispatchParams,
|
||||
VariableOverlap, CompactReturnDispatchParams, LUnixRelocatableCode,
|
||||
// runtime check options
|
||||
CheckIndexOutOfBounds,
|
||||
// special options
|
||||
@@ -150,6 +153,7 @@ object CompilationFlag extends Enumeration {
|
||||
val allWarnings: Set[CompilationFlag.Value] = Set(ExtraComparisonWarnings)
|
||||
|
||||
val fromString = Map(
|
||||
"lunix" -> LUnixRelocatableCode,
|
||||
"emit_illegals" -> EmitIllegals,
|
||||
"emit_cmos" -> EmitCmosOpcodes,
|
||||
"emit_65ce02" -> Emit65CE02Opcodes,
|
||||
|
||||
@@ -13,7 +13,7 @@ import org.apache.commons.configuration2.INIConfiguration
|
||||
*/
|
||||
|
||||
object OutputStyle extends Enumeration {
|
||||
val Single, PerBank = Value
|
||||
val Single, PerBank, LUnix = Value
|
||||
}
|
||||
|
||||
class Platform(
|
||||
@@ -135,7 +135,7 @@ object Platform {
|
||||
|
||||
val freePointers = as.get(classOf[String], "zp_pointers", "all") match {
|
||||
case "all" => List.tabulate(128)(_ * 2)
|
||||
case xs => xs.split("[, ]+").map(parseNumber).toList
|
||||
case xs => xs.split("[, ]+").flatMap(parseNumberOrRange).toList
|
||||
}
|
||||
|
||||
val codeAllocators = banks.map(b => b -> new UpwardByteAllocator(bankStarts(b), bankCodeEnds(b)))
|
||||
@@ -148,7 +148,9 @@ object Platform {
|
||||
val os = conf.getSection("output")
|
||||
val outputPackager = SequenceOutput(os.get(classOf[String], "format", "").split("[, ]+").filter(_.nonEmpty).map {
|
||||
case "startaddr" => StartAddressOutput
|
||||
case "startpage" => StartPageOutput
|
||||
case "endaddr" => EndAddressOutput
|
||||
case "pagecount" => PageCountOutput
|
||||
case "allocated" => AllocatedDataOutput
|
||||
case n => n.split(":").filter(_.nonEmpty) match {
|
||||
case Array(b, s, e) => BankFragmentOutput(b, parseNumber(s), parseNumber(e))
|
||||
@@ -162,6 +164,7 @@ object Platform {
|
||||
val outputStyle = os.get(classOf[String], "style", "single") match {
|
||||
case "" | "single" => OutputStyle.Single
|
||||
case "per_bank" | "per_segment" => OutputStyle.PerBank
|
||||
case "lunix" => OutputStyle.LUnix
|
||||
case x => ErrorReporting.fatal(s"Invalid output style: `$x`")
|
||||
}
|
||||
|
||||
@@ -175,6 +178,18 @@ object Platform {
|
||||
outputStyle)
|
||||
}
|
||||
|
||||
def parseNumberOrRange(s:String): Seq[Int] = {
|
||||
if (s.contains("-")) {
|
||||
var segments = s.split("-")
|
||||
if (segments.length != 2) {
|
||||
ErrorReporting.fatal(s"Invalid range: `$s`")
|
||||
}
|
||||
Range(parseNumber(segments(0)), parseNumber(segments(1)), 2)
|
||||
} else {
|
||||
Seq(parseNumber(s))
|
||||
}
|
||||
}
|
||||
|
||||
def parseNumber(s: String): Int = {
|
||||
if (s.startsWith("$")) {
|
||||
Integer.parseInt(s.substring(1), 16)
|
||||
|
||||
+9
-7
@@ -70,7 +70,7 @@ sealed trait Constant {
|
||||
|
||||
def quickSimplify: Constant = this
|
||||
|
||||
def isRelatedTo(v: Variable): Boolean
|
||||
def isRelatedTo(v: Thing): Boolean
|
||||
}
|
||||
|
||||
case class AssertByte(c: Constant) extends Constant {
|
||||
@@ -78,13 +78,15 @@ case class AssertByte(c: Constant) extends Constant {
|
||||
|
||||
override def requiredSize: Int = 1
|
||||
|
||||
override def isRelatedTo(v: Variable): Boolean = c.isRelatedTo(v)
|
||||
override def isRelatedTo(v: Thing): Boolean = c.isRelatedTo(v)
|
||||
|
||||
override def quickSimplify: Constant = AssertByte(c.quickSimplify)
|
||||
}
|
||||
|
||||
case class UnexpandedConstant(name: String, requiredSize: Int) extends Constant {
|
||||
override def isRelatedTo(v: Variable): Boolean = false
|
||||
override def isRelatedTo(v: Thing): Boolean = false
|
||||
|
||||
override def toString: String = name
|
||||
}
|
||||
|
||||
case class NumericConstant(value: Long, requiredSize: Int) extends Constant {
|
||||
@@ -111,7 +113,7 @@ case class NumericConstant(value: Long, requiredSize: Int) extends Constant {
|
||||
|
||||
override def toString: String = if (value > 9) value.formatted("$%X") else value.toString
|
||||
|
||||
override def isRelatedTo(v: Variable): Boolean = false
|
||||
override def isRelatedTo(v: Thing): Boolean = false
|
||||
}
|
||||
|
||||
case class MemoryAddressConstant(var thing: ThingInMemory) extends Constant {
|
||||
@@ -119,7 +121,7 @@ case class MemoryAddressConstant(var thing: ThingInMemory) extends Constant {
|
||||
|
||||
override def toString: String = thing.name
|
||||
|
||||
override def isRelatedTo(v: Variable): Boolean = thing.name == v.name
|
||||
override def isRelatedTo(v: Thing): Boolean = thing.name == v.name
|
||||
}
|
||||
|
||||
case class SubbyteConstant(base: Constant, index: Int) extends Constant {
|
||||
@@ -144,7 +146,7 @@ case class SubbyteConstant(base: Constant, index: Int) extends Constant {
|
||||
case 3 => ".b3"
|
||||
})
|
||||
|
||||
override def isRelatedTo(v: Variable): Boolean = base.isRelatedTo(v)
|
||||
override def isRelatedTo(v: Thing): Boolean = base.isRelatedTo(v)
|
||||
}
|
||||
|
||||
object MathOperator extends Enumeration {
|
||||
@@ -304,5 +306,5 @@ case class CompoundConstant(operator: MathOperator.Value, lhs: Constant, rhs: Co
|
||||
|
||||
override def requiredSize: Int = lhs.requiredSize max rhs.requiredSize
|
||||
|
||||
override def isRelatedTo(v: Variable): Boolean = lhs.isRelatedTo(v) || rhs.isRelatedTo(v)
|
||||
override def isRelatedTo(v: Thing): Boolean = lhs.isRelatedTo(v) || rhs.isRelatedTo(v)
|
||||
}
|
||||
+68
-33
@@ -100,7 +100,7 @@ class Environment(val parent: Option[Environment], val prefix: String) {
|
||||
}
|
||||
}.toSet
|
||||
val toAdd = things.values.flatMap {
|
||||
case m: UninitializedMemory if nf.isDefined == isLocalVariableName(m.name) =>
|
||||
case m: UninitializedMemory if nf.isDefined == isLocalVariableName(m.name) && !m.name.endsWith(".addr") && maybeGet[Thing](m.name + ".array").isEmpty =>
|
||||
val vertex = if (options.flag(CompilationFlag.VariableOverlap)) {
|
||||
nf.fold[VariableVertex](GlobalVertex) { f =>
|
||||
if (m.alloc == VariableAllocationMethod.Static) {
|
||||
@@ -240,20 +240,23 @@ class Environment(val parent: Option[Environment], val prefix: String) {
|
||||
if (parent.isEmpty) {
|
||||
addThing(VoidType, None)
|
||||
addThing(BuiltInBooleanType, None)
|
||||
addThing(BasicPlainType("byte", 1), None)
|
||||
addThing(BasicPlainType("word", 2), None)
|
||||
val b = BasicPlainType("byte", 1)
|
||||
val w = BasicPlainType("word", 2)
|
||||
addThing(b, None)
|
||||
addThing(w, None)
|
||||
addThing(BasicPlainType("farword", 3), None)
|
||||
addThing(BasicPlainType("long", 4), None)
|
||||
addThing(DerivedPlainType("pointer", get[PlainType]("word"), isSigned = false), None)
|
||||
// addThing(DerivedPlainType("farpointer", get[PlainType]("farword"), isSigned = false), None)
|
||||
addThing(DerivedPlainType("ubyte", get[PlainType]("byte"), isSigned = false), None)
|
||||
addThing(DerivedPlainType("sbyte", get[PlainType]("byte"), isSigned = true), None)
|
||||
addThing(DerivedPlainType("pointer", w, isSigned = false), None)
|
||||
// addThing(DerivedPlainType("farpointer", get[PlainType]("farword"), isSigned = false), None)
|
||||
addThing(DerivedPlainType("ubyte", b, isSigned = false), None)
|
||||
addThing(DerivedPlainType("sbyte", b, isSigned = true), None)
|
||||
val trueType = ConstantBooleanType("true$", value = true)
|
||||
val falseType = ConstantBooleanType("false$", value = false)
|
||||
addThing(trueType, None)
|
||||
addThing(falseType, None)
|
||||
addThing(ConstantThing("true", NumericConstant(0, 0), trueType), None)
|
||||
addThing(ConstantThing("false", NumericConstant(0, 0), falseType), None)
|
||||
addThing(ConstantThing("__zeropage_usage", UnexpandedConstant("__zeropage_usage", 1), b), None)
|
||||
addThing(FlagBooleanType("set_carry", Opcode.BCS, Opcode.BCC), None)
|
||||
addThing(FlagBooleanType("clear_carry", Opcode.BCC, Opcode.BCS), None)
|
||||
addThing(FlagBooleanType("set_overflow", Opcode.BVS, Opcode.BVC), None)
|
||||
@@ -502,7 +505,7 @@ class Environment(val parent: Option[Environment], val prefix: String) {
|
||||
}
|
||||
|
||||
val env = new Environment(Some(this), name + "$")
|
||||
stmt.params.foreach(p => env.registerParameter(p))
|
||||
stmt.params.foreach(p => env.registerParameter(p, options))
|
||||
val params = if (stmt.assembly) {
|
||||
AssemblyParamSignature(stmt.params.map {
|
||||
pd =>
|
||||
@@ -539,7 +542,7 @@ class Environment(val parent: Option[Environment], val prefix: String) {
|
||||
stmt.bank
|
||||
)
|
||||
addThing(mangled, stmt.position)
|
||||
registerAddressConstant(mangled, stmt.position)
|
||||
registerAddressConstant(mangled, stmt.position, options)
|
||||
addThing(ConstantThing(name + '`', addr, w), stmt.position)
|
||||
}
|
||||
|
||||
@@ -585,19 +588,29 @@ class Environment(val parent: Option[Environment], val prefix: String) {
|
||||
declaredBank = stmt.bank
|
||||
)
|
||||
addThing(mangled, stmt.position)
|
||||
registerAddressConstant(mangled, stmt.position)
|
||||
registerAddressConstant(mangled, stmt.position, options)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private def registerAddressConstant(thing: ThingInMemory, position: Option[Position]): Unit = {
|
||||
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)
|
||||
private def registerAddressConstant(thing: ThingInMemory, position: Option[Position], options: CompilationOptions): Unit = {
|
||||
if (!thing.zeropage && options.flag(CompilationFlag.LUnixRelocatableCode)) {
|
||||
val b = get[Type]("byte")
|
||||
val w = get[Type]("word")
|
||||
val relocatable = UninitializedMemoryVariable(thing.name + ".addr", w, VariableAllocationMethod.Static, None)
|
||||
val addr = relocatable.toAddress
|
||||
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)
|
||||
} 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)
|
||||
}
|
||||
}
|
||||
|
||||
def registerParameter(stmt: ParameterDeclaration): Unit = {
|
||||
def registerParameter(stmt: ParameterDeclaration, options: CompilationOptions): Unit = {
|
||||
val typ = get[Type](stmt.typ)
|
||||
val b = get[Type]("byte")
|
||||
val w = get[Type]("word")
|
||||
@@ -607,7 +620,7 @@ class Environment(val parent: Option[Environment], val prefix: String) {
|
||||
val zp = typ.name == "pointer" // TODO
|
||||
val v = UninitializedMemoryVariable(prefix + name, typ, if (zp) VariableAllocationMethod.Zeropage else VariableAllocationMethod.Auto, None)
|
||||
addThing(v, stmt.position)
|
||||
registerAddressConstant(v, stmt.position)
|
||||
registerAddressConstant(v, stmt.position, options)
|
||||
val addr = v.toAddress
|
||||
typ.size match {
|
||||
case 2 =>
|
||||
@@ -674,7 +687,7 @@ class Environment(val parent: Option[Environment], val prefix: String) {
|
||||
}
|
||||
}
|
||||
|
||||
def registerArray(stmt: ArrayDeclarationStatement): Unit = {
|
||||
def registerArray(stmt: ArrayDeclarationStatement, options: CompilationOptions): Unit = {
|
||||
val b = get[Type]("byte")
|
||||
val p = get[Type]("pointer")
|
||||
stmt.elements match {
|
||||
@@ -694,18 +707,30 @@ class Environment(val parent: Option[Environment], val prefix: String) {
|
||||
declaredBank = stmt.bank)
|
||||
}
|
||||
addThing(array, stmt.position)
|
||||
registerAddressConstant(UninitializedMemoryVariable(stmt.name, p, VariableAllocationMethod.None, stmt.bank), stmt.position)
|
||||
registerAddressConstant(UninitializedMemoryVariable(stmt.name, p, VariableAllocationMethod.None, stmt.bank), stmt.position, options)
|
||||
val a = address match {
|
||||
case None => array.toAddress
|
||||
case Some(aa) => aa
|
||||
}
|
||||
addThing(RelativeVariable(stmt.name + ".first", a, b, zeropage = false,
|
||||
declaredBank = stmt.bank), stmt.position)
|
||||
addThing(ConstantThing(stmt.name, a, p), stmt.position)
|
||||
addThing(ConstantThing(stmt.name + ".hi", a.hiByte.quickSimplify, b), stmt.position)
|
||||
addThing(ConstantThing(stmt.name + ".lo", a.loByte.quickSimplify, b), stmt.position)
|
||||
addThing(ConstantThing(stmt.name + ".array.hi", a.hiByte.quickSimplify, b), stmt.position)
|
||||
addThing(ConstantThing(stmt.name + ".array.lo", a.loByte.quickSimplify, b), stmt.position)
|
||||
if (options.flag(CompilationFlag.LUnixRelocatableCode)) {
|
||||
val b = get[Type]("byte")
|
||||
val w = get[Type]("word")
|
||||
val relocatable = UninitializedMemoryVariable(stmt.name, w, VariableAllocationMethod.Static, None)
|
||||
val addr = relocatable.toAddress
|
||||
addThing(relocatable, stmt.position)
|
||||
addThing(RelativeVariable(stmt.name + ".addr.hi", addr + 1, b, zeropage = false, None), stmt.position)
|
||||
addThing(RelativeVariable(stmt.name + ".addr.lo", addr, b, zeropage = false, None), stmt.position)
|
||||
addThing(RelativeVariable(stmt.name + ".array.hi", addr + 1, b, zeropage = false, None), stmt.position)
|
||||
addThing(RelativeVariable(stmt.name + ".array.lo", addr, b, zeropage = false, None), stmt.position)
|
||||
} else {
|
||||
addThing(ConstantThing(stmt.name, a, p), stmt.position)
|
||||
addThing(ConstantThing(stmt.name + ".hi", a.hiByte.quickSimplify, b), stmt.position)
|
||||
addThing(ConstantThing(stmt.name + ".lo", a.loByte.quickSimplify, b), stmt.position)
|
||||
addThing(ConstantThing(stmt.name + ".array.hi", a.hiByte.quickSimplify, b), stmt.position)
|
||||
addThing(ConstantThing(stmt.name + ".array.lo", a.loByte.quickSimplify, b), stmt.position)
|
||||
}
|
||||
if (length < 256) {
|
||||
addThing(ConstantThing(stmt.name + ".length", lengthConst, b), stmt.position)
|
||||
}
|
||||
@@ -730,18 +755,28 @@ class Environment(val parent: Option[Environment], val prefix: String) {
|
||||
val array = InitializedArray(stmt.name + ".array", address, contents, declaredBank = stmt.bank)
|
||||
addThing(array, stmt.position)
|
||||
registerAddressConstant(UninitializedMemoryVariable(stmt.name, p, VariableAllocationMethod.None,
|
||||
declaredBank = stmt.bank), stmt.position)
|
||||
declaredBank = stmt.bank), stmt.position, options)
|
||||
val a = address match {
|
||||
case None => array.toAddress
|
||||
case Some(aa) => aa
|
||||
}
|
||||
addThing(RelativeVariable(stmt.name + ".first", a, b, zeropage = false,
|
||||
declaredBank = stmt.bank), stmt.position)
|
||||
addThing(ConstantThing(stmt.name, a, p), stmt.position)
|
||||
addThing(ConstantThing(stmt.name + ".hi", a.hiByte.quickSimplify, b), stmt.position)
|
||||
addThing(ConstantThing(stmt.name + ".lo", a.loByte.quickSimplify, b), stmt.position)
|
||||
addThing(ConstantThing(stmt.name + ".array.hi", a.hiByte.quickSimplify, b), stmt.position)
|
||||
addThing(ConstantThing(stmt.name + ".array.lo", a.loByte.quickSimplify, b), stmt.position)
|
||||
if (options.flag(CompilationFlag.LUnixRelocatableCode)) {
|
||||
val b = get[Type]("byte")
|
||||
val w = get[Type]("word")
|
||||
val relocatable = UninitializedMemoryVariable(stmt.name, w, VariableAllocationMethod.Static, None)
|
||||
val addr = relocatable.toAddress
|
||||
addThing(relocatable, stmt.position)
|
||||
addThing(RelativeVariable(stmt.name + ".array.hi", addr + 1, b, zeropage = false, None), stmt.position)
|
||||
addThing(RelativeVariable(stmt.name + ".array.lo", addr, b, zeropage = false, None), stmt.position)
|
||||
} else {
|
||||
addThing(ConstantThing(stmt.name, a, p), stmt.position)
|
||||
addThing(ConstantThing(stmt.name + ".hi", a.hiByte.quickSimplify, b), stmt.position)
|
||||
addThing(ConstantThing(stmt.name + ".lo", a.loByte.quickSimplify, b), stmt.position)
|
||||
addThing(ConstantThing(stmt.name + ".array.hi", a.hiByte.quickSimplify, b), stmt.position)
|
||||
addThing(ConstantThing(stmt.name + ".array.lo", a.loByte.quickSimplify, b), stmt.position)
|
||||
}
|
||||
if (length < 256) {
|
||||
addThing(ConstantThing(stmt.name + ".length", NumericConstant(length, 1), b), stmt.position)
|
||||
}
|
||||
@@ -846,7 +881,7 @@ class Environment(val parent: Option[Environment], val prefix: String) {
|
||||
}
|
||||
InitializedMemoryVariable(name, None, typ, ive, declaredBank = stmt.bank)
|
||||
}
|
||||
registerAddressConstant(v, stmt.position)
|
||||
registerAddressConstant(v, stmt.position, options)
|
||||
(v, v.toAddress)
|
||||
})(a => {
|
||||
val addr = eval(a).getOrElse(Constant.error(s"Address of `$name` has a non-constant value", position))
|
||||
@@ -856,7 +891,7 @@ class Environment(val parent: Option[Environment], val prefix: String) {
|
||||
}
|
||||
val v = RelativeVariable(prefix + name, addr, typ, zeropage = zp,
|
||||
declaredBank = stmt.bank)
|
||||
registerAddressConstant(v, stmt.position)
|
||||
registerAddressConstant(v, stmt.position, options)
|
||||
(v, addr)
|
||||
})
|
||||
addThing(v, stmt.position)
|
||||
@@ -927,7 +962,7 @@ class Environment(val parent: Option[Environment], val prefix: String) {
|
||||
program.declarations.foreach {
|
||||
case f: FunctionDeclarationStatement => registerFunction(f, options)
|
||||
case v: VariableDeclarationStatement => registerVariable(v, options)
|
||||
case a: ArrayDeclarationStatement => registerArray(a)
|
||||
case a: ArrayDeclarationStatement => registerArray(a, options)
|
||||
case i: ImportStatement => ()
|
||||
}
|
||||
if (options.flag(CompilationFlag.ZeropagePseudoregister) && !things.contains("__reg")) {
|
||||
|
||||
+14
-1
@@ -78,6 +78,8 @@ sealed trait TypedThing extends Thing {
|
||||
|
||||
|
||||
sealed trait ThingInMemory extends Thing {
|
||||
def zeropage: Boolean
|
||||
|
||||
def toAddress: Constant
|
||||
|
||||
var farFlag: Option[Boolean] = None
|
||||
@@ -105,12 +107,13 @@ case class Label(name: String) extends ThingInMemory {
|
||||
declaredBank.getOrElse(compilationOptions.platform.defaultCodeBank)
|
||||
|
||||
override val declaredBank: Option[String] = None
|
||||
|
||||
override def zeropage: Boolean = false
|
||||
}
|
||||
|
||||
sealed trait Variable extends TypedThing with VariableLikeThing
|
||||
|
||||
sealed trait VariableInMemory extends Variable with ThingInMemory with IndexableThing {
|
||||
def zeropage: Boolean
|
||||
|
||||
override def isFar(compilationOptions: CompilationOptions): Boolean =
|
||||
!zeropage && farFlag.getOrElse(false)
|
||||
@@ -175,6 +178,8 @@ case class UninitializedArray(name: String, sizeInBytes: Int, declaredBank: Opti
|
||||
override def isFar(compilationOptions: CompilationOptions): Boolean = farFlag.getOrElse(false)
|
||||
|
||||
override def bank(compilationOptions: CompilationOptions): String = declaredBank.getOrElse("default")
|
||||
|
||||
override def zeropage: Boolean = false
|
||||
}
|
||||
|
||||
case class RelativeArray(name: String, address: Constant, sizeInBytes: Int, declaredBank: Option[String]) extends MfArray {
|
||||
@@ -183,6 +188,8 @@ case class RelativeArray(name: String, address: Constant, sizeInBytes: Int, decl
|
||||
override def isFar(compilationOptions: CompilationOptions): Boolean = farFlag.getOrElse(false)
|
||||
|
||||
override def bank(compilationOptions: CompilationOptions): String = declaredBank.getOrElse("default")
|
||||
|
||||
override def zeropage: Boolean = false
|
||||
}
|
||||
|
||||
case class InitializedArray(name: String, address: Option[Constant], contents: List[Expression], declaredBank: Option[String]) extends MfArray with PreallocableThing {
|
||||
@@ -191,6 +198,8 @@ case class InitializedArray(name: String, address: Option[Constant], contents: L
|
||||
override def isFar(compilationOptions: CompilationOptions): Boolean = farFlag.getOrElse(false)
|
||||
|
||||
override def bank(compilationOptions: CompilationOptions): String = declaredBank.getOrElse(compilationOptions.platform.defaultCodeBank)
|
||||
|
||||
override def zeropage: Boolean = false
|
||||
}
|
||||
|
||||
case class RelativeVariable(name: String, address: Constant, typ: Type, zeropage: Boolean, declaredBank: Option[String]) extends VariableInMemory {
|
||||
@@ -242,6 +251,8 @@ case class ExternFunction(name: String,
|
||||
override def toAddress: Constant = address
|
||||
|
||||
override def interrupt = false
|
||||
|
||||
override def zeropage: Boolean = false
|
||||
}
|
||||
|
||||
case class NormalFunction(name: String,
|
||||
@@ -257,6 +268,8 @@ case class NormalFunction(name: String,
|
||||
position: Option[Position],
|
||||
declaredBank: Option[String]) extends FunctionInMemory with PreallocableThing {
|
||||
override def shouldGenerate = true
|
||||
|
||||
override def zeropage: Boolean = false
|
||||
}
|
||||
|
||||
case class ConstantThing(name: String, value: Constant, typ: Type) extends TypedThing with VariableLikeThing with IndexableThing {
|
||||
|
||||
@@ -78,7 +78,7 @@ class Assembler(private val program: Program, private val rootEnv: Environment,
|
||||
try {
|
||||
if (labelMap.contains(th.name)) return labelMap(th.name)
|
||||
if (labelMap.contains(th.name + "`")) return labelMap(th.name)
|
||||
if (labelMap.contains(th.name + ".addr")) return labelMap(th.name)
|
||||
if (labelMap.contains(th.name + ".addr")) return labelMap.getOrElse[Int](th.name, labelMap(th.name + ".array"))
|
||||
val x1 = env.maybeGet[ConstantThing](th.name).map(_.value)
|
||||
val x2 = env.maybeGet[ConstantThing](th.name + "`").map(_.value)
|
||||
val x3 = env.maybeGet[NormalFunction](th.name).flatMap(_.address)
|
||||
@@ -97,6 +97,9 @@ class Assembler(private val program: Program, private val rootEnv: Environment,
|
||||
case e: StackOverflowError =>
|
||||
ErrorReporting.fatal("Stack overflow " + c)
|
||||
}
|
||||
case UnexpandedConstant(name, _) =>
|
||||
if (labelMap.contains(name)) labelMap(name)
|
||||
else ???
|
||||
case SubbyteConstant(cc, i) => deepConstResolve(cc).>>>(i * 8).&(0xff)
|
||||
case CompoundConstant(operator, lc, rc) =>
|
||||
val l = deepConstResolve(lc)
|
||||
@@ -282,6 +285,42 @@ class Assembler(private val program: Program, private val rootEnv: Environment,
|
||||
}
|
||||
case _ =>
|
||||
}
|
||||
if (options.flag(CompilationFlag.LUnixRelocatableCode)) {
|
||||
env.allThings.things.foreach {
|
||||
case (_, m@UninitializedMemoryVariable(name, typ, _, _)) if name.endsWith(".addr") || env.maybeGet[Thing](name + ".array").isDefined =>
|
||||
val isUsed = compiledFunctions.values.exists(_.exists(_.parameter.isRelatedTo(m)))
|
||||
// println(m.name -> isUsed)
|
||||
if (isUsed) {
|
||||
val bank = m.bank(options)
|
||||
if (bank != "default") ???
|
||||
val bank0 = mem.banks(bank)
|
||||
var index = codeAllocators(bank).allocateBytes(bank0, options, typ.size + 1, initialized = true, writeable = false)
|
||||
labelMap(name) = index + 1
|
||||
val altName = m.name.stripPrefix(env.prefix) + "`"
|
||||
val thing = if (name.endsWith(".addr")) env.get[ThingInMemory](name.stripSuffix(".addr")) else env.get[ThingInMemory](name + ".array")
|
||||
env.things += altName -> ConstantThing(altName, NumericConstant(index, 2), env.get[Type]("pointer"))
|
||||
assembly.append("* = $" + index.toHexString)
|
||||
assembly.append(" !byte $2c")
|
||||
assembly.append(name)
|
||||
val c = thing.toAddress
|
||||
writeByte(bank, index, 0x2c.toByte) // BIT abs
|
||||
index += 1
|
||||
for (i <- 0 until typ.size) {
|
||||
writeByte(bank, index, c.subbyte(i))
|
||||
assembly.append(" !byte " + c.subbyte(i).quickSimplify)
|
||||
index += 1
|
||||
}
|
||||
initializedVariablesSize += typ.size
|
||||
justAfterCode += bank -> index
|
||||
}
|
||||
case _ => ()
|
||||
}
|
||||
val index = codeAllocators("default").allocateBytes(mem.banks("default"), options, 1, initialized = true, writeable = false)
|
||||
writeByte("default", index, 2.toByte) // BIT abs
|
||||
assembly.append("* = $" + index.toHexString)
|
||||
assembly.append(" !byte 2 ;; end of LUnix relocatable segment")
|
||||
justAfterCode += "default" -> (index + 1)
|
||||
}
|
||||
env.allPreallocatables.foreach {
|
||||
case thing@InitializedArray(name, None, items, _) =>
|
||||
val bank = thing.bank(options)
|
||||
@@ -305,7 +344,7 @@ class Assembler(private val program: Program, private val rootEnv: Environment,
|
||||
}
|
||||
initializedVariablesSize += items.length
|
||||
justAfterCode += bank -> index
|
||||
case m@InitializedMemoryVariable(name, None, typ, value, _) =>
|
||||
case m@InitializedMemoryVariable(name, None, typ, value, _) =>
|
||||
val bank = m.bank(options)
|
||||
val bank0 = mem.banks(bank)
|
||||
var index = codeAllocators(bank).allocateBytes(bank0, options, typ.size, initialized = true, writeable = true)
|
||||
@@ -335,9 +374,15 @@ class Assembler(private val program: Program, private val rootEnv: Environment,
|
||||
for(i <- 0 until size) bank0.occupied(addr + i) = true
|
||||
}
|
||||
val variableAllocators = platform.variableAllocators
|
||||
variableAllocators.foreach{case (b,a) => a.notifyAboutEndOfCode(justAfterCode(b))}
|
||||
variableAllocators.foreach { case (b, a) => a.notifyAboutEndOfCode(justAfterCode(b)) }
|
||||
env.allocateVariables(None, mem, callGraph, variableAllocators, options, labelMap.put)
|
||||
|
||||
val zeropageOccupation = mem.banks("default").occupied.slice(variableAllocators("default").pointers.head, variableAllocators("default").pointers.last + 2)
|
||||
labelMap += "__zeropage_usage" -> (zeropageOccupation.lastIndexOf(true) - zeropageOccupation.indexOf(true) + 1)
|
||||
labelMap += "__zeropage_first" -> (zeropageOccupation.indexOf(true) max 0)
|
||||
labelMap += "__zeropage_last" -> (zeropageOccupation.lastIndexOf(true) max 0)
|
||||
labelMap += "__zeropage_end" -> (zeropageOccupation.lastIndexOf(true) + 1)
|
||||
|
||||
env = rootEnv.allThings
|
||||
|
||||
for ((bank, addr, b) <- bytesToWriteLater) {
|
||||
@@ -367,7 +412,7 @@ class Assembler(private val program: Program, private val rootEnv: Environment,
|
||||
|
||||
// TODO:
|
||||
val code = (platform.outputStyle match {
|
||||
case OutputStyle.Single => List("default")
|
||||
case OutputStyle.Single | OutputStyle.LUnix => List("default")
|
||||
case OutputStyle.PerBank => platform.bankNumbers.keys.toList
|
||||
}).map(b => b -> platform.outputPackager.packageOutput(mem, b)).toMap
|
||||
AssemblerOutput(code, assembly.toArray, labelMap.toList)
|
||||
|
||||
@@ -45,6 +45,13 @@ object StartAddressOutput extends OutputPackager {
|
||||
}
|
||||
}
|
||||
|
||||
object StartPageOutput extends OutputPackager {
|
||||
def packageOutput(mem: CompiledMemory, bank: String): Array[Byte] = {
|
||||
val b = mem.banks(bank)
|
||||
Array(b.start.>>(8).toByte)
|
||||
}
|
||||
}
|
||||
|
||||
object EndAddressOutput extends OutputPackager {
|
||||
def packageOutput(mem: CompiledMemory, bank: String): Array[Byte] = {
|
||||
val b = mem.banks(bank)
|
||||
@@ -52,6 +59,14 @@ object EndAddressOutput extends OutputPackager {
|
||||
}
|
||||
}
|
||||
|
||||
object PageCountOutput extends OutputPackager {
|
||||
def packageOutput(mem: CompiledMemory, bank: String): Array[Byte] = {
|
||||
val e = mem.banks(bank).end.>>(8)
|
||||
val s = mem.banks(bank).start.>>(8)
|
||||
Array((e - s + 1).toByte)
|
||||
}
|
||||
}
|
||||
|
||||
object AllocatedDataOutput extends OutputPackager {
|
||||
def packageOutput(mem: CompiledMemory, bank: String): Array[Byte] = {
|
||||
val b = mem.banks(bank)
|
||||
|
||||
@@ -50,7 +50,7 @@ class AfterCodeByteAllocator(val endBefore: Int) extends ByteAllocator {
|
||||
def notifyAboutEndOfCode(org: Int): Unit = startAt = org
|
||||
}
|
||||
|
||||
class VariableAllocator(private val pointers: List[Int], private val bytes: ByteAllocator) {
|
||||
class VariableAllocator(val pointers: List[Int], private val bytes: ByteAllocator) {
|
||||
|
||||
private val pointerMap = mutable.Map[Int, Set[VariableVertex]]()
|
||||
private val variableMap = mutable.Map[Int, mutable.Map[Int, Set[VariableVertex]]]()
|
||||
|
||||
Reference in New Issue
Block a user