aboutsummaryrefslogtreecommitdiff
path: root/lib/xixanta/src/cfg.rs
diff options
context:
space:
mode:
authorMiquel Sabaté Solà <mikisabate@gmail.com>2025-01-22 16:05:24 +0100
committerMiquel Sabaté Solà <mikisabate@gmail.com>2025-01-22 16:05:24 +0100
commit3f643b961cc54aa5b198c7edfc354ffec0b28a67 (patch)
tree1b4ddc8115bb5987353423956ec2fba0bc7fb65f /lib/xixanta/src/cfg.rs
parent61ef02df2c128cd86efcddd3fa53870bc8d575c4 (diff)
downloadtools.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/src/cfg.rs')
-rw-r--r--lib/xixanta/src/cfg.rs86
1 files changed, 83 insertions, 3 deletions
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::*;