feat: Add real-time data display for CPU registers, RAM, and ROM

This commit is contained in:
Jan-Peter von Hunnius 2026-02-26 19:36:59 +01:00
parent 3530ea5f28
commit 6636417d18
22 changed files with 1233 additions and 188 deletions

View file

@ -50,10 +50,29 @@
//! ```
use crate::component::Component;
use crate::components::cpu::intel_4004::Intel4004;
use crate::components::memory::intel_4001::Intel4001;
use crate::components::memory::intel_4002::Intel4002;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
/// CPU register data for display purposes
#[derive(Debug, Clone, Default)]
pub struct CpuRegisterData {
pub program_counter: u16,
pub accumulator: u8,
pub carry: bool,
pub stack_pointer: u8,
pub index_registers: [u8; 16], // Intel 4004 has 16 index registers (R0-R15)
}
/// RAM data for display purposes (chip name -> banks of nibbles)
pub type RamData = Vec<(String, Vec<Vec<u8>>)>;
/// ROM data for display purposes (chip name -> bytes)
pub type RomData = Vec<(String, Vec<u8>)>;
/// JSON-based system configuration structures
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SystemConfig {
@ -616,6 +635,95 @@ impl ConfigurableSystem {
println!("DEBUG: Program loading completed");
Ok(())
}
/// Get CPU register data from Intel 4004 CPU
/// Returns: CpuRegisterData if Intel 4004 CPU is found, None otherwise
pub fn get_cpu_register_data(&self) -> Option<CpuRegisterData> {
// Look for Intel 4004 CPU components
for (_name, component) in &self.components {
if let Ok(comp) = component.lock() {
// Try to downcast to Intel4004
if let Some(cpu) = comp.as_any().downcast_ref::<Intel4004>() {
let mut index_registers = [0u8; 16];
for i in 0..16 {
index_registers[i] = cpu.get_register(i as u8).unwrap_or(0);
}
return Some(CpuRegisterData {
program_counter: cpu.get_program_counter(),
accumulator: cpu.get_accumulator(),
carry: cpu.get_carry(),
stack_pointer: cpu.get_stack_pointer(),
index_registers,
});
}
}
}
None
}
/// Get RAM data from Intel 4002 RAM chips
/// Parameters: max_rows - Maximum number of rows to return per bank
/// Returns: Vector of (chip_name, banks) where each bank is a vector of nibbles
pub fn get_ram_data(&self, max_rows: usize) -> RamData {
let mut ram_data = Vec::new();
for (name, component) in &self.components {
if let Ok(comp) = component.lock() {
// Try to downcast to Intel4002
if let Some(ram) = comp.as_any().downcast_ref::<Intel4002>() {
let mut banks = Vec::new();
// Intel 4002 has 4 banks of 16 4-bit words each (64 nibbles total per chip)
// But actually it has 4 main memory registers, each with 16 4-bit characters
// and 4 status characters = 4 x 20 = 80 nibbles
for bank in 0..4 {
let mut bank_data = Vec::new();
// Read up to max_rows * 4 nibbles per bank
// The read_ram_direct takes a single address parameter
for addr in 0..(max_rows * 4).min(20) {
// Calculate the combined address for this bank and offset
let full_addr = (bank * 20 + addr) as u8;
// Use read_ram_direct to get the nibble at this address
let value = ram.read_ram_direct(full_addr).unwrap_or(0);
bank_data.push(value);
}
banks.push(bank_data);
}
ram_data.push((name.clone(), banks));
}
}
}
ram_data
}
/// Get ROM data from Intel 4001 ROM chips
/// Parameters: max_rows - Maximum number of bytes to return per chip
/// Returns: Vector of (chip_name, bytes)
pub fn get_rom_data(&self, max_rows: usize) -> RomData {
let mut rom_data = Vec::new();
for (name, component) in &self.components {
if let Ok(comp) = component.lock() {
// Try to downcast to Intel4001
if let Some(rom) = comp.as_any().downcast_ref::<Intel4001>() {
let mut data = Vec::new();
// Intel 4001 has 256 bytes of ROM
for addr in 0..max_rows.min(256) {
let value = rom.read_rom(addr as u8).unwrap_or(0);
data.push(value);
}
rom_data.push((name.clone(), data));
}
}
}
rom_data
}
}
#[derive(Debug, Clone)]