diff --git a/src/cpu.rs b/src/cpu.rs index adbde98..e2775dd 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -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, } 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(); @@ -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) { @@ -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); @@ -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); @@ -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); @@ -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); @@ -136,7 +154,8 @@ 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); @@ -144,7 +163,8 @@ mod tests { #[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 @@ -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); + } } diff --git a/src/io.rs b/src/io.rs new file mode 100644 index 0000000..d0bd59d --- /dev/null +++ b/src/io.rs @@ -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>, +} + +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; + } +} diff --git a/src/main.rs b/src/main.rs index b9281de..d919744 100644 --- a/src/main.rs +++ b/src/main.rs @@ -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(); } -