From 3df3a98f3c06c14d63aaa6cdcc3bc418f5619ed3 Mon Sep 17 00:00:00 2001 From: Ry Date: Tue, 13 Sep 2022 16:48:06 -0700 Subject: [PATCH] Rework the paging system a little bit, add FLP instr., bump ver to 0.5.0 --- Cargo.lock | 2 +- Cargo.toml | 2 +- docs/encoding.md | 2 +- src/cpu.rs | 21 ++++++-- src/memory.rs | 122 ++++++++++++++++++++++++++++------------------- 5 files changed, 92 insertions(+), 57 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3c45f67..e758ee5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -866,7 +866,7 @@ dependencies = [ [[package]] name = "fox32" -version = "0.4.0" +version = "0.5.0" dependencies = [ "anyhow", "chrono", diff --git a/Cargo.toml b/Cargo.toml index ed39913..20c36fb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "fox32" -version = "0.4.0" +version = "0.5.0" authors = ["ry"] edition = "2021" build = "build.rs" diff --git a/docs/encoding.md b/docs/encoding.md index c23dfbf..78424be 100644 --- a/docs/encoding.md +++ b/docs/encoding.md @@ -19,7 +19,7 @@ If the instruction doesn't allow variable sizes or a size was not specified, set | 0- | NOP | ADD[.8,16,32] | MUL[.8,16,32] | AND[.8,16,32] | SLA[.8,16,32] | SRA[.8,16,32] | BSE[.8,16,32] | CMP[.8,16,32] | JMP | RJMP | PUSH[.8,16,32] | IN | ISE | MSE | | | | 1- | HALT | INC[.8,16,32] | | OR[.8,16,32] | | SRL[.8,16,32] | BCL[.8,16,32] | MOV[.8,16,32] | CALL | RCALL | POP[.8,16,32] | OUT | ICL | MCL | | | | 2- | BRK | SUB[.8,16,32] | DIV[.8,16,32] | XOR[.8,16,32] | ROL[.8,16,32] | ROR[.8,16,32] | BTS[.8,16,32] | MOVZ[.8,16,32] | LOOP | RLOOP | RET | | INT | TLB | | | -| 3- | | DEC[.8,16,32] | REM[.8,16,32] | NOT[.8,16,32] | | | | | | RTA | RETI | | | | | | +| 3- | | DEC[.8,16,32] | REM[.8,16,32] | NOT[.8,16,32] | | | | | | RTA | RETI | | | FLP | | | # Condition table | | | | diff --git a/src/cpu.rs b/src/cpu.rs index 4e0c925..248983a 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -80,7 +80,7 @@ impl Cpu { fn relative_to_absolute(&self, relative_address: u32) -> u32 { self.instruction_pointer.wrapping_add(relative_address) } - fn read_source(&self, source: Operand) -> (u32, u32) { + fn read_source(&mut self, source: Operand) -> (u32, u32) { let mut instruction_pointer_offset = 2; // increment past opcode half let source_value = match source { Operand::Register => { @@ -2344,7 +2344,8 @@ impl Cpu { instruction_pointer_offset += 1; // increment past 8 bit register number } Operand::ImmediatePtr(_) => { - let pointer = self.relative_to_absolute(self.bus.memory.read_32(self.instruction_pointer + instruction_pointer_offset)); + let word = self.bus.memory.read_32(self.instruction_pointer + instruction_pointer_offset); + let pointer = self.relative_to_absolute(word); if should_run { self.bus.memory.write_32(pointer, self.relative_to_absolute(source_value)); } @@ -2527,14 +2528,16 @@ impl Cpu { let pointer = self.read_register(register); instruction_pointer_offset += 1; // increment past 8 bit register number if should_run { - self.bus.write_io(self.bus.memory.read_32(pointer), source_value); + let word = self.bus.memory.read_32(pointer); + self.bus.write_io(word, source_value); } } Operand::ImmediatePtr(_) => { let pointer = self.bus.memory.read_32(self.instruction_pointer + instruction_pointer_offset); instruction_pointer_offset += 4; // increment past 32 bit pointer if should_run { - self.bus.write_io(self.bus.memory.read_32(pointer), source_value); + let word = self.bus.memory.read_32(pointer); + self.bus.write_io(word, source_value); } } _ => panic!("Attempting to use an immediate value as a destination"), @@ -2594,6 +2597,14 @@ impl Cpu { } self.instruction_pointer + instruction_pointer_offset } + Instruction::Flp(condition, source) => { + let (source_value, instruction_pointer_offset) = self.read_source(source); + let should_run = self.check_condition(condition); + if should_run { + self.bus.memory.flush_page(source_value); + } + self.instruction_pointer + instruction_pointer_offset + } } } } @@ -2688,6 +2699,7 @@ enum Instruction { Mse(Condition), Mcl(Condition), Tlb(Condition, Operand), + Flp(Condition, Operand), } impl Instruction { @@ -2787,6 +2799,7 @@ impl Instruction { 0x0D => Some(Instruction::Mse(condition)), 0x1D => Some(Instruction::Mcl(condition)), 0x2D => Some(Instruction::Tlb(condition, source)), + 0x3D => Some(Instruction::Flp(condition, source)), _ => None, } diff --git a/src/memory.rs b/src/memory.rs index 023b4ba..b2e3944 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -1,7 +1,5 @@ // memory.rs -const DEBUG: bool = false; - use crate::error; use crate::cpu::Exception; @@ -84,54 +82,58 @@ impl Memory { file.write_all(self.ram()).expect("failed to write memory dump file"); } + // each table contains 1024 entries + // the paging directory contains pointers to paging tables with the following format: + // bit 0: present + // remaining bits are ignored, should be zero + // bits 12-31: physical address of paging table + + // the paging table contains pointers to physical memory pages with the following format: + // bit 0: present + // bit 1: r/w + // remaining bits are ignored, should be zero + // bits 12-31: physical address + pub fn flush_tlb(&self, paging_directory_address: Option) { - let directory_address = if let Some(address) = paging_directory_address { + if let Some(address) = paging_directory_address { *self.paging_directory_address() = address; - address - } else { - *self.paging_directory_address() }; self.tlb().clear(); - - // each table contains 1024 entries - // the paging directory contains pointers to paging tables with the following format: - // bit 0: present - // remaining bits are ignored, should be zero - // bits 12-31: physical address of paging table - - // the paging table contains pointers to physical memory pages with the following format: - // bit 0: present - // bit 1: r/w - // remaining bits are ignored, should be zero - // bits 12-31: physical address - - for directory_index in 0..1024 { - let directory = self.read_32(directory_address + (directory_index * 4)); - let dir_present = directory & 0b1 != 0; - let dir_address = directory & 0xFFFFF000; - if dir_present { - for table_index in 0..1024 { - let table = self.read_32(dir_address + (table_index * 4)); - let table_present = table & 0b01 != 0; - let table_rw = table & 0b10 != 0; - let table_address = table & 0xFFFFF000; - - if table_present { - let tlb_entry = MemoryPage { - physical_address: table_address, - present: table_present, - rw: table_rw, - }; - self.tlb().entry((directory_index << 22) | (table_index << 12)).or_insert(tlb_entry); - } - } - } - } - if DEBUG { println!("{:#X?}", self.tlb()); } } - pub fn virtual_to_physical(&self, virtual_address: u32) -> Option<(u32, bool)> { + pub fn flush_page(&self, virtual_address: u32) { + let virtual_page = virtual_address & 0xFFFFF000; + self.tlb().remove(&virtual_page); + } + + pub fn insert_tlb_entry_from_tables(&mut self, page_directory_index: u32, page_table_index: u32) -> bool { + let old_state = *self.mmu_enabled(); + *self.mmu_enabled() = false; + let directory_address = *self.paging_directory_address(); + let directory = self.read_32(directory_address + (page_directory_index * 4)); + let dir_present = directory & 0b1 != 0; + let dir_address = directory & 0xFFFFF000; + if dir_present { + let table = self.read_32(dir_address + (page_table_index * 4)); + let table_present = table & 0b01 != 0; + let table_rw = table & 0b10 != 0; + let table_address = table & 0xFFFFF000; + + if table_present { + let tlb_entry = MemoryPage { + physical_address: table_address, + present: table_present, + rw: table_rw, + }; + self.tlb().entry((page_directory_index << 22) | (page_table_index << 12)).or_insert(tlb_entry); + } + } + *self.mmu_enabled() = old_state; + dir_present + } + + pub fn virtual_to_physical(&mut self, virtual_address: u32) -> Option<(u32, bool)> { let virtual_page = virtual_address & 0xFFFFF000; let offset = virtual_address & 0x00000FFF; let physical_page = self.tlb().get(&virtual_page); @@ -143,12 +145,32 @@ impl Memory { None } }, - None => None, + None => { + let page_directory_index = virtual_address >> 22; + let page_table_index = (virtual_address >> 12) & 0x03FF; + let dir_present = self.insert_tlb_entry_from_tables(page_directory_index, page_table_index); + if !dir_present { + return None; + } + // try again after inserting the TLB entry + let physical_page = self.tlb().get(&virtual_page); + let physical_address = match physical_page { + Some(page) => { + if page.present { + Some((page.physical_address | offset, page.rw)) + } else { + None + } + }, + None => None, + }; + physical_address + }, }; physical_address } - pub fn read_8(&self, mut address: u32) -> u8 { + pub fn read_8(&mut self, mut address: u32) -> u8 { if *self.mmu_enabled() { (address, _) = self.virtual_to_physical(address as u32).unwrap_or_else(|| { self.exception_sender().send(Exception::PageFault(address)).unwrap(); @@ -173,18 +195,18 @@ impl Memory { } } } - pub fn read_16(&self, address: u32) -> u16 { + pub fn read_16(&mut self, address: u32) -> u16 { (self.read_8(address) as u16) | (self.read_8(address + 1) as u16) << 8 } - pub fn read_32(&self, address: u32) -> u32 { + pub fn read_32(&mut self, address: u32) -> u32 { (self.read_8(address) as u32) | (self.read_8(address + 1) as u32) << 8 | (self.read_8(address + 2) as u32) << 16 | (self.read_8(address + 3) as u32) << 24 } - pub fn write_8(&self, mut address: u32, byte: u8) { + pub fn write_8(&mut self, mut address: u32, byte: u8) { let mut writable = true; if *self.mmu_enabled() { (address, writable) = self.virtual_to_physical(address as u32).unwrap_or_else(|| { @@ -212,11 +234,11 @@ impl Memory { self.exception_sender().send(Exception::PageFault(address)).unwrap(); } } - pub fn write_16(&self, address: u32, half: u16) { + pub fn write_16(&mut self, address: u32, half: u16) { self.write_8(address, (half & 0x00FF) as u8); self.write_8(address + 1, (half >> 8) as u8); } - pub fn write_32(&self, address: u32, word: u32) { + pub fn write_32(&mut self, address: u32, word: u32) { self.write_8(address, (word & 0x000000FF) as u8); self.write_8(address + 1, ((word & 0x0000FF00) >> 8) as u8); self.write_8(address + 2, ((word & 0x00FF0000) >> 16) as u8);