Finish basic functions of MMU card

This commit is contained in:
pjht 2023-01-27 11:55:45 -06:00
parent 77054589c6
commit 9642cf82f0
Signed by: pjht
GPG Key ID: 7B5F6AFBEC7EE78E
3 changed files with 137 additions and 21 deletions

10
Cargo.lock generated
View File

@ -73,15 +73,6 @@ version = "3.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535"
[[package]]
name = "card_macro"
version = "0.1.0"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.0.78" version = "1.0.78"
@ -521,7 +512,6 @@ dependencies = [
"anyhow", "anyhow",
"bitflags", "bitflags",
"bitvec", "bitvec",
"card_macro",
"clap 3.2.23", "clap 3.2.23",
"derive-try-from-primitive", "derive-try-from-primitive",
"elf", "elf",

View File

@ -9,7 +9,6 @@ edition = "2021"
anyhow = "1.0.66" anyhow = "1.0.66"
bitflags = "1.3.2" bitflags = "1.3.2"
bitvec = "1.0.0" bitvec = "1.0.0"
card_macro = { version = "0.1.0", path = "card_macro" }
clap = { version = "3.2.23", features = ["clap_derive", "derive"] } clap = { version = "3.2.23", features = ["clap_derive", "derive"] }
derive-try-from-primitive = "1.0.0" derive-try-from-primitive = "1.0.0"
elf = "0.7.0" elf = "0.7.0"

View File

@ -4,7 +4,7 @@ use nullable_result::NullableResult;
use crate::{ use crate::{
backplane::{Backplane, CardAccessorBuilder, DMAHandler, MMUHandler}, backplane::{Backplane, CardAccessorBuilder, DMAHandler, MMUHandler},
card::{u16_get_be_byte, Card}, card::{u16_get_be_byte, u32_get_be_byte, u32_set_be_byte, Card},
m68k::BusError, m68k::BusError,
register, register,
}; };
@ -35,7 +35,10 @@ impl From<u32> for PagingEntry {
pub struct MmuCard { pub struct MmuCard {
enabled: bool, enabled: bool,
cache: [Option<PagingEntry>; 4096], cache: [Option<PagingEntry>; 4096],
map_frames: [Option<u32>; 4], map_frames: [u32; 4],
map_frames_enabled: [bool; 4],
tlb_clear_entry: u16,
print_debug: bool,
} }
impl Card for MmuCard { impl Card for MmuCard {
@ -44,7 +47,10 @@ impl Card for MmuCard {
Self { Self {
enabled: false, enabled: false,
cache: [None; 4096], cache: [None; 4096],
map_frames: [None; 4], map_frames: [0; 4],
map_frames_enabled: [false; 4],
tlb_clear_entry: 0,
print_debug: false,
}, },
None, None,
)) ))
@ -56,14 +62,78 @@ impl Card for MmuCard {
fn read_byte_io(&mut self, address: u8) -> NullableResult<u8, BusError> { fn read_byte_io(&mut self, address: u8) -> NullableResult<u8, BusError> {
match address { match address {
(0x0..=0xF) => {
let map_no = (address / 4) as usize;
let offset = address % 4;
match offset {
(0..=2) => NullableResult::Ok(u32_get_be_byte(self.map_frames[map_no], offset)),
3 => NullableResult::Ok(self.map_frames_enabled[map_no] as u8),
_ => unreachable!(),
}
}
(0xFE..=0xFF) => NullableResult::Ok(u16_get_be_byte(ID, address - 0xFE)), (0xFE..=0xFF) => NullableResult::Ok(u16_get_be_byte(ID, address - 0xFE)),
_ => NullableResult::Null, _ => NullableResult::Null,
} }
} }
fn write_byte_io(&mut self, address: u8, data: u8) -> NullableResult<(), BusError> {
match address {
(0x0..=0xF) => {
let map_no = (address / 4) as usize;
let offset = address % 4;
match offset {
(0..=1) => {
self.map_frames[map_no] =
u32_set_be_byte(self.map_frames[map_no], offset, data);
}
2 => {
self.map_frames[map_no] =
u32_set_be_byte(self.map_frames[map_no], offset, data & 0xf0);
}
3 => {
self.map_frames_enabled[map_no] = (data & 0x1) > 0;
for i in map_no * 1024..(map_no + 1) * 1024 {
self.cache[i] = None;
}
}
_ => unreachable!(),
};
}
(0x10..=0x13) => {
let offset = (address - 0x10) % 4;
match offset {
0 => (),
1 => {
self.tlb_clear_entry = (self.tlb_clear_entry & 0xF) | ((data as u16) << 4);
}
2 => {
self.tlb_clear_entry =
(self.tlb_clear_entry & 0xFF0) | (((data as u16) & 0xF0) >> 4);
}
3 => {
if self.print_debug {
println!(
"Clearing TLB entry {:#x} ( page start {:#x} )",
self.tlb_clear_entry,
(self.tlb_clear_entry as u32) << 12
);
}
self.cache[self.tlb_clear_entry as usize] = None;
}
_ => unreachable!(),
}
}
0x15 => {
self.enabled = (data & 0x1) > 0;
}
_ => (),
}
NullableResult::Ok(())
}
fn cmd(&mut self, cmd: &[&str]) -> anyhow::Result<()> { fn cmd(&mut self, cmd: &[&str]) -> anyhow::Result<()> {
if cmd[0] == "enable" && cmd.len() >= 2 { if cmd[0] == "debug" && cmd.len() >= 2 {
self.enabled = cmd[1].parse()?; self.print_debug = cmd[1].parse()?;
} }
Ok(()) Ok(())
} }
@ -75,9 +145,33 @@ impl Card for MmuCard {
impl Display for MmuCard { impl Display for MmuCard {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let q1 = if self.map_frames_enabled[0] {
Some(self.map_frames[0])
} else {
None
};
let q2 = if self.map_frames_enabled[1] {
Some(self.map_frames[1])
} else {
None
};
let q3 = if self.map_frames_enabled[2] {
Some(self.map_frames[2])
} else {
None
};
let q4 = if self.map_frames_enabled[3] {
Some(self.map_frames[3])
} else {
None
};
f.write_fmt(format_args!( f.write_fmt(format_args!(
"MMU card, {}", "MMU card, {} (Q1: {:?}, Q2: {:?}, Q3: {:?}, Q4: {:?})",
if self.enabled { "enabled" } else { "disabled" }, if self.enabled { "enabled" } else { "disabled" },
q1,
q2,
q3,
q4
)) ))
} }
} }
@ -94,26 +188,59 @@ impl MMUHandler for Mmu {
write: bool, write: bool,
) -> NullableResult<u32, BusError> { ) -> NullableResult<u32, BusError> {
let card_accessor = card_accessor.build::<MmuCard>(); let card_accessor = card_accessor.build::<MmuCard>();
if card_accessor.get().enabled { let card = card_accessor.get();
let print_debug = card.print_debug;
if card.enabled {
let page = address >> 12; let page = address >> 12;
let offset = address & 0xFFF; let offset = address & 0xFFF;
let entry = if let Some(entry) = card_accessor.get().cache[page as usize] { let entry = if let Some(entry) = card.cache[page as usize] {
if print_debug {
println!("TLB hit");
}
entry entry
} else { } else {
let map_frame = card_accessor.get().map_frames[(page >> 10) as usize]?; if print_debug {
let entry_address = (map_frame << 12) | ((page & 0x3FF) << 2); println!("TLB miss, fetching entry");
}
if card.map_frames_enabled[(page >> 10) as usize] == false {
if print_debug {
println!("No mapping frame for this quarter");
}
return NullableResult::Null;
}
let map_frame = card.map_frames[(page >> 10) as usize];
let entry_address = (map_frame) | ((page & 0x3FF) << 2);
if print_debug {
println!("Entry is at {:#x}", entry_address);
}
drop(card);
let entry_hi = backplane.read_word_phys(entry_address)?; let entry_hi = backplane.read_word_phys(entry_address)?;
let entry_lo = backplane.read_word_phys(entry_address + 2)?; let entry_lo = backplane.read_word_phys(entry_address + 2)?;
let entry = PagingEntry::from((entry_hi as u32) << 16 | entry_lo as u32); let entry = PagingEntry::from((entry_hi as u32) << 16 | entry_lo as u32);
card_accessor.get().cache[page as usize] = Some(entry); card_accessor.get().cache[page as usize] = Some(entry);
if print_debug {
println!("Fetched entry {:#?}", entry);
}
entry entry
}; };
if entry.present { if entry.present {
if write && !entry.writable { if write && !entry.writable {
if print_debug {
println!("Entry not writable");
}
return NullableResult::Err(BusError); return NullableResult::Err(BusError);
} }
if print_debug {
println!(
"Translation success, translated to {:#x}",
(entry.frame << 12) | offset
);
}
NullableResult::Ok((entry.frame << 12) | offset) NullableResult::Ok((entry.frame << 12) | offset)
} else { } else {
if print_debug {
println!("Entry not present");
}
NullableResult::Null NullableResult::Null
} }
} else { } else {