feat: add remaining instructions
This commit is contained in:
parent
cf1330bb21
commit
551b4468aa
4
SPEC.md
4
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`
|
||||
|
|
|
@ -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])),
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue