diff options
| author | Miquel Sabaté Solà <mikisabate@gmail.com> | 2025-01-22 16:05:24 +0100 |
|---|---|---|
| committer | Miquel Sabaté Solà <mikisabate@gmail.com> | 2025-01-22 16:05:24 +0100 |
| commit | 3f643b961cc54aa5b198c7edfc354ffec0b28a67 (patch) | |
| tree | 1b4ddc8115bb5987353423956ec2fba0bc7fb65f /lib/xixanta | |
| parent | 61ef02df2c128cd86efcddd3fa53870bc8d575c4 (diff) | |
| download | tools.nes-3f643b961cc54aa5b198c7edfc354ffec0b28a67.tar.gz tools.nes-3f643b961cc54aa5b198c7edfc354ffec0b28a67.zip | |
Remove dependency on TOML
When I introduced this dependency it looked like a good idea to have a
better-looking replacement to cl65's cfg format. That being said, the
end result wasn't *much* prettier either, and the end result could be
even bigger and equally confusing.
Since 5f48de69f46d ("Add support for cfg files") there is quite the
framework in order to support regular cl65's cfg files. Hence, this
commit takes another approach: let's tune this format to a more
compressed and simplified one. This is now the current "nasm cfg"
format, and it allowed us to re-use a lot of code while also being more
to the point for NES/Famicom development than the original cfg format.
With this new format, we can now remove the dependency on TOML and all
of the inner dependencies which were quite a lot.
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
Diffstat (limited to 'lib/xixanta')
| -rw-r--r-- | lib/xixanta/Cargo.toml | 1 | ||||
| -rw-r--r-- | lib/xixanta/fuzz/Cargo.lock | 137 | ||||
| -rw-r--r-- | lib/xixanta/src/cfg.rs | 86 | ||||
| -rw-r--r-- | lib/xixanta/src/mapping.rs | 147 | ||||
| -rw-r--r-- | lib/xixanta/src/mappings/empty.cfg | 4 | ||||
| -rw-r--r-- | lib/xixanta/src/mappings/empty.toml | 12 | ||||
| -rw-r--r-- | lib/xixanta/src/mappings/nrom.cfg | 6 | ||||
| -rw-r--r-- | lib/xixanta/src/mappings/nrom.toml | 27 | ||||
| -rw-r--r-- | lib/xixanta/src/mappings/nrom65.cfg | 6 | ||||
| -rw-r--r-- | lib/xixanta/src/mappings/nrom65.toml | 27 | ||||
| -rw-r--r-- | lib/xixanta/src/mappings/unrom.cfg | 12 | ||||
| -rw-r--r-- | lib/xixanta/src/mappings/unrom.toml | 69 |
12 files changed, 121 insertions, 413 deletions
diff --git a/lib/xixanta/Cargo.toml b/lib/xixanta/Cargo.toml index ada2ded..90a0050 100644 --- a/lib/xixanta/Cargo.toml +++ b/lib/xixanta/Cargo.toml @@ -10,4 +10,3 @@ rust-version.workspace = true [dependencies] lazy_static = "1.5.0" -toml = { version = "0.8", features = ["preserve_order"] } diff --git a/lib/xixanta/fuzz/Cargo.lock b/lib/xixanta/fuzz/Cargo.lock index eb897dd..d06a484 100644 --- a/lib/xixanta/fuzz/Cargo.lock +++ b/lib/xixanta/fuzz/Cargo.lock @@ -20,28 +20,6 @@ dependencies = [ ] [[package]] -name = "equivalent" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" - -[[package]] -name = "hashbrown" -version = "0.15.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" - -[[package]] -name = "indexmap" -version = "2.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" -dependencies = [ - "equivalent", - "hashbrown", -] - -[[package]] name = "jobserver" version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -74,137 +52,22 @@ dependencies = [ ] [[package]] -name = "memchr" -version = "2.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" - -[[package]] name = "once_cell" version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] -name = "proc-macro2" -version = "1.0.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "serde" -version = "1.0.216" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.216" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_spanned" -version = "0.6.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" -dependencies = [ - "serde", -] - -[[package]] name = "shlex" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] -name = "syn" -version = "2.0.91" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d53cbcb5a243bd33b7858b1d7f4aca2153490815872d86d955d6ea29f743c035" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "toml" -version = "0.8.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" -dependencies = [ - "indexmap", - "serde", - "serde_spanned", - "toml_datetime", - "toml_edit", -] - -[[package]] -name = "toml_datetime" -version = "0.6.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" -dependencies = [ - "serde", -] - -[[package]] -name = "toml_edit" -version = "0.22.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" -dependencies = [ - "indexmap", - "serde", - "serde_spanned", - "toml_datetime", - "winnow", -] - -[[package]] -name = "unicode-ident" -version = "1.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" - -[[package]] -name = "winnow" -version = "0.6.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" -dependencies = [ - "memchr", -] - -[[package]] name = "xixanta" version = "0.1.0" dependencies = [ "lazy_static", - "toml", ] [[package]] diff --git a/lib/xixanta/src/cfg.rs b/lib/xixanta/src/cfg.rs index a6127b9..be3a9c1 100644 --- a/lib/xixanta/src/cfg.rs +++ b/lib/xixanta/src/cfg.rs @@ -18,6 +18,7 @@ struct RawMapping { fill: Option<String>, ignore: bool, line_num: usize, + segments: String, } // Fetch a line of values in the format of "Name: key1=value1, key2=value2, @@ -87,6 +88,7 @@ fn fetch_memory_definition(line: &str, line_num: usize) -> Result<RawMapping, St fill: None, ignore: false, line_num, + segments: String::from(""), }; for value in values.split(',') { @@ -106,6 +108,7 @@ fn fetch_memory_definition(line: &str, line_num: usize) -> Result<RawMapping, St "fillval" => res.fill = Some(val.to_string()), "start" => res.start = val.to_string(), "size" => res.size = val.to_string(), + "segments" => res.segments = val.to_string(), _ => {} } } @@ -150,8 +153,8 @@ fn find_value(key: &str, values: &str, line_num: usize) -> Result<String, String )) } -// Parse the given blob of `text` as a .cfg file as it's expected by ld65: -// https://www.cc65.org/doc/ld65-5.html. +/// Parse the given blob of `text` as a .cfg file as it's expected by ld65: +/// https://www.cc65.org/doc/ld65-5.html. pub fn parse_cfg_file(text: &str) -> Result<Vec<Mapping>, String> { let mut values = vec![]; let mut raw_segments = vec![]; @@ -265,7 +268,7 @@ pub fn parse_cfg_file(text: &str) -> Result<Vec<Mapping>, String> { // realized it's CHR ROM. if header { header = false; - } else if start == 0x00 { + } else if start == 0x0000 { section_type = SectionType::ChrRom; } else if section_type != SectionType::ChrRom { section_type = SectionType::PrgRom; @@ -294,6 +297,83 @@ pub fn parse_cfg_file(text: &str) -> Result<Vec<Mapping>, String> { Ok(res) } +fn get_segments_from(value: &str, line: usize) -> Result<Vec<Segment>, String> { + if !value.starts_with('[') || !value.ends_with(']') { + return Err(format!("should be enclosed inside of [] (line {})", line)); + } + + let mut res = vec![]; + for name in value[1..value.len() - 1].split(' ') { + let trimmed_name = name.trim(); + res.push(Segment::from(trimmed_name)); + } + + Ok(res) +} + +/// Parse the given blob of `text` as a simplified .cfg file. +pub fn parse_nasm_cfg_file(text: &str) -> Result<Vec<Mapping>, String> { + let mut mappings = vec![]; + let symbols = HashMap::new(); + let mut header = true; + let mut section_type = SectionType::Header; + + for (idx, line) in text.lines().enumerate() { + // Skip empty lines and comments. + let l = line.trim(); + if l.is_empty() || l.starts_with('#') { + continue; + } + + let real_line = match l.find(';') { + Some(idx) => &l[0..idx], + None => { + return Err(format!( + "line does not end with a semicolon (line {})", + idx + 1 + )) + } + }; + + // Parse the mapping definition. + let mapping = fetch_memory_definition(real_line, idx + 1)?; + + // Parse hexadecimal values from start, size and fill. + let start = get_hex_from(&mapping.start, mapping.line_num, &symbols)? as u16; + let size = get_hex_from(&mapping.size, mapping.line_num, &symbols)?; + let fill = match &mapping.fill { + Some(f) => Some(get_hex_from(f, mapping.line_num, &symbols)? as u8), + None => None, + }; + + // As with 'parse_cfg_file', the section type: + // 1. If it's the first mapping we see, then it's the header. + // 2. If after the header it claims to start at 0x00, then from now on + // it's CHR ROM. + // 3. Otherwise it's PRG ROM unless in a previous iteration we + // realized it's CHR ROM. + if header { + header = false; + } else if start == 0x0000 { + section_type = SectionType::ChrRom; + } else if section_type != SectionType::ChrRom { + section_type = SectionType::PrgRom; + }; + + mappings.push(Mapping { + name: mapping.name, + offset: 0, + start, + size, + fill, + section_type: section_type.clone(), + segments: get_segments_from(&mapping.segments, idx + 1)?, + }); + } + + Ok(mappings) +} + #[cfg(test)] mod tests { use super::*; diff --git a/lib/xixanta/src/mapping.rs b/lib/xixanta/src/mapping.rs index 49683ab..b3d22c7 100644 --- a/lib/xixanta/src/mapping.rs +++ b/lib/xixanta/src/mapping.rs @@ -1,11 +1,10 @@ -use crate::cfg::parse_cfg_file; +use crate::cfg::{parse_cfg_file, parse_nasm_cfg_file}; use crate::object::Bundle; -use toml::{Table, Value}; -const EMPTY_CONFIG: &str = include_str!("mappings/empty.toml"); -const NROM_CONFIG: &str = include_str!("mappings/nrom.toml"); -const NROM65_CONFIG: &str = include_str!("mappings/nrom65.toml"); -const UXROM_CONFIG: &str = include_str!("mappings/unrom.toml"); +const EMPTY_CONFIG: &str = include_str!("mappings/empty.cfg"); +const NROM_CONFIG: &str = include_str!("mappings/nrom.cfg"); +const NROM65_CONFIG: &str = include_str!("mappings/nrom65.cfg"); +const UXROM_CONFIG: &str = include_str!("mappings/unrom.cfg"); /// The type of section that a Mapping represents. #[derive(Debug, Clone, Eq, Ord, PartialEq, PartialOrd)] @@ -104,12 +103,11 @@ pub fn get_mapping_configuration(name: &str) -> Result<Vec<Mapping>, String> { let configuration = if std::fs::exists(name).unwrap_or(false) { match std::fs::read_to_string(name) { Ok(contents) => { - // If this is a file, then it might not be a TOML one, but a - // .cfg as used by cc65. - if name.ends_with(".cfg") { - parse_cfg_file(contents.as_str())? + // Call the right parse function. + if contents.starts_with("#!nasmcfg") { + parse_nasm_cfg_file(contents.as_str())? } else { - load_configuration_for(contents.as_str())? + parse_cfg_file(contents.as_str())? } } Err(_) => return Err(format!("could not read '{}'", name)), @@ -122,7 +120,7 @@ pub fn get_mapping_configuration(name: &str) -> Result<Vec<Mapping>, String> { "uxrom" | "unrom" => UXROM_CONFIG, _ => return Err("mapper configuration is not known".to_string()), }; - load_configuration_for(text)? + parse_nasm_cfg_file(text)? }; validate_configuration(&configuration)?; @@ -130,131 +128,6 @@ pub fn get_mapping_configuration(name: &str) -> Result<Vec<Mapping>, String> { Ok(configuration) } -// Returns the integer value for the mandatory integer contained in `value` that -// is named `prop_name` under the `section_name` section. This integer has to be -// lesser or equal to the `max` value. -fn get_integer( - section_name: &String, - prop_name: &str, - value: Option<&Value>, - max: usize, -) -> Result<usize, String> { - if value.is_none() { - return Err(format!( - "you have to define a value for '{}' in '{}'", - section_name, prop_name - )); - } - if !value.unwrap().is_integer() { - return Err(format!( - "value for '{}' in '{}' has to be an integer value", - section_name, prop_name - )); - } - - let val = value.unwrap().as_integer().unwrap() as usize; - if val > max { - return Err(format!( - "value for '{}' in '{}' is too big", - prop_name, section_name - )); - } - Ok(val) -} - -// Get a `SectionType` out of the given mandatory `value` which is under the -// `section_name`. -fn parse_section_type(section_name: &String, value: Option<&Value>) -> Result<SectionType, String> { - match value { - Some(v) => { - if !v.is_str() { - return Err(format!( - "'section_type' in '{}' has to be a string", - section_name - )); - } - match v.as_str().unwrap().to_lowercase().as_str() { - "header" => Ok(SectionType::Header), - "prgrom" => Ok(SectionType::PrgRom), - "chrrom" => Ok(SectionType::ChrRom), - _ => Err(format!( - "bad value for 'section_type' in '{}'", - section_name - )), - } - } - None => Err(format!( - "you have to define 'section_type' in '{}'", - section_name - )), - } -} - -// Returns a vector of segments which are contained inside of the mandatory -// `value`. -fn get_segments(section_name: &String, value: Option<&Value>) -> Result<Vec<Segment>, String> { - if value.is_none() { - return Err(format!( - "you have to define a value for 'segments' in '{}'", - section_name - )); - } - if !value.unwrap().is_array() { - return Err(format!( - "value for 'segments' in '{}' has to be an array value", - section_name - )); - } - - let mut res = vec![]; - for item in value.unwrap().as_array().unwrap() { - if !item.is_str() { - return Err(format!( - "every item in 'segments' has to be a string ({})", - section_name - )); - } - res.push(Segment::from(item.as_str().unwrap())); - } - - Ok(res) -} - -// Returns a vector of mappings that is retrieved by parsing the given text. -fn load_configuration_for(text: &str) -> Result<Vec<Mapping>, String> { - // Obtain the raw data by parsing the given text as a toml::Table. - let table = match text.parse::<Table>() { - Ok(t) => t, - Err(e) => return Err(format!("could not parse configuration file: {}", e)), - }; - - // Each section of the configuration file is a mapping, where the title is - // simply the name of it. - let mut mappings = vec![]; - for (name, value) in table { - let start = get_integer(&name, "start", value.get("start"), u16::MAX as usize)? as u16; - let size = get_integer(&name, "size", value.get("size"), u16::MAX as usize)?; - let fill = match value.get("fill") { - Some(_) => Some(get_integer(&name, "fill", value.get("fill"), u8::MAX as usize)? as u8), - None => None, - }; - let section_type = parse_section_type(&name, value.get("section_type"))?; - let segments = get_segments(&name, value.get("segments"))?; - - mappings.push(Mapping { - name, - start, - size, - offset: 0, - fill, - section_type, - segments, - }); - } - - Ok(mappings) -} - // Ensure that the given mappings conform to a minimum standard. fn validate_configuration(mappings: &[Mapping]) -> Result<(), String> { if mappings.is_empty() { diff --git a/lib/xixanta/src/mappings/empty.cfg b/lib/xixanta/src/mappings/empty.cfg new file mode 100644 index 0000000..985cf31 --- /dev/null +++ b/lib/xixanta/src/mappings/empty.cfg @@ -0,0 +1,4 @@ +#!nasmcfg + +HEADER: start = $0000, size = $0010, fillval = $00, segments = [HEADER]; +ROM0: start = $8000, size = $8000, segments = [CODE]; diff --git a/lib/xixanta/src/mappings/empty.toml b/lib/xixanta/src/mappings/empty.toml deleted file mode 100644 index ae6312c..0000000 --- a/lib/xixanta/src/mappings/empty.toml +++ /dev/null @@ -1,12 +0,0 @@ -[HEADER] -start = 0x0000 -size = 0x0010 -fill = 0x00 -section_type = "Header" -segments = ["HEADER"] - -[ROM0] -start = 0x8000 -size = 0x8000 -section_type = "PRGROM" -segments = ["CODE"] diff --git a/lib/xixanta/src/mappings/nrom.cfg b/lib/xixanta/src/mappings/nrom.cfg new file mode 100644 index 0000000..920318b --- /dev/null +++ b/lib/xixanta/src/mappings/nrom.cfg @@ -0,0 +1,6 @@ +#!nasmcfg + +HEADER: start = $0000, size = $0010, fillval = $00, segments = [HEADER]; +ROM0: start = $8000, size = $7FFA, fillval = $00, segments = [CODE]; +ROMV: start = $FFFA, size = $0006, fillval = $00, segments = [VECTORS]; +ROM2: start = $0000, size = $2000, fillval = $00, segments = [CHARS]; diff --git a/lib/xixanta/src/mappings/nrom.toml b/lib/xixanta/src/mappings/nrom.toml deleted file mode 100644 index 18711a6..0000000 --- a/lib/xixanta/src/mappings/nrom.toml +++ /dev/null @@ -1,27 +0,0 @@ -[HEADER] -start = 0x0000 -size = 0x0010 -fill = 0x00 -section_type = "Header" -segments = ["HEADER"] - -[ROM0] -start = 0x8000 -size = 0x7FFA -fill = 0x00 -section_type = "PRGROM" -segments = ["CODE"] - -[ROMV] -start = 0xFFFA -size = 0x0006 -fill = 0x00 -section_type = "PRGROM" -segments = ["VECTORS"] - -[ROM2] -start = 0x0000 -size = 0x2000 -fill = 0x00 -section_type = "CHRROM" -segments = ["CHARS"] diff --git a/lib/xixanta/src/mappings/nrom65.cfg b/lib/xixanta/src/mappings/nrom65.cfg new file mode 100644 index 0000000..6a90b2d --- /dev/null +++ b/lib/xixanta/src/mappings/nrom65.cfg @@ -0,0 +1,6 @@ +#!nasmcfg + +HEADER: start = $0000, size = $0010, fillval = $00, segments = [HEADER]; +ROM0: start = $8000, size = $7FFA, fillval = $00, segments = [STARTUP CODE]; +ROMV: start = $FFFA, size = $0006, fillval = $00, segments = [VECTORS]; +ROM2: start = $0000, size = $2000, fillval = $00, segments = [CHARS]; diff --git a/lib/xixanta/src/mappings/nrom65.toml b/lib/xixanta/src/mappings/nrom65.toml deleted file mode 100644 index d4775e4..0000000 --- a/lib/xixanta/src/mappings/nrom65.toml +++ /dev/null @@ -1,27 +0,0 @@ -[HEADER] -start = 0x0000 -size = 0x0010 -fill = 0x00 -section_type = "Header" -segments = ["HEADER"] - -[ROM0] -start = 0x8000 -size = 0x7FFA -fill = 0x00 -section_type = "PRGROM" -segments = ["STARTUP", "CODE"] - -[ROMV] -start = 0xFFFA -size = 0x0006 -fill = 0x00 -section_type = "PRGROM" -segments = ["VECTORS"] - -[ROM2] -start = 0x0000 -size = 0x2000 -fill = 0x00 -section_type = "CHRROM" -segments = ["CHARS"] diff --git a/lib/xixanta/src/mappings/unrom.cfg b/lib/xixanta/src/mappings/unrom.cfg new file mode 100644 index 0000000..91d0382 --- /dev/null +++ b/lib/xixanta/src/mappings/unrom.cfg @@ -0,0 +1,12 @@ +#!nasmcfg + +HEADER: start = $0000, size = $0010, fillval = $00, segments = [HEADER]; +PRG0: start = $8000, size = $4000, fillval = $F8, segments = [BANK0]; +PRG1: start = $8000, size = $4000, fillval = $F9, segments = [BANK1]; +PRG2: start = $8000, size = $4000, fillval = $FA, segments = [BANK2]; +PRG3: start = $8000, size = $4000, fillval = $FB, segments = [BANK3]; +PRG4: start = $8000, size = $4000, fillval = $FC, segments = [BANK4]; +PRG5: start = $8000, size = $4000, fillval = $FD, segments = [BANK5]; +PRG6: start = $8000, size = $4000, fillval = $FE, segments = [BANK6]; +PRG: start = $C000, size = $3FFA, fillval = $FF, segments = [FIXED]; +ROMV: start = $FFFA, size = $0006, fillval = $00, segments = [VECTORS]; diff --git a/lib/xixanta/src/mappings/unrom.toml b/lib/xixanta/src/mappings/unrom.toml deleted file mode 100644 index 070cfd1..0000000 --- a/lib/xixanta/src/mappings/unrom.toml +++ /dev/null @@ -1,69 +0,0 @@ -[HEADER] -start = 0x0000 -size = 0x0010 -fill = 0x00 -section_type = "Header" -segments = ["HEADER"] - -[PRG0] -start = 0x8000 -size = 0x4000 -fill = 0xF8 -section_type = "PRGROM" -segments = ["BANK0"] - -[PRG1] -start = 0x8000 -size = 0x4000 -fill = 0xF9 -section_type = "PRGROM" -segments = ["BANK1"] - -[PRG2] -start = 0x8000 -size = 0x4000 -fill = 0xFA -section_type = "PRGROM" -segments = ["BANK2"] - -[PRG3] -start = 0x8000 -size = 0x4000 -fill = 0xFB -section_type = "PRGROM" -segments = ["BANK3"] - -[PRG4] -start = 0x8000 -size = 0x4000 -fill = 0xFC -section_type = "PRGROM" -segments = ["BANK4"] - -[PRG5] -start = 0x8000 -size = 0x4000 -fill = 0xFD -section_type = "PRGROM" -segments = ["BANK5"] - -[PRG6] -start = 0x8000 -size = 0x4000 -fill = 0xFE -section_type = "PRGROM" -segments = ["BANK6"] - -[PRG] -start = 0xC000 -size = 0x3FFA -fill = 0xFF -section_type = "PRGROM" -segments = ["FIXED"] - -[ROMV] -start = 0xFFFA -size = 0x0006 -fill = 0x00 -section_type = "PRGROM" -segments = ["VECTORS"] |
