mirror of
https://github.com/0xNikilite/oboromi.git
synced 2026-01-31 01:15:22 +01:00
Add GUI module using egui and update project structure
Introduces a new `gui` module with initial implementation and tests using egui, updates dependencies in Cargo.toml and Cargo.lock to include egui and related crates, and ui is renamed from ui to gui. Updates .gitignore to exclude oboromi.log. Refactors main.rs and lib.rs to integrate the new GUI, and removes the obsolete ui module.
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1 +1,2 @@
|
||||
/target
|
||||
/oboromi.log
|
||||
|
||||
3794
Cargo.lock
generated
3794
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
10
Cargo.toml
10
Cargo.toml
@@ -9,6 +9,14 @@ repository = "https://github.com/0xNikilite/oboromi"
|
||||
|
||||
[dependencies]
|
||||
bitflags = "2.9"
|
||||
log = "0.4"
|
||||
fern = { version = "0.6", features = ["colored"] }
|
||||
parking_lot = "0.12"
|
||||
crossbeam-channel = "0.5"
|
||||
egui = { version = "0.32", optional = true }
|
||||
eframe = { version = "0.32", optional = true }
|
||||
|
||||
[features]
|
||||
trace = []
|
||||
trace = []
|
||||
default = ["gui"]
|
||||
gui = ["dep:egui", "dep:eframe"]
|
||||
|
||||
@@ -3,14 +3,31 @@ use bitflags::bitflags;
|
||||
|
||||
bitflags! {
|
||||
/// Processor State Flags: Negative, Zero, Carry, Overflow
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct Flags: u32 {
|
||||
const NEGATIVE = 1 << 31; // N flag: result is negative
|
||||
const ZERO = 1 << 30; // Z flag: result is zero
|
||||
const CARRY = 1 << 29; // C flag: carry/borrow
|
||||
const OVERFLOW = 1 << 28; // V flag: signed overflow
|
||||
// ARMv8.3-A Pointer Authentication
|
||||
const PAC_FAIL = 1 << 27; // Pointer authentication failed
|
||||
}
|
||||
}
|
||||
|
||||
/// ARM Processor State
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ProcessorState {
|
||||
pub el: u8, // Exception Level (0-3)
|
||||
pub spsel: bool, // Stack Pointer Selection
|
||||
pub nzcv: Flags, // Condition flags
|
||||
pub daif: u8, // Debug, SError, IRQ, FIQ masks
|
||||
pub pan: bool, // Privileged Access Never
|
||||
pub uao: bool, // User Access Override
|
||||
pub dit: bool, // Data Independent Timing
|
||||
pub tco: bool, // Tag Check Override
|
||||
pub pstate: u32, // Complete PSTATE
|
||||
}
|
||||
|
||||
/// ARM64 registers X0–X30, SP, PC and processor flags.
|
||||
pub struct Registers {
|
||||
pub x: [u64; 31],
|
||||
@@ -263,9 +280,9 @@ impl CPU {
|
||||
if (opcode & LS_MASK) == LDR || (opcode & LS_MASK) == STR {
|
||||
let rt = (opcode & 0x1F) as usize;
|
||||
let rn = ((opcode >> 5) & 0x1F) as usize;
|
||||
let imm = ((opcode & 0x3FFC00) >> 10) as usize * 8;
|
||||
let imm = ((opcode & 0x3FFC00) >> 10) as usize; // Immediate is in units of 8 bytes
|
||||
let base= self.regs.x.get(rn).copied().unwrap_or(0) as usize;
|
||||
let addr= base.wrapping_add(imm);
|
||||
let addr= base.wrapping_add(imm * 8); // Scale by 8
|
||||
if (opcode & LS_MASK) == LDR {
|
||||
let v = self.memory.read_u64(addr);
|
||||
if rt < 31 {
|
||||
@@ -305,4 +322,4 @@ impl Registers {
|
||||
self.flags.set(Flags::NEGATIVE, (res >> 63) != 0);
|
||||
self.flags.set(Flags::ZERO, res == 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
33
src/gui/gui.rs
Normal file
33
src/gui/gui.rs
Normal file
@@ -0,0 +1,33 @@
|
||||
use eframe::egui::{ScrollArea, CentralPanel};
|
||||
use crate::gui::run_tests;
|
||||
|
||||
/// GUI with a button to run tests and display results
|
||||
pub struct GUI {
|
||||
pub logs: Vec<String>,
|
||||
}
|
||||
|
||||
impl Default for GUI {
|
||||
fn default() -> Self {
|
||||
Self { logs: vec![] }
|
||||
}
|
||||
}
|
||||
|
||||
impl eframe::App for GUI {
|
||||
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
|
||||
CentralPanel::default().show(ctx, |ui| {
|
||||
ui.heading("oboromi");
|
||||
|
||||
if ui.button("Run Tests").clicked() {
|
||||
self.logs = run_tests();
|
||||
}
|
||||
|
||||
ui.separator();
|
||||
ui.label("Test Results:");
|
||||
ScrollArea::vertical().show(ui, |ui| {
|
||||
for line in &self.logs {
|
||||
ui.label(line);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
5
src/gui/mod.rs
Normal file
5
src/gui/mod.rs
Normal file
@@ -0,0 +1,5 @@
|
||||
mod gui;
|
||||
mod tests;
|
||||
|
||||
pub use gui::GUI;
|
||||
pub use tests::run_tests;
|
||||
153
src/gui/tests.rs
Normal file
153
src/gui/tests.rs
Normal file
@@ -0,0 +1,153 @@
|
||||
use crate::cpu::{CPU, Flags};
|
||||
use crate::memory::Memory;
|
||||
|
||||
pub fn run_tests() -> Vec<String> {
|
||||
let mut results = Vec::new();
|
||||
|
||||
// 1) Memory subsystem test
|
||||
let mut mem = Memory::new(64 * 1024 * 1024);
|
||||
mem.write_byte(10, 0xAB);
|
||||
assert_eq!(mem.read_byte(10), 0xAB);
|
||||
mem.write_byte(100, 0x11);
|
||||
mem.write_byte(101, 0x22);
|
||||
mem.write_byte(102, 0x33);
|
||||
mem.write_byte(103, 0x44);
|
||||
assert_eq!(mem.read_u32(100), 0x4433_2211);
|
||||
println!("✅ Memory OK");
|
||||
|
||||
// 2) NOP instruction test
|
||||
let mut cpu = CPU::new(1024);
|
||||
cpu.regs.pc = 0;
|
||||
let nop = 0xD503201F_u32.to_le_bytes();
|
||||
for i in 0..4 { cpu.memory.write_byte(i, nop[i]); }
|
||||
cpu.step();
|
||||
assert_eq!(cpu.regs.pc, 4);
|
||||
println!("✅ NOP OK");
|
||||
|
||||
// 3) ADD immediate test
|
||||
cpu = CPU::new(1024);
|
||||
cpu.regs.pc = 0;
|
||||
cpu.regs.x[1] = 5;
|
||||
let addi = 0x9100_0821_u32.to_le_bytes(); // ADD X1, X1, #0x2
|
||||
for i in 0..4 { cpu.memory.write_byte(i, addi[i]); }
|
||||
cpu.step();
|
||||
assert_eq!(cpu.regs.x[1], 7);
|
||||
println!("✅ ADDI OK");
|
||||
|
||||
// 4) SUB immediate test
|
||||
cpu = CPU::new(1024);
|
||||
cpu.regs.pc = 0;
|
||||
cpu.regs.x[2] = 10;
|
||||
let subi = 0xD100_0442_u32.to_le_bytes(); // SUB X2, X2, #0x1
|
||||
for i in 0..4 { cpu.memory.write_byte(i, subi[i]); }
|
||||
cpu.step();
|
||||
assert_eq!(cpu.regs.x[2], 9);
|
||||
println!("✅ SUBI OK");
|
||||
|
||||
// 5) ADD register test
|
||||
cpu = CPU::new(1024);
|
||||
cpu.regs.pc = 0;
|
||||
cpu.regs.x[0] = 7;
|
||||
cpu.regs.x[1] = 3;
|
||||
let addr = 0x8B01_0000_u32.to_le_bytes(); // ADD X0, X0, X1
|
||||
for i in 0..4 { cpu.memory.write_byte(i, addr[i]); }
|
||||
cpu.step();
|
||||
assert_eq!(cpu.regs.x[0], 10);
|
||||
println!("✅ ADDR OK");
|
||||
|
||||
// 6) SUB register test
|
||||
cpu = CPU::new(1024);
|
||||
cpu.regs.pc = 0;
|
||||
cpu.regs.x[3] = 8;
|
||||
cpu.regs.x[4] = 2;
|
||||
let subr = 0xCB04_0063_u32.to_le_bytes(); // SUB X3, X3, X4
|
||||
for i in 0..4 { cpu.memory.write_byte(i, subr[i]); }
|
||||
cpu.step();
|
||||
assert_eq!(cpu.regs.x[3], 6);
|
||||
println!("✅ SUBR OK");
|
||||
|
||||
// 7) AND register test
|
||||
cpu = CPU::new(1024);
|
||||
cpu.regs.pc = 0;
|
||||
cpu.regs.x[5] = 0b1010;
|
||||
cpu.regs.x[6] = 0b1100;
|
||||
let andr = 0x8A06_00A5_u32.to_le_bytes(); // AND X5, X5, X6
|
||||
for i in 0..4 { cpu.memory.write_byte(i, andr[i]); }
|
||||
cpu.step();
|
||||
assert_eq!(cpu.regs.x[5], 0b1000);
|
||||
println!("✅ AND OK");
|
||||
|
||||
// 8) CMP (SUBS XZR, X7, X8) test
|
||||
cpu = CPU::new(1024);
|
||||
cpu.regs.pc = 0;
|
||||
cpu.regs.x[7] = 3;
|
||||
cpu.regs.x[8] = 3;
|
||||
let cmp = 0xEB08_00FF_u32.to_le_bytes(); // CMP X7, X8
|
||||
for i in 0..4 { cpu.memory.write_byte(i, cmp[i]); }
|
||||
cpu.step();
|
||||
assert!(cpu.regs.flags.contains(Flags::ZERO));
|
||||
println!("✅ CMP OK");
|
||||
|
||||
// 9) LDR/STR immediate (64-bit) test
|
||||
cpu = CPU::new(1024);
|
||||
cpu.regs.pc = 0;
|
||||
cpu.regs.x[9] = 100;
|
||||
cpu.regs.x[10] = 0x1234_5678;
|
||||
|
||||
// STR X10, [X9, #16]
|
||||
let stri = 0xF900092A_u32.to_le_bytes();
|
||||
for i in 0..4 { cpu.memory.write_byte(i, stri[i]); }
|
||||
cpu.step();
|
||||
|
||||
// LDR X11, [X9, #16]
|
||||
let ldri = 0xF940092B_u32.to_le_bytes();
|
||||
for i in 0..4 { cpu.memory.write_byte(i + 4, ldri[i]); }
|
||||
cpu.step();
|
||||
|
||||
assert_eq!(cpu.regs.x[11], 0x1234_5678);
|
||||
println!("✅ LDR/STR OK");
|
||||
|
||||
// 10) Branch test
|
||||
cpu = CPU::new(1024);
|
||||
cpu.regs.pc = 0;
|
||||
let b = 0x1400_0002_u32.to_le_bytes(); // B +2
|
||||
for i in 0..4 { cpu.memory.write_byte(i, b[i]); }
|
||||
cpu.step();
|
||||
assert_eq!(cpu.regs.pc, 8);
|
||||
println!("✅ B OK");
|
||||
|
||||
// 11) RET test
|
||||
cpu = CPU::new(1024);
|
||||
cpu.regs.pc = 0;
|
||||
cpu.regs.x[30] = 16;
|
||||
let ret = 0xD65F_03C0_u32.to_le_bytes();
|
||||
for i in 0..4 { cpu.memory.write_byte(i, ret[i]); }
|
||||
cpu.step();
|
||||
assert_eq!(cpu.regs.pc, 16);
|
||||
println!("✅ RET OK");
|
||||
|
||||
// 12) MMU Basic Functionality Test
|
||||
println!("\nTesting MMU Basic Functionality...");
|
||||
let mut cpu = CPU::new(4096); // 4KB memory for MMU test
|
||||
|
||||
let vaddr = 0x10;
|
||||
let paddr = cpu.memory.mmu.translate(vaddr).expect("Translation failed");
|
||||
println!("MMU: 0x{:x} → 0x{:x}", vaddr, paddr);
|
||||
assert_eq!(vaddr, paddr);
|
||||
|
||||
// Test: write through MMU
|
||||
cpu.memory.write_byte(vaddr as usize, 0xAB);
|
||||
let value = cpu.memory.ram[paddr as usize];
|
||||
println!("Wrote 0xAB to vaddr 0x{:x} (paddr 0x{:x}), read back: 0x{:x}",
|
||||
vaddr, paddr, value);
|
||||
assert_eq!(value, 0xAB);
|
||||
|
||||
// Test: read through MMU
|
||||
let read_value = cpu.memory.read_byte(vaddr as usize);
|
||||
println!("Read from vaddr 0x{:x}: 0x{:x}", vaddr, read_value);
|
||||
assert_eq!(read_value, 0xAB);
|
||||
|
||||
println!("✅ MMU Basic Functionality OK");
|
||||
results.push("All tests passed".to_string());
|
||||
results
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
pub mod cpu;
|
||||
pub mod memory;
|
||||
pub mod mmu;
|
||||
pub mod gui;
|
||||
|
||||
191
src/main.rs
191
src/main.rs
@@ -1,5 +1,5 @@
|
||||
use oboromi::cpu::{CPU, Flags};
|
||||
use oboromi::memory::Memory;
|
||||
#[cfg(feature = "gui")]
|
||||
use oboromi::gui::GUI;
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn decode_arm64_fields(opcode: u32) -> (u8, u8, u8, u8) {
|
||||
@@ -10,152 +10,47 @@ fn decode_arm64_fields(opcode: u32) -> (u8, u8, u8, u8) {
|
||||
(sf, opc, rn, rd)
|
||||
}
|
||||
|
||||
fn setup_logger() -> Result<(), fern::InitError> {
|
||||
fern::Dispatch::new()
|
||||
.format(|out, message, record| {
|
||||
out.finish(format_args!(
|
||||
"[{}][{}] {}",
|
||||
record.level(),
|
||||
record.target(),
|
||||
message
|
||||
))
|
||||
})
|
||||
.level(log::LevelFilter::Debug)
|
||||
.chain(std::io::stdout())
|
||||
.chain(fern::log_file("oboromi.log")?)
|
||||
.apply()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(feature = "gui")]
|
||||
fn run_gui() {
|
||||
let options = eframe::NativeOptions {
|
||||
viewport: egui::ViewportBuilder::default()
|
||||
.with_inner_size([1200.0, 800.0])
|
||||
.with_title("oboromi"),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
eframe::run_native(
|
||||
"oboromi",
|
||||
options,
|
||||
Box::new(|_cc| Ok(Box::new(GUI::default()))),
|
||||
).expect("Failed to run GUI");
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// Initialize logging
|
||||
setup_logger().expect("Failed to initialize logger");
|
||||
|
||||
#[cfg(feature = "trace")]
|
||||
println!("-- TRACING ENABLED --");
|
||||
|
||||
// 1) Memory subsystem test
|
||||
let mut mem = Memory::new(64 * 1024 * 1024);
|
||||
mem.write_byte(10, 0xAB);
|
||||
assert_eq!(mem.read_byte(10), 0xAB);
|
||||
mem.write_byte(100, 0x11);
|
||||
mem.write_byte(101, 0x22);
|
||||
mem.write_byte(102, 0x33);
|
||||
mem.write_byte(103, 0x44);
|
||||
assert_eq!(mem.read_u32(100), 0x4433_2211);
|
||||
println!("✅ Memory OK");
|
||||
log::info!("-- TRACING ENABLED --");
|
||||
|
||||
// 2) NOP instruction test
|
||||
let mut cpu = CPU::new(1024);
|
||||
cpu.regs.pc = 0;
|
||||
let nop = 0xD503201F_u32.to_le_bytes();
|
||||
for i in 0..4 { cpu.memory.write_byte(i, nop[i]); }
|
||||
cpu.step();
|
||||
assert_eq!(cpu.regs.pc, 4);
|
||||
println!("✅ NOP OK");
|
||||
|
||||
// 3) ADD immediate test
|
||||
cpu = CPU::new(1024);
|
||||
cpu.regs.pc = 0;
|
||||
cpu.regs.x[1] = 5;
|
||||
let addi = 0x9100_0821_u32.to_le_bytes(); // ADD X1, X1, #0x2
|
||||
for i in 0..4 { cpu.memory.write_byte(i, addi[i]); }
|
||||
cpu.step();
|
||||
assert_eq!(cpu.regs.x[1], 7);
|
||||
println!("✅ ADDI OK");
|
||||
|
||||
// 4) SUB immediate test
|
||||
cpu = CPU::new(1024);
|
||||
cpu.regs.pc = 0;
|
||||
cpu.regs.x[2] = 10;
|
||||
let subi = 0xD100_0442_u32.to_le_bytes(); // SUB X2, X2, #0x1
|
||||
for i in 0..4 { cpu.memory.write_byte(i, subi[i]); }
|
||||
cpu.step();
|
||||
assert_eq!(cpu.regs.x[2], 9);
|
||||
println!("✅ SUBI OK");
|
||||
|
||||
// 5) ADD register test
|
||||
cpu = CPU::new(1024);
|
||||
cpu.regs.pc = 0;
|
||||
cpu.regs.x[0] = 7;
|
||||
cpu.regs.x[1] = 3;
|
||||
let addr = 0x8B01_0000_u32.to_le_bytes(); // ADD X0, X0, X1
|
||||
for i in 0..4 { cpu.memory.write_byte(i, addr[i]); }
|
||||
cpu.step();
|
||||
assert_eq!(cpu.regs.x[0], 10);
|
||||
println!("✅ ADDR OK");
|
||||
|
||||
// 6) SUB register test
|
||||
cpu = CPU::new(1024);
|
||||
cpu.regs.pc = 0;
|
||||
cpu.regs.x[3] = 8;
|
||||
cpu.regs.x[4] = 2;
|
||||
let subr = 0xCB04_0063_u32.to_le_bytes(); // SUB X3, X3, X4
|
||||
for i in 0..4 { cpu.memory.write_byte(i, subr[i]); }
|
||||
cpu.step();
|
||||
assert_eq!(cpu.regs.x[3], 6);
|
||||
println!("✅ SUBR OK");
|
||||
|
||||
// 7) AND register test
|
||||
cpu = CPU::new(1024);
|
||||
cpu.regs.pc = 0;
|
||||
cpu.regs.x[5] = 0b1010;
|
||||
cpu.regs.x[6] = 0b1100;
|
||||
let andr = 0x8A06_00A5_u32.to_le_bytes(); // AND X5, X5, X6
|
||||
for i in 0..4 { cpu.memory.write_byte(i, andr[i]); }
|
||||
cpu.step();
|
||||
assert_eq!(cpu.regs.x[5], 0b1000);
|
||||
println!("✅ AND OK");
|
||||
|
||||
// 8) CMP (SUBS XZR, X7, X8) test
|
||||
cpu = CPU::new(1024);
|
||||
cpu.regs.pc = 0;
|
||||
cpu.regs.x[7] = 3;
|
||||
cpu.regs.x[8] = 3;
|
||||
let cmp = 0xEB08_00FF_u32.to_le_bytes(); // CMP X7, X8
|
||||
for i in 0..4 { cpu.memory.write_byte(i, cmp[i]); }
|
||||
cpu.step();
|
||||
assert!(cpu.regs.flags.contains(Flags::ZERO));
|
||||
println!("✅ CMP OK");
|
||||
|
||||
// 9) LDR/STR immediate (64-bit) test
|
||||
cpu = CPU::new(1024);
|
||||
cpu.regs.pc = 0;
|
||||
cpu.regs.x[9] = 100;
|
||||
cpu.regs.x[10] = 0x1234_5678;
|
||||
|
||||
// STR X10, [X9, #16]
|
||||
let stri = 0xF900092A_u32.to_le_bytes();
|
||||
for i in 0..4 { cpu.memory.write_byte(i, stri[i]); }
|
||||
cpu.step();
|
||||
|
||||
// LDR X11, [X9, #16]
|
||||
let ldri = 0xF940092B_u32.to_le_bytes();
|
||||
for i in 0..4 { cpu.memory.write_byte(i + 4, ldri[i]); }
|
||||
cpu.step();
|
||||
|
||||
assert_eq!(cpu.regs.x[11], 0x1234_5678);
|
||||
println!("✅ LDR/STR OK");
|
||||
|
||||
// 10) Branch test
|
||||
cpu = CPU::new(1024);
|
||||
cpu.regs.pc = 0;
|
||||
let b = 0x1400_0002_u32.to_le_bytes(); // B +2
|
||||
for i in 0..4 { cpu.memory.write_byte(i, b[i]); }
|
||||
cpu.step();
|
||||
assert_eq!(cpu.regs.pc, 8);
|
||||
println!("✅ B OK");
|
||||
|
||||
// 11) RET test
|
||||
cpu = CPU::new(1024);
|
||||
cpu.regs.pc = 0;
|
||||
cpu.regs.x[30] = 16;
|
||||
let ret = 0xD65F_03C0_u32.to_le_bytes();
|
||||
for i in 0..4 { cpu.memory.write_byte(i, ret[i]); }
|
||||
cpu.step();
|
||||
assert_eq!(cpu.regs.pc, 16);
|
||||
println!("✅ RET OK");
|
||||
|
||||
// 12) MMU Basic Functionality Test
|
||||
println!("\nTesting MMU Basic Functionality...");
|
||||
let mut cpu = CPU::new(4096); // 4KB memory for MMU test
|
||||
|
||||
let vaddr = 0x10;
|
||||
let paddr = cpu.memory.mmu.translate(vaddr).expect("Translation failed");
|
||||
println!("MMU: 0x{:x} → 0x{:x}", vaddr, paddr);
|
||||
assert_eq!(vaddr, paddr);
|
||||
|
||||
// Test: write through MMU
|
||||
cpu.memory.write_byte(vaddr as usize, 0xAB);
|
||||
let value = cpu.memory.ram[paddr as usize];
|
||||
println!("Wrote 0xAB to vaddr 0x{:x} (paddr 0x{:x}), read back: 0x{:x}",
|
||||
vaddr, paddr, value);
|
||||
assert_eq!(value, 0xAB);
|
||||
|
||||
// Test: read through MMU
|
||||
let read_value = cpu.memory.read_byte(vaddr as usize);
|
||||
println!("Read from vaddr 0x{:x}: 0x{:x}", vaddr, read_value);
|
||||
assert_eq!(read_value, 0xAB);
|
||||
|
||||
println!("✅ MMU Basic Functionality OK");
|
||||
}
|
||||
#[cfg(feature = "gui")] {
|
||||
run_gui();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,9 +28,9 @@ impl Memory {
|
||||
pub fn read_byte(&mut self, vaddr: usize) -> u8 {
|
||||
match self.mmu.translate(vaddr as u64) {
|
||||
Some(paddr) => {
|
||||
let paddr_usize = paddr as usize;
|
||||
if paddr_usize < self.ram.len() {
|
||||
self.ram[paddr_usize]
|
||||
let paddr = paddr as usize;
|
||||
if paddr < self.ram.len() {
|
||||
self.ram[paddr]
|
||||
} else {
|
||||
0
|
||||
}
|
||||
@@ -46,9 +46,9 @@ impl Memory {
|
||||
pub fn write_byte(&mut self, vaddr: usize, val: u8) {
|
||||
match self.mmu.translate(vaddr as u64) {
|
||||
Some(paddr) => {
|
||||
let paddr_usize = paddr as usize;
|
||||
if paddr_usize < self.ram.len() {
|
||||
self.ram[paddr_usize] = val;
|
||||
let paddr = paddr as usize;
|
||||
if paddr < self.ram.len() {
|
||||
self.ram[paddr] = val;
|
||||
}
|
||||
}
|
||||
None => println!("⚠️ Page fault writing at {:#x}", vaddr),
|
||||
@@ -84,4 +84,4 @@ impl Memory {
|
||||
self.write_u32(addr, value as u32);
|
||||
self.write_u32(addr + 4, (value >> 32) as u32);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,10 +35,7 @@ impl MMU {
|
||||
/// Set identity mapping for a memory range
|
||||
pub fn set_identity_mapping(&mut self, start_page: usize, end_page: usize) {
|
||||
for i in start_page..end_page {
|
||||
if i < self.page_table.len() {
|
||||
// Mappa la pagina virtuale i alla stessa pagina fisica
|
||||
self.page_table.set_entry(i, (i * 4096) as u64);
|
||||
}
|
||||
self.page_table.set_entry(i, (i * 4096) as u64);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,24 +1,23 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Debug)]
|
||||
/// Page Table implementation
|
||||
/// Page Table implementation with sparse entries
|
||||
pub struct PageTable {
|
||||
entries: Vec<Option<u64>>,
|
||||
entries: HashMap<usize, u64>,
|
||||
}
|
||||
|
||||
impl PageTable {
|
||||
/// Create new page table with identity mapping disabled
|
||||
/// Create new empty page table
|
||||
pub fn new() -> Self {
|
||||
PageTable {
|
||||
entries: vec![None; 1 << 10],
|
||||
entries: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Perform page table walk
|
||||
pub fn walk(&self, vaddr: u64) -> Option<u64> {
|
||||
let vpn = (vaddr >> 12) & 0x3FF; // Virtual Page Number (4KB pages)
|
||||
let base = match self.entries.get(vpn as usize)? {
|
||||
Some(addr) => *addr,
|
||||
None => return None, // Page not mapped
|
||||
};
|
||||
let vpn = (vaddr >> 12) as usize; // Virtual Page Number (4KB pages)
|
||||
let base = self.entries.get(&vpn)?;
|
||||
|
||||
// Physical address = page base + offset
|
||||
Some(base | (vaddr & 0xFFF))
|
||||
@@ -26,13 +25,6 @@ impl PageTable {
|
||||
|
||||
/// Set a page table entry at index
|
||||
pub fn set_entry(&mut self, index: usize, value: u64) {
|
||||
if index < self.entries.len() {
|
||||
self.entries[index] = Some(value & !0xFFF);
|
||||
}
|
||||
self.entries.insert(index, value & !0xFFF);
|
||||
}
|
||||
|
||||
/// Get the number of entries in the page table
|
||||
pub fn len(&self) -> usize {
|
||||
self.entries.len()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user