1
0
mirror of https://github.com/KarolS/millfork.git synced 2024-07-05 09:28:54 +00:00

Preliminary support for object alignment

This commit is contained in:
Karol Stasiak 2018-08-07 17:31:41 +02:00
parent 60d2cc1959
commit c846a19eef
12 changed files with 113 additions and 63 deletions

View File

@ -29,7 +29,10 @@ class AbstractExpressionCompiler[T <: AbstractCode] {
def callingContext(ctx: CompilationContext, v: MemoryVariable): CompilationContext = {
val result = new Environment(Some(ctx.env), "", ctx.options.platform.cpuFamily, ctx.jobContext)
result.registerVariable(VariableDeclarationStatement(v.name, v.typ.name, stack = false, global = false, constant = false, volatile = false, register = false, initialValue = None, address = None, bank = v.declaredBank), ctx.options)
result.registerVariable(VariableDeclarationStatement(
v.name, v.typ.name,
stack = false, global = false, constant = false, volatile = false, register = false,
initialValue = None, address = None, bank = v.declaredBank, alignment = None), ctx.options)
ctx.copy(env = result)
}

View File

@ -5,6 +5,7 @@ import millfork.assembly.AbstractCode
import millfork.env._
import millfork.error.ConsoleLogger
import millfork.node._
import millfork.output.NoAlignment
import scala.collection.mutable
@ -132,7 +133,7 @@ abstract class AbstractReturnDispatch[T <: AbstractCode] {
val a = InitializedArray(label + "$" + ix + ".array", None, (paramMins(ix) to paramMaxes(ix)).map { key =>
map(key)._2.lift(ix).getOrElse(LiteralExpression(0, 1))
}.toList,
ctx.function.declaredBank, b, b)
ctx.function.declaredBank, b, b, NoAlignment)
env.registerUnnamedArray(a)
a
}

View File

