Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Exercice: Shift left and right operations [Julien D] #13

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`) |
135 changes: 134 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -21,34 +22,62 @@ impl Instruction {
}
}

/// Represent an operation code
#[allow(dead_code)]
#[derive(Debug, PartialEq)]
enum OpCode {
LDW = 0x00,
STW = 0x01,
ADD = 0x02,
XOR = 0x03,
SHL = 0x04,
SHR = 0x05,
}

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,
0x01 => OpCode::STW,
0x02 => OpCode::ADD,
0x03 => OpCode::XOR,
0x04 => OpCode::SHL,
0x05 => OpCode::SHR,
_ => panic!("Unknown opcode {:?}", 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
} else {
panic!("Attempt to shift left by {:?} which would overflow", op1);
}
}

/// Perform a right shifting from `op0` of `op1` bits
fn shift_right(op0: u32, op1: u32) -> u32 {
if op1 < 32 {
op0 >> op1
} else {
panic!("Attempt to shift right by {:?} which would overflow", op1);
}
}

/// 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
Expand Down Expand Up @@ -78,6 +107,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),
}

Expand All @@ -89,7 +120,27 @@ 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() {
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() {
Expand All @@ -100,4 +151,86 @@ 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);
}

#[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);
}
}