feat: add remaining instructions

This commit is contained in:
Nat 2024-12-17 15:52:42 -08:00
parent cf1330bb21
commit 551b4468aa
3 changed files with 115 additions and 27 deletions

View File

@ -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`

View File

@ -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<u16, String> {
}
}
// e.g. not r t
fn parse_unary_op(tokens: &Vec<&str>, opcode: u16, signed: bool) -> Result<u16, String> {
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<u16, String> {
assert_argument_count!(tokens, 4);
@ -53,6 +51,33 @@ fn parse_binary_op(tokens: &Vec<&str>, opcode: u16, signed: bool) -> Result<u16,
Ok(opcode<<11 | left<<10 | right<<9 | dest<<8 | (signed as u16)<<7)
}
fn parse_binary_immediate_op(tokens: &Vec<&str>, opcode: u16, signed: bool) -> Result<u16, String> {
assert_argument_count!(tokens, 4);
let signed_immediate = tokens[2].parse::<i16>()
.map_err(|_| format!("Cannot parse number: {t}", t=tokens[2]))?;
let unsigned_immediate = tokens[2].parse::<u16>()
.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<u16, String> {
assert_argument_count!(tokens, 3);
@ -72,6 +97,15 @@ fn parse_push(tokens: &Vec<&str>, opcode: u16, signed: bool) -> Result<u16, Stri
Ok(opcode<<11 | dest<<10 | (signed as u16) << 9 | immediate)
}
fn parse_stack_op(tokens: &Vec<&str>, opcode: u16) -> Result<u16, String> {
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<u16, String> {
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<u16, String> = 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::<u16>() & 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])),
};

View File

@ -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;