@ -34,7 +34,7 @@ abstract class AbstractStatementPreprocessor(ctx: CompilationContext, statements
}
protected val reentrantVars: Set[String] = trackableVars.filter(v => env.get[Variable](v) match {
case _: StackVariable => true
case UninitializedMemoryVariable(_, _, VariableAllocationMethod.Auto, _) => ctx.options.flag(CompilationFlag.DangerousOptimizations)
case UninitializedMemoryVariable(_, _, VariableAllocationMethod.Auto, _, _) => ctx.options.flag(CompilationFlag.DangerousOptimizations)
case _ => false
})
protected val nonreentrantVars: Set[String] = trackableVars -- reentrantVars
@ -172,7 +172,7 @@ abstract class AbstractStatementPreprocessor(ctx: CompilationContext, statements
case TextLiteralExpression(characters) =>
val name = genName(characters)
if (ctx.env.maybeGet[Thing](name).isEmpty) {
ctx.env.root.registerArray(ArrayDeclarationStatement(name, None, None, None, Some(LiteralContents(characters))).pos(pos), ctx.options)
ctx.env.root.registerArray(ArrayDeclarationStatement(name, None, None, None, Some(LiteralContents(characters)), None).pos(pos), ctx.options)
}
VariableExpression(name).pos(pos)
case VariableExpression(v) if currentVarValues.contains(v) =>

View File

@ -7,6 +7,7 @@ import millfork.compiler.{AbstractReturnDispatch, BranchSpec, CompilationContext
import millfork.env._
import millfork.error.ConsoleLogger
import millfork.node._
import millfork.output.NoAlignment
import scala.collection.mutable
@ -40,7 +41,7 @@ object MosReturnDispatch extends AbstractReturnDispatch[AssemblyLine] {
}
if (useJmpaix) {
val jumpTable = InitializedArray(label + "$jt.array", None, (actualMin to actualMax).flatMap(i => List(lobyte0(map(i)._1), hibyte0(map(i)._1))).toList, ctx.function.declaredBank, b, b)
val jumpTable = InitializedArray(label + "$jt.array", None, (actualMin to actualMax).flatMap(i => List(lobyte0(map(i)._1), hibyte0(map(i)._1))).toList, ctx.function.declaredBank, b, b, NoAlignment)
env.registerUnnamedArray(jumpTable)
if (copyParams.isEmpty) {
val loadIndex = MosExpressionCompiler.compile(ctx, stmt.indexer, Some(b -> RegisterVariable(MosRegister.A, b)), BranchSpec.None)
@ -55,8 +56,8 @@ object MosReturnDispatch extends AbstractReturnDispatch[AssemblyLine] {
}
} else {
val loadIndex = MosExpressionCompiler.compile(ctx, stmt.indexer, Some(b -> RegisterVariable(MosRegister.X, b)), BranchSpec.None)
val jumpTableLo = InitializedArray(label + "$jl.array", None, (actualMin to actualMax).map(i => lobyte1(map(i)._1)).toList, ctx.function.declaredBank, b, b)
val jumpTableHi = InitializedArray(label + "$jh.array", None, (actualMin to actualMax).map(i => hibyte1(map(i)._1)).toList, ctx.function.declaredBank, b, b)
val jumpTableLo = InitializedArray(label + "$jl.array", None, (actualMin to actualMax).map(i => lobyte1(map(i)._1)).toList, ctx.function.declaredBank, b, b, NoAlignment)
val jumpTableHi = InitializedArray(label + "$jh.array", None, (actualMin to actualMax).map(i => hibyte1(map(i)._1)).toList, ctx.function.declaredBank, b, b, NoAlignment)
env.registerUnnamedArray(jumpTableLo)
env.registerUnnamedArray(jumpTableHi)
val actualJump = if (ctx.options.flag(CompilationFlag.LUnixRelocatableCode)) {

View File

@ -5,6 +5,7 @@ import millfork.compiler.{AbstractReturnDispatch, CompilationContext}
import millfork.env.{Constant, InitializedArray, ThingInMemory, VariableType}
import millfork.error.ConsoleLogger
import millfork.node.{Expression, ReturnDispatchStatement, ZRegister}
import millfork.output.NoAlignment
import scala.collection.mutable
@ -50,8 +51,8 @@ object Z80ReturnDispatch extends AbstractReturnDispatch[ZLine] {
}
val copyParams = pair._2.reverse.flatten
val offsetAfterParams = pair._1
val jumpTableLo = InitializedArray(label + "$jl.array", None, (actualMin to actualMax).map(i => lobyte0(map(i)._1)).toList, ctx.function.declaredBank, b, b)
val jumpTableHi = InitializedArray(label + "$jh.array", None, (actualMin to actualMax).map(i => hibyte0(map(i)._1)).toList, ctx.function.declaredBank, b, b)
val jumpTableLo = InitializedArray(label + "$jl.array", None, (actualMin to actualMax).map(i => lobyte0(map(i)._1)).toList, ctx.function.declaredBank, b, b, NoAlignment)
val jumpTableHi = InitializedArray(label + "$jh.array", None, (actualMin to actualMax).map(i => hibyte0(map(i)._1)).toList, ctx.function.declaredBank, b, b, NoAlignment)
env.registerUnnamedArray(jumpTableLo)
env.registerUnnamedArray(jumpTableHi)

View File

@ -7,7 +7,7 @@ import millfork.assembly.z80.{IfFlagClear, IfFlagSet, ZFlag}
import millfork.compiler.LabelGenerator
import millfork.error.Logger
import millfork.node._
import millfork.output.{AllocationLocation, CompiledMemory, VariableAllocator}
import millfork.output._
import scala.collection.mutable
@ -156,7 +156,7 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
case VariableAllocationMethod.Zeropage =>
if (forZpOnly || !options.platform.hasZeroPage) {
val addr =
allocators(bank).allocateBytes(mem.banks(bank), callGraph, vertex, options, m.sizeInBytes, initialized = false, writeable = true, location = AllocationLocation.Zeropage)
allocators(bank).allocateBytes(mem.banks(bank), callGraph, vertex, options, m.sizeInBytes, initialized = false, writeable = true, location = AllocationLocation.Zeropage, alignment = m.alignment)
onEachVariable(m.name, addr)
List(
ConstantThing(m.name.stripPrefix(prefix) + "`", NumericConstant(addr, 2), p)
@ -170,7 +170,7 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
val graveName = m.name.stripPrefix(prefix) + "`"
if (forZpOnly) {
if (bank == "default") {
allocators(bank).tryAllocateZeropageBytes(mem.banks(bank), callGraph, vertex, options, m.sizeInBytes) match {
allocators(bank).tryAllocateZeropageBytes(mem.banks(bank), callGraph, vertex, options, m.sizeInBytes, alignment = m.alignment) match {
case None => Nil
case Some(addr) =>
onEachVariable(m.name, addr)
@ -182,7 +182,7 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
} else if (things.contains(graveName)) {
Nil
} else {
val addr = allocators(bank).allocateBytes(mem.banks(bank), callGraph, vertex, options, m.sizeInBytes, initialized = false, writeable = true, location = AllocationLocation.Either)
val addr = allocators(bank).allocateBytes(mem.banks(bank), callGraph, vertex, options, m.sizeInBytes, initialized = false, writeable = true, location = AllocationLocation.Either, alignment = m.alignment)
onEachVariable(m.name, addr)
List(
ConstantThing(graveName, NumericConstant(addr, 2), p)
@ -294,8 +294,8 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
InitializedMemoryVariable
UninitializedMemoryVariable
getArrayOrPointer(name) match {
case th@InitializedArray(_, _, cs, _, i, e) => ConstantPointy(th.toAddress, Some(name), Some(cs.length), i, e)
case th@UninitializedArray(_, size, _, i, e) => ConstantPointy(th.toAddress, Some(name), Some(size), i, e)
case th@InitializedArray(_, _, cs, _, i, e, _) => ConstantPointy(th.toAddress, Some(name), Some(cs.length), i, e)
case th@UninitializedArray(_, size, _, i, e, _) => ConstantPointy(th.toAddress, Some(name), Some(size), i, e)
case th@RelativeArray(_, _, size, _, i, e) => ConstantPointy(th.toAddress, Some(name), Some(size), i, e)
case ConstantThing(_, value, typ) if typ.size <= 2 =>
val b = get[VariableType]("byte")
@ -713,7 +713,7 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
})
}
if (resultType.size > Cpu.getMaxSizeReturnableViaRegisters(options.platform.cpu, options)) {
registerVariable(VariableDeclarationStatement(stmt.name + ".return", stmt.resultType, None, global = true, stack = false, constant = false, volatile = false, register = false, None, None), options)
registerVariable(VariableDeclarationStatement(stmt.name + ".return", stmt.resultType, None, global = true, stack = false, constant = false, volatile = false, register = false, None, None, None), options)
}
stmt.statements match {
case None =>
@ -786,7 +786,7 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
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 relocatable = UninitializedMemoryVariable(thing.name + ".addr", w, VariableAllocationMethod.Static, None, defaultVariableAlignment(options, 2))
val addr = relocatable.toAddress
addThing(relocatable, position)
addThing(RelativeVariable(thing.name + ".addr.hi", addr + 1, b, zeropage = false, None), position)
@ -814,7 +814,7 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
stmt.assemblyParamPassingConvention match {
case ByVariable(name) =>
val zp = typ.name == "pointer" // TODO
val v = UninitializedMemoryVariable(prefix + name, typ, if (zp) VariableAllocationMethod.Zeropage else VariableAllocationMethod.Auto, None)
val v = UninitializedMemoryVariable(prefix + name, typ, if (zp) VariableAllocationMethod.Zeropage else VariableAllocationMethod.Auto, None, defaultVariableAlignment(options, 2))
addThing(v, stmt.position)
registerAddressConstant(v, stmt.position, options)
val addr = v.toAddress
@ -870,6 +870,18 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
}
}
private def defaultArrayAlignment(options: CompilationOptions, size: Long): MemoryAlignment = {
if (options.platform.cpuFamily == CpuFamily.M6502 &&
options.flag(CompilationFlag.OptimizeForSpeed) &&
size <= 256) WithinPageAlignment
else NoAlignment
}
private def defaultVariableAlignment(options: CompilationOptions, size: Long): MemoryAlignment = {
if (options.flag(CompilationFlag.PreventJmpIndirectBug) && size == 2) WithinPageAlignment
else NoAlignment
}
def registerArray(stmt: ArrayDeclarationStatement, options: CompilationOptions): Unit = {
val b = get[VariableType]("byte")
val w = get[VariableType]("word")
@ -897,14 +909,15 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
lengthConst match {
case NumericConstant(length, _) =>
if (length > 0xffff || length < 0) log.error(s"Array `${stmt.name}` has invalid length", stmt.position)
val alignment = stmt.alignment.getOrElse(defaultArrayAlignment(options, length))
val array = address match {
case None => UninitializedArray(stmt.name + ".array", length.toInt,
declaredBank = stmt.bank, indexType, b)
declaredBank = stmt.bank, indexType, b, alignment)
case Some(aa) => RelativeArray(stmt.name + ".array", aa, length.toInt,
declaredBank = stmt.bank, indexType, b)
}
addThing(array, stmt.position)
registerAddressConstant(UninitializedMemoryVariable(stmt.name, p, VariableAllocationMethod.None, stmt.bank), stmt.position, options)
registerAddressConstant(UninitializedMemoryVariable(stmt.name, p, VariableAllocationMethod.None, stmt.bank, NoAlignment), stmt.position, options)
val a = address match {
case None => array.toAddress
case Some(aa) => aa
@ -914,7 +927,7 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
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 relocatable = UninitializedMemoryVariable(stmt.name, w, VariableAllocationMethod.Static, None, NoAlignment)
val addr = relocatable.toAddress
addThing(relocatable, stmt.position)
addThing(RelativeVariable(stmt.name + ".addr.hi", addr + 1, b, zeropage = false, None), stmt.position)
@ -968,11 +981,12 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
}
val length = contents.length
if (length > 0xffff || length < 0) log.error(s"Array `${stmt.name}` has invalid length", stmt.position)
val alignment = stmt.alignment.getOrElse(defaultArrayAlignment(options, length))
val address = stmt.address.map(a => eval(a).getOrElse(errorConstant(s"Array `${stmt.name}` has non-constant address", stmt.position)))
val array = InitializedArray(stmt.name + ".array", address, contents, declaredBank = stmt.bank, indexType, b)
val array = InitializedArray(stmt.name + ".array", address, contents, declaredBank = stmt.bank, indexType, b, alignment)
addThing(array, stmt.position)
registerAddressConstant(UninitializedMemoryVariable(stmt.name, p, VariableAllocationMethod.None,
declaredBank = stmt.bank), stmt.position, options)
declaredBank = stmt.bank, alignment), stmt.position, options)
val a = address match {
case None => array.toAddress
case Some(aa) => aa
@ -982,7 +996,7 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
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 relocatable = UninitializedMemoryVariable(stmt.name, w, VariableAllocationMethod.Static, None, NoAlignment)
val addr = relocatable.toAddress
addThing(relocatable, stmt.position)
addThing(RelativeVariable(stmt.name + ".array.hi", addr + 1, b, zeropage = false, None), stmt.position)
@ -1023,6 +1037,7 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
case _ => ()
}
}
val alignment = stmt.alignment.getOrElse(defaultVariableAlignment(options, typ.size))
if (stmt.constant) {
if (stmt.stack) log.error(s"`$name` is a constant and cannot be on stack", position)
if (stmt.register) log.error(s"`$name` is a constant and cannot be in a register", position)
@ -1060,11 +1075,11 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
log.error(s"`$name` cannot be preinitialized`", position)
}
val v = stmt.initialValue.fold[MemoryVariable](UninitializedMemoryVariable(prefix + name, typ, alloc,
declaredBank = stmt.bank)){ive =>
declaredBank = stmt.bank, alignment)){ive =>
if (options.flags(CompilationFlag.ReadOnlyArrays)) {
log.warn("Initialized variable in read-only segment", position)
}
InitializedMemoryVariable(name, None, typ, ive, declaredBank = stmt.bank)
InitializedMemoryVariable(name, None, typ, ive, declaredBank = stmt.bank, alignment)
}
registerAddressConstant(v, stmt.position, options)
(v, v.toAddress)
@ -1096,6 +1111,7 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
if (typ.name == "__reg$type") {
return (".lo", 0, b) ::
(".hi", 1, b) ::
(".loword", 0, w) ::
(".b2b3", 2, w) ::
List.tabulate(typ.size) { i => (".b" + i, i, b) }
}
@ -1161,7 +1177,7 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
def collectDeclarations(program: Program, options: CompilationOptions): Unit = {
val b = get[VariableType]("byte")
if (options.flag(CompilationFlag.OptimizeForSonicSpeed)) {
addThing(InitializedArray("identity$", None, List.tabulate(256)(n => LiteralExpression(n, 1)), declaredBank = None, b, b), None)
addThing(InitializedArray("identity$", None, List.tabulate(256)(n => LiteralExpression(n, 1)), declaredBank = None, b, b, defaultArrayAlignment(options, 256)), None)
}
program.declarations.foreach {
case a: AliasDefinitionStatement => registerAlias(a)
@ -1189,11 +1205,12 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
volatile = false,
register = false,
initialValue = None,
address = None), options)
address = None,
alignment = None), options)
}
if (CpuFamily.forType(options.platform.cpu) == CpuFamily.M6502) {
if (!things.contains("__constant8")) {
things("__constant8") = InitializedArray("__constant8", None, List(LiteralExpression(8, 1)), declaredBank = None, b, b)
things("__constant8") = InitializedArray("__constant8", None, List(LiteralExpression(8, 1)), declaredBank = None, b, b, NoAlignment)
}
}
}

View File

@ -1,9 +1,9 @@
package millfork.env
import millfork.assembly.BranchingOpcodeMapping
import millfork.{CompilationFlag, CompilationOptions, CpuFamily}
import millfork.assembly.mos.Opcode
import millfork.{CompilationFlag, CompilationOptions}
import millfork.node._
import millfork.output.{MemoryAlignment, NoAlignment}
sealed trait Thing {
def name: String
@ -27,7 +27,7 @@ sealed trait Type extends CallableThing {
def isCompatible(other: Type): Boolean = this == other
override def toString(): String = name
override def toString: String = name
def isAssignableTo(targetType: Type): Boolean = isCompatible(targetType)
@ -110,6 +110,8 @@ sealed trait PreallocableThing extends ThingInMemory {
def address: Option[Constant]
def alignment: MemoryAlignment
def toAddress: Constant = address.getOrElse(MemoryAddressConstant(this))
}
@ -152,6 +154,8 @@ sealed trait UninitializedMemory extends ThingInMemory {
def sizeInBytes: Int
def alloc: VariableAllocationMethod.Value
def alignment: MemoryAlignment
}
object VariableAllocationMethod extends Enumeration {
@ -170,7 +174,7 @@ abstract class MemoryVariable extends VariableInMemory {
def alloc: VariableAllocationMethod.Value
}
case class UninitializedMemoryVariable(name: String, typ: Type, alloc: VariableAllocationMethod.Value, declaredBank: Option[String]) extends MemoryVariable with UninitializedMemory {
case class UninitializedMemoryVariable(name: String, typ: Type, alloc: VariableAllocationMethod.Value, declaredBank: Option[String], override val alignment: MemoryAlignment) extends MemoryVariable with UninitializedMemory {
override def sizeInBytes: Int = typ.size
override def zeropage: Boolean = alloc == VariableAllocationMethod.Zeropage
@ -178,7 +182,7 @@ case class UninitializedMemoryVariable(name: String, typ: Type, alloc: VariableA
override def toAddress: MemoryAddressConstant = MemoryAddressConstant(this)
}
case class InitializedMemoryVariable(name: String, address: Option[Constant], typ: Type, initialValue: Expression, declaredBank: Option[String]) extends MemoryVariable with PreallocableThing {
case class InitializedMemoryVariable(name: String, address: Option[Constant], typ: Type, initialValue: Expression, declaredBank: Option[String], override val alignment: MemoryAlignment) extends MemoryVariable with PreallocableThing {
override def zeropage: Boolean = false
override def toAddress: MemoryAddressConstant = MemoryAddressConstant(this)
@ -193,10 +197,10 @@ trait MfArray extends ThingInMemory with IndexableThing {
def elementType: VariableType
}
case class UninitializedArray(name: String, sizeInBytes: Int, declaredBank: Option[String], indexType: VariableType, elementType: VariableType) extends MfArray with UninitializedMemory {
case class UninitializedArray(name: String, sizeInBytes: Int, declaredBank: Option[String], indexType: VariableType, elementType: VariableType, override val alignment: MemoryAlignment) extends MfArray with UninitializedMemory {
override def toAddress: MemoryAddressConstant = MemoryAddressConstant(this)
override def alloc = VariableAllocationMethod.Static
override def alloc: VariableAllocationMethod.Value = VariableAllocationMethod.Static
override def isFar(compilationOptions: CompilationOptions): Boolean = farFlag.getOrElse(false)
@ -215,7 +219,7 @@ case class RelativeArray(name: String, address: Constant, sizeInBytes: Int, decl
override def zeropage: Boolean = false
}
case class InitializedArray(name: String, address: Option[Constant], contents: List[Expression], declaredBank: Option[String], indexType: VariableType, elementType: VariableType) extends MfArray with PreallocableThing {
case class InitializedArray(name: String, address: Option[Constant], contents: List[Expression], declaredBank: Option[String], indexType: VariableType, elementType: VariableType, override val alignment: MemoryAlignment) extends MfArray with PreallocableThing {
override def shouldGenerate = true
override def isFar(compilationOptions: CompilationOptions): Boolean = farFlag.getOrElse(false)
@ -293,6 +297,8 @@ case class NormalFunction(name: String,
override def shouldGenerate = true
override def zeropage: Boolean = false
override def alignment: MemoryAlignment = NoAlignment
}
case class ConstantThing(name: String, value: Constant, typ: Type) extends TypedThing with VariableLikeThing with IndexableThing {

View File

@ -3,6 +3,7 @@ package millfork.node
import millfork.assembly.mos.{AddrMode, Opcode}
import millfork.assembly.z80.{ZOpcode, ZRegisters}
import millfork.env.{Constant, ParamPassingConvention, Type}
import millfork.output.MemoryAlignment
case class Position(moduleName: String, line: Int, column: Int, cursor: Int)
@ -203,7 +204,8 @@ case class VariableDeclarationStatement(name: String,
volatile: Boolean,
register: Boolean,
initialValue: Option[Expression],
address: Option[Expression]) extends DeclarationStatement {
address: Option[Expression],
alignment: Option[MemoryAlignment]) extends DeclarationStatement {
override def getAllExpressions: List[Expression] = List(initialValue, address).flatten
}
@ -268,7 +270,8 @@ case class ArrayDeclarationStatement(name: String,
bank: Option[String],
length: Option[Expression],
address: Option[Expression],
elements: Option[ArrayContents]) extends DeclarationStatement {
elements: Option[ArrayContents],
alignment: Option[MemoryAlignment]) extends DeclarationStatement {
override def getAllExpressions: List[Expression] = List(length, address).flatten ++ elements.fold(List[Expression]())(_.getAllExpressions)
}

View File

@ -227,7 +227,7 @@ abstract class AbstractAssembler[T <: AbstractCode](private val program: Program
}
env.allPreallocatables.foreach {
case thing@InitializedArray(name, Some(NumericConstant(address, _)), items, _, _, _) =>
case thing@InitializedArray(name, Some(NumericConstant(address, _)), items, _, _, _, NoAlignment) =>
val bank = thing.bank(options)
val bank0 = mem.banks(bank)
var index = address.toInt
@ -251,7 +251,7 @@ abstract class AbstractAssembler[T <: AbstractCode](private val program: Program
}).mkString(", "))
}
initializedVariablesSize += items.length
case thing@InitializedArray(name, Some(_), items, _, _, _) => ???
case thing@InitializedArray(name, Some(_), items, _, _, _, NoAlignment) => ???
case f: NormalFunction if f.address.isDefined =>
val bank = f.bank(options)
val bank0 = mem.banks(bank)
@ -279,7 +279,7 @@ abstract class AbstractAssembler[T <: AbstractCode](private val program: Program
// already done before
case (name, NormalCompiledFunction(bank, code, false)) =>
val size = code.map(_.sizeInBytes).sum
val index = codeAllocators(bank).allocateBytes(mem.banks(bank), options, size, initialized = true, writeable = false, location = AllocationLocation.High)
val index = codeAllocators(bank).allocateBytes(mem.banks(bank), options, size, initialized = true, writeable = false, location = AllocationLocation.High, alignment = NoAlignment)
labelMap(name) = index
justAfterCode += bank -> outputFunction(bank, code, index, assembly, options)
case (_, NonexistentFunction()) =>
@ -289,7 +289,7 @@ abstract class AbstractAssembler[T <: AbstractCode](private val program: Program
if (options.flag(CompilationFlag.LUnixRelocatableCode)) {
env.allThings.things.foreach {
case (_, m@UninitializedMemoryVariable(name, typ, _, _)) if name.endsWith(".addr") || env.maybeGet[Thing](name + ".array").isDefined =>
case (_, m@UninitializedMemoryVariable(name, typ, _, _, NoAlignment)) if name.endsWith(".addr") || env.maybeGet[Thing](name + ".array").isDefined =>
val isUsed = compiledFunctions.values.exists{
case NormalCompiledFunction(_, code, _) => code.exists(_.parameter.isRelatedTo(m))
case _ => false
@ -299,7 +299,7 @@ abstract class AbstractAssembler[T <: AbstractCode](private val program: Program
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, location = AllocationLocation.High)
var index = codeAllocators(bank).allocateBytes(bank0, options, typ.size + 1, initialized = true, writeable = false, location = AllocationLocation.High, alignment = NoAlignment)
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")
@ -320,17 +320,17 @@ abstract class AbstractAssembler[T <: AbstractCode](private val program: Program
}
case _ => ()
}
val index = codeAllocators("default").allocateBytes(mem.banks("default"), options, 1, initialized = true, writeable = false, location = AllocationLocation.High)
val index = codeAllocators("default").allocateBytes(mem.banks("default"), options, 1, initialized = true, writeable = false, location = AllocationLocation.High, alignment = NoAlignment)
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, _, _, _) =>
case thing@InitializedArray(name, None, items, _, _, _, alignment) =>
val bank = thing.bank(options)
val bank0 = mem.banks(bank)
var index = codeAllocators(bank).allocateBytes(bank0, options, items.size, initialized = true, writeable = true, location = AllocationLocation.High)
var index = codeAllocators(bank).allocateBytes(bank0, options, items.size, initialized = true, writeable = true, location = AllocationLocation.High, alignment = alignment)
labelMap(name) = index
assembly.append("* = $" + index.toHexString)
assembly.append(name)
@ -349,10 +349,10 @@ abstract class AbstractAssembler[T <: AbstractCode](private val program: Program
}
initializedVariablesSize += items.length
justAfterCode += bank -> index
case m@InitializedMemoryVariable(name, None, typ, value, _) =>
case m@InitializedMemoryVariable(name, None, typ, value, _, alignment) =>
val bank = m.bank(options)
val bank0 = mem.banks(bank)
var index = codeAllocators(bank).allocateBytes(bank0, options, typ.size, initialized = true, writeable = true, location = AllocationLocation.High)
var index = codeAllocators(bank).allocateBytes(bank0, options, typ.size, initialized = true, writeable = true, location = AllocationLocation.High, alignment = alignment)
labelMap(name) = index
val altName = m.name.stripPrefix(env.prefix) + "`"
env.things += altName -> ConstantThing(altName, NumericConstant(index, 2), env.get[Type]("pointer"))

View File

@ -0,0 +1,10 @@
package millfork.output
/**
* @author Karol Stasiak
*/
sealed trait MemoryAlignment
case object NoAlignment extends MemoryAlignment
case object WithinPageAlignment extends MemoryAlignment
case class DivisibleAlignment(divisor: Int) extends MemoryAlignment

View File

@ -28,13 +28,19 @@ sealed trait ByteAllocator {
def notifyAboutEndOfCode(org: Int): Unit
def findFreeBytes(mem: MemoryBank, count: Int, options: CompilationOptions): Int = {
def findFreeBytes(mem: MemoryBank, count: Int, options: CompilationOptions, alignment: MemoryAlignment): Int = {
var lastFree = startAt
var counter = 0
val occupied = mem.occupied
var previous = -800
for(i <- preferredOrder.getOrElse(startAt until endBefore)) {
if (occupied(i) || counter == 0 && count == 2 && i.&(0xff) == 0xff && options.flags(CompilationFlag.PreventJmpIndirectBug)) {
if (occupied(i)) {
counter = 0
} else if (counter == 0 && (alignment match {
case WithinPageAlignment => i.&(0xff00) != i.+(count - 1).&(0xff00)
case DivisibleAlignment(divisor) => i % divisor != 0
case NoAlignment => false
})) {
counter = 0
} else {
if (previous != i - 1) {
@ -87,7 +93,7 @@ class VariableAllocator(pointers: List[Int], private val bytes: ByteAllocator) {
var heapStart: Int = bytes.startAt
def allocateBytes(mem: MemoryBank, callGraph: CallGraph, p: VariableVertex, options: CompilationOptions, count: Int, initialized: Boolean, writeable: Boolean, location: AllocationLocation.Value): Int = {
def allocateBytes(mem: MemoryBank, callGraph: CallGraph, p: VariableVertex, options: CompilationOptions, count: Int, initialized: Boolean, writeable: Boolean, location: AllocationLocation.Value, alignment: MemoryAlignment): Int = {
if (!variableMap.contains(count)) {
variableMap(count) = mutable.Map()
}
@ -97,12 +103,12 @@ class VariableAllocator(pointers: List[Int], private val bytes: ByteAllocator) {
return a
}
}
val addr = allocateBytes(mem, options, count, initialized, writeable, location)
val addr = allocateBytes(mem, options, count, initialized, writeable, location, alignment)
variableMap(count)(addr) = Set(p)
addr
}
def tryAllocateZeropageBytes(mem: MemoryBank, callGraph: CallGraph, p: VariableVertex, options: CompilationOptions, count: Int): Option[Int]={
def tryAllocateZeropageBytes(mem: MemoryBank, callGraph: CallGraph, p: VariableVertex, options: CompilationOptions, count: Int, alignment: MemoryAlignment): Option[Int]={
if (!variableMap.contains(count)) {
variableMap(count) = mutable.Map()
}
@ -112,32 +118,32 @@ class VariableAllocator(pointers: List[Int], private val bytes: ByteAllocator) {
return Some(a)
}
}
val addr = zeropage.findFreeBytes(mem, count, options)
val addr = zeropage.findFreeBytes(mem, count, options, alignment)
if (addr < 0) None else {
markBytes(options.log, mem, addr, count, initialized = false, writeable = true)
Some(addr)
}
}
def allocateBytes(mem: MemoryBank, options: CompilationOptions, count: Int, initialized: Boolean, writeable: Boolean, location: AllocationLocation.Value): Int = {
def allocateBytes(mem: MemoryBank, options: CompilationOptions, count: Int, initialized: Boolean, writeable: Boolean, location: AllocationLocation.Value, alignment: MemoryAlignment): Int = {
val addr = if (options.platform.hasZeroPage) {
location match {
case AllocationLocation.Zeropage =>
val a = zeropage.findFreeBytes(mem, count, options)
val a = zeropage.findFreeBytes(mem, count, options, alignment)
if (a < 0) {
options.log.fatal("Out of zeropage memory")
}
a
case AllocationLocation.High =>
val a = bytes.findFreeBytes(mem, count, options)
val a = bytes.findFreeBytes(mem, count, options, alignment)
if (a < 0) {
options.log.fatal("Out of high memory")
}
a
case AllocationLocation.Either =>
var a = zeropage.findFreeBytes(mem, count, options)
var a = zeropage.findFreeBytes(mem, count, options, alignment)
if (a < 0) {
a = bytes.findFreeBytes(mem, count, options)
a = bytes.findFreeBytes(mem, count, options, alignment)
if (a < 0) {
options.log.fatal("Out of high memory")
}
@ -145,7 +151,7 @@ class VariableAllocator(pointers: List[Int], private val bytes: ByteAllocator) {
a
}
} else {
val a = bytes.findFreeBytes(mem, count, options)
val a = bytes.findFreeBytes(mem, count, options, alignment)
if (a < 0) {
options.log.fatal("Out of high memory")
}

View File

@ -107,6 +107,7 @@ abstract class MfParser[T](fileId: String, input: String, currentDirectory: Stri
name <- identifier ~/ HWS ~/ Pass
addr <- ("@" ~/ HWS ~/ mfExpression(1, false)).?.opaque("<address>") ~ HWS
initialValue <- ("=" ~/ HWS ~/ mfExpression(1, false)).? ~ HWS
alignment = None // TODO
_ <- &(EOL) ~/ ""
} yield {
Seq(VariableDeclarationStatement(name, typ,
@ -116,7 +117,7 @@ abstract class MfParser[T](fileId: String, input: String, currentDirectory: Stri
constant = flags("const"),
volatile = flags("volatile"),
register = flags("register"),
initialValue, addr).pos(p))
initialValue, addr, alignment).pos(p))
}
val paramDefinition: P[ParameterDeclaration] = for {
@ -216,8 +217,9 @@ abstract class MfParser[T](fileId: String, input: String, currentDirectory: Stri
name <- "array" ~ !letterOrDigit ~/ SWS ~ identifier ~ HWS
length <- ("[" ~/ AWS ~/ mfExpression(nonStatementLevel, false) ~ AWS ~ "]").? ~ HWS
addr <- ("@" ~/ HWS ~/ mfExpression(1, false)).? ~/ HWS
alignment = None // TODO
contents <- ("=" ~/ HWS ~/ arrayContents).? ~/ HWS
} yield Seq(ArrayDeclarationStatement(name, bank, length, addr, contents).pos(p))
} yield Seq(ArrayDeclarationStatement(name, bank, length, addr, contents, alignment).pos(p))
def tightMfExpression(allowIntelHex: Boolean): P[Expression] = {
val a = if (allowIntelHex) atomWithIntel else atom