1
0
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:
Karol Stasiak 2019-06-26 18:33:59 +02:00
parent c580ba33ea
commit 51599c9615
14 changed files with 50 additions and 30 deletions

View File

@ -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.

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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()))
}
}

View File

@ -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))

View File

@ -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]]]()

View File

@ -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,