mirror of
https://github.com/KarolS/millfork.git
synced 2024-12-28 11:31:58 +00:00
Allow defining free zeropage bytes instead of pointers
This commit is contained in:
parent
c580ba33ea
commit
51599c9615
@ -50,6 +50,8 @@
|
||||
|
||||
* **Potentially breaking change!** Commodore 128 target no longer defines `CBM_64` feature.
|
||||
|
||||
* 6502 targets can now define free zeropage bytes, not only pointers.
|
||||
|
||||
* 6502: Fixed optimizations using index registers.
|
||||
|
||||
* 6502: Fixed optimizations of comparisons.
|
||||
|
@ -118,7 +118,11 @@ See the [preprocessor documentation](../lang/preprocessor.md) for more info.
|
||||
* `zp_pointers` –
|
||||
either a list of comma separated zeropage addresses that can be used by the program as zeropage pointers, or `all` for all.
|
||||
Each value should be the address of the first of two free bytes in the zeropage.
|
||||
Only used for 6502-based targets.
|
||||
Only used for 6502-based targets. Cannot be used together with `zp_bytes`.
|
||||
|
||||
* `zp_bytes` –
|
||||
either a list of comma separated zeropage byte addresses or address ranges that can be used by the program in zeropage, or `all` for all.
|
||||
Only used for 6502-based targets. Cannot be used together with `zp_pointers`.
|
||||
|
||||
* `segments` – a comma-separated list of segment names.
|
||||
A segment named `default` is always required.
|
||||
|
@ -5,7 +5,7 @@ encoding=atascii
|
||||
|
||||
[allocation]
|
||||
; TODO
|
||||
zp_pointers=$80,$82,$84,$86,$88,$8a,$8c,$8e,$90,$92,$94,$96,$98,$9a,$9c,$9e,$a0,$a2,$a4
|
||||
zp_bytes=$80-$A5
|
||||
segment_default_start=$2000
|
||||
; TODO
|
||||
segment_default_end=$3fff
|
||||
|
@ -7,7 +7,7 @@ lenient_encoding=true
|
||||
|
||||
[allocation]
|
||||
; TODO
|
||||
zp_pointers=6,8,$EB,$ED,$FA,$FC
|
||||
zp_bytes=6-9, $EB-$EE, $FA-$FD
|
||||
segment_default_start=$0C00
|
||||
segment_default_end=$95FF
|
||||
|
||||
|
@ -7,7 +7,7 @@ modules=bbc_kernal,bbc_hardware,default_panic,stdlib
|
||||
|
||||
[allocation]
|
||||
; TODO
|
||||
zp_pointers=$70, $72, $74, $76, $78, $7A, $7C, $7E, $80, $82, $84, $86, $88, $8A, $8C, $8E
|
||||
zp_bytes=$70-$8F
|
||||
; $0E00 increases chances it will work on Electrons
|
||||
segment_default_start=$0E00
|
||||
; The following is for Model B; for Model A, consider changing it to $31FF
|
||||
|
@ -10,7 +10,7 @@ ro_arrays=true
|
||||
|
||||
|
||||
[allocation]
|
||||
zp_pointers=2-$ff
|
||||
zp_bytes=2-$ff
|
||||
segments=default,prgrom
|
||||
default_code_segment=prgrom
|
||||
segment_default_start=$800
|
||||
|
@ -9,7 +9,7 @@ lunix=true
|
||||
|
||||
|
||||
[allocation]
|
||||
zp_pointers=$80-$bf
|
||||
zp_bytes=$80-$bf
|
||||
segments=default
|
||||
default_code_segment=default
|
||||
segment_default_start=$1006
|
||||
|
@ -14,7 +14,7 @@ modules=nes_hardware,nes_routines,default_panic,nes_mmc4,stdlib
|
||||
ro_arrays=true
|
||||
|
||||
[allocation]
|
||||
zp_pointers=all
|
||||
zp_bytes=all
|
||||
|
||||
segments=default,ram,prgrom0,prgrom1,prgrom2,prgrom3,prgrom4,prgrom5,prgrom6,prgrom7,chrrom0,chrrom1
|
||||
default_code_segment=prgrom7
|
||||
|
@ -10,7 +10,7 @@ modules=nes_hardware,nes_routines,default_panic,stdlib
|
||||
ro_arrays=true
|
||||
|
||||
[allocation]
|
||||
zp_pointers=all
|
||||
zp_bytes=all
|
||||
|
||||
segments=default,prgrom,chrrom
|
||||
default_code_segment=prgrom
|
||||
|
@ -10,7 +10,7 @@ zeropage_register=false
|
||||
|
||||
|
||||
[allocation]
|
||||
zp_pointers=$80,$82,$84,$86,$88,$8a,$8c,$8e,$90,$92,$94,$96,$98,$9a,$9c,$9e,$a0,$a2,$a4
|
||||
zp_bytes=$80-$a5
|
||||
segments=default,prgrom
|
||||
default_code_segment=prgrom
|
||||
|
||||
|
@ -29,7 +29,7 @@ class Platform(
|
||||
val codeAllocators: Map[String, UpwardByteAllocator],
|
||||
val variableAllocators: Map[String, VariableAllocator],
|
||||
val zpRegisterSize: Int,
|
||||
val freeZpPointers: List[Int],
|
||||
val freeZpBytes: List[Int],
|
||||
val fileExtension: String,
|
||||
val generateBbcMicroInfFile: Boolean,
|
||||
val generateGameBoyChecksums: Boolean,
|
||||
@ -166,14 +166,29 @@ object Platform {
|
||||
bankDataStarts(b).foreach(dataStarts => if (dataStarts >= bankEnds(b)) log.error(s"Segment $b has invalid range"))
|
||||
})
|
||||
|
||||
val freePointers = as.get(classOf[String], "zp_pointers", "all") match {
|
||||
case "all" => List.tabulate(128)(_ * 2)
|
||||
case xs => xs.split("[, ]+").flatMap(parseNumberOrRange).toList
|
||||
val freePointers: Option[List[Int]] = as.get(classOf[String], "zp_pointers", "") match {
|
||||
case "all" => Some(List.tabulate(128)(_ * 2))
|
||||
case "" => None
|
||||
case xs => Some(xs.split("[, ]+").flatMap(s => parseNumberOrRange(s, 2)).toList)
|
||||
}
|
||||
val freeExplicitBytes: Option[List[Int]] = as.get(classOf[String], "zp_bytes", "") match {
|
||||
case "all" => Some(List.tabulate(256)(identity))
|
||||
case "" => None
|
||||
case xs => Some(xs.split("[, ]+").flatMap(s => parseNumberOrRange(s, 1)).toList)
|
||||
}
|
||||
|
||||
val freeZpBytes: List[Int] = (freePointers, freeExplicitBytes) match {
|
||||
case (Some(l), None) => l.flatMap(i => List(i, i+1))
|
||||
case (None, Some(l)) => l
|
||||
case (None, None) => List.tabulate(256)(identity)
|
||||
case (Some(_), Some(l)) =>
|
||||
log.error(s"Cannot define both zp_pointers and zp_bytes")
|
||||
l
|
||||
}
|
||||
|
||||
val codeAllocators = banks.map(b => b -> new UpwardByteAllocator(bankStarts(b), bankCodeEnds(b)))
|
||||
val variableAllocators = banks.map(b => b -> new VariableAllocator(
|
||||
if (b == "default" && CpuFamily.forType(cpu) == CpuFamily.M6502) freePointers else Nil, bankDataStarts(b) match {
|
||||
if (b == "default" && CpuFamily.forType(cpu) == CpuFamily.M6502) freeZpBytes else Nil, bankDataStarts(b) match {
|
||||
case None => new AfterCodeByteAllocator(bankEnds(b))
|
||||
case Some(start) => new UpwardByteAllocator(start, bankEnds(b))
|
||||
}))
|
||||
@ -232,7 +247,7 @@ object Platform {
|
||||
codeAllocators.toMap,
|
||||
variableAllocators.toMap,
|
||||
zpRegisterSize,
|
||||
freePointers,
|
||||
freeZpBytes,
|
||||
if (fileExtension == "" || fileExtension.startsWith(".")) fileExtension else "." + fileExtension,
|
||||
generateBbcMicroInfFile,
|
||||
generateGameBoyChecksums,
|
||||
@ -269,15 +284,15 @@ object Platform {
|
||||
)
|
||||
}
|
||||
|
||||
def parseNumberOrRange(s:String)(implicit log: Logger): Seq[Int] = {
|
||||
def parseNumberOrRange(s:String, step: Int)(implicit log: Logger): Seq[Int] = {
|
||||
if (s.contains("-")) {
|
||||
val segments = s.split("-")
|
||||
if (segments.length != 2) {
|
||||
log.fatal(s"Invalid range: `$s`")
|
||||
}
|
||||
Range(parseNumber(segments(0)), parseNumber(segments(1)), 2)
|
||||
Range(parseNumber(segments(0).trim()), parseNumber(segments(1).trim()), step)
|
||||
} else {
|
||||
Seq(parseNumber(s))
|
||||
Seq(parseNumber(s.trim()))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -184,9 +184,8 @@ abstract class AbstractAssembler[T <: AbstractCode](private val program: Program
|
||||
val variableAllocators = platform.variableAllocators
|
||||
val zpOccupied = mem.banks("default").occupied
|
||||
(0 until 0x100).foreach(i => zpOccupied(i) = true)
|
||||
platform.freeZpPointers.foreach { i =>
|
||||
platform.freeZpBytes.foreach { i =>
|
||||
zpOccupied(i) = false
|
||||
zpOccupied(i + 1) = false
|
||||
}
|
||||
|
||||
val optimizations = unfilteredOptimizations.filter(_.requiredFlags.forall(options.flag))
|
||||
@ -430,9 +429,9 @@ abstract class AbstractAssembler[T <: AbstractCode](private val program: Program
|
||||
env.allocateVariables(None, mem, callGraph, variableAllocators, options, labelMap.put, 3, forZpOnly = false)
|
||||
|
||||
val defaultBank = mem.banks("default").index
|
||||
if (platform.freeZpPointers.nonEmpty) {
|
||||
val zpUsageOffset = platform.freeZpPointers.min
|
||||
val zeropageOccupation = zpOccupied.slice(zpUsageOffset, platform.freeZpPointers.max + 2)
|
||||
if (platform.freeZpBytes.nonEmpty) {
|
||||
val zpUsageOffset = platform.freeZpBytes.min
|
||||
val zeropageOccupation = zpOccupied.slice(zpUsageOffset, platform.freeZpBytes.max + 1)
|
||||
labelMap += "__zeropage_usage" -> (defaultBank, zeropageOccupation.lastIndexOf(true) - zeropageOccupation.indexOf(true) + 1)
|
||||
labelMap += "__zeropage_first" -> (defaultBank, zpUsageOffset + (zeropageOccupation.indexOf(true) max 0))
|
||||
labelMap += "__zeropage_last" -> (defaultBank, zpUsageOffset + (zeropageOccupation.lastIndexOf(true) max 0))
|
||||
|
@ -68,14 +68,14 @@ class UpwardByteAllocator(val startAt: Int, val endBefore: Int) extends ByteAllo
|
||||
override def preferredOrder: Option[List[Int]] = None
|
||||
}
|
||||
|
||||
class ZeropageAllocator(val freeZpPointers: List[Int]) extends ByteAllocator {
|
||||
class ZeropageAllocator(val freeZpBytes: List[Int]) extends ByteAllocator {
|
||||
|
||||
def notifyAboutEndOfCode(org: Int): Unit = ()
|
||||
override def preferredOrder: Option[List[Int]] = if (freeZpPointers.isEmpty) None else Some(freeZpPointers.flatMap(i => Seq(i,i+1)))
|
||||
override def preferredOrder: Option[List[Int]] = if (freeZpBytes.isEmpty) None else Some(freeZpBytes)
|
||||
|
||||
override def startAt: Int = if (freeZpPointers.isEmpty) 2 else freeZpPointers.min
|
||||
override def startAt: Int = if (freeZpBytes.isEmpty) 2 else freeZpBytes.min
|
||||
|
||||
override def endBefore: Int = if (freeZpPointers.isEmpty) 2 else freeZpPointers.max + 2
|
||||
override def endBefore: Int = if (freeZpBytes.isEmpty) 2 else freeZpBytes.max + 1
|
||||
}
|
||||
|
||||
class AfterCodeByteAllocator(val endBefore: Int) extends ByteAllocator {
|
||||
@ -85,9 +85,9 @@ class AfterCodeByteAllocator(val endBefore: Int) extends ByteAllocator {
|
||||
override def preferredOrder: Option[List[Int]] = None
|
||||
}
|
||||
|
||||
class VariableAllocator(pointers: List[Int], private val bytes: ByteAllocator) {
|
||||
class VariableAllocator(zpBytes: List[Int], private val bytes: ByteAllocator) {
|
||||
|
||||
val zeropage: ByteAllocator = new ZeropageAllocator(pointers)
|
||||
val zeropage: ByteAllocator = new ZeropageAllocator(zpBytes)
|
||||
|
||||
private val variableMap = mutable.Map[Int, mutable.Map[Int, Set[VariableVertex]]]()
|
||||
|
||||
|
@ -8,7 +8,7 @@ import millfork.{Cpu, CpuFamily, OutputStyle, Platform, ViceDebugOutputFormat}
|
||||
* @author Karol Stasiak
|
||||
*/
|
||||
object EmuPlatform {
|
||||
private val pointers: List[Int] = (0 until 256 by 2).toList
|
||||
private val pointers: List[Int] = (0 until 256).toList
|
||||
|
||||
def get(cpu: Cpu.Value) = new Platform(
|
||||
cpu,
|
||||
|
Loading…
Reference in New Issue
Block a user