diff --git a/docs/spec.md b/docs/spec.md index 06e2fa3..46e4014 100644 --- a/docs/spec.md +++ b/docs/spec.md @@ -6,15 +6,22 @@ Corten is based on Fletcher Haynes's [So you want to build a language VM](https: ## Instruction Set -| Register | Opcode | -| --- | --- | -| 0 | LOAD | +| Opcode | Function | Comment | +| --- | --- | --- | +| 0 | LOAD | Load program | | 1 | ADD | | 2 | SUB | | 3 | MUL | | 4 | DIV | -| 6 | HLT | -| 5 | JMP | -| 8 | JMPF | -| 9 | JMPB | -| _ | IGL | \ No newline at end of file +| 6 | HLT | Halt | +| 5 | JMP | Jump | +| 8 | JMPF | Jump forward | +| 9 | JMPB | Jump backward | +| 10 | EQ | Equal | +| 11 | NEQ | Not equal | +| 12 | GTE | Greater then or equal to | +| 13 | GT | Greater then | +| 14 | LTE | Less then or equal | +| 15 | LT | Less then +| 16 | JMPE | Jump if equal | +| _ | IGL | Illegal action | \ No newline at end of file diff --git a/src/instruction.rs b/src/instruction.rs index 7f3e701..7b120c4 100644 --- a/src/instruction.rs +++ b/src/instruction.rs @@ -1,4 +1,4 @@ -use crate::instruction::Opcode::LOAD; +#![allow(dead_code)] #[derive(Debug, PartialEq)] pub enum Opcode { @@ -9,7 +9,26 @@ pub enum Opcode { SUB, MUL, DIV, + /// Equal + EQ, + /// Not equal + NEQ, + /// Greater then + GT, + /// Less then + LT, + /// Greater then or equal to + GTE, + /// less then or equal + LTE, + /// jump if equal + JMPE, + /// Jump JMP, + /// Jump forward + JMPF, + /// Jump backward + JMPB, } impl From for Opcode { @@ -22,6 +41,15 @@ impl From for Opcode { 4 => Opcode::DIV, 6 => Opcode::HLT, 7 => Opcode::JMP, + 8 => Opcode::JMPF, + 9 => Opcode::JMPB, + 10 => Opcode::EQ, + 11 => Opcode::NEQ, + 12 => Opcode::GTE, + 13 => Opcode::GT, + 14 => Opcode::LTE, + 15 => Opcode::LT, + 16 => Opcode::JMPE, _ => Opcode::IGL, } } diff --git a/src/vm.rs b/src/vm.rs index 5e77305..653c2d9 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -6,6 +6,7 @@ pub struct VM { pc: usize, program: Vec, remainder: u32, + equal_flag: bool, } impl VM { @@ -15,6 +16,7 @@ impl VM { pc: 0, program: vec![], remainder: 0, + equal_flag: false } } @@ -63,6 +65,7 @@ impl VM { } Opcode::IGL => { println!("Unrecognized opcode found! Terminating!"); + return false; } Opcode::ADD => { let reg1 = self.registers[self.next_8_bits() as usize]; @@ -89,6 +92,21 @@ impl VM { let reg2 = self.registers[self.next_8_bits() as usize]; self.registers[self.next_8_bits() as usize] = reg1 - reg2; } + Opcode::JMPF => { + let target = self.registers[self.next_8_bits() as usize]; + self.pc += target as usize; + } + Opcode::JMPB => { + let target = self.registers[self.next_8_bits() as usize]; + self.pc -= target as usize; + } + Opcode::EQ => {} + Opcode::NEQ => {} + Opcode::GT => {} + Opcode::LT => {} + Opcode::GTE => {} + Opcode::LTE => {} + Opcode::JMPE => {} } true } @@ -121,6 +139,30 @@ mod vm_tests { assert_eq!(vm.pc, 1); } + #[test] + fn test_add_opcode() { + let mut vm = get_test_vm(); + vm.program = vec![1, 0, 1, 2]; + vm.run(); + assert_eq!(vm.registers[2], 15); + } + + #[test] + fn test_sub_opcode() { + let mut vm = get_test_vm(); + vm.program = vec![2, 1, 0, 2]; + vm.run(); + assert_eq!(vm.registers[2], 5); + } + + #[test] + fn test_div_opcode() { + let mut vm = get_test_vm(); + vm.program = vec![4, 1, 0, 2]; + vm.run(); + assert_eq!(vm.registers[2], 2); + } + #[test] fn test_opcode_igl() { let mut vm = get_test_vm(); @@ -139,6 +181,25 @@ mod vm_tests { assert_eq!(vm.pc, 1); } + #[test] + fn test_jmpf_opcode() { + let mut vm = get_test_vm(); + vm.registers[0] = 2; + vm.program = vec![8, 0, 0, 0, 6, 0, 0, 0]; + vm.run_once(); + assert_eq!(vm.pc, 4); + } + + #[test] + fn test_jmpb_opcode() { + let mut vm = get_test_vm(); + vm.registers[1] = 6; + vm.program = vec![0, 0, 0, 10, 9, 1, 0, 0]; + vm.run_once(); + vm.run_once(); + assert_eq!(vm.pc, 0); + } + #[test] fn test_load_opcode() { let mut vm = get_test_vm();