Added debug output

Added GUI
This commit is contained in:
Jan-Peter von Hunnius 2025-10-03 11:44:55 +02:00
parent 3d4de8b268
commit e17d6ad177
18 changed files with 3137 additions and 162 deletions

View file

@ -140,6 +140,17 @@ impl Component for TwoPhaseClock {
self.update_outputs();
if self.should_transition() {
// Reduced debug output - only show occasional transitions
static mut TRANSITION_COUNT: u32 = 0;
unsafe {
TRANSITION_COUNT += 1;
if TRANSITION_COUNT % 1000 == 0 {
println!(
"DEBUG: [CLOCK] Transitioning - PHI1: {:?} -> PHI2: {:?} (cycle {})",
self.phi1_state, self.phi2_state, TRANSITION_COUNT
);
}
}
self.perform_transition();
}
}

View file

@ -218,11 +218,22 @@ pub trait Intel400xControlPins {
fn read_sync_pin(&self) -> bool {
if let Ok(pin) = self.get_base().get_pin("SYNC") {
if let Ok(pin_guard) = pin.lock() {
pin_guard.read() == PinValue::High
let value = pin_guard.read() == PinValue::High;
if value {
println!(
"DEBUG: [COMMON] SYNC pin is HIGH for {}",
self.get_base().name()
);
}
value
} else {
false
}
} else {
println!(
"DEBUG: [COMMON] SYNC pin not found for {}",
self.get_base().name()
);
false
}
}

View file

@ -143,14 +143,13 @@ impl Intel4004 {
/// Returns: New Intel4004 instance with initialized state
pub fn new(name: String, clock_speed: f64) -> Self {
let pin_names = vec![
"D0", "D1", "D2", "D3", // Data bus pins
"SYNC", // Sync signal
"CM_ROM", // ROM chip select
"CM_RAM", // RAM chip select
"TEST", // Test pin
"RESET", // Reset
"PHI1", // Clock phase 1
"PHI2", // Clock phase 2
"D0", "D1", "D2", "D3", // Data bus pins
"SYNC", // Sync signal
"CM", // Chip select for memory
"TEST", // Test pin
"RESET", // Reset
"PHI1", // Clock phase 1
"PHI2", // Clock phase 2
];
let pins = BaseComponent::create_pin_map(&pin_names, &name);
@ -224,8 +223,7 @@ impl Intel4004 {
self.full_address_ready = false;
self.set_sync(false);
self.set_cm_rom(false);
self.set_cm_ram(false);
self.set_cm(false);
self.tri_state_data_bus();
}
@ -291,21 +289,10 @@ impl Intel4004 {
}
}
/// Set the CM-ROM (Chip Select ROM) pin state
/// Set the CM (Chip Select) pin state
/// Parameters: high - true for high voltage, false for low voltage
fn set_cm_rom(&self, high: bool) {
if let Ok(pin) = self.base.get_pin("CM_ROM") {
if let Ok(mut pin_guard) = pin.lock() {
let value = if high { PinValue::High } else { PinValue::Low };
pin_guard.set_driver(Some(self.base.get_name().parse().unwrap()), value);
}
}
}
/// Set the CM-RAM (Chip Select RAM) pin state
/// Parameters: high - true for high voltage, false for low voltage
fn set_cm_ram(&self, high: bool) {
if let Ok(pin) = self.base.get_pin("CM_RAM") {
fn set_cm(&self, high: bool) {
if let Ok(pin) = self.base.get_pin("CM") {
if let Ok(mut pin_guard) = pin.lock() {
let value = if high { PinValue::High } else { PinValue::Low };
pin_guard.set_driver(Some(self.base.get_name().parse().unwrap()), value);
@ -314,8 +301,8 @@ impl Intel4004 {
}
/// Read the state of all control pins
/// Returns: (sync, cm_rom, cm_ram, test) - State of control signals
fn read_control_pins(&self) -> (bool, bool, bool, bool) {
/// Returns: (sync, cm, test) - State of control signals
fn read_control_pins(&self) -> (bool, bool, bool) {
let sync = if let Ok(pin) = self.base.get_pin("SYNC") {
if let Ok(pin_guard) = pin.lock() {
pin_guard.read() == PinValue::High
@ -326,17 +313,7 @@ impl Intel4004 {
false
};
let cm_rom = if let Ok(pin) = self.base.get_pin("CM_ROM") {
if let Ok(pin_guard) = pin.lock() {
pin_guard.read() == PinValue::High
} else {
false
}
} else {
false
};
let cm_ram = if let Ok(pin) = self.base.get_pin("CM_RAM") {
let cm = if let Ok(pin) = self.base.get_pin("CM") {
if let Ok(pin_guard) = pin.lock() {
pin_guard.read() == PinValue::High
} else {
@ -356,7 +333,7 @@ impl Intel4004 {
false
};
(sync, cm_rom, cm_ram, test)
(sync, cm, test)
}
/// Read the two-phase clock pins from CPU
@ -394,9 +371,13 @@ impl Intel4004 {
self.handle_reset();
// Check for memory operation start on Φ1 rising edge with SYNC high
let (sync, cm_rom, cm_ram, _) = self.read_control_pins();
if sync && (cm_rom || cm_ram) {
let (sync, cm, _) = self.read_control_pins();
if sync && cm {
// Start memory address phase on Φ1 rising edge
println!(
"DEBUG: [CPU] Starting memory operation - SYNC: {}, CM: {}",
sync, cm
);
self.start_memory_address_phase();
}
@ -584,18 +565,18 @@ impl Intel4004 {
/// Handle data driving during DriveData state
fn handle_data_driving(&mut self) {
let (sync, cm_rom, cm_ram, _) = self.read_control_pins();
let (sync, cm, _) = self.read_control_pins();
// Memory read: SYNC=1, (CM_ROM=1 or CM_RAM=1), valid address
if sync && (cm_rom || cm_ram) && self.full_address_ready {
// Memory read: SYNC=1, CM=1, valid address
if sync && cm && self.full_address_ready {
// All conditions met: drive data on bus
let data = self.data_latch;
self.write_data_bus(data);
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: {}",
self.base.name(), self.program_counter.value(), self.cycle_count, self.accumulator, sync, cm_rom, cm_ram, self.full_address_ready);
println!("DEBUG: [{}] CPU State | PC: 0x{:03X} | Cycles: {} | ACC: 0x{:X} | SYNC: {} | CM: {} | Ready: {}",
self.base.name(), self.program_counter.value(), self.cycle_count, self.accumulator, sync, cm, self.full_address_ready);
}
} else {
// Conditions not met, tri-state
@ -1090,7 +1071,7 @@ impl Intel4004 {
// Jump on Test Instructions
Instruction::Jnt(addr) => {
// Jump if test pin is high
let (_, _, _, test) = self.read_control_pins();
let (_, _, test) = self.read_control_pins();
if test {
self.program_counter.set(addr);
} else {
@ -1100,7 +1081,7 @@ impl Intel4004 {
Instruction::JntInvert(addr) => {
// Jump if test pin is low (inverted)
let (_, _, _, test) = self.read_control_pins();
let (_, _, test) = self.read_control_pins();
if !test {
self.program_counter.set(addr);
} else {
@ -1432,32 +1413,85 @@ impl Component for Intel4004 {
self.prev_phi2 = phi2;
if phi1_rising {
// Reduced debug output - only show occasional cycles
static mut CYCLE_COUNT: u32 = 0;
unsafe {
CYCLE_COUNT += 1;
if CYCLE_COUNT % 1000 == 0 {
let (sync, cm, _) = self.read_control_pins();
println!("DEBUG: [CPU] Φ1 Rising Edge - PC: 0x{:03X}, ACC: 0x{:X}, Phase: {:?}, SYNC: {}, CM: {} (cycle {})",
self.program_counter.value(), self.accumulator, self.instruction_phase, sync, cm, CYCLE_COUNT);
}
}
self.handle_phi1_rising();
}
if phi1_falling {
// Φ1 Falling Edge: End of address phase
// Reduced debug output - only show occasional cycles
static mut CYCLE_COUNT: u32 = 0;
unsafe {
CYCLE_COUNT += 1;
if CYCLE_COUNT % 1000 == 0 {
println!("DEBUG: [CPU] Φ1 Falling Edge (cycle {})", CYCLE_COUNT);
}
}
self.handle_phi1_falling();
}
if phi2_rising {
// Φ2 Rising Edge: Data phase (peripherals drive bus) - handle data operations
// Reduced debug output - only show occasional cycles
static mut CYCLE_COUNT: u32 = 0;
unsafe {
CYCLE_COUNT += 1;
if CYCLE_COUNT % 1000 == 0 {
println!(
"DEBUG: [CPU] Φ2 Rising Edge - Memory State: {:?} (cycle {})",
self.memory_state, CYCLE_COUNT
);
}
}
self.handle_phi2_rising();
}
if phi2_falling {
// Φ2 Falling Edge: End of data phase - tri-state bus and return to idle
// Reduced debug output - only show occasional cycles
static mut CYCLE_COUNT: u32 = 0;
unsafe {
CYCLE_COUNT += 1;
if CYCLE_COUNT % 1000 == 0 {
println!("DEBUG: [CPU] Φ2 Falling Edge (cycle {})", CYCLE_COUNT);
}
}
self.handle_phi2_falling();
}
// Handle instruction execution during appropriate phases
// Set SYNC signal during fetch phase to initiate memory read
if self.instruction_phase == InstructionPhase::Fetch {
self.set_sync(true);
self.set_cm(true);
println!("DEBUG: [CPU] Setting signals - SYNC: HIGH, CM: HIGH");
} else {
self.set_sync(false);
println!("DEBUG: [CPU] Setting SYNC: LOW");
}
println!(
"DEBUG: [CPU] Instruction phase: {:?}, PC: 0x{:03X}, State: {:?}",
self.instruction_phase,
self.program_counter.value(),
self.memory_state
);
match self.instruction_phase {
InstructionPhase::Fetch => {
// Check if we're waiting for an operand (two-instruction format)
if let Instruction::JunHigh(_) | Instruction::JmsHigh(_) = self.current_op {
// Waiting for operand - fetch it
let (sync, cm_rom, cm_ram, _) = self.read_control_pins();
if sync && cm_rom && !cm_ram {
let (sync, cm, _) = self.read_control_pins();
if sync && cm {
if self.memory_state == MemoryState::DriveData {
let operand = self.read_data_bus();
self.program_counter.inc(); // Advance PC after fetching operand
@ -1484,9 +1518,14 @@ impl Component for Intel4004 {
}
} else {
// Normal instruction fetch
let (sync, cm_rom, cm_ram, _) = self.read_control_pins();
if sync && cm_rom && !cm_ram {
// ROM access - fetch instruction
let (sync, cm, _) = self.read_control_pins();
println!(
"DEBUG: [CPU] Normal fetch - SYNC: {}, CM: {}, State: {:?}",
sync, cm, self.memory_state
);
if sync && cm {
// Memory access - fetch instruction
println!("DEBUG: [CPU] Fetching instruction from memory - PC: 0x{:03X}, State: {:?}", self.program_counter.value(), self.memory_state);
if self.memory_state == MemoryState::DriveData {
let instruction = self.read_data_bus();
self.current_instruction = instruction;
@ -1529,9 +1568,15 @@ impl Component for Intel4004 {
self.execute_instruction();
let new_pc = self.program_counter.value();
// Debug: Show instruction execution details
println!("DEBUG: [CPU] Executed {:?} | PC: 0x{:03X} -> 0x{:03X} | ACC: 0x{:X} | RAM_Ready: {}",
self.current_op, old_pc, new_pc, self.accumulator, self.full_address_ready);
// Debug: Show instruction execution details (reduced frequency)
static mut EXEC_COUNT: u32 = 0;
unsafe {
EXEC_COUNT += 1;
if EXEC_COUNT % 10 == 0 {
println!("DEBUG: [CPU] Executed {:?} | PC: 0x{:03X} -> 0x{:03X} | ACC: 0x{:X} | RAM_Ready: {}",
self.current_op, old_pc, new_pc, self.accumulator, self.full_address_ready);
}
}
self.instruction_phase = InstructionPhase::Fetch;
}
@ -1551,7 +1596,7 @@ impl Component for Intel4004 {
while self.is_running() {
self.update();
thread::sleep(Duration::from_micros(10));
thread::sleep(Duration::from_micros(1));
}
}
@ -1561,8 +1606,7 @@ impl Component for Intel4004 {
self.base.set_running(false);
self.tri_state_data_bus();
self.set_sync(false);
self.set_cm_rom(false);
self.set_cm_ram(false);
self.set_cm(false);
}
fn is_running(&self) -> bool {

View file

@ -291,9 +291,23 @@ impl Intel4001 {
let chip_select = self.read_cm_rom_pin();
let io_select = self.read_ci_pin();
println!(
"DEBUG: [ROM] Checking memory access - SYNC: {}, CM: {}, CI: {}",
sync, chip_select, io_select
);
if sync && chip_select && !io_select {
// Start memory address phase on Φ1 rising edge (ROM access)
println!(
"DEBUG: [ROM] Starting memory address phase - SYNC: {}, CM: {}, CI: {}",
sync, chip_select, io_select
);
self.start_memory_address_phase();
} else {
println!(
"DEBUG: [ROM] Memory access conditions not met - SYNC: {}, CM: {}, CI: {}",
sync, chip_select, io_select
);
}
// Handle I/O operations (higher priority than memory operations)
@ -512,59 +526,32 @@ impl Intel4001 {
/// Hardware-accurate: Φ2 is when peripherals drive data, so we handle data driving
/// Focus: Data driving operations
fn handle_memory_data_operations(&mut self) {
println!(
"DEBUG: {} - handle_memory_data_operations: state={:?}, address_ready={}",
self.base.name(),
self.memory_state,
self.full_address_ready
);
// Reduced debug output - only show when actually driving data
match self.memory_state {
MemoryState::Idle => {
// During data phase, idle state means tri-state the bus
println!("DEBUG: {} - In Idle state, tri-stating", self.base.name());
self.tri_state_data_bus();
}
MemoryState::AddressPhase => {
// Address phase should be handled by Φ1, not Φ2
// Tri-state bus during wrong phase
println!(
"DEBUG: {} - In AddressPhase during Φ2, tri-stating",
self.base.name()
);
self.tri_state_data_bus();
}
MemoryState::WaitLatency => {
// Address latched, waiting for access latency
// Check if latency has elapsed and we can transition to data phase
println!(
"DEBUG: {} - In WaitLatency, checking latency",
self.base.name()
);
self.handle_latency_wait();
// If we transitioned to DriveData, handle data driving
if self.memory_state == MemoryState::DriveData {
println!(
"DEBUG: {} - Transitioned to DriveData, calling handle_data_driving",
self.base.name()
);
self.handle_data_driving();
} else {
println!(
"DEBUG: {} - Still in WaitLatency after handle_latency_wait",
self.base.name()
);
}
}
MemoryState::DriveData => {
// Latency elapsed, drive data on bus during Φ2
// Data will remain on bus until Φ2 falling edge
println!(
"DEBUG: {} - In DriveData state, calling handle_data_driving",
self.base.name()
);
self.handle_data_driving();
}
}
@ -630,27 +617,11 @@ impl Intel4001 {
fn handle_latency_wait(&mut self) {
if let Some(latch_time) = self.address_latch_time {
let elapsed = latch_time.elapsed();
println!(
"DEBUG: {} - handle_latency_wait: elapsed={:?}, access_time={:?}, ready={}",
self.base.get_name(),
elapsed,
self.access_time,
self.full_address_ready
);
if elapsed >= self.access_time {
// Latency elapsed, transition to data driving
// Data will be driven on next Φ2 rising edge
println!(
"DEBUG: {} - Latency elapsed, transitioning to DriveData",
self.base.get_name()
);
self.start_data_driving();
}
} else {
println!(
"DEBUG: {} - handle_latency_wait: no latch_time set",
self.base.get_name()
);
}
}
@ -668,15 +639,6 @@ impl Intel4001 {
let chip_select = self.read_cm_rom_pin();
let io_select = self.read_ci_pin();
println!(
"DEBUG: {} - handle_data_driving: SYNC={}, CM={}, CI={}, Address_Ready={}",
self.base.name(),
sync,
chip_select,
io_select,
self.full_address_ready
);
// Memory read: CM=1 (chip_select), CI=0 (!io_select), valid address
if sync && chip_select && !io_select && self.full_address_ready {
// All conditions met: drive data on bus
@ -684,33 +646,14 @@ impl Intel4001 {
let address = self.last_address;
if (address as usize) < self.memory.len() {
let data = self.memory[address as usize];
println!(
"DEBUG: {} - All conditions met, driving data 0x{:x} to address 0x{:x}",
self.base.name(),
data,
address
);
self.write_data_bus(data);
// Note: Don't call return_to_idle() here - wait for Φ2 falling edge
} else {
// Invalid address, tri-state
println!(
"DEBUG: {} - Invalid address 0x{:x}, tri-stating",
self.base.name(),
address
);
self.tri_state_data_bus();
}
} else {
// Bus contention guard: ROM should not drive when conditions not met
// In real hardware, this would cause a short if CPU is still driving
if self.full_address_ready {
println!("DEBUG: {} - Bus contention detected! ROM attempting to drive data bus when conditions not met (SYNC={}, CM={}, CI={}, Address_Ready={})",
self.base.name(), sync, chip_select, io_select, self.full_address_ready);
}
// Conditions not met, tri-state
println!("DEBUG: {} - Conditions not met, tri-stating (SYNC={}, CM={}, CI={}, Address_Ready={})",
self.base.name(), sync, chip_select, io_select, self.full_address_ready);
self.tri_state_data_bus();
}
}

View file

@ -789,22 +789,29 @@ impl Component for Intel4002 {
self.prev_phi2 = phi2;
if phi1_rising {
println!(
"DEBUG: [RAM] Φ1 Rising Edge - State: {:?}, Ready: {}",
self.ram_state, self.full_address_ready
);
// Φ1 Rising Edge: Address phase (CPU drives bus) - handle address latching
self.handle_phi1_rising();
}
if phi1_falling {
// Φ1 Falling Edge: End of address phase
println!("DEBUG: [RAM] Φ1 Falling Edge");
self.handle_phi1_falling();
}
if phi2_rising {
// Φ2 Rising Edge: Data phase (RAM drives bus if ready) - handle data operations
println!("DEBUG: [RAM] Φ2 Rising Edge - State: {:?}", self.ram_state);
self.handle_phi2_rising();
}
if phi2_falling {
// Φ2 Falling Edge: End of data phase - tri-state bus and return to idle
println!("DEBUG: [RAM] Φ2 Falling Edge");
self.handle_phi2_falling();
}