From 35ebf2aa0476d07164178eebda233bdee470b9e2 Mon Sep 17 00:00:00 2001 From: Julien Dubois Date: Mon, 28 Feb 2022 11:02:49 +0100 Subject: [PATCH 1/4] d0-core1: Implement SHL and SHR instructions --- src/main.rs | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/src/main.rs b/src/main.rs index 41e96c2..85d36eb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -28,6 +28,8 @@ enum OpCode { STW = 0x01, ADD = 0x02, XOR = 0x03, + SHL = 0x04, + SHR = 0x05, } impl OpCode { @@ -37,6 +39,8 @@ impl OpCode { 0x01 => OpCode::STW, 0x02 => OpCode::ADD, 0x03 => OpCode::XOR, + 0x04 => OpCode::SHL, + 0x05 => OpCode::SHR, _ => panic!("Unknown opcode {:?}", opcode), } } @@ -49,6 +53,22 @@ fn xor(op0: u32, op1: u32) -> u32 { op0 ^ op1 } +fn shift_left(op0: u32, op1: u32) -> u32 { + if op1 < 32 { + op0 << op1 + } else { + panic!("Attempt to shift left by {:?} which would overflow", op1); + } +} + +fn shift_right(op0: u32, op1: u32) -> u32 { + if op1 < 32 { + op0 >> op1 + } else { + panic!("Attempt to shift right by {:?} which would overflow", op1); + } +} + fn main() { // ADD R1, R3 -> Opcode is 2 (ADD), op0 is 1 (R1) and op1 is 3 (R3) // The first 6 bits of the instruction are the opcode (2): 0b000010 @@ -78,6 +98,8 @@ fn main() { match decoded_instruction.opcode { OpCode::ADD => r1 = add(r1, r3), OpCode::XOR => r1 = xor(r1, r3), + OpCode::SHL => r1 = shift_left(r1, r3), + OpCode::SHR => r1 = shift_right(r1, r3), _ => panic!("Unknown opcode {:?}", decoded_instruction.opcode), } @@ -91,6 +113,26 @@ fn main() { mod tests { use crate::{Instruction, OpCode}; + #[test] + fn test_instruction_disassemble_ldw_r1_r3() { + let insn_bytes: u32 = 0x1840; + let insn = Instruction::disassemble(insn_bytes); + + assert_eq!(insn.opcode, OpCode::LDW); + assert_eq!(insn.op0, 1); + assert_eq!(insn.op1, 3); + } + + #[test] + fn test_instruction_disassemble_stw_r1_r3() { + let insn_bytes: u32 = 0x1841; + let insn = Instruction::disassemble(insn_bytes); + + assert_eq!(insn.opcode, OpCode::STW); + assert_eq!(insn.op0, 1); + assert_eq!(insn.op1, 3); + } + #[test] fn test_instruction_disassemble_add_r1_r3() { let insn_bytes: u32 = 0x1842; @@ -100,4 +142,34 @@ mod tests { assert_eq!(insn.op0, 1); assert_eq!(insn.op1, 3); } + + #[test] + fn test_instruction_disassemble_xor_r1_r3() { + let insn_bytes: u32 = 0x1843; + let insn = Instruction::disassemble(insn_bytes); + + assert_eq!(insn.opcode, OpCode::XOR); + assert_eq!(insn.op0, 1); + assert_eq!(insn.op1, 3); + } + + #[test] + fn test_instruction_disassemble_shift_left_r1_r3() { + let insn_bytes: u32 = 0x1844; + let insn = Instruction::disassemble(insn_bytes); + + assert_eq!(insn.opcode, OpCode::SHL); + assert_eq!(insn.op0, 1); + assert_eq!(insn.op1, 3); + } + + #[test] + fn test_instruction_disassemble_shift_right_r1_r3() { + let insn_bytes: u32 = 0x1845; + let insn = Instruction::disassemble(insn_bytes); + + assert_eq!(insn.opcode, OpCode::SHR); + assert_eq!(insn.op0, 1); + assert_eq!(insn.op1, 3); + } } From fe7efa61a652ab15199b928fd48f78fa07526c7c Mon Sep 17 00:00:00 2001 From: Julien Dubois Date: Mon, 28 Feb 2022 11:03:15 +0100 Subject: [PATCH 2/4] README: Add SHL and SHR doc to README --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 7c6ab92..e284f06 100644 --- a/README.md +++ b/README.md @@ -55,3 +55,5 @@ architecture and supports the following instructions: | `0x01` | `STW Rn, Rm` | **ST**ore **W**ord: Store the 32-bit value from `Rn` into the memory address contained in `Rm` | | `0x02` | `ADD Rn, Rm` | **ADD**: Add the value contained in `Rm` into `Rn` (`Rn = Rn + Rm`) | | `0x03` | `XOR Rn, Rm` | e**X**clusive **OR**: Perform a bitwise exclusive OR between `Rn` and `Rm` (`Rn = Rn ^ Rm`) | +| `0x04` | `SHL Rn, Rm` | **SH**ift **L**eft: Perform a left shifting of `Rn` by `Rm` (`Rn = Rn << Rm`) | +| `0x05` | `SHR Rn, Rm` | **SH**ift **R**ight: Perform a right shifting of `Rn` by `Rm` (`Rn = Rn >> Rm`) | From 56ea6899eaa3624c520f15c92e168531118f8824 Mon Sep 17 00:00:00 2001 From: Julien Dubois Date: Mon, 28 Feb 2022 11:23:56 +0100 Subject: [PATCH 3/4] d0-core1: Add unit tests for operations --- src/main.rs | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/src/main.rs b/src/main.rs index 85d36eb..cf88c6f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -111,7 +111,7 @@ fn main() { #[cfg(test)] mod tests { - use crate::{Instruction, OpCode}; + use crate::{Instruction, OpCode, add, xor, shift_left, shift_right}; #[test] fn test_instruction_disassemble_ldw_r1_r3() { @@ -172,4 +172,56 @@ mod tests { assert_eq!(insn.op0, 1); assert_eq!(insn.op1, 3); } + + #[test] + fn test_add_op0_op1() { + let op0: u32 = 1; + let op1: u32 = 2; + let result: u32 = add(op0, op1); + + assert_eq!(result, 3); + } + + #[test] + fn test_xor_op0_op1() { + let op0: u32 = 1; + let op1: u32 = 2; + let result: u32 = xor(op0, op1); + + assert_eq!(result, 3); + } + + #[test] + fn test_shift_left_ok_op0_op1() { + let op0: u32 = 1; + let op1: u32 = 2; + let result: u32 = shift_left(op0, op1); + + assert_eq!(result, 4); + } + + #[test] + fn test_shift_right_ok_op0_op1() { + let op0: u32 = 2; + let op1: u32 = 1; + let result: u32 = shift_right(op0, op1); + + assert_eq!(result, 1); + } + + #[test] + #[should_panic] + fn test_shift_left_panic_op0_op1() { + let op0: u32 = 1; + let op1: u32 = 0xff; + shift_left(op0, op1); + } + + #[test] + #[should_panic] + fn test_shift_right_panic_op0_op1() { + let op0: u32 = 1; + let op1: u32 = 0xff; + shift_right(op0, op1); + } } From 94d011448be1d83e37fe1de7ad71396209feced1 Mon Sep 17 00:00:00 2001 From: Julien Dubois Date: Mon, 28 Feb 2022 11:59:29 +0100 Subject: [PATCH 4/4] d0-core1: Add documentation --- src/main.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/main.rs b/src/main.rs index cf88c6f..1e47201 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,4 @@ +/// An instruction must have an opcode to defined which operation to run on op0 and op1 #[derive(Debug)] struct Instruction { opcode: OpCode, @@ -21,6 +22,7 @@ impl Instruction { } } +/// Represent an operation code #[allow(dead_code)] #[derive(Debug, PartialEq)] enum OpCode { @@ -33,6 +35,7 @@ enum OpCode { } impl OpCode { + /// Provides a `from_u8` function to convert an opcode from u8 to OpCode fn from_u8(opcode: u8) -> OpCode { match opcode { 0x00 => OpCode::LDW, @@ -45,14 +48,18 @@ impl OpCode { } } } + +/// Add `op0` with `op1` fn add(op0: u32, op1: u32) -> u32 { op0 + op1 } +/// Perform a xor operation on `op0` and `op1` fn xor(op0: u32, op1: u32) -> u32 { op0 ^ op1 } +/// Perform a left shifting from `op0` of `op1` bits fn shift_left(op0: u32, op1: u32) -> u32 { if op1 < 32 { op0 << op1 @@ -61,6 +68,7 @@ fn shift_left(op0: u32, op1: u32) -> u32 { } } +/// Perform a right shifting from `op0` of `op1` bits fn shift_right(op0: u32, op1: u32) -> u32 { if op1 < 32 { op0 >> op1 @@ -69,6 +77,7 @@ fn shift_right(op0: u32, op1: u32) -> u32 { } } +/// Main entrypoint fn main() { // ADD R1, R3 -> Opcode is 2 (ADD), op0 is 1 (R1) and op1 is 3 (R3) // The first 6 bits of the instruction are the opcode (2): 0b000010