Skip to content

Commit

Permalink
Merge pull request #3 from yezzfusl/test
Browse files Browse the repository at this point in the history
Add basic I/O operations for virtual devices.
  • Loading branch information
yezzfusl authored Aug 6, 2024
2 parents cd857c7 + bae1302 commit a0e94ad
Show file tree
Hide file tree
Showing 3 changed files with 128 additions and 9 deletions.
50 changes: 43 additions & 7 deletions src/cpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,23 @@
use std::collections::HashMap;
mod memory;
use memory::MemoryManagementUnit;
use crate::io::IOController;

pub struct CPU {
registers: [u32; 8],
program_counter: usize,
mmu: MemoryManagementUnit,
io_controller: IOController,
instruction_set: HashMap<u8, fn(&mut CPU, u8, u8, u8)>,
}

impl CPU {
pub fn new() -> Self {
pub fn new(io_controller: IOController) -> Self {
let mut cpu = CPU {
registers: [0; 8],
program_counter: 0,
mmu: MemoryManagementUnit::new(),
io_controller,
instruction_set: HashMap::new(),
};
cpu.initialize_instruction_set();
Expand All @@ -30,6 +33,8 @@ impl CPU {
self.instruction_set.insert(0x03, CPU::div);
self.instruction_set.insert(0x04, CPU::load);
self.instruction_set.insert(0x05, CPU::store);
self.instruction_set.insert(0x06, CPU::input);
self.instruction_set.insert(0x07, CPU::output);
}

pub fn run(&mut self) {
Expand Down Expand Up @@ -91,15 +96,25 @@ impl CPU {
let address = self.registers[r2 as usize] as usize;
self.mmu.write_word(address, self.registers[r1 as usize]);
}

fn input(&mut self, r1: u8, _r2: u8, _r3: u8) {
self.registers[r1 as usize] = self.io_controller.input();
}

fn output(&mut self, r1: u8, _r2: u8, _r3: u8) {
self.io_controller.output(self.registers[r1 as usize]);
}
}

#[cfg(test)]
mod tests {
use super::*;
use crate::io::MockIOController;

#[test]
fn test_add_instruction() {
let mut cpu = CPU::new();
let io_controller = MockIOController::new();
let mut cpu = CPU::new(io_controller);
cpu.registers[0] = 5;
cpu.registers[1] = 10;
cpu.add(0, 1, 0);
Expand All @@ -108,7 +123,8 @@ mod tests {

#[test]
fn test_sub_instruction() {
let mut cpu = CPU::new();
let io_controller = MockIOController::new();
let mut cpu = CPU::new(io_controller);
cpu.registers[0] = 10;
cpu.registers[1] = 5;
cpu.sub(0, 1, 0);
Expand All @@ -117,7 +133,8 @@ mod tests {

#[test]
fn test_mul_instruction() {
let mut cpu = CPU::new();
let io_controller = MockIOController::new();
let mut cpu = CPU::new(io_controller);
cpu.registers[0] = 3;
cpu.registers[1] = 4;
cpu.mul(0, 1, 0);
Expand All @@ -126,7 +143,8 @@ mod tests {

#[test]
fn test_div_instruction() {
let mut cpu = CPU::new();
let io_controller = MockIOController::new();
let mut cpu = CPU::new(io_controller);
cpu.registers[0] = 15;
cpu.registers[1] = 3;
cpu.div(0, 1, 0);
Expand All @@ -136,15 +154,17 @@ mod tests {
#[test]
#[should_panic(expected = "Division by zero")]
fn test_div_by_zero() {
let mut cpu = CPU::new();
let io_controller = MockIOController::new();
let mut cpu = CPU::new(io_controller);
cpu.registers[0] = 15;
cpu.registers[1] = 0;
cpu.div(0, 1, 0);
}

#[test]
fn test_load_and_store_instructions() {
let mut cpu = CPU::new();
let io_controller = MockIOController::new();
let mut cpu = CPU::new(io_controller);
cpu.registers[0] = 42;
cpu.registers[1] = 100; // memory address

Expand All @@ -156,4 +176,20 @@ mod tests {

assert_eq!(cpu.registers[2], 42);
}

#[test]
fn test_input_and_output_instructions() {
let mut io_controller = MockIOController::new();
io_controller.set_next_input(42);
let mut cpu = CPU::new(io_controller);

// Test input instruction
cpu.input(0, 0, 0);
assert_eq!(cpu.registers[0], 42);

// Test output instruction
cpu.registers[1] = 84;
cpu.output(1, 0, 0);
assert_eq!(cpu.io_controller.get_last_output(), 84);
}
}
79 changes: 79 additions & 0 deletions src/io.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// src/io.rs

use std::io::{self, Write};

pub trait IODevice {
fn input(&mut self) -> u32;
fn output(&mut self, value: u32);
}

pub struct IOController {
devices: Vec<Box<dyn IODevice>>,
}

impl IOController {
pub fn new() -> Self {
IOController {
devices: vec![Box::new(ConsoleDevice {})],
}
}

pub fn input(&mut self) -> u32 {
self.devices[0].input()
}

pub fn output(&mut self, value: u32) {
self.devices[0].output(value);
}
}

struct ConsoleDevice {}

impl IODevice for ConsoleDevice {
fn input(&mut self) -> u32 {
print!("Enter a number: ");
io::stdout().flush().unwrap();
let mut input = String::new();
io::stdin().read_line(&mut input).unwrap();
input.trim().parse().unwrap_or(0)
}

fn output(&mut self, value: u32) {
println!("Output: {}", value);
}
}

#[cfg(test)]
pub struct MockIOController {
next_input: u32,
last_output: u32,
}

#[cfg(test)]
impl MockIOController {
pub fn new() -> Self {
MockIOController {
next_input: 0,
last_output: 0,
}
}

pub fn set_next_input(&mut self, value: u32) {
self.next_input = value;
}

pub fn get_last_output(&self) -> u32 {
self.last_output
}
}

#[cfg(test)]
impl IODevice for MockIOController {
fn input(&mut self) -> u32 {
self.next_input
}

fn output(&mut self, value: u32) {
self.last_output = value;
}
}
8 changes: 6 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
mod cpu;
mod io;

use cpu::CPU;
use io::IOController;

fn main() {
println!("Virtual Machine Initializing...");
let mut cpu = cpu::CPU::new();
let io_controller = IOController::new();
let mut cpu = CPU::new(io_controller);
cpu.run();
}

0 comments on commit a0e94ad

Please sign in to comment.