mirror of
https://github.com/KarolS/millfork.git
synced 2025-01-11 12:29:46 +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.
|
* **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.
|
||||||
|
@ -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.
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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))
|
||||||
|
@ -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]]]()
|
||||||
|
|
||||||
|
@ -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,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user