Syntax cleanup, fixed never-ending test suite (console in doc-test)

This commit is contained in:
Jan-Peter von Hunnius 2025-09-30 11:43:49 +02:00
parent f46cde7ef0
commit 3d4de8b268
11 changed files with 161 additions and 92 deletions

View file

@ -126,10 +126,14 @@ use rusty_emu::system_config::SystemFactory;
// Create system from JSON configuration // Create system from JSON configuration
let factory = SystemFactory::new(); let factory = SystemFactory::new();
let mut system = factory.create_from_json("configs/mcs4_basic.json") ?; let system = factory.create_from_json("configs/mcs4_basic.json") ?;
// Run simulation // Get system information
system.run(); let info = system.get_system_info();
println!("Created system: {} with {} components", info.name, info.component_count);
// Run simulation (in a real application)
// system.run();
``` ```
### Command Line Usage ### Command Line Usage

View file

@ -148,13 +148,17 @@ rom.update(); // Process one clock cycle
use rusty_emu::systems::intel_mcs_4::IntelMCS4; use rusty_emu::systems::intel_mcs_4::IntelMCS4;
// Create complete MCS-4 system // Create complete MCS-4 system
let mut system = IntelMCS4::new(); let system = IntelMCS4::new();
// Load program into ROM // Load program into ROM
system.load_program(0, & program_data) ?; system.load_program(0, & program_data) ?;
// Run simulation // Get system information
system.run(); let info = system.get_system_info();
println!("Loaded system: {} with {} components", info.name, info.component_count);
// Run simulation (in a real application)
// system.run();
``` ```
## Development Guidelines ## Development Guidelines

View file

@ -173,7 +173,6 @@ impl Component for GenericClock {
} }
} }
// Advanced clock features // Advanced clock features
impl GenericClock {} impl GenericClock {}

View file

