From 182bea67b3a368c80452f1672624d0c4f148d38e Mon Sep 17 00:00:00 2001 From: Henrique Lorenzi Date: Sat, 22 Jun 2019 23:23:48 -0300 Subject: [PATCH] fix #10: add c, comma-separated, and logisim output formats; update rust syntax --- README.md | 3 +- build_wasm.ps1 | 2 +- src/asm/assembler.rs | 2 +- src/asm/binary_output.rs | 109 ++++++++++++++++++++++++++++++++++++++- src/asm/parser.rs | 6 +-- src/diagn/report.rs | 16 +++--- src/driver.rs | 55 +++++++++++++------- src/test/asm.rs | 4 +- src/test/cpudef.rs | 2 +- src/test/mod.rs | 2 +- src/webasm/mod.rs | 18 ++++--- web/index.html | 6 +++ web/main.js | 2 +- 13 files changed, 183 insertions(+), 44 deletions(-) diff --git a/README.md b/README.md index c118f538..a489c05d 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,8 @@ Usage: customasm [options] ... Options: -f, --format FORMAT The format of the output file. Possible formats: binary, binstr, hexstr, bindump, hexdump, - mif, intelhex + mif, intelhex, deccomma, hexcomma, decc, hexc, + logisim8, logisim16 -o, --output FILE The name of the output file. -p, --print Print output to stdout instead of writing to a file. diff --git a/build_wasm.ps1 b/build_wasm.ps1 index 839fd8bc..ef8ed63c 100644 --- a/build_wasm.ps1 +++ b/build_wasm.ps1 @@ -1,5 +1,5 @@ # Build wasm binary -cargo +nightly build --target wasm32-unknown-unknown --release +cargo +nightly build --lib --target wasm32-unknown-unknown --release # Reduce binary size wasm-gc "./target/wasm32-unknown-unknown/release/customasm.wasm" -o "./target/wasm32-unknown-unknown/release/customasm.gc.wasm" diff --git a/src/asm/assembler.rs b/src/asm/assembler.rs index 1b088a73..43cdc236 100644 --- a/src/asm/assembler.rs +++ b/src/asm/assembler.rs @@ -71,7 +71,7 @@ impl AssemblerState } - pub fn process_file(&mut self, report: RcReport, fileserver: &FileServer, filename: S) -> Result<(), ()> + pub fn process_file(&mut self, report: RcReport, fileserver: &dyn FileServer, filename: S) -> Result<(), ()> where S: Into { AssemblerParser::parse_file(report.clone(), self, fileserver, filename, None)?; diff --git a/src/asm/binary_output.rs b/src/asm/binary_output.rs index 8b0b574d..57f85177 100644 --- a/src/asm/binary_output.rs +++ b/src/asm/binary_output.rs @@ -220,6 +220,8 @@ impl BinaryOutput let mut index = start_bit; while index < end_bit { + result.push_str(&format!(" {:1$X}: ", index / 8, addr_max_width)); + let mut byte: u8 = 0; for _ in 0..8 { @@ -228,7 +230,6 @@ impl BinaryOutput index += 1; } - result.push_str(&format!("{:1$X}: ", index / 8, addr_max_width)); result.push_str(&format!("{:02X};\n", byte)); } @@ -280,4 +281,110 @@ impl BinaryOutput result.push_str(":00000001FF"); result } + + + pub fn generate_comma(&self, start_bit: usize, end_bit: usize, radix: usize) -> String + { + let mut result = String::new(); + + let mut index = start_bit; + while index < end_bit + { + let mut byte: u8 = 0; + for _ in 0..8 + { + byte <<= 1; + byte |= if self.read(index) { 1 } else { 0 }; + index += 1; + } + + match radix + { + 10 => result.push_str(&format!("{}", byte)), + 16 => result.push_str(&format!("0x{:02x}", byte)), + _ => panic!("invalid radix") + } + + if index < end_bit + { + result.push_str(", "); + + if (index / 8) % 16 == 0 + { result.push('\n'); } + } + } + + result + } + + + pub fn generate_c_array(&self, start_bit: usize, end_bit: usize, radix: usize) -> String + { + let mut result = String::new(); + + result.push_str("const unsigned char data[] = {\n"); + + let byte_num = (end_bit - start_bit) / 8 + if (end_bit - start_bit) % 8 != 0 { 1 } else { 0 }; + let addr_max_width = format!("{:x}", byte_num - 1).len(); + + let mut index = start_bit; + result.push_str(&format!("\t/* 0x{:01$x} */ ", 0, addr_max_width)); + + while index < end_bit + { + let mut byte: u8 = 0; + for _ in 0..8 + { + byte <<= 1; + byte |= if self.read(index) { 1 } else { 0 }; + index += 1; + } + + match radix + { + 10 => result.push_str(&format!("{}", byte)), + 16 => result.push_str(&format!("0x{:02x}", byte)), + _ => panic!("invalid radix") + } + + if index < end_bit + { + result.push_str(", "); + + if (index / 8) % 16 == 0 + { + result.push_str(&format!("\n\t/* 0x{:01$x} */ ", index / 8, addr_max_width)); + } + } + } + + result.push_str("\n};"); + result + } + + + // From: https://github.com/milanvidakovic/customasm/blob/master/src/asm/binary_output.rs#L84 + pub fn generate_logisim(&self, start_bit: usize, end_bit: usize, bits_per_chunk: usize) -> String + { + let mut result = String::new(); + result.push_str("v2.0 raw\n"); + + let mut index = start_bit; + while index < end_bit + { + let mut value: u16 = 0; + for _ in 0..bits_per_chunk + { + value <<= 1; + value |= if self.read(index) { 1 } else { 0 }; + index += 1; + } + + result.push_str(&format!("{:01$x} ", value, bits_per_chunk / 4)); + if (index / 8) % 16 == 0 + { result.push('\n'); } + } + + result + } } \ No newline at end of file diff --git a/src/asm/parser.rs b/src/asm/parser.rs index 574708ce..d8c3eff6 100644 --- a/src/asm/parser.rs +++ b/src/asm/parser.rs @@ -14,7 +14,7 @@ use num_traits::ToPrimitive; pub struct AssemblerParser<'a> { - pub fileserver: &'a FileServer, + pub fileserver: &'a dyn FileServer, pub state: &'a mut AssemblerState, pub cur_filename: String, pub parser: Parser @@ -23,12 +23,12 @@ pub struct AssemblerParser<'a> impl<'a> AssemblerParser<'a> { - pub fn parse_file(report: RcReport, state: &mut AssemblerState, fileserver: &FileServer, filename: S, filename_span: Option<&Span>) -> Result<(), ()> + pub fn parse_file(report: RcReport, state: &mut AssemblerState, fileserver: &dyn FileServer, filename: S, filename_span: Option<&Span>) -> Result<(), ()> where S: Into { let filename_owned = filename.into(); let chars = fileserver.get_chars(report.clone(), &filename_owned, filename_span)?; - let tokens = tokenize(report.clone(), filename_owned.as_ref(), &chars)?; + let tokens = tokenize(report.clone(), AsRef::::as_ref(&filename_owned), &chars)?; let mut parser = AssemblerParser { diff --git a/src/diagn/report.rs b/src/diagn/report.rs index 0bad6c87..87adcc73 100644 --- a/src/diagn/report.rs +++ b/src/diagn/report.rs @@ -130,7 +130,7 @@ impl Report } - pub fn has_error_at(&self, fileserver: &FileServer, filename: &str, line: usize, error_excerpt: &str) -> bool + pub fn has_error_at(&self, fileserver: &dyn FileServer, filename: &str, line: usize, error_excerpt: &str) -> bool { for msg in &self.messages { @@ -142,7 +142,7 @@ impl Report } - fn msg_has_error_at(&self, msg: &Message, fileserver: &FileServer, filename: &str, line: usize, error_excerpt: &str) -> bool + fn msg_has_error_at(&self, msg: &Message, fileserver: &dyn FileServer, filename: &str, line: usize, error_excerpt: &str) -> bool { match msg.inner { @@ -183,7 +183,7 @@ impl Report } - pub fn print_all(&self, writer: &mut Write, fileserver: &FileServer) + pub fn print_all(&self, writer: &mut dyn Write, fileserver: &dyn FileServer) { for msg in &self.messages { @@ -193,7 +193,7 @@ impl Report } - fn print_msg(&self, writer: &mut Write, fileserver: &FileServer, msg: &Message, indent: usize) + fn print_msg(&self, writer: &mut dyn Write, fileserver: &dyn FileServer, msg: &Message, indent: usize) { let kind_label = msg.kind.get_label(); let highlight_color = msg.kind.get_color(); @@ -259,14 +259,14 @@ impl Report } - fn print_indent(&self, writer: &mut Write, indent: usize) + fn print_indent(&self, writer: &mut dyn Write, indent: usize) { for _ in 0..indent { write!(writer, " ").unwrap(); } } - fn print_msg_src(&self, writer: &mut Write, counter: &CharCounter, highlight_color: &'static str, line1: usize, col1: usize, line2: usize, col2: usize, indent: usize) + fn print_msg_src(&self, writer: &mut dyn Write, counter: &CharCounter, highlight_color: &'static str, line1: usize, col1: usize, line2: usize, col2: usize, indent: usize) { let first_line = if (line1 as isize - 2) < 0 { 0 } @@ -409,13 +409,13 @@ impl RcReport } - pub fn has_error_at(&self, fileserver: &FileServer, filename: &str, line: usize, error_excerpt: &str) -> bool + pub fn has_error_at(&self, fileserver: &dyn FileServer, filename: &str, line: usize, error_excerpt: &str) -> bool { self.report.borrow_mut().has_error_at(fileserver, filename, line, error_excerpt) } - pub fn print_all(&self, writer: &mut Write, fileserver: &FileServer) + pub fn print_all(&self, writer: &mut dyn Write, fileserver: &dyn FileServer) { self.report.borrow_mut().print_all(writer, fileserver); } diff --git a/src/driver.rs b/src/driver.rs index 101f9c73..99211f3b 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -16,10 +16,16 @@ enum OutputFormat HexDump, Mif, IntelHex, + DecComma, + HexComma, + DecC, + HexC, + LogiSim8, + LogiSim16, } -pub fn drive(args: &Vec, fileserver: &mut FileServer) -> Result<(), ()> +pub fn drive(args: &Vec, fileserver: &mut dyn FileServer) -> Result<(), ()> { let opts = make_opts(); @@ -43,7 +49,7 @@ pub fn drive(args: &Vec, fileserver: &mut FileServer) -> Result<(), ()> } -fn drive_inner(report: RcReport, opts: &getopts::Options, args: &Vec, fileserver: &mut FileServer) -> Result<(), bool> +fn drive_inner(report: RcReport, opts: &getopts::Options, args: &Vec, fileserver: &mut dyn FileServer) -> Result<(), bool> { let matches = parse_opts(report.clone(), opts, args).map_err(|_| true)?; @@ -64,13 +70,20 @@ fn drive_inner(report: RcReport, opts: &getopts::Options, args: &Vec, fi let out_format = match matches.opt_str("f").as_ref().map(|s| s.as_ref()) { - Some("binstr") => OutputFormat::BinStr, - Some("bindump") => OutputFormat::BinDump, - Some("hexstr") => OutputFormat::HexStr, - Some("hexdump") => OutputFormat::HexDump, - Some("binary") => OutputFormat::Binary, - Some("mif") => OutputFormat::Mif, - Some("intelhex") => OutputFormat::IntelHex, + Some("binstr") => OutputFormat::BinStr, + Some("bindump") => OutputFormat::BinDump, + Some("hexstr") => OutputFormat::HexStr, + Some("hexdump") => OutputFormat::HexDump, + Some("binary") => OutputFormat::Binary, + Some("mif") => OutputFormat::Mif, + Some("intelhex") => OutputFormat::IntelHex, + Some("deccomma") => OutputFormat::DecComma, + Some("hexcomma") => OutputFormat::HexComma, + Some("decc") => OutputFormat::DecC, + Some("hexc") => OutputFormat::HexC, + Some("c") => OutputFormat::HexC, + Some("logisim8") => OutputFormat::LogiSim8, + Some("logisim16") => OutputFormat::LogiSim16, None => if out_stdout { OutputFormat::HexDump } @@ -110,13 +123,19 @@ fn drive_inner(report: RcReport, opts: &getopts::Options, args: &Vec, fi let output_data = match out_format { - OutputFormat::Binary => assembled.generate_binary (0, assembled.len()), - OutputFormat::BinStr => assembled.generate_binstr (0, assembled.len()).bytes().collect::>(), - OutputFormat::BinDump => assembled.generate_bindump (0, assembled.len()).bytes().collect::>(), - OutputFormat::HexStr => assembled.generate_hexstr (0, assembled.len()).bytes().collect::>(), - OutputFormat::HexDump => assembled.generate_hexdump (0, assembled.len()).bytes().collect::>(), - OutputFormat::Mif => assembled.generate_mif (0, assembled.len()).bytes().collect::>(), - OutputFormat::IntelHex => assembled.generate_intelhex(0, assembled.len()).bytes().collect::>(), + OutputFormat::Binary => assembled.generate_binary (0, assembled.len()), + OutputFormat::BinStr => assembled.generate_binstr (0, assembled.len()).bytes().collect::>(), + OutputFormat::BinDump => assembled.generate_bindump (0, assembled.len()).bytes().collect::>(), + OutputFormat::HexStr => assembled.generate_hexstr (0, assembled.len()).bytes().collect::>(), + OutputFormat::HexDump => assembled.generate_hexdump (0, assembled.len()).bytes().collect::>(), + OutputFormat::Mif => assembled.generate_mif (0, assembled.len()).bytes().collect::>(), + OutputFormat::IntelHex => assembled.generate_intelhex(0, assembled.len()).bytes().collect::>(), + OutputFormat::DecComma => assembled.generate_comma (0, assembled.len(), 10).bytes().collect::>(), + OutputFormat::HexComma => assembled.generate_comma (0, assembled.len(), 16).bytes().collect::>(), + OutputFormat::DecC => assembled.generate_c_array (0, assembled.len(), 10).bytes().collect::>(), + OutputFormat::HexC => assembled.generate_c_array (0, assembled.len(), 16).bytes().collect::>(), + OutputFormat::LogiSim8 => assembled.generate_logisim (0, assembled.len(), 8).bytes().collect::>(), + OutputFormat::LogiSim16 => assembled.generate_logisim (0, assembled.len(), 16).bytes().collect::>(), }; if out_stdout @@ -145,7 +164,7 @@ fn drive_inner(report: RcReport, opts: &getopts::Options, args: &Vec, fi fn make_opts() -> getopts::Options { let mut opts = getopts::Options::new(); - opts.optopt("f", "format", "The format of the output file. Possible formats: binary, binstr, hexstr, bindump, hexdump, mif, intelhex", "FORMAT"); + opts.optopt("f", "format", "The format of the output file. Possible formats: binary, binstr, hexstr, bindump, hexdump, mif, intelhex, deccomma, hexcomma, decc, hexc, logisim8, logisim16", "FORMAT"); opts.optmulti("i", "include", "Specifies an additional file for processing before the given . [deprecated]", "FILE"); opts.optopt("o", "output", "The name of the output file.", "FILE"); opts.optflag("p", "print", "Print output to stdout instead of writing to a file."); @@ -201,7 +220,7 @@ fn get_default_output_filename(report: RcReport, input_filename: &str) -> Result } -pub fn assemble(report: RcReport, fileserver: &FileServer, filenames: &[String], quiet: bool) -> Result +pub fn assemble(report: RcReport, fileserver: &dyn FileServer, filenames: &[String], quiet: bool) -> Result { if !quiet { print_header(); } diff --git a/src/test/asm.rs b/src/test/asm.rs index ad1e878c..1e29b638 100644 --- a/src/test/asm.rs +++ b/src/test/asm.rs @@ -39,7 +39,7 @@ where S: Into> } -fn test_fileserver(fileserver: &FileServer, asm_filename: S, expected: ExpectedResult<(usize, &'static str)>) +fn test_fileserver(fileserver: &dyn FileServer, asm_filename: S, expected: ExpectedResult<(usize, &'static str)>) where S: Into { let bits = if let Pass(expected) = expected @@ -47,7 +47,7 @@ where S: Into else { 4 }; - let assemble = |report: RcReport, fileserver: &FileServer, filename: S| -> Result<(usize, String), ()> + let assemble = |report: RcReport, fileserver: &dyn FileServer, filename: S| -> Result<(usize, String), ()> { let mut asm = AssemblerState::new(); asm.process_file(report.clone(), fileserver, filename)?; diff --git a/src/test/cpudef.rs b/src/test/cpudef.rs index 68325eff..9f4da92f 100644 --- a/src/test/cpudef.rs +++ b/src/test/cpudef.rs @@ -9,7 +9,7 @@ use super::{ExpectedResult, expect_result}; fn test(src: S, expected: ExpectedResult<()>) where S: Into> { - let compile = |report: RcReport, fileserver: &FileServer| -> Result<(), ()> + let compile = |report: RcReport, fileserver: &dyn FileServer| -> Result<(), ()> { let chars = fileserver.get_chars(report.clone(), "test", None)?; let tokens = tokenize(report.clone(), "test", &chars)?; diff --git a/src/test/mod.rs b/src/test/mod.rs index 78473d27..45395fb2 100644 --- a/src/test/mod.rs +++ b/src/test/mod.rs @@ -19,7 +19,7 @@ pub enum ExpectedResult } -pub fn expect_result(report: RcReport, fileserver: &FileServer, got: Option, expected: ExpectedResult) +pub fn expect_result(report: RcReport, fileserver: &dyn FileServer, got: Option, expected: ExpectedResult) where T: Debug + PartialEq { enable_windows_ansi_support(); diff --git a/src/webasm/mod.rs b/src/webasm/mod.rs index 806bb7af..9f8886fe 100644 --- a/src/webasm/mod.rs +++ b/src/webasm/mod.rs @@ -22,12 +22,18 @@ pub unsafe extern fn wasm_assemble(format: u32, src: *mut String) -> *mut String let output = asm.get_binary_output(); match format { - 0 => Ok(output.generate_hexdump (0, output.len())), - 1 => Ok(output.generate_bindump (0, output.len())), - 2 => Ok(output.generate_hexstr (0, output.len())), - 3 => Ok(output.generate_binstr (0, output.len())), - 4 => Ok(output.generate_mif (0, output.len())), - 5 => Ok(output.generate_intelhex(0, output.len())), + 0 => Ok(output.generate_hexdump (0, output.len())), + 1 => Ok(output.generate_bindump (0, output.len())), + 2 => Ok(output.generate_hexstr (0, output.len())), + 3 => Ok(output.generate_binstr (0, output.len())), + 4 => Ok(output.generate_mif (0, output.len())), + 5 => Ok(output.generate_intelhex(0, output.len())), + 6 => Ok(output.generate_comma (0, output.len(), 10)), + 7 => Ok(output.generate_comma (0, output.len(), 16)), + 8 => Ok(output.generate_c_array (0, output.len(), 10)), + 9 => Ok(output.generate_c_array (0, output.len(), 16)), + 10 => Ok(output.generate_logisim (0, output.len(), 8)), + 11 => Ok(output.generate_logisim (0, output.len(), 16)), _ => unreachable!() } }; diff --git a/web/index.html b/web/index.html index 53152c30..797a35f9 100644 --- a/web/index.html +++ b/web/index.html @@ -96,6 +96,12 @@ + + + + + + diff --git a/web/main.js b/web/main.js index 4cfafbad..8c08737a 100644 --- a/web/main.js +++ b/web/main.js @@ -121,7 +121,7 @@ function assemble() let divText = document.getElementById("divOutputText") divText.innerHTML = output - divText.style.whiteSpace = (isError || format <= 1) ? "pre" : "normal" + divText.style.whiteSpace = (isError || format <= 1) ? "pre" : "no-wrap" }