Skip to content

Commit

Permalink
Add output format for the game "Turing Complete"
Browse files Browse the repository at this point in the history
Players of the game "Turing Complete" often use
customasm to design a richer assembly language
than the game provides and then copy the resulting
binary into the game.

This change introduces an annotated format compatible
with the Turing Complete assembly editor, using '#'
for comments and '0x' or '0b' to prefix data groups.
  • Loading branch information
thenorili committed Nov 5, 2023
1 parent 3913be5 commit ab4b0f9
Show file tree
Hide file tree
Showing 3 changed files with 158 additions and 1 deletion.
12 changes: 12 additions & 0 deletions src/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ struct CommandOutput
pub enum OutputFormat
{
Binary,
TMGame {
base: usize,
group: usize,
},
Annotated {
base: usize,
group: usize,
Expand Down Expand Up @@ -568,6 +572,11 @@ pub fn parse_output_format(
group: get_arg_usize("group", 2, check_nonzero)?,
},

"tmgame" => OutputFormat::TMGame{
base: get_arg_usize("base", 16, check_valid_base)?,
group: get_arg_usize("group", 2, check_nonzero)?,
},

"annotatedhex" => OutputFormat::Annotated {
base: 16,
group: 2,
Expand Down Expand Up @@ -730,6 +739,9 @@ pub fn format_output(
OutputFormat::Annotated { base, group } =>
output.format_annotated(fileserver, base, group),

OutputFormat::TMGame { base, group } =>
output.format_tcgame(fileserver, base, group),

OutputFormat::BinStr => output.format_binstr(),
OutputFormat::HexStr => output.format_hexstr(),

Expand Down
9 changes: 8 additions & 1 deletion src/usage_help.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,14 @@ Examples:

* `annotated,base:16,group:2`
Annotates the output data with snippets
of the source code.
of the source code. Supports base 2 and 16.
* `tcgame,base:16,group:2`
Annotates the output data with snippets
of the source code in a format compatible
with the assembly editor for the game
'Turing Complete'. Supports base 2 and 16.
Comments out annotations with '#' and prefixes
each group with 0x or 0b.

* `annotatedbin`
Same as: `annotated,base:2,group:8`
Expand Down
138 changes: 138 additions & 0 deletions src/util/bitvec_format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,144 @@ impl util::BitVec
result
}

// Turing Complete is a game in which you advance from nand gates to
// computer architecture. Its assembly editor uses `#` comments,
// `0b` and `0x` prefixes for binary and hex, and groups of 8 or 8x4 bytes.
// This format produces annotated bytecode that meets these constraints.
pub fn format_tcgame(
&self,
fileserver: &dyn util::FileServer,
base: usize,
digits_per_group: usize)
-> String
{
let mut result = String::new();
assert!(base == 2 || base == 16);
let prefix: &str = if base == 2 { "0b" } else { "0x" };
let comment: &str = "#";

let bits_per_digit = (base - 1).count_ones() as usize;
let bits_per_group = digits_per_group * bits_per_digit;

let mut outp_width = 2;
let mut outp_bit_width = 1;
let mut addr_width = 4;
let mut content_width = (digits_per_group + 1) * 1 - 1;

let mut sorted_spans = self.spans.clone();
sorted_spans.sort_by(|a, b|
a.offset.cmp(&b.offset));

for span in &sorted_spans
{
if let Some(offset) = span.offset
{
outp_width = std::cmp::max(
outp_width,
format!("{:x}", offset / bits_per_group).len());

outp_bit_width = std::cmp::max(
outp_bit_width,
format!("{:x}", offset % bits_per_group).len());

addr_width = std::cmp::max(
addr_width,
format!("{:x}", span.addr).len());

let data_digits = span.size / bits_per_digit + if span.size % bits_per_digit == 0 { 0 } else { 1 };
let this_content_width = data_digits + data_digits / digits_per_group;

if this_content_width > 1 && this_content_width <= (digits_per_group + 1) * 5
{
content_width = std::cmp::max(
content_width,
this_content_width - 1);
}
}
}
// differs from format-annotated only in the pound
result.push_str(&format!("{comment} {:>1$} |", "outp", outp_width + outp_bit_width + 1));
result.push_str(&format!(" {:>1$} |", "addr", addr_width));
result.push_str(&format!(" data (base {})", base));
result.push_str("\n");
result.push_str("\n");

let mut prev_file_handle = util::FileServerHandle::MAX;
let mut prev_file_chars = "".to_string();

for span in &sorted_spans
{
result.push_str(&format!("{comment} "));
// offset
if let Some(offset) = span.offset
{
result.push_str(&format!(" {:1$x}", offset / bits_per_group, outp_width));
result.push_str(&format!(":{:1$x} | ", offset % bits_per_group, outp_bit_width));
}
else
{
result.push_str(&format!(" {:>1$}", "--", outp_width));
result.push_str(&format!(":{:>1$} | ", "-", outp_bit_width));
}

// addr
result.push_str(&format!("{:1$x} \n", span.addr, addr_width));

// instruction excerpt
if span.span.file_handle != prev_file_handle
{
prev_file_handle = span.span.file_handle;
prev_file_chars = fileserver
.get_str_unwrap(prev_file_handle);
}

// FIXME - probably don't want the span locations
let span_location = span.span.location().unwrap();
let char_counter = util::CharCounter::new(&prev_file_chars);
result.push_str(&format!("{comment} {}\n", char_counter.get_excerpt(span_location.0, span_location.1)));


// bits
let mut contents_str = String::new();
let digit_num = span.size / bits_per_digit + if span.size % bits_per_digit == 0 { 0 } else { 1 };
for digit_index in 0..digit_num
{
if digit_index % digits_per_group == 0
{
if digit_index > 0
{
contents_str.push_str(" ");
}
contents_str.push_str(prefix);
}

let mut digit = 0;
for bit_index in 0..bits_per_digit
{
let i = span.offset.unwrap() + digit_index * bits_per_digit + bit_index;
let bit = self.read_bit(i);

digit <<= 1;
digit |= if bit { 1 } else { 0 };
}

let c = if digit < 10
{ ('0' as u8 + digit) as char }
else
{ ('a' as u8 + digit - 10) as char };

contents_str.push(c);
}


result.push_str(&format!("{:1$}", contents_str, content_width));
// moved the excerpt before the instruction
// result.push_str(&format!(" ; {}", char_counter.get_excerpt(span_location.0, span_location.1)));
result.push_str("\n");
}
result
}


pub fn format_annotated(
&self,
Expand Down

0 comments on commit ab4b0f9

Please sign in to comment.