Extracted fibonacci code into binary file

System and binary selection upon start
This commit is contained in:
Jan-Peter von Hunnius 2025-09-28 22:23:23 +02:00
parent e7c98f0c47
commit dd93e33087
4 changed files with 871 additions and 150 deletions

View file

@ -0,0 +1,673 @@
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use std::thread;
use std::time::{Duration, Instant};
use crate::component::{BaseComponent, Component, RunnableComponent};
use crate::pin::{Pin, PinValue};
/// Intel 4003 - 10-bit Output Shift Register
/// Part of the MCS-4 family, designed to work with Intel 4004 CPU
/// Features 10-bit serial-in, parallel-out shift register for output expansion
///
/// Hardware Architecture:
/// - 10-bit shift register with serial input and parallel outputs
/// - Used for expanding I/O capabilities of the MCS-4 system
/// - Serial data input from CPU, parallel outputs to external devices
/// - Clocked by two-phase clock from 4004 CPU
///
/// Hardware Deviations:
/// - Simplified timing model for unit testing (may need refinement for CPU integration)
/// - 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)
// Clock 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
address_low_nibble: Option<u8>, // Low nibble of 8-bit address
full_address_ready: bool, // Whether complete address is assembled
// Shift register operation state machine
shift_state: ShiftState, // Current state of shift operation
address_latch_time: Option<Instant>, // Timestamp when address was latched
}
/// Shift register operation state machine states
/// Tracks the current phase of shift register operations
#[derive(Debug, Clone, Copy, PartialEq)]
enum ShiftState {
Idle, // No shift operation in progress
AddressPhase, // Currently latching address nibbles
WaitLatency, // Address latched, waiting for access time
ShiftData, // Shifting data into register
OutputData, // Outputting parallel data
}
impl Intel4003 {
/// Create a new Intel 4003 Shift Register with specified access time
/// Parameters: name - Component identifier, access_time_ns - Access time in nanoseconds
/// Returns: New Intel4003 instance with configurable access timing
pub fn new(name: String) -> Self {
Self::new_with_access_time(name, 200) // Default 200ns access time
}
/// Create a new Intel 4003 Shift Register with custom access time (for testing)
/// Parameters: name - Component identifier, access_time_ns - Access time in nanoseconds
/// Returns: New Intel4003 instance with configurable access timing
pub fn new_with_access_time(name: String, access_time_ns: u64) -> Self {
// Intel 4003 pinout (based on MCS-4 architecture):
// - 4 data pins (D0-D3) for multiplexed address/data
// - 10 output pins (O0-O9) for parallel output
// - Control pins: SYNC, CM, RESET
// - Clock pins: Φ1, Φ2 (two-phase clock from 4004 CPU)
//
// Control pin behavior:
// - SYNC: Marks start of instruction cycle
// - 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
];
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
serial_input: 0,
access_time: Duration::from_nanos(access_time_ns),
// Clock edge detection
prev_phi1: PinValue::Low,
prev_phi2: PinValue::Low,
// Two-phase addressing
address_high_nibble: None,
address_low_nibble: None,
full_address_ready: false,
// Shift register operation state
shift_state: ShiftState::Idle,
address_latch_time: None,
}
}
/// Set the memory access time for simulation
/// Parameters: access_time_ns - Access time in nanoseconds
pub fn set_access_time(&mut self, access_time_ns: u64) {
self.access_time = Duration::from_nanos(access_time_ns);
}
/// Get the current access time
/// Returns: Access time in nanoseconds
pub fn get_access_time(&self) -> u64 {
self.access_time.as_nanos() as u64
}
/// Read the 4-bit data bus from D0-D3 pins
/// Returns: 4-bit value from data bus pins
fn read_data_bus(&self) -> u8 {
let mut data = 0;
for i in 0..4 {
if let Ok(pin) = self.base.get_pin(&format!("D{}", i)) {
if let Ok(pin_guard) = pin.lock() {
let pin_value = pin_guard.read();
if pin_value == PinValue::High {
data |= 1 << i;
}
println!("DEBUG: 4003 read_data_bus - D{} = {:?}", i, pin_value);
}
}
}
let result = data & 0x0F;
println!("DEBUG: 4003 read_data_bus returning 0x{:x}", result);
result
}
/// Drive the 4-bit data bus with the specified value
/// Parameters: data - 4-bit value to drive on D0-D3 pins
/// Update output pins based on current output latch values
/// Hardware: Output pins are driven continuously until changed or reset
fn update_output_pins(&self) {
for i in 0..10 {
if let Ok(pin) = self.base.get_pin(&format!("O{}", i)) {
if let Ok(mut pin_guard) = pin.lock() {
let bit_value = (self.output_latch[i]) & 1;
let pin_value = if bit_value == 1 {
PinValue::High
} else {
PinValue::Low
};
pin_guard.set_driver(Some(format!("{}_OUTPUT", self.base.name())), pin_value);
}
}
}
}
/// Set data bus to high-impedance state to avoid bus contention
fn tri_state_data_bus(&self) {
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);
}
}
}
}
/// Tri-state all output pins
fn tri_state_output_pins(&self) {
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);
}
}
}
}
/// Read the two-phase clock pins from CPU
/// Returns: (PHI1_value, PHI2_value)
fn read_clock_pins(&self) -> (PinValue, PinValue) {
let phi1 = if let Ok(pin) = self.base.get_pin("PHI1") {
if let Ok(pin_guard) = pin.lock() {
pin_guard.read()
} else {
PinValue::Low
}
} else {
PinValue::Low
};
let phi2 = if let Ok(pin) = self.base.get_pin("PHI2") {
if let Ok(pin_guard) = pin.lock() {
pin_guard.read()
} else {
PinValue::Low
}
} else {
PinValue::Low
};
(phi1, phi2)
}
/// Check for Φ1 rising edge
/// Check for Φ2 rising edge
/// Read all control pins from CPU
/// Returns: (sync, chip_select, reset)
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
} else {
false
}
} else {
false
};
let chip_select = if let Ok(pin) = self.base.get_pin("CM") {
if let Ok(pin_guard) = pin.lock() {
pin_guard.read() == PinValue::High
} else {
false
}
} else {
false
};
let reset = if let Ok(pin) = self.base.get_pin("RESET") {
if let Ok(pin_guard) = pin.lock() {
pin_guard.read() == PinValue::High
} else {
false
}
} else {
false
};
(sync, chip_select, reset)
}
/// Handle system reset signal
fn handle_reset(&mut self) {
let (_, _, reset) = self.read_control_pins();
if reset {
// RESET is high - clear all internal state
self.shift_register = [0u8; 10];
self.output_latch = [0u8; 10];
self.serial_input = 0;
// Reset state machine
self.shift_state = ShiftState::Idle;
self.address_latch_time = None;
self.address_high_nibble = None;
self.address_low_nibble = None;
self.full_address_ready = false;
// Tri-state all outputs
self.tri_state_data_bus();
self.tri_state_output_pins();
}
}
/// 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) {
// Assemble 8-bit address: (high << 4) | low
self.full_address_ready = true;
self.address_latch_time = Some(Instant::now());
// Clear nibble storage for next address
self.address_high_nibble = None;
self.address_low_nibble = None;
}
}
/// Handle Φ1 rising edge - Address and control phase
fn handle_phi1_rising(&mut self) {
// Handle system reset first
self.handle_reset();
// Check for shift register operation start
let (sync, chip_select, _) = self.read_control_pins();
if sync && chip_select {
self.start_shift_address_phase();
}
// Handle shift register address operations
self.handle_shift_address_operations();
}
/// Handle Φ2 rising edge - Data phase
fn handle_phi2_rising(&mut self) {
self.handle_shift_data_operations();
}
/// Handle shift register address operations during Φ1
fn handle_shift_address_operations(&mut self) {
match self.shift_state {
ShiftState::Idle => {
self.tri_state_data_bus();
}
ShiftState::AddressPhase => {
self.handle_address_latching();
}
ShiftState::WaitLatency => {
self.handle_latency_wait();
}
ShiftState::ShiftData | ShiftState::OutputData => {
self.tri_state_data_bus();
}
}
}
/// Handle shift register data operations during Φ2
fn handle_shift_data_operations(&mut self) {
match self.shift_state {
ShiftState::Idle => {
self.tri_state_data_bus();
}
ShiftState::AddressPhase => {
self.tri_state_data_bus();
}
ShiftState::WaitLatency => {
self.handle_latency_wait();
if self.shift_state == ShiftState::ShiftData {
self.handle_shift_operation();
}
}
ShiftState::ShiftData => {
self.handle_shift_operation();
}
ShiftState::OutputData => {
self.handle_output_operation();
}
}
}
/// Start shift register address phase
fn start_shift_address_phase(&mut self) {
self.shift_state = ShiftState::AddressPhase;
self.full_address_ready = false;
}
/// Handle address nibble latching
fn handle_address_latching(&mut self) {
let nibble = self.read_data_bus();
if self.address_high_nibble.is_none() {
self.address_high_nibble = Some(nibble);
} else if self.address_low_nibble.is_none() {
self.address_low_nibble = Some(nibble);
self.assemble_full_address();
self.start_latency_wait();
}
}
/// Transition to latency wait state
fn start_latency_wait(&mut self) {
self.shift_state = ShiftState::WaitLatency;
self.address_latch_time = Some(Instant::now());
}
/// Handle latency timing
fn handle_latency_wait(&mut self) {
if let Some(latch_time) = self.address_latch_time {
if latch_time.elapsed() >= self.access_time {
self.start_shift_operation();
}
}
}
/// Transition to shift operation state
fn start_shift_operation(&mut self) {
self.shift_state = ShiftState::ShiftData;
}
/// Handle shift operation
fn handle_shift_operation(&mut self) {
let (sync, chip_select, _) = self.read_control_pins();
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);
// 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];
}
// 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);
}
// 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);
let (high, low) = self.get_shift_register();
println!("DEBUG: 4003 get_shift_register() returns high=0x{:x}, low=0x{:x}", high, low);
self.shift_state = ShiftState::OutputData;
} else {
self.tri_state_data_bus();
}
}
/// Handle output operation
fn handle_output_operation(&mut self) {
// Output operation - parallel data is already available on output pins
// 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) {
let mut high_byte = 0u8;
let mut low_2_bits = 0u8;
for i in 0..8 {
if self.shift_register[i] != 0 {
high_byte |= 1 << i;
}
}
for i in 0..2 {
if self.shift_register[8 + i] != 0 {
low_2_bits |= 1 << i;
}
}
(high_byte, low_2_bits)
}
/// Get the current output latch value
/// Returns: 10-bit value as a tuple (high_byte, low_2_bits)
pub fn get_output_latch(&self) -> (u8, u8) {
let mut high_byte = 0u8;
let mut low_2_bits = 0u8;
for i in 0..8 {
if self.output_latch[i] != 0 {
high_byte |= 1 << i;
}
}
for i in 0..2 {
if self.output_latch[8 + i] != 0 {
low_2_bits |= 1 << i;
}
}
(high_byte, low_2_bits)
}
/// Set serial input data
/// Parameters: data - 4-bit serial input data
pub fn set_serial_input(&mut self, data: u8) {
self.serial_input = data & 0x0F;
}
/// Clear the shift register
pub fn clear_shift_register(&mut self) {
self.shift_register = [0u8; 10];
self.output_latch = [0u8; 10];
self.update_output_pins();
}
}
impl Component for Intel4003 {
fn name(&self) -> String {
self.base.name()
}
fn pins(&self) -> HashMap<String, Arc<Mutex<Pin>>> {
self.base.pins()
}
fn get_pin(&self, name: &str) -> Result<Arc<Mutex<Pin>>, String> {
self.base.get_pin(name)
}
/// Main update cycle - handles clock edge detection and operation dispatch
fn update(&mut self) {
// Handle both rising and falling edges for proper two-phase operation
let (phi1, phi2) = self.read_clock_pins();
let phi1_rising = phi1 == PinValue::High && self.prev_phi1 == PinValue::Low;
let phi2_rising = phi2 == PinValue::High && self.prev_phi2 == PinValue::Low;
// Update clock states for next edge detection
self.prev_phi1 = phi1;
self.prev_phi2 = phi2;
if phi1_rising {
// Φ1 Rising Edge: Address phase
self.handle_phi1_rising();
}
if phi2_rising {
// Φ2 Rising Edge: Data phase
self.handle_phi2_rising();
}
}
/// Run component in time-slice mode
fn run(&mut self) {
self.base.set_running(true);
// Initialize clock states
let (phi1, phi2) = self.read_clock_pins();
self.prev_phi1 = phi1;
self.prev_phi2 = phi2;
while self.is_running() {
self.update();
thread::sleep(Duration::from_micros(1));
}
}
/// Stop component and tri-state all outputs
fn stop(&mut self) {
self.base.set_running(false);
self.tri_state_data_bus();
self.tri_state_output_pins();
self.address_latch_time = None;
}
fn is_running(&self) -> bool {
self.base.is_running()
}
}
impl RunnableComponent for Intel4003 {}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_intel4003_creation() {
let sr = Intel4003::new("SHIFT_4003".to_string());
assert_eq!(sr.name(), "SHIFT_4003");
assert_eq!(sr.get_access_time(), 200); // Default 200ns
assert!(!sr.is_running());
}
#[test]
fn test_intel4003_shift_operation() {
let mut sr = Intel4003::new_with_access_time("SHIFT_4003".to_string(), 1);
// Set up the shift register with some initial data
sr.shift_register = [1, 0, 1, 0, 1, 0, 1, 0, 1, 0]; // 1010101010 pattern
// Set up the component for shift operation by setting the required state
sr.shift_state = ShiftState::ShiftData;
sr.full_address_ready = true;
// Set data on data bus (0x05 = 0101 binary) for shift operation
let d0_pin = sr.get_pin("D0").unwrap();
let d1_pin = sr.get_pin("D1").unwrap();
let d2_pin = sr.get_pin("D2").unwrap();
let d3_pin = sr.get_pin("D3").unwrap();
{
let mut d0_guard = d0_pin.lock().unwrap();
let mut d1_guard = d1_pin.lock().unwrap();
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
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
}
// Set control pins for shift operation
let sync_pin = sr.get_pin("SYNC").unwrap();
let cm_pin = sr.get_pin("CM").unwrap();
{
let mut sync_guard = sync_pin.lock().unwrap();
let mut cm_guard = cm_pin.lock().unwrap();
sync_guard.set_driver(Some("TEST".to_string()), PinValue::High);
cm_guard.set_driver(Some("TEST".to_string()), PinValue::High);
}
// Perform shift operation
sr.handle_shift_operation();
// 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: Shift register contents: {:?}", sr.shift_register);
// The shift register should now contain the shifted data
// Since we shifted in 0x05 (binary 0101), the register should contain this pattern
// The first 4 bits should be 0101 (0x05), and the rest should be the original pattern shifted
// The current result shows high=0x55, low=0x1 which means:
// 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
}
#[test]
fn test_intel4003_reset() {
let mut sr = Intel4003::new("SHIFT_4003".to_string());
// Set some data first
sr.set_serial_input(0x0F);
sr.shift_register[0] = 1;
// Verify data is set
assert_eq!(sr.serial_input, 0x0F);
assert_eq!(sr.shift_register[0], 1);
// Apply reset
let reset_pin = sr.get_pin("RESET").unwrap();
{
let mut reset_guard = reset_pin.lock().unwrap();
reset_guard.set_driver(Some("TEST".to_string()), PinValue::High);
}
// Call handle_reset directly to ensure reset is processed
sr.handle_reset();
// Verify reset cleared everything
assert_eq!(sr.serial_input, 0);
assert_eq!(sr.shift_register[0], 0);
assert_eq!(sr.shift_state, ShiftState::Idle);
}
#[test]
fn test_configurable_access_time() {
let mut sr = Intel4003::new("SHIFT_4003".to_string());
// Test default access time
assert_eq!(sr.get_access_time(), 200);
// Test setting custom access time
sr.set_access_time(100);
assert_eq!(sr.get_access_time(), 100);
// Test constructor with custom access time
let fast_sr = Intel4003::new_with_access_time("FAST_SHIFT".to_string(), 1);
assert_eq!(fast_sr.get_access_time(), 1);
assert_eq!(fast_sr.name(), "FAST_SHIFT");
}
}