Add support for ld65 label file format (#128)

This commit is contained in:
Karol Stasiak 2021-11-12 00:47:12 +01:00
parent 73a223b9b6
commit c9313e5dbe
5 changed files with 61 additions and 2 deletions

1
.gitignore vendored
View File

@ -36,6 +36,7 @@ issue*.mfk
*.fns
*.sym
*.mlb
*.dbg
*.deb
*.xex
*.nes

View File

@ -50,6 +50,8 @@ The extension and the file format are platform-dependent.
* `-G mesen` format used by the Mesen emulator. The extension is `.mlb`.
* `-G ld65` a simplified version of the format used by the `ld65` linker (used by CC65 and CA65). The extension is `.dbg`.
* `-G raw` Millfork-specific format. The extension is '.labels'. Each row contains bank number, start address, end address (if known), object type, and Millfork-specific object identifier.
* `-fbreakpoints`, `-fno-breakpoints`

View File

@ -269,3 +269,5 @@ Default: `main,*`
* `fceux` multi-file format used by the FCEUX emulator. The extension is `.nl`.
* `mesen` format used by the Mesen emulator. The extension is `.mlb`.
* `ld65` format used by the `ld65` linker. The extension is `.dbg`.

View File

@ -3,6 +3,7 @@ package millfork
import millfork.output.{BankLayoutInFile, FormattableLabel}
import java.util.regex.Pattern
import scala.collection.mutable
import scala.util.control.Breaks.{break, breakable}
/**
@ -20,6 +21,10 @@ object DebugOutputFormat {
"mlb" -> MesenOutputFormat,
"mesen" -> MesenOutputFormat,
"asm6f" -> MesenOutputFormat,
"ld65" -> Ld65OutputFormat,
"ca65" -> Ld65OutputFormat,
"cc65" -> Ld65OutputFormat,
"dbg" -> Ld65OutputFormat,
"sym" -> SymDebugOutputFormat)
}
@ -175,4 +180,49 @@ object MesenOutputFormat extends DebugOutputFormat {
override def filePerBank: Boolean = false
override def addOutputExtension: Boolean = false
}
}
object Ld65OutputFormat extends DebugOutputFormat {
override def formatLine(label: FormattableLabel): String = throw new UnsupportedOperationException()
override def formatBreakpoint(bank: Int, value: Int): Option[String] = None
override def fileExtension(bank: Int): String = ".dbg"
override def filePerBank: Boolean = false
override def addOutputExtension: Boolean = true
override def formatAll(b: BankLayoutInFile, labels: Seq[FormattableLabel], breakpoints: Seq[(Int, Int)]): String = {
val q = '"'
val allBanksInFile = b.allBanks()
val allBanks = (labels.map(_.bankName).distinct ++ allBanksInFile).distinct
val result = mutable.ListBuffer[String]()
result += "version\tmajor=2,minor=0"
result += s"info\tcsym=0,file=0,lib=0,line=0,mod=0,scope=1,seg=${allBanks.size},span=0,sym=${labels.size},type=4"
for ((bank, ix) <- allBanks.zipWithIndex) {
val common = s"seg\tid=${ix},name=$q${bank}$q,start=0x${b.getStart(bank).toHexString},size=0x0,addrsize=absolute"
if (allBanksInFile.contains(bank)) {
result += common + s",ooffs=${b.ld65Offset(bank)}"
} else {
result += common
}
}
result += "scope\tid=0,name=\"\""
for ((label, ix) <- labels.sortBy(l => (l.bankName, l.startValue, l.labelName)).zipWithIndex) {
val name = label.labelName.replace('$', '@').replace('.', '@')
val sb = new StringBuilder
sb ++= s"sym\tid=${ix},name=$q${name}$q,addrsize=absolute,"
label.endValue match {
case Some(e) =>
if (!labels.exists(l => l.ne(label) && l.startValue >= label.startValue && l.startValue <= e)) {
sb ++= s"size=${ e - label.startValue + 1 },"
}
case None =>
}
sb ++= s"scope=0,val=0x${label.startValue.toHexString},seg=${allBanks.indexOf(label.bankName)},type=lab"
result += sb.toString
}
result.mkString("\n")
}
}

View File

@ -28,5 +28,9 @@ class BankLayoutInFile(startInFile: Map[String, Int], firstAddress: Map[String,
def wasWritten(bank: String): Boolean = startInFile.contains(bank)
def Ld65Offset(bank: String): Int = startInFile(bank)
def getStart(bank:String): Int = firstAddress.getOrElse(bank, 0) // ??
def ld65Offset(bank: String): Int = startInFile(bank)
def allBanks(): Set[String] = firstAddress.keySet
}