diff --git a/docs/lang/predefined_constants.md b/docs/lang/predefined_constants.md index 9f305435..1e36a112 100644 --- a/docs/lang/predefined_constants.md +++ b/docs/lang/predefined_constants.md @@ -12,6 +12,10 @@ * `pointer segment.N.start` – the value of `segment_N_start` from the platform definition +* `pointer segment.N.codeend` – the value of `segment_N_codeend` from the platform definition + +* `pointer segment.N.datastart` – the value of `segment_N_datastart` from the platform definition + * `pointer segment.N.end` – the value of `segment_N_end` from the platform definition * `pointer segment.N.heapstart` – the address of the first byte in the `N` segment that was not automatically allocated @@ -19,3 +23,5 @@ * `word segment.N.length` – the number of byte locations between `segment_N_start` and `segment_N_end`, inclusive * `byte segment.N.bank` – the value of `segment_N_bank` from the platform definition + +* `byte segment.N.fill` – the value of `segment_N_fill` from the platform definition diff --git a/docs/lang/suffixes.md b/docs/lang/suffixes.md index 478e9ebb..da0c276a 100644 --- a/docs/lang/suffixes.md +++ b/docs/lang/suffixes.md @@ -38,6 +38,12 @@ These suffixes can be applied to variables, arrays, or functions: * `.segment.start` – returns the start address of the segment the object is in +* `.segment.codeend` – returns the last address of code in the segment the object is in + +* `.segment.datastart` – returns the start address of data in the segment the object is in + +* `.segment.heapstart` – returns the start address of uninitialized data in the segment the object is in + * `.segment.end` – returns the last address of the segment the object is in * `.segment.fill` – returns the byte value used to fill gaps and other unused space in the segment the object is in diff --git a/src/main/scala/millfork/env/Environment.scala b/src/main/scala/millfork/env/Environment.scala index 4adad685..325a74a5 100644 --- a/src/main/scala/millfork/env/Environment.scala +++ b/src/main/scala/millfork/env/Environment.scala @@ -508,6 +508,8 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa } for(segment <- options.platform.bankNumbers.keys) { addUnexpandedPointerConstant(s"segment.$segment.start") + addUnexpandedPointerConstant(s"segment.$segment.codeend") + addUnexpandedPointerConstant(s"segment.$segment.datastart") addUnexpandedPointerConstant(s"segment.$segment.heapstart") addUnexpandedPointerConstant(s"segment.$segment.end") addUnexpandedWordConstant(s"segment.$segment.length") @@ -1443,6 +1445,8 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa addThing(ConstantThing(thing.name + ".segment.fill", NumericConstant(bankFill, 1), b), position) } addThing(ConstantThing(thing.name + ".segment.start", UnexpandedConstant(s"segment.$segment.start", 2), ptr), position) + addThing(ConstantThing(thing.name + ".segment.codeend", UnexpandedConstant(s"segment.$segment.codeend", 2), ptr), position) + addThing(ConstantThing(thing.name + ".segment.datastart", UnexpandedConstant(s"segment.$segment.datastart", 2), ptr), position) addThing(ConstantThing(thing.name + ".segment.heapstart", UnexpandedConstant(s"segment.$segment.heapstart", 2), ptr), position) addThing(ConstantThing(thing.name + ".segment.end", UnexpandedConstant(s"segment.$segment.end", 2), ptr), position) addThing(ConstantThing(thing.name + ".segment.length", UnexpandedConstant(s"segment.$segment.length", 2), w), position) diff --git a/src/main/scala/millfork/output/AbstractAssembler.scala b/src/main/scala/millfork/output/AbstractAssembler.scala index 77bec253..07342827 100644 --- a/src/main/scala/millfork/output/AbstractAssembler.scala +++ b/src/main/scala/millfork/output/AbstractAssembler.scala @@ -649,11 +649,14 @@ abstract class AbstractAssembler[T <: AbstractCode](private val program: Program unimportantLabelMap += "__rwdata_end" -> (defaultBank -> rwDataEnd) unimportantLabelMap += "__heap_start" -> (defaultBank -> variableAllocators("default").heapStart) for (segment <- platform.bankNumbers.keys) { - val allocator = options.platform.variableAllocators(segment) - unimportantLabelMap += s"segment.$segment.start" -> (defaultBank -> allocator.startAt) - unimportantLabelMap += s"segment.$segment.end" -> (defaultBank -> (allocator.endBefore - 1)) - unimportantLabelMap += s"segment.$segment.heapstart" -> (defaultBank -> allocator.heapStart) - unimportantLabelMap += s"segment.$segment.length" -> (defaultBank -> (allocator.endBefore - allocator.startAt)) + val variableAllocator = options.platform.variableAllocators(segment) + val codeAllocator = options.platform.codeAllocators(segment) + unimportantLabelMap += s"segment.$segment.start" -> (defaultBank -> codeAllocator.startAt) + unimportantLabelMap += s"segment.$segment.codeend" -> (defaultBank -> (codeAllocator.endBefore - 1)) + unimportantLabelMap += s"segment.$segment.datastart" -> (defaultBank -> variableAllocator.startAt) + unimportantLabelMap += s"segment.$segment.heapstart" -> (defaultBank -> variableAllocator.heapStart) + unimportantLabelMap += s"segment.$segment.end" -> (defaultBank -> (variableAllocator.endBefore - 1)) + unimportantLabelMap += s"segment.$segment.length" -> (defaultBank -> (variableAllocator.endBefore - codeAllocator.startAt)) unimportantLabelMap += s"segment.$segment.bank" -> (defaultBank -> platform.bankNumbers(segment)) unimportantLabelMap += s"segment.$segment.fill" -> (defaultBank -> platform.bankFill(segment)) } diff --git a/src/main/scala/millfork/output/VariableAllocator.scala b/src/main/scala/millfork/output/VariableAllocator.scala index a4ffff31..1149dc91 100644 --- a/src/main/scala/millfork/output/VariableAllocator.scala +++ b/src/main/scala/millfork/output/VariableAllocator.scala @@ -150,7 +150,7 @@ class VariableAllocator(zpBytes: List[Int], private val bytes: ByteAllocator) { case AllocationLocation.High => val a = bytes.findFreeBytes(mem, count, options, alignment) if (a < 0) { - options.log.fatal("Out of high memory") + options.log.fatal("Out of high memory in bank ${mem.index}") } a case AllocationLocation.Either => @@ -158,7 +158,7 @@ class VariableAllocator(zpBytes: List[Int], private val bytes: ByteAllocator) { if (a < 0) { a = bytes.findFreeBytes(mem, count, options, alignment) if (a < 0) { - options.log.fatal("Out of high memory") + options.log.fatal("Out of high memory in bank ${mem.index}") } } a @@ -166,7 +166,7 @@ class VariableAllocator(zpBytes: List[Int], private val bytes: ByteAllocator) { } else { val a = bytes.findFreeBytes(mem, count, options, alignment) if (a < 0) { - options.log.fatal("Out of high memory") + options.log.fatal(s"Out of high memory in bank ${mem.index}") } a } @@ -188,8 +188,13 @@ class VariableAllocator(zpBytes: List[Int], private val bytes: ByteAllocator) { //TODO: Everything about the three methods below is ugly and wrong. Fix later. - def notifyAboutEndOfCode(org: Int): Unit = bytes.notifyAboutEndOfCode(org) - def notifyAboutEndOfData(org: Int): Unit = heapStart = heapStart max org + def notifyAboutEndOfCode(org: Int): Unit = { + heapStart = heapStart max org + bytes.notifyAboutEndOfCode(org) + } + def notifyAboutEndOfData(org: Int): Unit = { + heapStart = heapStart max org + } def notifyAboutHole(mem: MemoryBank, addr: Int, size: Int): Unit = { if (Math.abs(addr - heapStart) <= 1) { diff --git a/src/test/scala/millfork/test/SegmentSuite.scala b/src/test/scala/millfork/test/SegmentSuite.scala index 7990ffd8..4d8aa1bf 100644 --- a/src/test/scala/millfork/test/SegmentSuite.scala +++ b/src/test/scala/millfork/test/SegmentSuite.scala @@ -21,6 +21,9 @@ class SegmentSuite extends FunSuite with Matchers { | byte output @$c000 | volatile byte output2 @$c001 | volatile byte output3 @$c002 + | volatile pointer output4 @$c006 + | volatile pointer output5 @$c008 + | volatile pointer output6 @$c00a | void main() { | output = 0 | if a1.addr.hi & $e0 == $80 { output += 1 } @@ -31,11 +34,17 @@ class SegmentSuite extends FunSuite with Matchers { | output2 = a1.segment.bank ^ main.segment.bank | output2 ^= segment.second.bank ^ segment.default.bank | output3 = lo(main.segment.start) + | output4 = segment.default.start + | output5 = segment.default.datastart + | output6 = segment.default.heapstart | } """.stripMargin EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Motorola6809)(source) { m => m.readByte(0xc000) should equal(source.count(_ == '+')) m.readByte(0xc001) should equal(0) + m.readWord(0xc006) should equal(0x200) + m.readWord(0xc008) should be >(0x200) + m.readWord(0xc00a) should be >(0x200) } } }