aboutsummaryrefslogtreecommitdiff
path: root/lib/xixanta/src
diff options
context:
space:
mode:
Diffstat (limited to 'lib/xixanta/src')
-rw-r--r--lib/xixanta/src/cfg.rs86
-rw-r--r--lib/xixanta/src/mapping.rs147
-rw-r--r--lib/xixanta/src/mappings/empty.cfg4
-rw-r--r--lib/xixanta/src/mappings/empty.toml12
-rw-r--r--lib/xixanta/src/mappings/nrom.cfg6
-rw-r--r--lib/xixanta/src/mappings/nrom.toml27
-rw-r--r--lib/xixanta/src/mappings/nrom65.cfg6
-rw-r--r--lib/xixanta/src/mappings/nrom65.toml27
-rw-r--r--lib/xixanta/src/mappings/unrom.cfg12
-rw-r--r--lib/xixanta/src/mappings/unrom.toml69
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"]