feat: Add real-time data display for CPU registers, RAM, and ROM
This commit is contained in:
parent
3530ea5f28
commit
6636417d18
22 changed files with 1233 additions and 188 deletions
|
|
@ -74,6 +74,8 @@ pub struct GuiComponents {
|
|||
control_panel: ControlPanel,
|
||||
/// RAM content inspection and visualization
|
||||
memory_viewer: MemoryViewer,
|
||||
/// ROM content inspection and visualization
|
||||
rom_viewer: RomViewer,
|
||||
/// CPU register state display
|
||||
register_viewer: RegisterViewer,
|
||||
/// ROM file loading and management
|
||||
|
|
@ -103,6 +105,7 @@ impl GuiComponents {
|
|||
Self {
|
||||
control_panel: ControlPanel::new(),
|
||||
memory_viewer: MemoryViewer::new(),
|
||||
rom_viewer: RomViewer::new(),
|
||||
register_viewer: RegisterViewer::new(),
|
||||
rom_loader: RomLoader::new(),
|
||||
status_bar: StatusBar::new(),
|
||||
|
|
@ -128,11 +131,23 @@ impl GuiComponents {
|
|||
///
|
||||
/// # Arguments
|
||||
/// * `ui` - egui UI context for rendering
|
||||
/// * `state` - Immutable reference to GUI state for display
|
||||
pub fn render_memory_viewer(&self, ui: &mut egui::Ui, state: &GuiState) {
|
||||
/// * `state` - Mutable reference to GUI state for display and interaction
|
||||
pub fn render_memory_viewer(&self, ui: &mut egui::Ui, state: &mut GuiState) {
|
||||
self.memory_viewer.render(ui, state);
|
||||
}
|
||||
|
||||
/// Render the ROM viewer component
|
||||
///
|
||||
/// Displays ROM contents in a tabular format with address selection
|
||||
/// and hex/decimal viewing options.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `ui` - egui UI context for rendering
|
||||
/// * `state` - Mutable reference to GUI state for display and interaction
|
||||
pub fn render_rom_viewer(&self, ui: &mut egui::Ui, state: &mut GuiState) {
|
||||
self.rom_viewer.render(ui, state);
|
||||
}
|
||||
|
||||
/// Render the register viewer component
|
||||
///
|
||||
/// Shows CPU register state including accumulator, program counter,
|
||||
|
|
@ -140,8 +155,8 @@ impl GuiComponents {
|
|||
///
|
||||
/// # Arguments
|
||||
/// * `ui` - egui UI context for rendering
|
||||
/// * `state` - Immutable reference to GUI state for display
|
||||
pub fn render_register_viewer(&self, ui: &mut egui::Ui, state: &GuiState) {
|
||||
/// * `state` - Mutable reference to GUI state for display and interaction
|
||||
pub fn render_register_viewer(&self, ui: &mut egui::Ui, state: &mut GuiState) {
|
||||
self.register_viewer.render(ui, state);
|
||||
}
|
||||
|
||||
|
|
@ -330,8 +345,6 @@ impl ControlPanel {
|
|||
/// - **4 Bytes per Bank**: Addresses 0x00-0x03 in each bank
|
||||
/// - **4-bit Values**: Each memory location stores a 4-bit nibble
|
||||
pub struct MemoryViewer {
|
||||
/// Display mode: true for hexadecimal, false for decimal
|
||||
show_hex: bool,
|
||||
/// Number of bytes to display per row (currently fixed at 16)
|
||||
#[allow(dead_code)]
|
||||
// bytes_per_row is currently fixed at 16 but kept for future flexibility
|
||||
|
|
@ -341,16 +354,12 @@ pub struct MemoryViewer {
|
|||
impl MemoryViewer {
|
||||
/// Create a new memory viewer with default configuration
|
||||
///
|
||||
/// Initializes the viewer with hexadecimal display mode and standard
|
||||
/// layout optimized for the Intel 4002 RAM structure.
|
||||
/// Initializes the viewer with standard layout optimized for the Intel 4002 RAM structure.
|
||||
///
|
||||
/// # Returns
|
||||
/// A new `MemoryViewer` instance ready for RAM content display
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
show_hex: true,
|
||||
bytes_per_row: 16,
|
||||
}
|
||||
Self { bytes_per_row: 16 }
|
||||
}
|
||||
|
||||
/// Render the memory viewer interface
|
||||
|
|
@ -360,7 +369,7 @@ impl MemoryViewer {
|
|||
///
|
||||
/// # Arguments
|
||||
/// * `ui` - egui UI context for rendering
|
||||
/// * `state` - Immutable reference to GUI state containing memory data
|
||||
/// * `state` - Mutable reference to GUI state containing memory data
|
||||
///
|
||||
/// # Layout Structure
|
||||
/// ```text
|
||||
|
|
@ -375,7 +384,7 @@ impl MemoryViewer {
|
|||
/// │ [03] [55] [66] [77] [88] │
|
||||
/// └─────────────────────────────────────────────────┘
|
||||
/// ```
|
||||
pub fn render(&self, ui: &mut egui::Ui, state: &GuiState) {
|
||||
pub fn render(&self, ui: &mut egui::Ui, state: &mut GuiState) {
|
||||
ui.vertical(|ui| {
|
||||
// Section header
|
||||
ui.heading("Memory Viewer");
|
||||
|
|
@ -385,10 +394,9 @@ impl MemoryViewer {
|
|||
ui.label("Bank:");
|
||||
// Bank selector (0-3 for Intel 4002)
|
||||
ui.add(
|
||||
egui::DragValue::new(&mut state.memory_state.selected_bank.clone())
|
||||
.clamp_range(0..=3),
|
||||
egui::DragValue::new(&mut state.memory_state.selected_bank).clamp_range(0..=3),
|
||||
);
|
||||
ui.checkbox(&mut self.show_hex.clone(), "Hex View");
|
||||
ui.checkbox(&mut state.memory_state.show_hex, "Hex View");
|
||||
});
|
||||
|
||||
ui.separator();
|
||||
|
|
@ -411,7 +419,7 @@ impl MemoryViewer {
|
|||
// Bank data columns
|
||||
for bank in 0..4 {
|
||||
let value = state.memory_state.ram_contents[bank][addr];
|
||||
if self.show_hex {
|
||||
if state.memory_state.show_hex {
|
||||
ui.label(format!("{:02X}", value));
|
||||
} else {
|
||||
ui.label(format!("{}", value));
|
||||
|
|
@ -458,22 +466,19 @@ impl MemoryViewer {
|
|||
/// - **Flags**: System status indicators
|
||||
/// - **Index Registers**: General-purpose register file
|
||||
pub struct RegisterViewer {
|
||||
/// Currently selected index register for detailed view (0-15)
|
||||
selected_register: usize,
|
||||
// No internal state - all UI state is stored in GuiState
|
||||
}
|
||||
|
||||
impl RegisterViewer {
|
||||
/// Create a new register viewer with default configuration
|
||||
///
|
||||
/// Initializes the viewer with index register 0 selected and standard
|
||||
/// display formatting optimized for the Intel 4004 architecture.
|
||||
/// Initializes the viewer with standard display formatting optimized
|
||||
/// for the Intel 4004 architecture.
|
||||
///
|
||||
/// # Returns
|
||||
/// A new `RegisterViewer` instance ready for CPU state display
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
selected_register: 0,
|
||||
}
|
||||
Self {}
|
||||
}
|
||||
|
||||
/// Render the register viewer interface
|
||||
|
|
@ -483,7 +488,7 @@ impl RegisterViewer {
|
|||
///
|
||||
/// # Arguments
|
||||
/// * `ui` - egui UI context for rendering
|
||||
/// * `state` - Immutable reference to GUI state containing register data
|
||||
/// * `state` - Mutable reference to GUI state containing register data
|
||||
///
|
||||
/// # Layout Structure
|
||||
/// ```text
|
||||
|
|
@ -499,7 +504,7 @@ impl RegisterViewer {
|
|||
/// │ Stack Pointer │ 08 │ 8 │
|
||||
/// └─────────────────────────────────────────────────┘
|
||||
/// ```
|
||||
pub fn render(&self, ui: &mut egui::Ui, state: &GuiState) {
|
||||
pub fn render(&self, ui: &mut egui::Ui, state: &mut GuiState) {
|
||||
ui.vertical(|ui| {
|
||||
// Section header
|
||||
ui.heading("CPU Registers");
|
||||
|
|
@ -508,7 +513,8 @@ impl RegisterViewer {
|
|||
ui.horizontal(|ui| {
|
||||
ui.label("Index Register:");
|
||||
ui.add(
|
||||
egui::DragValue::new(&mut self.selected_register.clone()).clamp_range(0..=15),
|
||||
egui::DragValue::new(&mut state.register_state.selected_register)
|
||||
.clamp_range(0..=15),
|
||||
);
|
||||
});
|
||||
|
||||
|
|
@ -526,7 +532,7 @@ impl RegisterViewer {
|
|||
|
||||
// Core CPU registers
|
||||
ui.label("Accumulator");
|
||||
ui.label(format!("{:02X}", state.register_state.accumulator));
|
||||
ui.label(format!("{:X}", state.register_state.accumulator));
|
||||
ui.label(format!("{}", state.register_state.accumulator));
|
||||
ui.end_row();
|
||||
|
||||
|
|
@ -551,20 +557,21 @@ impl RegisterViewer {
|
|||
ui.end_row();
|
||||
|
||||
// Selected index register (highlighted)
|
||||
ui.label(format!("Index R{}", self.selected_register));
|
||||
let selected = state.register_state.selected_register;
|
||||
ui.label(format!("Index R{}", selected));
|
||||
ui.label(format!(
|
||||
"{:02X}",
|
||||
state.register_state.index_registers[self.selected_register]
|
||||
"{:X}",
|
||||
state.register_state.index_registers[selected]
|
||||
));
|
||||
ui.label(format!(
|
||||
"{}",
|
||||
state.register_state.index_registers[self.selected_register]
|
||||
state.register_state.index_registers[selected]
|
||||
));
|
||||
ui.end_row();
|
||||
|
||||
// Stack management
|
||||
ui.label("Stack Pointer");
|
||||
ui.label(format!("{:02X}", state.register_state.stack_pointer));
|
||||
ui.label(format!("{:X}", state.register_state.stack_pointer));
|
||||
ui.label(format!("{}", state.register_state.stack_pointer));
|
||||
ui.end_row();
|
||||
});
|
||||
|
|
@ -574,6 +581,132 @@ impl RegisterViewer {
|
|||
}
|
||||
}
|
||||
|
||||
/// ROM viewer component for displaying ROM contents
|
||||
///
|
||||
/// The ROM viewer provides comprehensive ROM inspection capabilities,
|
||||
/// allowing users to examine program memory contents with flexible
|
||||
/// display options and intuitive navigation.
|
||||
///
|
||||
/// ## Features
|
||||
///
|
||||
/// - **Program Memory Display**: View ROM contents from Intel 4001 chips
|
||||
/// - **Flexible Formatting**: Toggle between hexadecimal and decimal display
|
||||
/// - **Address Navigation**: Jump to specific memory addresses
|
||||
/// - **Scrollable Interface**: Navigate through memory contents efficiently
|
||||
/// - **Real-time Updates**: Live ROM content display
|
||||
///
|
||||
/// ## Display Format
|
||||
///
|
||||
/// The ROM viewer shows data in a structured grid:
|
||||
/// - **Address Column**: Memory addresses in hexadecimal format
|
||||
/// - **Data Columns**: 16 bytes per row for easy viewing
|
||||
/// - **Value Display**: Configurable hex or decimal representation
|
||||
///
|
||||
/// ## Memory Organization
|
||||
///
|
||||
/// The Intel 4001 ROM has the following structure:
|
||||
/// - **256 Bytes**: Total ROM capacity per chip
|
||||
/// - **8-bit Values**: Each memory location stores a full byte
|
||||
pub struct RomViewer {
|
||||
/// Number of bytes to display per row
|
||||
bytes_per_row: usize,
|
||||
}
|
||||
|
||||
impl RomViewer {
|
||||
/// Create a new ROM viewer with default configuration
|
||||
///
|
||||
/// Initializes the viewer with standard layout optimized for the Intel 4001 ROM structure.
|
||||
///
|
||||
/// # Returns
|
||||
/// A new `RomViewer` instance ready for ROM content display
|
||||
pub fn new() -> Self {
|
||||
Self { bytes_per_row: 16 }
|
||||
}
|
||||
|
||||
/// Render the ROM viewer interface
|
||||
///
|
||||
/// Creates a comprehensive ROM inspection interface with address navigation,
|
||||
/// display options, and a scrollable memory contents grid.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `ui` - egui UI context for rendering
|
||||
/// * `state` - Mutable reference to GUI state containing ROM data
|
||||
///
|
||||
/// # Layout Structure
|
||||
/// ```text
|
||||
/// ┌─────────────────────────────────────────────────┐
|
||||
/// │ ROM Viewer (Chip: ROM_4001_1) [─] [□] │
|
||||
/// │ □ Hex View │
|
||||
/// ├─────────────────────────────────────────────────┤
|
||||
/// │ Address 00 01 02 03 04 05 06 07 08 09 0A 0B... │
|
||||
/// │ 0x000 D4 C3 B2 A1 00 11 22 33 44 55 66 77... │
|
||||
/// │ 0x010 88 99 AA BB CC DD EE FF 00 11 22 33... │
|
||||
/// │ ... │
|
||||
/// └─────────────────────────────────────────────────┘
|
||||
/// ```
|
||||
pub fn render(&self, ui: &mut egui::Ui, state: &mut GuiState) {
|
||||
ui.vertical(|ui| {
|
||||
// Section header with chip name
|
||||
let header = if state.rom_state.chip_name.is_empty() {
|
||||
"ROM Viewer".to_string()
|
||||
} else {
|
||||
format!("ROM Viewer ({})", state.rom_state.chip_name)
|
||||
};
|
||||
ui.heading(header);
|
||||
|
||||
// Control bar with display options
|
||||
ui.horizontal(|ui| {
|
||||
ui.checkbox(&mut state.rom_state.show_hex, "Hex View");
|
||||
});
|
||||
|
||||
ui.separator();
|
||||
|
||||
// ROM contents in scrollable area
|
||||
egui::ScrollArea::vertical()
|
||||
.max_height(200.0)
|
||||
.show(ui, |ui| {
|
||||
egui::Grid::new("rom_grid").striped(true).show(ui, |ui| {
|
||||
// Header row with column labels
|
||||
ui.label("Addr");
|
||||
for i in 0..self.bytes_per_row {
|
||||
ui.label(format!("{:02X}", i));
|
||||
}
|
||||
ui.end_row();
|
||||
|
||||
// ROM contents rows
|
||||
let total_rows = (state.rom_state.rom_contents.len() + self.bytes_per_row
|
||||
- 1)
|
||||
/ self.bytes_per_row;
|
||||
for row in 0..total_rows {
|
||||
let addr = row * self.bytes_per_row;
|
||||
|
||||
// Address column
|
||||
ui.label(format!("{:03X}", addr));
|
||||
|
||||
// Data columns
|
||||
for col in 0..self.bytes_per_row {
|
||||
let idx = addr + col;
|
||||
if idx < state.rom_state.rom_contents.len() {
|
||||
let value = state.rom_state.rom_contents[idx];
|
||||
if state.rom_state.show_hex {
|
||||
ui.label(format!("{:02X}", value));
|
||||
} else {
|
||||
ui.label(format!("{:3}", value));
|
||||
}
|
||||
} else {
|
||||
ui.label("--");
|
||||
}
|
||||
}
|
||||
ui.end_row();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
ui.separator();
|
||||
}
|
||||
}
|
||||
|
||||
/// ROM loader component for file dialog integration and program management
|
||||
///
|
||||
/// The ROM loader handles program file selection, loading, and management.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue