Rework the paging system a little bit, add FLP instr., bump ver to 0.5.0
This commit is contained in:
parent
9970a04cc9
commit
3df3a98f3c
2
Cargo.lock
generated
2
Cargo.lock
generated
|
@ -866,7 +866,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fox32"
|
name = "fox32"
|
||||||
version = "0.4.0"
|
version = "0.5.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"chrono",
|
"chrono",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "fox32"
|
name = "fox32"
|
||||||
version = "0.4.0"
|
version = "0.5.0"
|
||||||
authors = ["ry"]
|
authors = ["ry"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
build = "build.rs"
|
build = "build.rs"
|
||||||
|
|
|
@ -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 | | |
|
| 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 | | |
|
| 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 | | |
|
| 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
|
# Condition table
|
||||||
| | | |
|
| | | |
|
||||||
|
|
21
src/cpu.rs
21
src/cpu.rs
|
@ -80,7 +80,7 @@ impl Cpu {
|
||||||
fn relative_to_absolute(&self, relative_address: u32) -> u32 {
|
fn relative_to_absolute(&self, relative_address: u32) -> u32 {
|
||||||
self.instruction_pointer.wrapping_add(relative_address)
|
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 mut instruction_pointer_offset = 2; // increment past opcode half
|
||||||
let source_value = match source {
|
let source_value = match source {
|
||||||
Operand::Register => {
|
Operand::Register => {
|
||||||
|
@ -2344,7 +2344,8 @@ impl Cpu {
|
||||||
instruction_pointer_offset += 1; // increment past 8 bit register number
|
instruction_pointer_offset += 1; // increment past 8 bit register number
|
||||||
}
|
}
|
||||||
Operand::ImmediatePtr(_) => {
|
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 {
|
if should_run {
|
||||||
self.bus.memory.write_32(pointer, self.relative_to_absolute(source_value));
|
self.bus.memory.write_32(pointer, self.relative_to_absolute(source_value));
|
||||||
}
|
}
|
||||||
|
@ -2527,14 +2528,16 @@ impl Cpu {
|
||||||
let pointer = self.read_register(register);
|
let pointer = self.read_register(register);
|
||||||
instruction_pointer_offset += 1; // increment past 8 bit register number
|
instruction_pointer_offset += 1; // increment past 8 bit register number
|
||||||
if should_run {
|
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(_) => {
|
Operand::ImmediatePtr(_) => {
|
||||||
let pointer = self.bus.memory.read_32(self.instruction_pointer + instruction_pointer_offset);
|
let pointer = self.bus.memory.read_32(self.instruction_pointer + instruction_pointer_offset);
|
||||||
instruction_pointer_offset += 4; // increment past 32 bit pointer
|
instruction_pointer_offset += 4; // increment past 32 bit pointer
|
||||||
if should_run {
|
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"),
|
_ => panic!("Attempting to use an immediate value as a destination"),
|
||||||
|
@ -2594,6 +2597,14 @@ impl Cpu {
|
||||||
}
|
}
|
||||||
self.instruction_pointer + instruction_pointer_offset
|
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),
|
Mse(Condition),
|
||||||
Mcl(Condition),
|
Mcl(Condition),
|
||||||
Tlb(Condition, Operand),
|
Tlb(Condition, Operand),
|
||||||
|
Flp(Condition, Operand),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Instruction {
|
impl Instruction {
|
||||||
|
@ -2787,6 +2799,7 @@ impl Instruction {
|
||||||
0x0D => Some(Instruction::Mse(condition)),
|
0x0D => Some(Instruction::Mse(condition)),
|
||||||
0x1D => Some(Instruction::Mcl(condition)),
|
0x1D => Some(Instruction::Mcl(condition)),
|
||||||
0x2D => Some(Instruction::Tlb(condition, source)),
|
0x2D => Some(Instruction::Tlb(condition, source)),
|
||||||
|
0x3D => Some(Instruction::Flp(condition, source)),
|
||||||
|
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
|
|
122
src/memory.rs
122
src/memory.rs
|
@ -1,7 +1,5 @@
|
||||||
// memory.rs
|
// memory.rs
|
||||||
|
|
||||||
const DEBUG: bool = false;
|
|
||||||
|
|
||||||
use crate::error;
|
use crate::error;
|
||||||
use crate::cpu::Exception;
|
use crate::cpu::Exception;
|
||||||
|
|
||||||
|
@ -84,54 +82,58 @@ impl Memory {
|
||||||
file.write_all(self.ram()).expect("failed to write memory dump file");
|
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<u32>) {
|
pub fn flush_tlb(&self, paging_directory_address: Option<u32>) {
|
||||||
let directory_address = if let Some(address) = paging_directory_address {
|
if let Some(address) = paging_directory_address {
|
||||||
*self.paging_directory_address() = address;
|
*self.paging_directory_address() = address;
|
||||||
address
|
|
||||||
} else {
|
|
||||||
*self.paging_directory_address()
|
|
||||||
};
|
};
|
||||||
|
|
||||||
self.tlb().clear();
|
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 virtual_page = virtual_address & 0xFFFFF000;
|
||||||
let offset = virtual_address & 0x00000FFF;
|
let offset = virtual_address & 0x00000FFF;
|
||||||
let physical_page = self.tlb().get(&virtual_page);
|
let physical_page = self.tlb().get(&virtual_page);
|
||||||
|
@ -143,12 +145,32 @@ impl Memory {
|
||||||
None
|
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
|
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() {
|
if *self.mmu_enabled() {
|
||||||
(address, _) = self.virtual_to_physical(address as u32).unwrap_or_else(|| {
|
(address, _) = self.virtual_to_physical(address as u32).unwrap_or_else(|| {
|
||||||
self.exception_sender().send(Exception::PageFault(address)).unwrap();
|
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) as u16) |
|
||||||
(self.read_8(address + 1) as u16) << 8
|
(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) as u32) |
|
||||||
(self.read_8(address + 1) as u32) << 8 |
|
(self.read_8(address + 1) as u32) << 8 |
|
||||||
(self.read_8(address + 2) as u32) << 16 |
|
(self.read_8(address + 2) as u32) << 16 |
|
||||||
(self.read_8(address + 3) as u32) << 24
|
(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;
|
let mut writable = true;
|
||||||
if *self.mmu_enabled() {
|
if *self.mmu_enabled() {
|
||||||
(address, writable) = self.virtual_to_physical(address as u32).unwrap_or_else(|| {
|
(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();
|
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, (half & 0x00FF) as u8);
|
||||||
self.write_8(address + 1, (half >> 8) 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, (word & 0x000000FF) as u8);
|
||||||
self.write_8(address + 1, ((word & 0x0000FF00) >> 8) as u8);
|
self.write_8(address + 1, ((word & 0x0000FF00) >> 8) as u8);
|
||||||
self.write_8(address + 2, ((word & 0x00FF0000) >> 16) as u8);
|
self.write_8(address + 2, ((word & 0x00FF0000) >> 16) as u8);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user