diff options
Diffstat (limited to 'lib/xixanta/src')
| -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 |
10 files changed, 121 insertions, 275 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::*; 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"] |
