1
0
mirror of https://github.com/KarolS/millfork.git synced 2024-06-25 19:29:49 +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. * **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 using index registers.
* 6502: Fixed optimizations of comparisons. * 6502: Fixed optimizations of comparisons.

View File

@ -118,7 +118,11 @@ See the [preprocessor documentation](../lang/preprocessor.md) for more info.
* `zp_pointers` * `zp_pointers`
either a list of comma separated zeropage addresses that can be used by the program as zeropage pointers, or `all` for all. 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. 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. * `segments` a comma-separated list of segment names.
A segment named `default` is always required. A segment named `default` is always required.

View File

@ -5,7 +5,7 @@ encoding=atascii
[allocation] [allocation]
; TODO ; 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 segment_default_start=$2000
; TODO ; TODO
segment_default_end=$3fff segment_default_end=$3fff

View File

@ -7,7 +7,7 @@ lenient_encoding=true
[allocation] [allocation]
; TODO ; TODO
zp_pointers=6,8,$EB,$ED,$FA,$FC zp_bytes=6-9, $EB-$EE, $FA-$FD
segment_default_start=$0C00 segment_default_start=$0C00
segment_default_end=$95FF segment_default_end=$95FF

View File

@ -7,7 +7,7 @@ modules=bbc_kernal,bbc_hardware,default_panic,stdlib
[allocation] [allocation]
; TODO ; 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 ; $0E00 increases chances it will work on Electrons
segment_default_start=$0E00 segment_default_start=$0E00
; The following is for Model B; for Model A, consider changing it to $31FF ; The following is for Model B; for Model A, consider changing it to $31FF

View File

@ -10,7 +10,7 @@ ro_arrays=true
[allocation] [allocation]
zp_pointers=2-$ff zp_bytes=2-$ff
segments=default,prgrom segments=default,prgrom
default_code_segment=prgrom default_code_segment=prgrom
segment_default_start=$800 segment_default_start=$800

View File

@ -9,7 +9,7 @@ lunix=true
[allocation] [allocation]
zp_pointers=$80-$bf zp_bytes=$80-$bf
segments=default segments=default
default_code_segment=default default_code_segment=default
segment_default_start=$1006 segment_default_start=$1006

View File

@ -14,7 +14,7 @@ modules=nes_hardware,nes_routines,default_panic,nes_mmc4,stdlib
ro_arrays=true ro_arrays=true
[allocation] [allocation]
zp_pointers=all zp_bytes=all
segments=default,ram,prgrom0,prgrom1,prgrom2,prgrom3,prgrom4,prgrom5,prgrom6,prgrom7,chrrom0,chrrom1 segments=default,ram,prgrom0,prgrom1,prgrom2,prgrom3,prgrom4,prgrom5,prgrom6,prgrom7,chrrom0,chrrom1
default_code_segment=prgrom7 default_code_segment=prgrom7

View File

@ -10,7 +10,7 @@ modules=nes_hardware,nes_routines,default_panic,stdlib
ro_arrays=true ro_arrays=true
[allocation] [allocation]
zp_pointers=all zp_bytes=all
segments=default,prgrom,chrrom segments=default,prgrom,chrrom
default_code_segment=prgrom default_code_segment=prgrom

View File

@ -10,7 +10,7 @@ zeropage_register=false
[allocation] [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 segments=default,prgrom
default_code_segment=prgrom default_code_segment=prgrom

View File

@ -29,7 +29,7 @@ class Platform(
val codeAllocators: Map[String, UpwardByteAllocator], val codeAllocators: Map[String, UpwardByteAllocator],
val variableAllocators: Map[String, VariableAllocator], val variableAllocators: Map[String, VariableAllocator],
val zpRegisterSize: Int, val zpRegisterSize: Int,
val freeZpPointers: List[Int], val freeZpBytes: List[Int],
val fileExtension: String, val fileExtension: String,
val generateBbcMicroInfFile: Boolean, val generateBbcMicroInfFile: Boolean,
val generateGameBoyChecksums: 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")) 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 { val freePointers: Option[List[Int]] = as.get(classOf[String], "zp_pointers", "") match {
case "all" => List.tabulate(128)(_ * 2) case "all" => Some(List.tabulate(128)(_ * 2))
case xs => xs.split("[, ]+").flatMap(parseNumberOrRange).toList 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 codeAllocators = banks.map(b => b -> new UpwardByteAllocator(bankStarts(b), bankCodeEnds(b)))
val variableAllocators = banks.map(b => b -> new VariableAllocator( 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 None => new AfterCodeByteAllocator(bankEnds(b))
case Some(start) => new UpwardByteAllocator(start, bankEnds(b)) case Some(start) => new UpwardByteAllocator(start, bankEnds(b))
})) }))
@ -232,7 +247,7 @@ object Platform {
codeAllocators.toMap, codeAllocators.toMap,
variableAllocators.toMap, variableAllocators.toMap,
zpRegisterSize, zpRegisterSize,
freePointers, freeZpBytes,
if (fileExtension == "" || fileExtension.startsWith(".")) fileExtension else "." + fileExtension, if (fileExtension == "" || fileExtension.startsWith(".")) fileExtension else "." + fileExtension,
generateBbcMicroInfFile, generateBbcMicroInfFile,
generateGameBoyChecksums, 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("-")) { if (s.contains("-")) {
val segments = s.split("-") val segments = s.split("-")
if (segments.length != 2) { if (segments.length != 2) {
log.fatal(s"Invalid range: `$s`") 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 { } 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 variableAllocators = platform.variableAllocators
val zpOccupied = mem.banks("default").occupied val zpOccupied = mem.banks("default").occupied
(0 until 0x100).foreach(i => zpOccupied(i) = true) (0 until 0x100).foreach(i => zpOccupied(i) = true)
platform.freeZpPointers.foreach { i => platform.freeZpBytes.foreach { i =>
zpOccupied(i) = false zpOccupied(i) = false
zpOccupied(i + 1) = false
} }
val optimizations = unfilteredOptimizations.filter(_.requiredFlags.forall(options.flag)) 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) env.allocateVariables(None, mem, callGraph, variableAllocators, options, labelMap.put, 3, forZpOnly = false)
val defaultBank = mem.banks("default").index val defaultBank = mem.banks("default").index
if (platform.freeZpPointers.nonEmpty) { if (platform.freeZpBytes.nonEmpty) {
val zpUsageOffset = platform.freeZpPointers.min val zpUsageOffset = platform.freeZpBytes.min
val zeropageOccupation = zpOccupied.slice(zpUsageOffset, platform.freeZpPointers.max + 2) val zeropageOccupation = zpOccupied.slice(zpUsageOffset, platform.freeZpBytes.max + 1)
labelMap += "__zeropage_usage" -> (defaultBank, zeropageOccupation.lastIndexOf(true) - zeropageOccupation.indexOf(true) + 1) labelMap += "__zeropage_usage" -> (defaultBank, zeropageOccupation.lastIndexOf(true) - zeropageOccupation.indexOf(true) + 1)
labelMap += "__zeropage_first" -> (defaultBank, zpUsageOffset + (zeropageOccupation.indexOf(true) max 0)) labelMap += "__zeropage_first" -> (defaultBank, zpUsageOffset + (zeropageOccupation.indexOf(true) max 0))
labelMap += "__zeropage_last" -> (defaultBank, zpUsageOffset + (zeropageOccupation.lastIndexOf(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 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 = () 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 { 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 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]]]() 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 * @author Karol Stasiak
*/ */
object EmuPlatform { 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( def get(cpu: Cpu.Value) = new Platform(
cpu, cpu,