@ -12,9 +12,7 @@ use crate::types::U12;
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Debug, Clone, Copy, PartialEq)]
enum InstructionPhase { enum InstructionPhase {
Fetch, // Fetching instruction from memory Fetch, // Fetching instruction from memory
Address, // Calculating or fetching address
Execute, // Executing the instruction Execute, // Executing the instruction
Wait, // Waiting for external operations
} }
/// Memory operation state machine states /// Memory operation state machine states
@ -32,13 +30,13 @@ enum MemoryState {
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Debug, Clone, Copy, PartialEq)]
enum Instruction { enum Instruction {
// Data Transfer Instructions (8) // Data Transfer Instructions (8)
Ldm(u8), // Load accumulator immediate (LDM #) Ldm(u8), // Load accumulator immediate (LDM #)
Ld(u8), // Load accumulator from register (LD R) Ld(u8), // Load accumulator from register (LD R)
Xch(u8), // Exchange accumulator with register (XCH R) Xch(u8), // Exchange accumulator with register (XCH R)
Add(u8), // Add register to accumulator (ADD R) Add(u8), // Add register to accumulator (ADD R)
Sub(u8), // Subtract register from accumulator (SUB R) Sub(u8), // Subtract register from accumulator (SUB R)
Inc(u8), // Increment register (INC R) Inc(u8), // Increment register (INC R)
Bbl(u8), // Branch back and load (BBL #) Bbl(u8), // Branch back and load (BBL #)
// Arithmetic Instructions (4) // Arithmetic Instructions (4)
AddC(u8), // Add register with carry (ADC R) AddC(u8), // Add register with carry (ADC R)
@ -594,7 +592,8 @@ impl Intel4004 {
let data = self.data_latch; let data = self.data_latch;
self.write_data_bus(data); self.write_data_bus(data);
if self.cycle_count % 1000 == 0 { // Log every 1000 cycles if self.cycle_count % 1000 == 0 {
// Log every 1000 cycles
println!("DEBUG: [{}] CPU State | PC: 0x{:03X} | Cycles: {} | ACC: 0x{:X} | SYNC: {} | CM_ROM: {} | CM_RAM: {} | RAM_Ready: {}", println!("DEBUG: [{}] CPU State | PC: 0x{:03X} | Cycles: {} | ACC: 0x{:X} | SYNC: {} | CM_ROM: {} | CM_RAM: {} | RAM_Ready: {}",
self.base.name(), self.program_counter.value(), self.cycle_count, self.accumulator, sync, cm_rom, cm_ram, self.full_address_ready); self.base.name(), self.program_counter.value(), self.cycle_count, self.accumulator, sync, cm_rom, cm_ram, self.full_address_ready);
} }
@ -928,22 +927,22 @@ impl Intel4004 {
Instruction::Jcn(condition, addr) => { Instruction::Jcn(condition, addr) => {
// Decode condition bits properly // Decode condition bits properly
let should_jump = match condition & 0x0F { let should_jump = match condition & 0x0F {
0x0 => !self.carry && self.accumulator != 0, // JNT (Jump if no carry and ACC != 0) 0x0 => !self.carry && self.accumulator != 0, // JNT (Jump if no carry and ACC != 0)
0x1 => self.carry, // JC (Jump if carry) 0x1 => self.carry, // JC (Jump if carry)
0x2 => self.accumulator == 0, // JZ (Jump if zero) 0x2 => self.accumulator == 0, // JZ (Jump if zero)
0x3 => self.accumulator != 0, // JNZ (Jump if not zero) 0x3 => self.accumulator != 0, // JNZ (Jump if not zero)
0x4 => true, // JUN (Jump unconditional) 0x4 => true, // JUN (Jump unconditional)
0x5 => false, // Always false 0x5 => false, // Always false
0x6 => true, // Always true 0x6 => true, // Always true
0x7 => false, // Always false 0x7 => false, // Always false
0x8 => true, // Always true 0x8 => true, // Always true
0x9 => false, // Always false 0x9 => false, // Always false
0xA => true, // Always true 0xA => true, // Always true
0xB => false, // Always false 0xB => false, // Always false
0xC => true, // Always true 0xC => true, // Always true
0xD => false, // Always false 0xD => false, // Always false
0xE => true, // Always true 0xE => true, // Always true
0xF => false, // Always false 0xF => false, // Always false
_ => false, _ => false,
}; };
@ -994,15 +993,20 @@ impl Intel4004 {
Instruction::Wrm => { Instruction::Wrm => {
// Write accumulator to RAM at current RAM address // Write accumulator to RAM at current RAM address
// This would interface with RAM chips - for now, just log // This would interface with RAM chips - for now, just log
println!("DEBUG: [CPU] WRM - Write ACC 0x{:X} to RAM address 0x{:02X}", println!(
self.accumulator, self.address_latch); "DEBUG: [CPU] WRM - Write ACC 0x{:X} to RAM address 0x{:02X}",
self.accumulator, self.address_latch
);
self.program_counter.inc(); self.program_counter.inc();
} }
Instruction::Wmp => { Instruction::Wmp => {
// Write memory pointer - set RAM address from accumulator // Write memory pointer - set RAM address from accumulator
self.address_latch = self.accumulator; self.address_latch = self.accumulator;
println!("DEBUG: [CPU] WMP - Set RAM address to 0x{:02X}", self.address_latch); println!(
"DEBUG: [CPU] WMP - Set RAM address to 0x{:02X}",
self.address_latch
);
self.program_counter.inc(); self.program_counter.inc();
} }
@ -1021,19 +1025,28 @@ impl Intel4004 {
Instruction::Adm => { Instruction::Adm => {
// Add from memory - add RAM data to accumulator // Add from memory - add RAM data to accumulator
// This would read from RAM and add to accumulator // This would read from RAM and add to accumulator
println!("DEBUG: [CPU] ADM - Add from RAM address 0x{:02X}", self.address_latch); println!(
"DEBUG: [CPU] ADM - Add from RAM address 0x{:02X}",
self.address_latch
);
self.program_counter.inc(); self.program_counter.inc();
} }
Instruction::Sbm => { Instruction::Sbm => {
// Subtract from memory - subtract RAM data from accumulator // Subtract from memory - subtract RAM data from accumulator
println!("DEBUG: [CPU] SBM - Subtract from RAM address 0x{:02X}", self.address_latch); println!(
"DEBUG: [CPU] SBM - Subtract from RAM address 0x{:02X}",
self.address_latch
);
self.program_counter.inc(); self.program_counter.inc();
} }
Instruction::Rdm => { Instruction::Rdm => {
// Read memory - read RAM data to accumulator // Read memory - read RAM data to accumulator
println!("DEBUG: [CPU] RDM - Read from RAM address 0x{:02X}", self.address_latch); println!(
"DEBUG: [CPU] RDM - Read from RAM address 0x{:02X}",
self.address_latch
);
self.program_counter.inc(); self.program_counter.inc();
} }
@ -1181,8 +1194,10 @@ impl Intel4004 {
self.execute_instruction(); self.execute_instruction();
let new_pc = self.program_counter.value(); let new_pc = self.program_counter.value();
println!("DEBUG: [TEST] Single Execute | PC: 0x{:03X} -> 0x{:03X} | ACC: 0x{:X}", println!(
old_pc, new_pc, self.accumulator); "DEBUG: [TEST] Single Execute | PC: 0x{:03X} -> 0x{:03X} | ACC: 0x{:X}",
old_pc, new_pc, self.accumulator
);
} }
} }
@ -1200,7 +1215,11 @@ impl Intel4004 {
} }
} }
println!("DEBUG: [{}] Loaded test program: {:02X?}", self.base.name(), program); println!(
"DEBUG: [{}] Loaded test program: {:02X?}",
self.base.name(),
program
);
} }
} }
@ -1283,9 +1302,9 @@ mod tests {
// Test XCH (exchange with register 1) - 0x11 = XCH 1 // Test XCH (exchange with register 1) - 0x11 = XCH 1
cpu.current_op = Instruction::Xch(1); cpu.current_op = Instruction::Xch(1);
cpu.execute_instruction(); cpu.execute_instruction();
assert_eq!(cpu.get_accumulator(), 0x05); // ACC gets R1's value assert_eq!(cpu.get_accumulator(), 0x05); // ACC gets R1's value
assert_eq!(cpu.get_register(0).unwrap(), 0x0A); // R0 gets old ACC value assert_eq!(cpu.get_register(0).unwrap(), 0x0A); // R0 gets old ACC value
assert_eq!(cpu.get_register(1).unwrap(), 0x0A); // R1 gets new ACC value assert_eq!(cpu.get_register(1).unwrap(), 0x0A); // R1 gets new ACC value
println!("DEBUG: Register operations test completed successfully"); println!("DEBUG: Register operations test completed successfully");
} }
@ -1518,10 +1537,6 @@ impl Component for Intel4004 {
} }
} }
} }
_ => {
// Other phases handled by memory operations
}
} }
self.cycle_count += 1; self.cycle_count += 1;

