Skip to content

Commit

Permalink
fix #10: add c, comma-separated, and logisim output formats; update r…
Browse files Browse the repository at this point in the history
…ust syntax
  • Loading branch information
hlorenzi committed Jun 23, 2019
1 parent 58f4f37 commit 182bea6
Show file tree
Hide file tree
Showing 13 changed files with 183 additions and 44 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ Usage: customasm [options] <asm-file-1> ... <asm-file-N>
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.
Expand Down
2 changes: 1 addition & 1 deletion build_wasm.ps1
Original file line number Diff line number Diff line change
@@ -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"
Expand Down
2 changes: 1 addition & 1 deletion src/asm/assembler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ impl AssemblerState
}


pub fn process_file<S>(&mut self, report: RcReport, fileserver: &FileServer, filename: S) -> Result<(), ()>
pub fn process_file<S>(&mut self, report: RcReport, fileserver: &dyn FileServer, filename: S) -> Result<(), ()>
where S: Into<String>
{
AssemblerParser::parse_file(report.clone(), self, fileserver, filename, None)?;
Expand Down
109 changes: 108 additions & 1 deletion src/asm/binary_output.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand All @@ -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));
}

Expand Down Expand Up @@ -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
}
}
6 changes: 3 additions & 3 deletions src/asm/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -23,12 +23,12 @@ pub struct AssemblerParser<'a>

impl<'a> AssemblerParser<'a>
{
pub fn parse_file<S>(report: RcReport, state: &mut AssemblerState, fileserver: &FileServer, filename: S, filename_span: Option<&Span>) -> Result<(), ()>
pub fn parse_file<S>(report: RcReport, state: &mut AssemblerState, fileserver: &dyn FileServer, filename: S, filename_span: Option<&Span>) -> Result<(), ()>
where S: Into<String>
{
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::<str>::as_ref(&filename_owned), &chars)?;

let mut parser = AssemblerParser
{
Expand Down
16 changes: 8 additions & 8 deletions src/diagn/report.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand All @@ -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
{
Expand Down Expand Up @@ -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
{
Expand All @@ -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();
Expand Down Expand Up @@ -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 }
Expand Down Expand Up @@ -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);
}
Expand Down
55 changes: 37 additions & 18 deletions src/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,16 @@ enum OutputFormat
HexDump,
Mif,
IntelHex,
DecComma,
HexComma,
DecC,
HexC,
LogiSim8,
LogiSim16,
}


pub fn drive(args: &Vec<String>, fileserver: &mut FileServer) -> Result<(), ()>
pub fn drive(args: &Vec<String>, fileserver: &mut dyn FileServer) -> Result<(), ()>
{
let opts = make_opts();

Expand All @@ -43,7 +49,7 @@ pub fn drive(args: &Vec<String>, fileserver: &mut FileServer) -> Result<(), ()>
}


fn drive_inner(report: RcReport, opts: &getopts::Options, args: &Vec<String>, fileserver: &mut FileServer) -> Result<(), bool>
fn drive_inner(report: RcReport, opts: &getopts::Options, args: &Vec<String>, fileserver: &mut dyn FileServer) -> Result<(), bool>
{
let matches = parse_opts(report.clone(), opts, args).map_err(|_| true)?;

Expand All @@ -64,13 +70,20 @@ fn drive_inner(report: RcReport, opts: &getopts::Options, args: &Vec<String>, 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 }
Expand Down Expand Up @@ -110,13 +123,19 @@ fn drive_inner(report: RcReport, opts: &getopts::Options, args: &Vec<String>, 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::<Vec<u8>>(),
OutputFormat::BinDump => assembled.generate_bindump (0, assembled.len()).bytes().collect::<Vec<u8>>(),
OutputFormat::HexStr => assembled.generate_hexstr (0, assembled.len()).bytes().collect::<Vec<u8>>(),
OutputFormat::HexDump => assembled.generate_hexdump (0, assembled.len()).bytes().collect::<Vec<u8>>(),
OutputFormat::Mif => assembled.generate_mif (0, assembled.len()).bytes().collect::<Vec<u8>>(),
OutputFormat::IntelHex => assembled.generate_intelhex(0, assembled.len()).bytes().collect::<Vec<u8>>(),
OutputFormat::Binary => assembled.generate_binary (0, assembled.len()),
OutputFormat::BinStr => assembled.generate_binstr (0, assembled.len()).bytes().collect::<Vec<u8>>(),
OutputFormat::BinDump => assembled.generate_bindump (0, assembled.len()).bytes().collect::<Vec<u8>>(),
OutputFormat::HexStr => assembled.generate_hexstr (0, assembled.len()).bytes().collect::<Vec<u8>>(),
OutputFormat::HexDump => assembled.generate_hexdump (0, assembled.len()).bytes().collect::<Vec<u8>>(),
OutputFormat::Mif => assembled.generate_mif (0, assembled.len()).bytes().collect::<Vec<u8>>(),
OutputFormat::IntelHex => assembled.generate_intelhex(0, assembled.len()).bytes().collect::<Vec<u8>>(),
OutputFormat::DecComma => assembled.generate_comma (0, assembled.len(), 10).bytes().collect::<Vec<u8>>(),
OutputFormat::HexComma => assembled.generate_comma (0, assembled.len(), 16).bytes().collect::<Vec<u8>>(),
OutputFormat::DecC => assembled.generate_c_array (0, assembled.len(), 10).bytes().collect::<Vec<u8>>(),
OutputFormat::HexC => assembled.generate_c_array (0, assembled.len(), 16).bytes().collect::<Vec<u8>>(),
OutputFormat::LogiSim8 => assembled.generate_logisim (0, assembled.len(), 8).bytes().collect::<Vec<u8>>(),
OutputFormat::LogiSim16 => assembled.generate_logisim (0, assembled.len(), 16).bytes().collect::<Vec<u8>>(),
};

if out_stdout
Expand Down Expand Up @@ -145,7 +164,7 @@ fn drive_inner(report: RcReport, opts: &getopts::Options, args: &Vec<String>, 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 <asm-files>. [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.");
Expand Down Expand Up @@ -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<BinaryOutput, ()>
pub fn assemble(report: RcReport, fileserver: &dyn FileServer, filenames: &[String], quiet: bool) -> Result<BinaryOutput, ()>
{
if !quiet
{ print_header(); }
Expand Down
4 changes: 2 additions & 2 deletions src/test/asm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,15 @@ where S: Into<Vec<u8>>
}


fn test_fileserver<S>(fileserver: &FileServer, asm_filename: S, expected: ExpectedResult<(usize, &'static str)>)
fn test_fileserver<S>(fileserver: &dyn FileServer, asm_filename: S, expected: ExpectedResult<(usize, &'static str)>)
where S: Into<String>
{
let bits = if let Pass(expected) = expected
{ expected.0 }
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)?;
Expand Down
2 changes: 1 addition & 1 deletion src/test/cpudef.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use super::{ExpectedResult, expect_result};
fn test<S>(src: S, expected: ExpectedResult<()>)
where S: Into<Vec<u8>>
{
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)?;
Expand Down
2 changes: 1 addition & 1 deletion src/test/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ pub enum ExpectedResult<T>
}


pub fn expect_result<T>(report: RcReport, fileserver: &FileServer, got: Option<T>, expected: ExpectedResult<T>)
pub fn expect_result<T>(report: RcReport, fileserver: &dyn FileServer, got: Option<T>, expected: ExpectedResult<T>)
where T: Debug + PartialEq
{
enable_windows_ansi_support();
Expand Down
Loading

0 comments on commit 182bea6

Please sign in to comment.