From 2a33b9f22320cc45bb941492f4b030bf57b3f016 Mon Sep 17 00:00:00 2001 From: YEZZFUSL <18398621+yezzfusl@users.noreply.github.com> Date: Mon, 5 Aug 2024 20:27:10 -0400 Subject: [PATCH] Create the main execution loop for the virtual machine. --- src/cpu.rs | 235 +++++++++++++++++++++++++++------------------------- src/main.rs | 19 ++++- 2 files changed, 140 insertions(+), 114 deletions(-) diff --git a/src/cpu.rs b/src/cpu.rs index 86a66a3..977b2a5 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -1,62 +1,72 @@ // src/cpu.rs use std::collections::HashMap; -mod memory; -use memory::MemoryManagementUnit; use crate::io::IOController; +use crate::memory::MemoryManagementUnit; pub struct CPU { registers: [u32; 8], program_counter: usize, mmu: MemoryManagementUnit, io_controller: IOController, - instruction_set: HashMap, - flags: u8, // New: Flags register for comparison results + instruction_set: HashMap, + flags: u8, + halted: bool, } impl CPU { - pub fn new(io_controller: IOController) -> Self { + pub fn new(io_controller: IOController, mmu: MemoryManagementUnit) -> Self { let mut cpu = CPU { registers: [0; 8], program_counter: 0, - mmu: MemoryManagementUnit::new(), + mmu, io_controller, instruction_set: HashMap::new(), flags: 0, + halted: false, }; cpu.initialize_instruction_set(); cpu } fn initialize_instruction_set(&mut self) { - self.instruction_set.insert(0x00, CPU::add); - self.instruction_set.insert(0x01, CPU::sub); - self.instruction_set.insert(0x02, CPU::mul); - 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); - // New instructions - self.instruction_set.insert(0x08, CPU::and); - self.instruction_set.insert(0x09, CPU::or); - self.instruction_set.insert(0x0A, CPU::xor); - self.instruction_set.insert(0x0B, CPU::not); - self.instruction_set.insert(0x0C, CPU::shl); - self.instruction_set.insert(0x0D, CPU::shr); - self.instruction_set.insert(0x0E, CPU::cmp); - self.instruction_set.insert(0x0F, CPU::jmp); - self.instruction_set.insert(0x10, CPU::je); - self.instruction_set.insert(0x11, CPU::jne); - self.instruction_set.insert(0x12, CPU::jg); - self.instruction_set.insert(0x13, CPU::jl); + self.instruction_set.insert(0x40, CPU::add); + self.instruction_set.insert(0x41, CPU::sub); + self.instruction_set.insert(0x42, CPU::mul); + self.instruction_set.insert(0x43, CPU::div); + self.instruction_set.insert(0x44, CPU::load); + self.instruction_set.insert(0x45, CPU::store); + self.instruction_set.insert(0x46, CPU::input); + self.instruction_set.insert(0x47, CPU::output); + self.instruction_set.insert(0x48, CPU::and); + self.instruction_set.insert(0x49, CPU::or); + self.instruction_set.insert(0x4A, CPU::xor); + self.instruction_set.insert(0x4B, CPU::not); + self.instruction_set.insert(0x4C, CPU::shl); + self.instruction_set.insert(0x4D, CPU::shr); + self.instruction_set.insert(0x4E, CPU::cmp); + self.instruction_set.insert(0x4F, CPU::jmp); + self.instruction_set.insert(0x50, CPU::je); + self.instruction_set.insert(0x51, CPU::jne); + self.instruction_set.insert(0x52, CPU::jg); + self.instruction_set.insert(0x53, CPU::jl); + self.instruction_set.insert(0xFF, CPU::halt); + } + + pub fn load_program(&mut self, program: &[u8]) { + for (i, &byte) in program.iter().enumerate() { + self.mmu.write_byte(i, byte); + } } pub fn run(&mut self) { - loop { + self.halted = false; + while !self.halted { let opcode = self.fetch(); self.decode_and_execute(opcode); } + println!("CPU halted. Final register state:"); + self.print_registers(); } fn fetch(&mut self) -> u8 { @@ -66,49 +76,87 @@ impl CPU { } fn decode_and_execute(&mut self, opcode: u8) { - let (op, r1, r2, r3) = self.decode(opcode); - if let Some(instruction) = self.instruction_set.get(&op) { - instruction(self, r1, r2, r3); + let r1 = self.fetch(); + let r2 = self.fetch(); + if let Some(instruction) = self.instruction_set.get(&opcode) { + instruction(self, r1, r2); + } else { + panic!("Unknown opcode: {:02X}", opcode); + } + } + + fn print_registers(&self) { + for (i, reg) in self.registers.iter().enumerate() { + println!("R{}: {:08X}", i, reg); + } + println!("Flags: {:08b}", self.flags); + } + + // Instruction implementations + + fn add(&mut self, r1: u8, r2: u8) { + self.registers[r1 as usize] = self.registers[r1 as usize].wrapping_add(self.registers[r2 as usize]); + } + + fn sub(&mut self, r1: u8, r2: u8) { + self.registers[r1 as usize] = self.registers[r1 as usize].wrapping_sub(self.registers[r2 as usize]); + } + + fn mul(&mut self, r1: u8, r2: u8) { + self.registers[r1 as usize] = self.registers[r1 as usize].wrapping_mul(self.registers[r2 as usize]); + } + + fn div(&mut self, r1: u8, r2: u8) { + if self.registers[r2 as usize] != 0 { + self.registers[r1 as usize] /= self.registers[r2 as usize]; } else { - panic!("Unknown opcode: {:02X}", op); + panic!("Division by zero"); } } - fn decode(&self, opcode: u8) -> (u8, u8, u8, u8) { - let op = (opcode & 0xF0) >> 4; - let r1 = (opcode & 0x0C) >> 2; - let r2 = opcode & 0x03; - let r3 = 0; // For future use - (op, r1, r2, r3) + fn load(&mut self, r1: u8, r2: u8) { + let address = self.registers[r2 as usize] as usize; + self.registers[r1 as usize] = self.mmu.read_word(address); } - // Existing arithmetic operations... + fn store(&mut self, r1: u8, r2: u8) { + let address = self.registers[r2 as usize] as usize; + self.mmu.write_word(address, self.registers[r1 as usize]); + } - fn and(&mut self, r1: u8, r2: u8, _r3: u8) { + fn input(&mut self, r1: u8, _r2: u8) { + self.registers[r1 as usize] = self.io_controller.input(); + } + + fn output(&mut self, r1: u8, _r2: u8) { + self.io_controller.output(self.registers[r1 as usize]); + } + + fn and(&mut self, r1: u8, r2: u8) { self.registers[r1 as usize] &= self.registers[r2 as usize]; } - fn or(&mut self, r1: u8, r2: u8, _r3: u8) { + fn or(&mut self, r1: u8, r2: u8) { self.registers[r1 as usize] |= self.registers[r2 as usize]; } - fn xor(&mut self, r1: u8, r2: u8, _r3: u8) { + fn xor(&mut self, r1: u8, r2: u8) { self.registers[r1 as usize] ^= self.registers[r2 as usize]; } - fn not(&mut self, r1: u8, _r2: u8, _r3: u8) { + fn not(&mut self, r1: u8, _r2: u8) { self.registers[r1 as usize] = !self.registers[r1 as usize]; } - fn shl(&mut self, r1: u8, r2: u8, _r3: u8) { + fn shl(&mut self, r1: u8, r2: u8) { self.registers[r1 as usize] <<= self.registers[r2 as usize]; } - fn shr(&mut self, r1: u8, r2: u8, _r3: u8) { + fn shr(&mut self, r1: u8, r2: u8) { self.registers[r1 as usize] >>= self.registers[r2 as usize]; } - fn cmp(&mut self, r1: u8, r2: u8, _r3: u8) { + fn cmp(&mut self, r1: u8, r2: u8) { let (result, overflow) = self.registers[r1 as usize].overflowing_sub(self.registers[r2 as usize]); self.flags = 0; if result == 0 { @@ -122,33 +170,37 @@ impl CPU { } } - fn jmp(&mut self, r1: u8, _r2: u8, _r3: u8) { + fn jmp(&mut self, r1: u8, _r2: u8) { self.program_counter = self.registers[r1 as usize] as usize; } - fn je(&mut self, r1: u8, _r2: u8, _r3: u8) { + fn je(&mut self, r1: u8, _r2: u8) { if self.flags & 0b0001 != 0 { self.program_counter = self.registers[r1 as usize] as usize; } } - fn jne(&mut self, r1: u8, _r2: u8, _r3: u8) { + fn jne(&mut self, r1: u8, _r2: u8) { if self.flags & 0b0001 == 0 { self.program_counter = self.registers[r1 as usize] as usize; } } - fn jg(&mut self, r1: u8, _r2: u8, _r3: u8) { + fn jg(&mut self, r1: u8, _r2: u8) { if self.flags & 0b0011 == 0 { self.program_counter = self.registers[r1 as usize] as usize; } } - fn jl(&mut self, r1: u8, _r2: u8, _r3: u8) { + fn jl(&mut self, r1: u8, _r2: u8) { if self.flags & 0b0010 != 0 { self.program_counter = self.registers[r1 as usize] as usize; } } + + fn halt(&mut self, _r1: u8, _r2: u8) { + self.halted = true; + } } #[cfg(test)] @@ -156,69 +208,26 @@ mod tests { use super::*; use crate::io::MockIOController; - // Existing tests... - - #[test] - fn test_logical_operations() { - let io_controller = MockIOController::new(); - let mut cpu = CPU::new(io_controller); - - cpu.registers[0] = 0b1100; - cpu.registers[1] = 0b1010; - - cpu.and(0, 1, 0); - assert_eq!(cpu.registers[0], 0b1000); - - cpu.registers[0] = 0b1100; - cpu.or(0, 1, 0); - assert_eq!(cpu.registers[0], 0b1110); - - cpu.registers[0] = 0b1100; - cpu.xor(0, 1, 0); - assert_eq!(cpu.registers[0], 0b0110); - - cpu.registers[0] = 0b1100; - cpu.not(0, 0, 0); - assert_eq!(cpu.registers[0], 0xFFFFFFF3); - } - - #[test] - fn test_shift_operations() { - let io_controller = MockIOController::new(); - let mut cpu = CPU::new(io_controller); - - cpu.registers[0] = 0b1100; - cpu.registers[1] = 2; - - cpu.shl(0, 1, 0); - assert_eq!(cpu.registers[0], 0b110000); - - cpu.registers[0] = 0b110000; - cpu.shr(0, 1, 0); - assert_eq!(cpu.registers[0], 0b1100); - } - #[test] - fn test_compare_and_jump() { + fn test_program_execution() { let io_controller = MockIOController::new(); - let mut cpu = CPU::new(io_controller); - - cpu.registers[0] = 10; - cpu.registers[1] = 10; - cpu.registers[2] = 100; // Jump target - - cpu.cmp(0, 1, 0); - assert_eq!(cpu.flags & 0b0001, 0b0001); // Zero flag should be set - - cpu.je(2, 0, 0); - assert_eq!(cpu.program_counter, 100); - - cpu.registers[1] = 11; - cpu.cmp(0, 1, 0); - assert_eq!(cpu.flags & 0b0010, 0b0010); // Negative flag should be set - - cpu.program_counter = 0; - cpu.jl(2, 0, 0); - assert_eq!(cpu.program_counter, 100); + let mmu = MemoryManagementUnit::new(); + let mut cpu = CPU::new(io_controller, mmu); + + let program = vec![ + 0x46, 0x00, // INPUT R0 + 0x40, 0x10, // ADD R1, R0 + 0x47, 0x01, // OUTPUT R1 + 0xFF, 0x00, // HALT + ]; + + cpu.load_program(&program); + cpu.io_controller.set_next_input(5); + cpu.run(); + + assert_eq!(cpu.registers[0], 5); + assert_eq!(cpu.registers[1], 5); + assert_eq!(cpu.io_controller.get_last_output(), 5); + assert!(cpu.halted); } } diff --git a/src/main.rs b/src/main.rs index d919744..3adf444 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,12 +1,29 @@ +// src/main.rs + mod cpu; mod io; +mod memory; use cpu::CPU; use io::IOController; +use memory::MemoryManagementUnit; fn main() { println!("Virtual Machine Initializing..."); let io_controller = IOController::new(); - let mut cpu = CPU::new(io_controller); + let mmu = MemoryManagementUnit::new(); + let mut cpu = CPU::new(io_controller, mmu); + + // Load a simple program into memory + let program = vec![ + 0x46, 0x00, // INPUT R0 + 0x47, 0x01, // OUTPUT R1 + 0x40, 0x10, // ADD R1, R0 + 0x47, 0x01, // OUTPUT R1 + 0x4E, 0x00, // CMP R0, R0 + 0x50, 0x00, // JE 0 (Loop back to start) + ]; + + cpu.load_program(&program); cpu.run(); }