Created factory for system creation.

Systems are now defined in JSON rather than hard-coded
This commit is contained in:
Jan-Peter von Hunnius 2025-09-29 12:41:16 +02:00
parent c039e9069a
commit 6f3295dc5e
31 changed files with 1610 additions and 1709 deletions

View file

@ -21,14 +21,14 @@ use crate::pin::{Pin, PinValue};
/// - Output behavior matches 4001/4002 I/O persistence model
pub struct Intel4003 {
base: BaseComponent,
shift_register: [u8; 10], // 10-bit shift register (stored as 10 bytes for simplicity)
output_latch: [u8; 10], // 10-bit output latch for parallel output
serial_input: u8, // Serial input data (4-bit)
access_time: Duration, // Shift register access latency (200ns typical)
shift_register: [u8; 10], // 10-bit shift register (stored as 10 bytes for simplicity)
output_latch: [u8; 10], // 10-bit output latch for parallel output
serial_input: u8, // Serial input data (4-bit)
access_time: Duration, // Shift register access latency (200ns typical)
// Clock edge detection
prev_phi1: PinValue, // Previous Φ1 clock state for edge detection
prev_phi2: PinValue, // Previous Φ2 clock state for edge detection
prev_phi1: PinValue, // Previous Φ1 clock state for edge detection
prev_phi2: PinValue, // Previous Φ2 clock state for edge detection
// Two-phase addressing for 8-bit address
address_high_nibble: Option<u8>, // High nibble of 8-bit address
@ -36,7 +36,7 @@ pub struct Intel4003 {
full_address_ready: bool, // Whether complete address is assembled
// Shift register operation state machine
shift_state: ShiftState, // Current state of shift operation
shift_state: ShiftState, // Current state of shift operation
address_latch_time: Option<Instant>, // Timestamp when address was latched
}
@ -74,21 +74,21 @@ impl Intel4003 {
// - CM: Chip select (must be HIGH for shift register access)
// - RESET: Clears internal state
let pin_names = vec![
"D0", "D1", "D2", "D3", // Data/Address pins
"O0", "O1", "O2", "O3", "O4", "O5", "O6", "O7", "O8", "O9", // 10 output pins
"SYNC", // Sync signal
"CM", // Chip Select
"RESET", // Reset
"PHI1", // Clock phase 1
"PHI2", // Clock phase 2
"D0", "D1", "D2", "D3", // Data/Address pins
"O0", "O1", "O2", "O3", "O4", "O5", "O6", "O7", "O8", "O9", // 10 output pins
"SYNC", // Sync signal
"CM", // Chip Select
"RESET", // Reset
"PHI1", // Clock phase 1
"PHI2", // Clock phase 2
];
let pins = BaseComponent::create_pin_map(&pin_names, &name);
Intel4003 {
base: BaseComponent::new(name, pins),
shift_register: [0u8; 10], // 10-bit shift register
output_latch: [0u8; 10], // 10-bit output latch
shift_register: [0u8; 10], // 10-bit shift register
output_latch: [0u8; 10], // 10-bit output latch
serial_input: 0,
access_time: Duration::from_nanos(access_time_ns),
@ -167,7 +167,8 @@ impl Intel4003 {
for i in 0..4 {
if let Ok(pin) = self.base.get_pin(&format!("D{}", i)) {
if let Ok(mut pin_guard) = pin.lock() {
pin_guard.set_driver(Some(format!("{}_DATA", self.base.name())), PinValue::HighZ);
pin_guard
.set_driver(Some(format!("{}_DATA", self.base.name())), PinValue::HighZ);
}
}
}
@ -178,7 +179,10 @@ impl Intel4003 {
for i in 0..10 {
if let Ok(pin) = self.base.get_pin(&format!("O{}", i)) {
if let Ok(mut pin_guard) = pin.lock() {
pin_guard.set_driver(Some(format!("{}_OUTPUT", self.base.name())), PinValue::HighZ);
pin_guard.set_driver(
Some(format!("{}_OUTPUT", self.base.name())),
PinValue::HighZ,
);
}
}
}
@ -274,7 +278,7 @@ impl Intel4003 {
/// Assemble complete 8-bit address from high and low nibbles
fn assemble_full_address(&mut self) {
if let (Some(high), Some(low)) = (self.address_high_nibble, self.address_low_nibble) {
if let (Some(_high), Some(_low)) = (self.address_high_nibble, self.address_low_nibble) {
// Assemble 8-bit address: (high << 4) | low
self.full_address_ready = true;
self.address_latch_time = Some(Instant::now());
@ -400,29 +404,41 @@ impl Intel4003 {
if sync && chip_select && self.full_address_ready {
// Read serial input data from data bus
let serial_data = self.read_data_bus();
println!("DEBUG: 4003 shift operation - serial_data = 0x{:x}", serial_data);
println!(
"DEBUG: 4003 shift operation - serial_data = 0x{:x}",
serial_data
);
// Shift in the new bits (serial input)
// For 4003, we shift in 4 bits at a time
// First, shift existing bits right by 4 positions
for j in (4..10).rev() {
self.shift_register[j] = self.shift_register[j-4];
self.shift_register[j] = self.shift_register[j - 4];
}
// Then insert the 4 new bits into positions 0-3
for i in 0..4 {
let bit = (serial_data >> i) & 1;
self.shift_register[i] = bit;
println!("DEBUG: 4003 shift step {} - inserted bit {} at position {}", i, bit, i);
println!(
"DEBUG: 4003 shift step {} - inserted bit {} at position {}",
i, bit, i
);
}
// Update output latch with new shift register contents
self.output_latch.copy_from_slice(&self.shift_register);
self.update_output_pins();
println!("DEBUG: 4003 shift register after operation: {:?}", self.shift_register);
println!(
"DEBUG: 4003 shift register after operation: {:?}",
self.shift_register
);
let (high, low) = self.get_shift_register();
println!("DEBUG: 4003 get_shift_register() returns high=0x{:x}, low=0x{:x}", high, low);
println!(
"DEBUG: 4003 get_shift_register() returns high=0x{:x}, low=0x{:x}",
high, low
);
self.shift_state = ShiftState::OutputData;
} else {
@ -436,7 +452,6 @@ impl Intel4003 {
// This state maintains the output until next operation
}
/// Get the current shift register value
/// Returns: 10-bit value as a tuple (high_byte, low_2_bits)
pub fn get_shift_register(&self) -> (u8, u8) {
@ -593,9 +608,9 @@ mod tests {
let mut d2_guard = d2_pin.lock().unwrap();
let mut d3_guard = d3_pin.lock().unwrap();
d0_guard.set_driver(Some("TEST".to_string()), PinValue::High); // Bit 0 = 1
d1_guard.set_driver(Some("TEST".to_string()), PinValue::Low); // Bit 1 = 0
d1_guard.set_driver(Some("TEST".to_string()), PinValue::Low); // Bit 1 = 0
d2_guard.set_driver(Some("TEST".to_string()), PinValue::High); // Bit 2 = 1
d3_guard.set_driver(Some("TEST".to_string()), PinValue::Low); // Bit 3 = 0
d3_guard.set_driver(Some("TEST".to_string()), PinValue::Low); // Bit 3 = 0
}
// Set control pins for shift operation
@ -613,7 +628,10 @@ mod tests {
// Verify shift operation occurred
let (high, low) = sr.get_shift_register();
println!("DEBUG: After shift operation - high=0x{:x}, low=0x{:x}", high, low);
println!(
"DEBUG: After shift operation - high=0x{:x}, low=0x{:x}",
high, low
);
println!("DEBUG: Shift register contents: {:?}", sr.shift_register);
// The shift register should now contain the shifted data
@ -623,7 +641,7 @@ mod tests {
// high byte: 01010101 (0x55) - this is correct, the first 4 bits are 0101 (0x05)
// low byte: 00000001 (0x01) - this is the remaining 2 bits from the original pattern
assert_eq!(high, 0x55); // First 8 bits should be 01010101
assert_eq!(low, 0x01); // Lower 2 bits should be 01
assert_eq!(low, 0x01); // Lower 2 bits should be 01
}
#[test]
@ -670,4 +688,4 @@ mod tests {
assert_eq!(fast_sr.get_access_time(), 1);
assert_eq!(fast_sr.name(), "FAST_SHIFT");
}
}
}