View file

@ -1062,18 +1062,25 @@ mod tests {
} }
// Debug: Check pin states before update // Debug: Check pin states before update
println!("DEBUG: Before update - SYNC: {:?}, CM: {:?}, CI: {:?}, PHI1: {:?}", println!(
sync_pin.lock().unwrap().read(), "DEBUG: Before update - SYNC: {:?}, CM: {:?}, CI: {:?}, PHI1: {:?}",
cm_pin.lock().unwrap().read(), sync_pin.lock().unwrap().read(),
ci_pin.lock().unwrap().read(), cm_pin.lock().unwrap().read(),
phi1_pin.lock().unwrap().read()); ci_pin.lock().unwrap().read(),
phi1_pin.lock().unwrap().read()
);
// Debug: Check conditions that would trigger memory operation // Debug: Check conditions that would trigger memory operation
let sync = rom.read_sync_pin(); let sync = rom.read_sync_pin();
let chip_select = rom.read_cm_rom_pin(); let chip_select = rom.read_cm_rom_pin();
let io_select = rom.read_ci_pin(); let io_select = rom.read_ci_pin();
println!("DEBUG: Conditions - sync: {}, chip_select: {}, io_select: {}, combined: {}", println!(
sync, chip_select, io_select, sync && chip_select && !io_select); "DEBUG: Conditions - sync: {}, chip_select: {}, io_select: {}, combined: {}",
sync,
chip_select,
io_select,
sync && chip_select && !io_select
);
// Debug: Check edge detection // Debug: Check edge detection
println!("DEBUG: Before update - prev_phi1: {:?}", rom.prev_phi1); println!("DEBUG: Before update - prev_phi1: {:?}", rom.prev_phi1);
@ -1084,8 +1091,10 @@ mod tests {
// Debug: Check edge detection logic manually // Debug: Check edge detection logic manually
let phi1_rising = read_phi1 == PinValue::High && rom.prev_phi1 == PinValue::Low; let phi1_rising = read_phi1 == PinValue::High && rom.prev_phi1 == PinValue::Low;
println!("DEBUG: Manual edge detection - PHI1: {:?}, prev_phi1: {:?}, rising: {}", println!(
read_phi1, rom.prev_phi1, phi1_rising); "DEBUG: Manual edge detection - PHI1: {:?}, prev_phi1: {:?}, rising: {}",
read_phi1, rom.prev_phi1, phi1_rising
);
// Update to process Φ1 rising edge // Update to process Φ1 rising edge
rom.update(); rom.update();

View file

@ -583,8 +583,13 @@ impl Intel4002 {
if self.address_high_nibble.is_none() { if self.address_high_nibble.is_none() {
self.address_high_nibble = Some(nibble); self.address_high_nibble = Some(nibble);
println!("DEBUG: [{}] Addr Latch High | Nibble: 0x{:X} | State: {:?} | Cycles: {}", println!(
self.base.name(), nibble, self.ram_state, self.get_cycle_count()); "DEBUG: [{}] Addr Latch High | Nibble: 0x{:X} | State: {:?} | Cycles: {}",
self.base.name(),
nibble,
self.ram_state,
self.get_cycle_count()
);
} else if self.address_low_nibble.is_none() { } else if self.address_low_nibble.is_none() {
self.address_low_nibble = Some(nibble); self.address_low_nibble = Some(nibble);
println!("DEBUG: [{}] Addr Latch Low | High: 0x{:X} | Low: 0x{:X} | State: {:?} | Cycles: {}", println!("DEBUG: [{}] Addr Latch Low | High: 0x{:X} | Low: 0x{:X} | State: {:?} | Cycles: {}",
@ -766,7 +771,8 @@ impl Component for Intel4002 {
static mut CYCLE_COUNTER: u64 = 0; static mut CYCLE_COUNTER: u64 = 0;
unsafe { unsafe {
CYCLE_COUNTER += 1; CYCLE_COUNTER += 1;
if CYCLE_COUNTER % 5000 == 0 { // Less frequent than CPU to avoid spam if CYCLE_COUNTER % 5000 == 0 {
// Less frequent than CPU to avoid spam
println!("DEBUG: [{}] RAM State | Bank: {} | Status: {:?} | Ready: {} | LastAddr: 0x{:02X} | Cycles: {} | HighNib: {:?} | LowNib: {:?}", println!("DEBUG: [{}] RAM State | Bank: {} | Status: {:?} | Ready: {} | LastAddr: 0x{:02X} | Cycles: {} | HighNib: {:?} | LowNib: {:?}",
self.base.name(), self.bank_select, self.ram_state, self.full_address_ready, self.last_address, self.get_cycle_count(), self.address_high_nibble, self.address_low_nibble); self.base.name(), self.bank_select, self.ram_state, self.full_address_ready, self.last_address, self.get_cycle_count(), self.address_high_nibble, self.address_low_nibble);
} }
@ -1161,17 +1167,27 @@ mod tests {
} }
// Debug: Check pin states before first update // Debug: Check pin states before first update
println!("DEBUG: Before first update - SYNC: {:?}, P0: {:?}, PHI1: {:?}", println!(
sync_pin.lock().unwrap().read(), "DEBUG: Before first update - SYNC: {:?}, P0: {:?}, PHI1: {:?}",
p0_pin.lock().unwrap().read(), sync_pin.lock().unwrap().read(),
phi1_pin.lock().unwrap().read()); p0_pin.lock().unwrap().read(),
phi1_pin.lock().unwrap().read()
);
// Debug: Check conditions that would trigger RAM operation // Debug: Check conditions that would trigger RAM operation
let (sync, _cm, p0, _) = ram.read_control_pins(); let (sync, _cm, p0, _) = ram.read_control_pins();
println!("DEBUG: Control pins - sync: {}, p0: {}, combined: {}", sync, p0, sync && p0); println!(
"DEBUG: Control pins - sync: {}, p0: {}, combined: {}",
sync,
p0,
sync && p0
);
// Debug: Check initial clock state // Debug: Check initial clock state
println!("DEBUG: Before first update - prev_phi1: {:?}", ram.prev_phi1); println!(
"DEBUG: Before first update - prev_phi1: {:?}",
ram.prev_phi1
);
// High nibble // High nibble
phi1_pin phi1_pin
@ -1207,8 +1223,10 @@ mod tests {
} }
// Debug: Check state before low nibble // Debug: Check state before low nibble
println!("DEBUG: Before low nibble - High: {:?}, Low: {:?}, Ready: {}", println!(
ram.address_high_nibble, ram.address_low_nibble, ram.full_address_ready); "DEBUG: Before low nibble - High: {:?}, Low: {:?}, Ready: {}",
ram.address_high_nibble, ram.address_low_nibble, ram.full_address_ready
);
// Low nibble // Low nibble
phi1_pin phi1_pin
@ -1218,8 +1236,10 @@ mod tests {
ram.update(); // rising edge -> latch low nibble ram.update(); // rising edge -> latch low nibble
// Debug: Check state after low nibble // Debug: Check state after low nibble
println!("DEBUG: After low nibble - High: {:?}, Low: {:?}, Ready: {}", println!(
ram.address_high_nibble, ram.address_low_nibble, ram.full_address_ready); "DEBUG: After low nibble - High: {:?}, Low: {:?}, Ready: {}",
ram.address_high_nibble, ram.address_low_nibble, ram.full_address_ready
);
phi1_pin phi1_pin
.lock() .lock()

View file

@ -414,7 +414,9 @@ impl ConsoleApp {
Line::from(vec![Span::raw("Status: Running (check console output)")]), Line::from(vec![Span::raw("Status: Running (check console output)")]),
Line::from(vec![Span::raw("PC: 0x000 (see DEBUG output)")]), Line::from(vec![Span::raw("PC: 0x000 (see DEBUG output)")]),
Line::from(vec![Span::raw("ACC: 0x0 (see DEBUG output)")]), Line::from(vec![Span::raw("ACC: 0x0 (see DEBUG output)")]),
Line::from(vec![Span::raw("Instructions: Executing (see DEBUG output)")]), Line::from(vec![Span::raw(
"Instructions: Executing (see DEBUG output)",
)]),
]; ];
let register_widget = Paragraph::new(register_info) let register_widget = Paragraph::new(register_info)

View file

@ -33,7 +33,6 @@ use std::sync::{Arc, Mutex};
use std::thread; use std::thread;
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
fn main() { fn main() {
// Parse command line arguments // Parse command line arguments
let args: Vec<String> = env::args().collect(); let args: Vec<String> = env::args().collect();
@ -255,9 +254,9 @@ fn create_system(system_type: &str, program_data: &[u8]) -> Result<ConfigurableS
_ => { _ => {
// Try to use provided config file directly // Try to use provided config file directly
if system_type.ends_with(".json") { if system_type.ends_with(".json") {
let mut system = factory let mut system = factory.create_from_json(system_type).map_err(|e| {
.create_from_json(system_type) format!("Failed to create system from '{}': {}", system_type, e)
.map_err(|e| format!("Failed to create system from '{}': {}", system_type, e))?; })?;
// Load program data into ROM components // Load program data into ROM components
system.load_program_data(program_data)?; system.load_program_data(program_data)?;

View file

@ -17,10 +17,11 @@
//! //!
//! // Create system from JSON configuration //! // Create system from JSON configuration
//! let factory = SystemFactory::new(); //! let factory = SystemFactory::new();
//! let mut system = factory.create_from_json("configs/mcs4_basic.json").expect("Could not create JSON test!"); //! let system = factory.create_from_json("configs/mcs4_basic.json").expect("Could not create system!");
//! //!
//! // Run the configured system //! // Get system information
//! system.run(); //! let info = system.get_system_info();
//! println!("Created system: {} with {} components", info.name, info.component_count);
//! ``` //! ```
//! //!
//! ## Configuration File Format //! ## Configuration File Format
@ -174,7 +175,9 @@ impl SystemFactory {
.and_then(|v| v.as_f64()) .and_then(|v| v.as_f64())
.unwrap_or(750000.0); .unwrap_or(750000.0);
Ok(Box::new( Ok(Box::new(
crate::components::clock::two_phase_clock::TwoPhaseClock::new(name, frequency), crate::components::clock::two_phase_clock::TwoPhaseClock::new(
name, frequency,
),
)) ))
} else { } else {
Err("Two-phase clock must be single component".to_string()) Err("Two-phase clock must be single component".to_string())
@ -439,9 +442,13 @@ impl ConfigurableSystem {
break; break;
} }
if i % 5 == 0 { // Show header every 5 cycles if i % 5 == 0 {
// Show header every 5 cycles
println!("\n┌─────────────────────────────────────────────────────────────┐"); println!("\n┌─────────────────────────────────────────────────────────────┐");
println!("│ CYCLE {:2} │", i); println!(
"│ CYCLE {:2} │",
i
);
println!("└─────────────────────────────────────────────────────────────┘"); println!("└─────────────────────────────────────────────────────────────┘");
} }
self.display_current_state(); self.display_current_state();
@ -494,10 +501,12 @@ impl ConfigurableSystem {
if let Some(cpu_component) = self.components.get("CPU_4004") { if let Some(cpu_component) = self.components.get("CPU_4004") {
if let Ok(_cpu) = cpu_component.lock() { if let Ok(_cpu) = cpu_component.lock() {
println!("│ CPU State: │"); println!("│ CPU State: │");
println!("│ Accumulator: 0x{:X} Carry: {} PC: 0x{:03X} │", println!(
0, // Placeholder - would need CPU-specific method "│ Accumulator: 0x{:X} Carry: {} PC: 0x{:03X} │",
0, // Placeholder - would need CPU-specific method
false, // Placeholder - would need CPU-specific method false, // Placeholder - would need CPU-specific method
0); // Placeholder - would need CPU-specific method 0
); // Placeholder - would need CPU-specific method
} }
} }
@ -509,11 +518,16 @@ impl ConfigurableSystem {
} }
// Component status summary // Component status summary
let running_count = self.components.values() let running_count = self
.components
.values()
.filter(|comp| comp.lock().map_or(false, |c| c.is_running())) .filter(|comp| comp.lock().map_or(false, |c| c.is_running()))
.count(); .count();
println!("│ Components: {}/{} running │", println!(
running_count, self.components.len()); "│ Components: {}/{} running │",
running_count,
self.components.len()
);
println!("└─────────────────────────────────────────────────────────────┘"); println!("└─────────────────────────────────────────────────────────────┘");
} }
@ -559,7 +573,10 @@ impl ConfigurableSystem {
/// Parameters: program_data - Binary program data to load /// Parameters: program_data - Binary program data to load
/// Returns: Ok(()) on success, Err(String) on failure /// Returns: Ok(()) on success, Err(String) on failure
pub fn load_program_data(&mut self, program_data: &[u8]) -> Result<(), String> { pub fn load_program_data(&mut self, program_data: &[u8]) -> Result<(), String> {
println!("DEBUG: Loading {} bytes of program data into ROM components", program_data.len()); println!(
"DEBUG: Loading {} bytes of program data into ROM components",
program_data.len()
);
// Load program data into ROM_4001_1 (first 256 bytes) // Load program data into ROM_4001_1 (first 256 bytes)
if let Some(rom1_component) = self.components.get_mut("ROM_4001_1") { if let Some(rom1_component) = self.components.get_mut("ROM_4001_1") {

View file

@ -53,8 +53,8 @@ impl Intel400xAddressHandling for MockComponent {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::thread;
use super::*; use super::*;
use std::thread;
#[test] #[test]
fn test_timing_constants() { fn test_timing_constants() {