Implement paging, bump version to 0.3.0
This works in a similar way to x86's paging, by using page directories which point to page tables, which point to physical addresses.
This commit is contained in:
parent
6edcda5b18
commit
82edb1d8da
2
Cargo.lock
generated
2
Cargo.lock
generated
|
@ -865,7 +865,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fox32"
|
name = "fox32"
|
||||||
version = "0.2.1"
|
version = "0.3.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"image",
|
"image",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "fox32"
|
name = "fox32"
|
||||||
version = "0.2.1"
|
version = "0.3.0"
|
||||||
authors = ["ry"]
|
authors = ["ry"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
build = "build.rs"
|
build = "build.rs"
|
||||||
|
|
|
@ -16,9 +16,9 @@ If the instruction doesn't allow variable sizes or a size was not specified, set
|
||||||
# Instruction table
|
# Instruction table
|
||||||
| 0x | -0 | -1 | -2 | -3 | -4 | -5 | -6 | -7 | -8 | -9 | -A | -B | -C | -D | -E | -F |
|
| 0x | -0 | -1 | -2 | -3 | -4 | -5 | -6 | -7 | -8 | -9 | -A | -B | -C | -D | -E | -F |
|
||||||
| :-: | ---- | ------------- | ------------- | ------------- | ------------- | ------------- | ------------- | -------------- | ---- | ----- | -------------- | --- | --- | --- | --- | --- |
|
| :-: | ---- | ------------- | ------------- | ------------- | ------------- | ------------- | ------------- | -------------- | ---- | ----- | -------------- | --- | --- | --- | --- | --- |
|
||||||
| 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 | | | |
|
| 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 | | | |
|
| 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 | | | |
|
| 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 | | | | | |
|
||||||
|
|
||||||
# Condition table
|
# Condition table
|
||||||
|
|
56
src/cpu.rs
56
src/cpu.rs
|
@ -35,6 +35,7 @@ impl std::convert::From<u8> for Flag {
|
||||||
pub enum Exception {
|
pub enum Exception {
|
||||||
DivideByZero,
|
DivideByZero,
|
||||||
InvalidOpcode(u32),
|
InvalidOpcode(u32),
|
||||||
|
PageFault(u32),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -159,52 +160,34 @@ impl Cpu {
|
||||||
pub fn push_stack_8(&mut self, byte: u8) {
|
pub fn push_stack_8(&mut self, byte: u8) {
|
||||||
let decremented_stack_pointer = self.stack_pointer.overflowing_sub(1);
|
let decremented_stack_pointer = self.stack_pointer.overflowing_sub(1);
|
||||||
self.stack_pointer = decremented_stack_pointer.0;
|
self.stack_pointer = decremented_stack_pointer.0;
|
||||||
if decremented_stack_pointer.1 {
|
|
||||||
// TODO: stack overflow exception
|
|
||||||
}
|
|
||||||
self.bus.memory.write_8(self.stack_pointer, byte);
|
self.bus.memory.write_8(self.stack_pointer, byte);
|
||||||
}
|
}
|
||||||
pub fn pop_stack_8(&mut self) -> u8 {
|
pub fn pop_stack_8(&mut self) -> u8 {
|
||||||
let byte = self.bus.memory.read_8(self.stack_pointer);
|
let byte = self.bus.memory.read_8(self.stack_pointer);
|
||||||
let incremented_stack_pointer = self.stack_pointer.overflowing_add(1);
|
let incremented_stack_pointer = self.stack_pointer.overflowing_add(1);
|
||||||
self.stack_pointer = incremented_stack_pointer.0;
|
self.stack_pointer = incremented_stack_pointer.0;
|
||||||
if incremented_stack_pointer.1 {
|
|
||||||
// TODO: stack overflow exception
|
|
||||||
}
|
|
||||||
byte
|
byte
|
||||||
}
|
}
|
||||||
pub fn push_stack_16(&mut self, half: u16) {
|
pub fn push_stack_16(&mut self, half: u16) {
|
||||||
let decremented_stack_pointer = self.stack_pointer.overflowing_sub(2);
|
let decremented_stack_pointer = self.stack_pointer.overflowing_sub(2);
|
||||||
self.stack_pointer = decremented_stack_pointer.0;
|
self.stack_pointer = decremented_stack_pointer.0;
|
||||||
if decremented_stack_pointer.1 {
|
|
||||||
// TODO: stack overflow exception
|
|
||||||
}
|
|
||||||
self.bus.memory.write_16(self.stack_pointer, half);
|
self.bus.memory.write_16(self.stack_pointer, half);
|
||||||
}
|
}
|
||||||
pub fn pop_stack_16(&mut self) -> u16 {
|
pub fn pop_stack_16(&mut self) -> u16 {
|
||||||
let half = self.bus.memory.read_16(self.stack_pointer);
|
let half = self.bus.memory.read_16(self.stack_pointer);
|
||||||
let incremented_stack_pointer = self.stack_pointer.overflowing_add(2);
|
let incremented_stack_pointer = self.stack_pointer.overflowing_add(2);
|
||||||
self.stack_pointer = incremented_stack_pointer.0;
|
self.stack_pointer = incremented_stack_pointer.0;
|
||||||
if incremented_stack_pointer.1 {
|
|
||||||
// TODO: stack overflow exception
|
|
||||||
}
|
|
||||||
half
|
half
|
||||||
}
|
}
|
||||||
pub fn push_stack_32(&mut self, word: u32) {
|
pub fn push_stack_32(&mut self, word: u32) {
|
||||||
let decremented_stack_pointer = self.stack_pointer.overflowing_sub(4);
|
let decremented_stack_pointer = self.stack_pointer.overflowing_sub(4);
|
||||||
self.stack_pointer = decremented_stack_pointer.0;
|
self.stack_pointer = decremented_stack_pointer.0;
|
||||||
if decremented_stack_pointer.1 {
|
|
||||||
// TODO: stack overflow exception
|
|
||||||
}
|
|
||||||
self.bus.memory.write_32(self.stack_pointer, word);
|
self.bus.memory.write_32(self.stack_pointer, word);
|
||||||
}
|
}
|
||||||
pub fn pop_stack_32(&mut self) -> u32 {
|
pub fn pop_stack_32(&mut self) -> u32 {
|
||||||
let word = self.bus.memory.read_32(self.stack_pointer);
|
let word = self.bus.memory.read_32(self.stack_pointer);
|
||||||
let incremented_stack_pointer = self.stack_pointer.overflowing_add(4);
|
let incremented_stack_pointer = self.stack_pointer.overflowing_add(4);
|
||||||
self.stack_pointer = incremented_stack_pointer.0;
|
self.stack_pointer = incremented_stack_pointer.0;
|
||||||
if incremented_stack_pointer.1 {
|
|
||||||
// TODO: stack overflow exception
|
|
||||||
}
|
|
||||||
word
|
word
|
||||||
}
|
}
|
||||||
pub fn interrupt(&mut self, interrupt: Interrupt) {
|
pub fn interrupt(&mut self, interrupt: Interrupt) {
|
||||||
|
@ -224,6 +207,10 @@ impl Cpu {
|
||||||
let vector: u16 = 1;
|
let vector: u16 = 1;
|
||||||
self.handle_exception(vector, Some(opcode));
|
self.handle_exception(vector, Some(opcode));
|
||||||
}
|
}
|
||||||
|
Exception::PageFault(virtual_address) => {
|
||||||
|
let vector: u16 = 2;
|
||||||
|
self.handle_exception(vector, Some(virtual_address));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2582,6 +2569,31 @@ impl Cpu {
|
||||||
self.instruction_pointer + instruction_pointer_offset
|
self.instruction_pointer + instruction_pointer_offset
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Instruction::Mse(condition) => {
|
||||||
|
let instruction_pointer_offset = 2; // increment past opcode half
|
||||||
|
let should_run = self.check_condition(condition);
|
||||||
|
if should_run {
|
||||||
|
*self.bus.memory.mmu_enabled() = true;
|
||||||
|
}
|
||||||
|
self.instruction_pointer + instruction_pointer_offset
|
||||||
|
}
|
||||||
|
Instruction::Mcl(condition) => {
|
||||||
|
let instruction_pointer_offset = 2; // increment past opcode half
|
||||||
|
let should_run = self.check_condition(condition);
|
||||||
|
if should_run {
|
||||||
|
*self.bus.memory.mmu_enabled() = false;
|
||||||
|
}
|
||||||
|
self.instruction_pointer + instruction_pointer_offset
|
||||||
|
}
|
||||||
|
Instruction::Tlb(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_tlb(Some(source_value));
|
||||||
|
}
|
||||||
|
self.instruction_pointer + instruction_pointer_offset
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2672,6 +2684,10 @@ enum Instruction {
|
||||||
Ise(Condition),
|
Ise(Condition),
|
||||||
Icl(Condition),
|
Icl(Condition),
|
||||||
Int(Condition, Operand),
|
Int(Condition, Operand),
|
||||||
|
|
||||||
|
Mse(Condition),
|
||||||
|
Mcl(Condition),
|
||||||
|
Tlb(Condition, Operand),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Instruction {
|
impl Instruction {
|
||||||
|
@ -2768,6 +2784,10 @@ impl Instruction {
|
||||||
0x1C => Some(Instruction::Icl(condition)),
|
0x1C => Some(Instruction::Icl(condition)),
|
||||||
0x2C => Some(Instruction::Int(condition, source)),
|
0x2C => Some(Instruction::Int(condition, source)),
|
||||||
|
|
||||||
|
0x0D => Some(Instruction::Mse(condition)),
|
||||||
|
0x1D => Some(Instruction::Mcl(condition)),
|
||||||
|
0x2D => Some(Instruction::Tlb(condition, source)),
|
||||||
|
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ pub mod disk;
|
||||||
|
|
||||||
use audio::AudioChannel;
|
use audio::AudioChannel;
|
||||||
use bus::Bus;
|
use bus::Bus;
|
||||||
use cpu::{Cpu, Interrupt};
|
use cpu::{Cpu, Exception, Interrupt};
|
||||||
use keyboard::Keyboard;
|
use keyboard::Keyboard;
|
||||||
use mouse::Mouse;
|
use mouse::Mouse;
|
||||||
use disk::DiskController;
|
use disk::DiskController;
|
||||||
|
@ -84,7 +84,9 @@ fn main() {
|
||||||
let audio_channel_2 = Arc::new(Mutex::new(AudioChannel::new(2)));
|
let audio_channel_2 = Arc::new(Mutex::new(AudioChannel::new(2)));
|
||||||
let audio_channel_3 = Arc::new(Mutex::new(AudioChannel::new(3)));
|
let audio_channel_3 = Arc::new(Mutex::new(AudioChannel::new(3)));
|
||||||
|
|
||||||
let memory = Memory::new(read_rom().as_slice());
|
let (exception_sender, exception_receiver) = mpsc::channel::<Exception>();
|
||||||
|
|
||||||
|
let memory = Memory::new(read_rom().as_slice(), exception_sender);
|
||||||
let mut bus = Bus {
|
let mut bus = Bus {
|
||||||
memory: memory.clone(),
|
memory: memory.clone(),
|
||||||
audio_channel_0: audio_channel_0.clone(),
|
audio_channel_0: audio_channel_0.clone(),
|
||||||
|
@ -155,6 +157,9 @@ fn main() {
|
||||||
move || {
|
move || {
|
||||||
loop {
|
loop {
|
||||||
while !cpu.halted {
|
while !cpu.halted {
|
||||||
|
if let Ok(exception) = exception_receiver.try_recv() {
|
||||||
|
cpu.interrupt(Interrupt::Exception(exception));
|
||||||
|
}
|
||||||
if let Ok(interrupt) = interrupt_receiver.try_recv() {
|
if let Ok(interrupt) = interrupt_receiver.try_recv() {
|
||||||
cpu.interrupt(interrupt);
|
cpu.interrupt(interrupt);
|
||||||
}
|
}
|
||||||
|
|
118
src/memory.rs
118
src/memory.rs
|
@ -1,9 +1,12 @@
|
||||||
// memory.rs
|
// memory.rs
|
||||||
|
|
||||||
use crate::error;
|
use crate::error;
|
||||||
|
use crate::cpu::Exception;
|
||||||
|
|
||||||
use std::cell::UnsafeCell;
|
use std::cell::UnsafeCell;
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use std::sync::mpsc::Sender;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
|
|
||||||
|
@ -16,18 +19,33 @@ pub const MEMORY_ROM_START: usize = 0xF0000000;
|
||||||
pub type MemoryRam = [u8; MEMORY_RAM_SIZE];
|
pub type MemoryRam = [u8; MEMORY_RAM_SIZE];
|
||||||
pub type MemoryRom = [u8; MEMORY_ROM_SIZE];
|
pub type MemoryRom = [u8; MEMORY_ROM_SIZE];
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct MemoryPage {
|
||||||
|
physical_address: u32,
|
||||||
|
present: bool,
|
||||||
|
rw: bool,
|
||||||
|
}
|
||||||
|
|
||||||
struct MemoryInner {
|
struct MemoryInner {
|
||||||
ram: Box<MemoryRam>,
|
ram: Box<MemoryRam>,
|
||||||
rom: Box<MemoryRom>,
|
rom: Box<MemoryRom>,
|
||||||
|
mmu_enabled: Box<bool>,
|
||||||
|
tlb: Box<HashMap<u32, MemoryPage>>,
|
||||||
|
paging_directory_address: Box<u32>,
|
||||||
|
exception_sender: Sender<Exception>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MemoryInner {
|
impl MemoryInner {
|
||||||
pub fn new(rom: &[u8]) -> Self {
|
pub fn new(rom: &[u8], exception_sender: Sender<Exception>) -> Self {
|
||||||
let mut this = Self {
|
let mut this = Self {
|
||||||
// HACK: allocate directly on the heap to avoid a stack overflow
|
// HACK: allocate directly on the heap to avoid a stack overflow
|
||||||
// at runtime while trying to move around a 64MB array
|
// at runtime while trying to move around a 64MB array
|
||||||
ram: unsafe { Box::from_raw(Box::into_raw(vec![0u8; MEMORY_RAM_SIZE].into_boxed_slice()) as *mut MemoryRam) },
|
ram: unsafe { Box::from_raw(Box::into_raw(vec![0u8; MEMORY_RAM_SIZE].into_boxed_slice()) as *mut MemoryRam) },
|
||||||
rom: unsafe { Box::from_raw(Box::into_raw(vec![0u8; MEMORY_ROM_SIZE].into_boxed_slice()) as *mut MemoryRom) },
|
rom: unsafe { Box::from_raw(Box::into_raw(vec![0u8; MEMORY_ROM_SIZE].into_boxed_slice()) as *mut MemoryRom) },
|
||||||
|
mmu_enabled: Box::from(false),
|
||||||
|
tlb: Box::from(HashMap::with_capacity(1024)),
|
||||||
|
paging_directory_address: Box::from(0x00000000),
|
||||||
|
exception_sender,
|
||||||
};
|
};
|
||||||
this.rom.as_mut_slice().write(rom).expect("failed to copy ROM to memory");
|
this.rom.as_mut_slice().write(rom).expect("failed to copy ROM to memory");
|
||||||
this
|
this
|
||||||
|
@ -44,8 +62,8 @@ unsafe impl Send for Memory {}
|
||||||
unsafe impl Sync for Memory {}
|
unsafe impl Sync for Memory {}
|
||||||
|
|
||||||
impl Memory {
|
impl Memory {
|
||||||
pub fn new(rom: &[u8]) -> Self {
|
pub fn new(rom: &[u8], exception_sender: Sender<Exception>) -> Self {
|
||||||
Self(Arc::new(UnsafeCell::new(MemoryInner::new(rom))))
|
Self(Arc::new(UnsafeCell::new(MemoryInner::new(rom, exception_sender))))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn inner(&self) -> &mut MemoryInner {
|
fn inner(&self) -> &mut MemoryInner {
|
||||||
|
@ -54,13 +72,87 @@ impl Memory {
|
||||||
|
|
||||||
pub fn ram(&self) -> &mut MemoryRam { &mut self.inner().ram }
|
pub fn ram(&self) -> &mut MemoryRam { &mut self.inner().ram }
|
||||||
pub fn rom(&self) -> &mut MemoryRom { &mut self.inner().rom }
|
pub fn rom(&self) -> &mut MemoryRom { &mut self.inner().rom }
|
||||||
|
pub fn mmu_enabled(&self) -> &mut bool { &mut self.inner().mmu_enabled }
|
||||||
|
pub fn tlb(&self) -> &mut HashMap<u32, MemoryPage> { &mut self.inner().tlb }
|
||||||
|
pub fn paging_directory_address(&self) -> &mut u32 { &mut self.inner().paging_directory_address }
|
||||||
|
pub fn exception_sender(&self) -> &mut Sender<Exception> { &mut self.inner().exception_sender }
|
||||||
|
|
||||||
pub fn dump(&self) {
|
pub fn dump(&self) {
|
||||||
let mut file = File::create("memory.dump").expect("failed to open memory dump file");
|
let mut file = File::create("memory.dump").expect("failed to open memory dump file");
|
||||||
file.write_all(self.ram()).expect("failed to write memory dump file");
|
file.write_all(self.ram()).expect("failed to write memory dump file");
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_8(&self, address: u32) -> u8 {
|
pub fn flush_tlb(&self, paging_directory_address: Option<u32>) {
|
||||||
|
let 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;
|
||||||
|
|
||||||
|
let tlb_entry = MemoryPage {
|
||||||
|
//physical_address: (((directory_index + 1) * (table_index + 1) * 4096) - 4096),
|
||||||
|
physical_address: (directory_index << 22) | (table_index << 12),
|
||||||
|
present: table_present,
|
||||||
|
rw: table_rw,
|
||||||
|
};
|
||||||
|
self.tlb().entry(table_address).or_insert(tlb_entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println!("{:#X?}", self.tlb());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn virtual_to_physical(&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);
|
||||||
|
let physical_address = match physical_page {
|
||||||
|
Some(page) => {
|
||||||
|
if page.present {
|
||||||
|
Some((page.physical_address | offset, page.rw))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
},
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
|
physical_address
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_8(&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();
|
||||||
|
(0, false)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
let address = address as usize;
|
let address = address as usize;
|
||||||
|
|
||||||
let result = if address >= MEMORY_ROM_START && address < MEMORY_ROM_START + MEMORY_ROM_SIZE {
|
let result = if address >= MEMORY_ROM_START && address < MEMORY_ROM_START + MEMORY_ROM_SIZE {
|
||||||
|
@ -74,7 +166,7 @@ impl Memory {
|
||||||
*value
|
*value
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
error(&format!("attempting to read from unmapped memory address: {:#010X}", address));
|
error(&format!("attempting to read from unmapped physical memory address: {:#010X}", address));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -89,7 +181,16 @@ impl Memory {
|
||||||
(self.read_8(address + 3) as u32) << 24
|
(self.read_8(address + 3) as u32) << 24
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write_8(&self, address: u32, byte: u8) {
|
pub fn write_8(&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(|| {
|
||||||
|
self.exception_sender().send(Exception::PageFault(address)).unwrap();
|
||||||
|
(0, false)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if writable {
|
||||||
let address = address as usize;
|
let address = address as usize;
|
||||||
|
|
||||||
if address >= MEMORY_ROM_START && address < MEMORY_ROM_START + MEMORY_ROM_SIZE {
|
if address >= MEMORY_ROM_START && address < MEMORY_ROM_START + MEMORY_ROM_SIZE {
|
||||||
|
@ -101,9 +202,12 @@ impl Memory {
|
||||||
*value = byte;
|
*value = byte;
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
error(&format!("attempting to write to unmapped memory address: {:#010X}", address));
|
error(&format!("attempting to write to unmapped physical memory address: {:#010X}", address));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
self.exception_sender().send(Exception::PageFault(address)).unwrap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
pub fn write_16(&self, address: u32, half: u16) {
|
pub fn write_16(&self, address: u32, half: u16) {
|
||||||
self.write_8(address, (half & 0x00FF) as u8);
|
self.write_8(address, (half & 0x00FF) as u8);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user