diff --git a/SPEC.md b/SPEC.md index 30e7609..b0b1f11 100644 --- a/SPEC.md +++ b/SPEC.md @@ -63,7 +63,9 @@ op code | stack | use literal? | signed? | literal --------|-------|--------------|---------|---------- 00000 | 000 | 0 | 0 | 000000 -- `and`; 0000 1 +If a literal value is used, the literal value replaces the right operand + +- `and` - `nand` - `or` - `nor` diff --git a/src/bin/ponderosa-asm.rs b/src/bin/ponderosa-asm.rs index 66a43c4..9459417 100644 --- a/src/bin/ponderosa-asm.rs +++ b/src/bin/ponderosa-asm.rs @@ -17,6 +17,14 @@ macro_rules! assert_argument_count { return Err("Too many arguments".to_owned()); } }; + + ($tokens:expr, $count:expr, $body:block) => { + if $tokens.len() < $count { + Err("Too few arguments".to_owned()); + } else if $tokens.len() > $count { + Err("Too many arguments".to_owned()); + } else $body + }; } fn parse_number(string: &str) -> u16 { @@ -32,16 +40,6 @@ fn stack_bit(token: &str) -> Result { } } -// e.g. not r t -fn parse_unary_op(tokens: &Vec<&str>, opcode: u16, signed: bool) -> Result { - assert_argument_count!(tokens, 3); - - let src = stack_bit(tokens[1])?; - let dest = stack_bit(tokens[2])?; - - Ok(opcode<<11 & src<<9 & dest<<8 & (signed as u16)<<7) -} - // e.g. add r r t fn parse_binary_op(tokens: &Vec<&str>, opcode: u16, signed: bool) -> Result { assert_argument_count!(tokens, 4); @@ -53,6 +51,33 @@ fn parse_binary_op(tokens: &Vec<&str>, opcode: u16, signed: bool) -> Result, opcode: u16, signed: bool) -> Result { + assert_argument_count!(tokens, 4); + + let signed_immediate = tokens[2].parse::() + .map_err(|_| format!("Cannot parse number: {t}", t=tokens[2]))?; + + let unsigned_immediate = tokens[2].parse::() + .map_err(|_| format!("Cannot parse number: {t}", t=tokens[2]))?; + + if signed { + if signed_immediate < -32 || signed_immediate > 31 { + return Err("Signed immediate values for math operations must be between -32 and 31".to_owned()); + } + } else { + if unsigned_immediate > 63 { + return Err("Unsigned immediate values for math operations must be between 0 and 61".to_owned()); + } + } + + let right = if signed { signed_immediate as u16 } else { unsigned_immediate }; + + let left = stack_bit(tokens[1])?; + let dest = stack_bit(tokens[3])?; + + Ok(opcode<<11 | right<<9 | dest<<8 | (signed as u16)<<7 | (left & 0b111111)) +} + fn parse_push(tokens: &Vec<&str>, opcode: u16, signed: bool) -> Result { assert_argument_count!(tokens, 3); @@ -72,6 +97,15 @@ fn parse_push(tokens: &Vec<&str>, opcode: u16, signed: bool) -> Result, opcode: u16) -> Result { + assert_argument_count!(tokens, 3); + + let src = stack_bit(tokens[1])?; + let dest= stack_bit(tokens[2])?; + + Ok(opcode<<11 | src<<10 | dest<<9) +} + // e.g. sow t -2 3 fn parse_forestry_op(tokens: &Vec<&str>, opcode: u16) -> Result { assert_argument_count!(tokens, 4); @@ -166,30 +200,82 @@ fn main() -> io::Result<()> { } if reading_rule { - let parse_instruction_result = match tokens[0] { + let parse_instruction_result: Result = match tokens[0] { "and" => parse_binary_op(&tokens, 0b00001, false), "nand" => parse_binary_op(&tokens, 0b00010, false), "or" => parse_binary_op(&tokens, 0b00011, false), "nor" => parse_binary_op(&tokens, 0b00100, false), "xor" => parse_binary_op(&tokens, 0b00101, false), - - "add" => parse_binary_op(&tokens, 0b00110, false), - "mult" => parse_binary_op(&tokens, 0b00111, false), - "div" => parse_binary_op(&tokens, 0b01000, false), - - "slt" => parse_binary_op(&tokens, 0b01001, false), - "not" => parse_unary_op(&tokens, 0b01010, false), + "add" => parse_binary_op(&tokens, 0b00110, true), + "mult" => parse_binary_op(&tokens, 0b00111, true), + "div" => parse_binary_op(&tokens, 0b01000, true), + "slt" => parse_binary_op(&tokens, 0b01001, true), + "not" => assert_argument_count!(tokens, 3, { + let opcode = 0b10010; + let (src, dest) = (stack_bit(tokens[1])?, stack_bit(tokens[2])?); + Ok(opcode<<11 & src<<9 & dest<<8) + }), "sll" => parse_binary_op(&tokens, 0b01011, false), "srl" => parse_binary_op(&tokens, 0b01100, false), - "push" => parse_push(&tokens, 0b01101, false), + "addu" => parse_binary_op(&tokens, 0b00110, false), + "multu" => parse_binary_op(&tokens, 0b00111, false), + "divu" => parse_binary_op(&tokens, 0b01000, false), + "sltu" => parse_binary_op(&tokens, 0b01001, false), - "sow" => parse_forestry_op(&tokens, 0b10101), - "reap" => parse_forestry_op(&tokens, 0b10110), - "plant" => parse_forestry_op(&tokens, 0b10111), - "replant" => parse_forestry_op(&tokens, 0b11000), - "yield" => Ok(0b11001_0_00000_00000), - "compost" => Ok(0b11010_0_00000_00000), + "andi" => parse_binary_immediate_op(&tokens, 0b00001, false), + "nandi" => parse_binary_immediate_op(&tokens, 0b00010, false), + "ori" => parse_binary_immediate_op(&tokens, 0b00011, false), + "nori" => parse_binary_immediate_op(&tokens, 0b00100, false), + "xori" => parse_binary_immediate_op(&tokens, 0b00101, false), + "addi" => parse_binary_immediate_op(&tokens, 0b00110, true), + "multi" => parse_binary_immediate_op(&tokens, 0b00111, true), + "divi" => parse_binary_immediate_op(&tokens, 0b01000, true), + "slti" => parse_binary_immediate_op(&tokens, 0b01001, true), + + "addiu" => parse_binary_immediate_op(&tokens, 0b00110, false), + "multiu" => parse_binary_immediate_op(&tokens, 0b00111, false), + "diviu" => parse_binary_immediate_op(&tokens, 0b01000, false), + "sltiu" => parse_binary_immediate_op(&tokens, 0b01001, false), + + "push" => parse_push(&tokens, 0b01101, true), + "pushu" => parse_push(&tokens, 0b01101, false), + "pull" => parse_stack_op(&tokens, 0b01110), + "swap" => parse_stack_op(&tokens, 0b01111), + "rotate" => parse_stack_op(&tokens, 0b10000), + "flip" => parse_stack_op(&tokens, 0b10001), + "clear" => { + let opcode = 0b10010; + assert_argument_count!(tokens, 2); + let to_clear = stack_bit(tokens[1])?; + Ok(opcode<<11 | to_clear<<10) + }, + + "skip" => { + let opcode = 0b10011; + assert_argument_count!(tokens, 2); + Ok(opcode<<11 | (tokens[1].parse::() & 0b111111111)) + }, + "skim" => { + let opcode = 0b10100; + assert_argument_count!(tokens, 2); + Ok(opcode<<11 | stack_bit(tokens[1])? << 9) + }, + + "sow" => parse_forestry_op(&tokens, 0b10101), + "reap" => parse_forestry_op(&tokens, 0b10110), + "plant" => parse_forestry_op(&tokens, 0b10111), + "replant" => parse_forestry_op(&tokens, 0b11000), + "yield" => Ok(0b11001_0_00000_00000), + "compost" => Ok(0b11010_0_00000_00000), + "define" => { + let opcode = 0b11011; + assert_argument_count!(tokens, 2); + Ok(opcode<<11 | stack_bit(tokens[1])? << 10) + }, + + "wait" => parse_forestry_op(&tokens, 0b11100), + "signal" => parse_forestry_op(&tokens, 0b11101), _ => Err(format!("Unknown instruction: {token}", token=tokens[0])), }; diff --git a/src/math.rs b/src/math.rs index f1d7233..ca1af9f 100644 --- a/src/math.rs +++ b/src/math.rs @@ -12,7 +12,7 @@ macro_rules! define_binary_op { let $left = tree.pull_by_stack_code((stack_code & 0b100) >> 2); let $right = tree.pull_by_stack_code((stack_code & 0b010) >> 1); - let $left = if !use_literal { $left } else { literal }; + let $right = if !use_literal { $left } else { literal }; if is_signed { let $left = $left as i16;