diff --git a/src/bus.rs b/src/bus.rs index 881db46..932a30c 100644 --- a/src/bus.rs +++ b/src/bus.rs @@ -4,7 +4,7 @@ use std::thread; use std::time::{Duration, Instant}; use crate::component::{BaseComponent, Component}; -use crate::pin::{Pin, PinValue, DriveStrength}; +use crate::pin::{DriveStrength, Pin, PinValue}; pub struct GenericBus { base: BaseComponent, @@ -105,7 +105,8 @@ impl GenericBus { } // Find the strongest driver - let max_strength = drivers.iter() + let max_strength = drivers + .iter() .map(|(_, strength)| *strength) .max() .unwrap_or(DriveStrength::HighImpedance); @@ -115,7 +116,8 @@ impl GenericBus { } // Get values from strongest drivers - let strong_drivers: Vec = drivers.iter() + let strong_drivers: Vec = drivers + .iter() .filter(|(_, strength)| *strength == max_strength) .map(|(value, _)| *value) .collect(); @@ -141,7 +143,7 @@ impl GenericBus { pin_guard.set_driver_with_strength( Some(self.base.get_name().to_string()), self.bus_value, - DriveStrength::Standard + DriveStrength::Standard, ); } } @@ -269,7 +271,7 @@ impl ActiveBus { pin_guard.set_driver_with_strength( Some(self.base.name() + "_pattern"), value, - DriveStrength::Strong + DriveStrength::Strong, ); } } @@ -390,33 +392,33 @@ mod tests { fn test_active_bus_pattern() { let mut bus = ActiveBus::new("ACTIVE_BUS".to_string()); - // let handle = thread::spawn(move || { - // bus.run(); - // }); + // let handle = thread::spawn(move || { + // bus.run(); + // }); // Give the thread a moment to start thread::sleep(Duration::from_millis(10)); -// assert!(bus.is_running()); + // assert!(bus.is_running()); let pattern = vec![PinValue::High, PinValue::Low, PinValue::High, PinValue::Low]; -// bus.set_test_pattern(pattern); -// bus.set_pattern_interval(Duration::from_millis(10)); + // bus.set_test_pattern(pattern); + // bus.set_pattern_interval(Duration::from_millis(10)); // Give the thread a moment to start thread::sleep(Duration::from_millis(100)); // Test that active bus can drive patterns -// bus.drive_pattern(); -// assert!(bus.test_pattern.eq(&pattern)); + // bus.drive_pattern(); + // assert!(bus.test_pattern.eq(&pattern)); // Clean up - stop the bus and join the thread -// bus.stop(); + // bus.stop(); thread::sleep(Duration::from_millis(100)); - assert!(! bus.is_running()); + assert!(!bus.is_running()); -// handle.join().unwrap(); + // handle.join().unwrap(); } -} \ No newline at end of file +} diff --git a/src/component.rs b/src/component.rs index e4612b3..722309b 100644 --- a/src/component.rs +++ b/src/component.rs @@ -1,5 +1,8 @@ use std::collections::HashMap; -use std::sync::{Arc, Mutex, atomic::{AtomicBool, Ordering}}; +use std::sync::{ + atomic::{AtomicBool, Ordering}, + Arc, Mutex, +}; use std::thread; use std::time::Duration; @@ -15,12 +18,21 @@ pub trait Component: Send + Sync { fn stop(&mut self); fn is_running(&self) -> bool; } - +pub trait RunnableComponent: Component + Send + 'static { + fn spawn_in_thread(mut self) -> thread::JoinHandle<()> + where + Self: Sized, + { + thread::spawn(move || { + self.run(); + }) + } +} // BaseComponent uses AtomicBool for thread-safe state pub struct BaseComponent { name: String, pins: HashMap>>, - running: AtomicBool, // Thread-safe running state + running: AtomicBool, // Thread-safe running state } impl BaseComponent { @@ -44,12 +56,18 @@ impl BaseComponent { self.running.store(running, Ordering::SeqCst); } - pub fn create_pin_map(pin_names: &[&str], component_name: &str) -> HashMap>> { + pub fn create_pin_map( + pin_names: &[&str], + component_name: &str, + ) -> HashMap>> { let mut pins = HashMap::new(); for pin_name in pin_names { pins.insert( pin_name.to_string(), - Arc::new(Mutex::new(Pin::new(format!("{}_{}", component_name, pin_name)))) + Arc::new(Mutex::new(Pin::new(format!( + "{}_{}", + component_name, pin_name + )))), ); } pins @@ -66,7 +84,8 @@ impl Component for BaseComponent { } fn get_pin(&self, name: &str) -> Result>, String> { - self.pins.get(name) + self.pins + .get(name) .cloned() .ok_or_else(|| format!("Pin {} not found", name)) } @@ -88,6 +107,8 @@ impl Component for BaseComponent { } fn is_running(&self) -> bool { - self.is_running() + self.running.load(Ordering::SeqCst) } -} \ No newline at end of file +} + +impl RunnableComponent for BaseComponent {} diff --git a/src/components/clock/generic_clock.rs b/src/components/clock/generic_clock.rs index b89b9a4..78a81a0 100644 --- a/src/components/clock/generic_clock.rs +++ b/src/components/clock/generic_clock.rs @@ -8,8 +8,8 @@ use crate::pin::{Pin, PinValue}; pub struct GenericClock { base: BaseComponent, - frequency: f64, // Frequency in Hz - duty_cycle: f64, // Duty cycle as percentage (0.0 to 1.0) + frequency: f64, // Frequency in Hz + duty_cycle: f64, // Duty cycle as percentage (0.0 to 1.0) current_state: PinValue, last_transition: Instant, half_period: Duration, @@ -232,8 +232,13 @@ impl GenericClock { let half_period = self.half_period; thread::spawn(move || { - for i in 0..count * 2 { // Each cycle has two transitions - let state = if i % 2 == 0 { PinValue::High } else { PinValue::Low }; + for i in 0..count * 2 { + // Each cycle has two transitions + let state = if i % 2 == 0 { + PinValue::High + } else { + PinValue::Low + }; if let Ok(mut pin_guard) = clock_pin.lock() { pin_guard.set_driver(Some(clock_name.clone()), state); @@ -313,6 +318,6 @@ mod tests { fn test_clock_burst() { let mut clock = GenericClock::new("BURST_CLK".to_string(), 1_000_000.0); clock.generate_clock_burst(5); // 5 clock cycles - // Note: In a real test, you'd want to verify the pin states + // Note: In a real test, you'd want to verify the pin states } -} \ No newline at end of file +} diff --git a/src/components/clock/mod.rs b/src/components/clock/mod.rs index 67c6f16..db80934 100644 --- a/src/components/clock/mod.rs +++ b/src/components/clock/mod.rs @@ -1 +1 @@ -pub(crate) mod generic_clock; \ No newline at end of file +pub(crate) mod generic_clock; diff --git a/src/components/cpu/cpu_traits.rs b/src/components/cpu/cpu_traits.rs index dfb279a..d1241bd 100644 --- a/src/components/cpu/cpu_traits.rs +++ b/src/components/cpu/cpu_traits.rs @@ -137,4 +137,4 @@ impl CMOS65C02Extensions for WDC65C02 { } // Implement other 65C02-specific methods... -} \ No newline at end of file +} diff --git a/src/components/cpu/intel_4004.rs b/src/components/cpu/intel_4004.rs index 468e130..1c7bf94 100644 --- a/src/components/cpu/intel_4004.rs +++ b/src/components/cpu/intel_4004.rs @@ -3,7 +3,7 @@ use std::sync::{Arc, Mutex}; use std::thread; use std::time::{Duration, Instant}; -use crate::component::{BaseComponent, Component}; +use crate::component::{BaseComponent, Component, RunnableComponent}; use crate::pin::{Pin, PinValue}; use crate::types::U12; @@ -44,8 +44,7 @@ pub struct Intel4004 { impl Intel4004 { pub fn new(name: String, clock_speed: f64) -> Self { let pin_names = vec![ - "D0", "D1", "D2", "D3", - "SYNC", "CM_ROM", "CM_RAM", "TEST", "RESET", "PHI1", "PHI2", + "D0", "D1", "D2", "D3", "SYNC", "CM_ROM", "CM_RAM", "TEST", "RESET", "PHI1", "PHI2", ]; let pin_strings: Vec = pin_names.iter().map(|s| s.to_string()).collect(); @@ -133,7 +132,8 @@ impl Intel4004 { 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(self.base.get_name().parse().unwrap()), PinValue::HighZ); + pin_guard + .set_driver(Some(self.base.get_name().parse().unwrap()), PinValue::HighZ); } } } @@ -207,7 +207,7 @@ impl Intel4004 { _ => { let mut a = 0; let mut b = 1; - for _ in 2..=n%32 { + for _ in 2..=n % 32 { let next: u32 = a + b; a = b; b = next; @@ -291,6 +291,7 @@ impl Component for Intel4004 { } fn run(&mut self) { + // Time-slice model: run in a loop calling update() each cycle self.base.set_running(true); self.reset(); @@ -311,4 +312,8 @@ impl Component for Intel4004 { fn is_running(&self) -> bool { self.base.is_running() } -} \ No newline at end of file +} + +impl RunnableComponent for Intel4004 { + // No custom run_loop needed - uses default Component::run() method +} diff --git a/src/components/cpu/mod.rs b/src/components/cpu/mod.rs index bdfd300..f695440 100644 --- a/src/components/cpu/mod.rs +++ b/src/components/cpu/mod.rs @@ -1,10 +1,10 @@ // CPU components module +mod cpu_traits; +pub mod intel_4004; pub mod mos_6502; pub mod wdc_65c02; -pub mod intel_4004; -mod cpu_traits; // Re-export the CPU types +pub use intel_4004::Intel4004; pub use mos_6502::MOS6502; pub use wdc_65c02::WDC65C02; -pub use intel_4004::Intel4004; \ No newline at end of file diff --git a/src/components/cpu/mos_6502.rs b/src/components/cpu/mos_6502.rs index 35fef5b..5525465 100644 --- a/src/components/cpu/mos_6502.rs +++ b/src/components/cpu/mos_6502.rs @@ -26,15 +26,16 @@ pub struct MOS6502 { impl MOS6502 { pub fn new(name: String) -> Self { let pin_names = vec![ - "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8", "A9", "A10", "A11", "A12", "A13", "A14", "A15", // 16 address lines - "D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7", // 8 data lines - "RW", // Read/Write - "IRQ", // Interrupt Request - "NMI", // Non-Maskable Interrupt - "RES", // Reset - "CLK", // Clock + "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8", "A9", "A10", "A11", "A12", "A13", + "A14", "A15", // 16 address lines + "D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7", // 8 data lines + "RW", // Read/Write + "IRQ", // Interrupt Request + "NMI", // Non-Maskable Interrupt + "RES", // Reset + "CLK", // Clock "SYNC", // Sync - "RDY", // Ready + "RDY", // Ready ]; let pins = BaseComponent::create_pin_map(&pin_names, &name); @@ -46,7 +47,7 @@ impl MOS6502 { y_register: 0, stack_pointer: 0xFD, program_counter: 0xFFFC, // Reset vector location - status_register: 0x20, // Always set bit 5 + status_register: 0x20, // Always set bit 5 cycle_count: 0, is_reset: false, is_running: false, @@ -73,7 +74,11 @@ impl MOS6502 { if let Ok(pin) = self.base.get_pin(&format!("A{}", i)) { if let Ok(mut pin_guard) = pin.lock() { let bit_value = (address >> i) & 1; - let pin_value = if bit_value == 1 { PinValue::High } else { PinValue::Low }; + let pin_value = if bit_value == 1 { + PinValue::High + } else { + PinValue::Low + }; pin_guard.set_driver(Some(self.base.get_name().parse().unwrap()), pin_value); } } @@ -85,7 +90,11 @@ impl MOS6502 { if let Ok(pin) = self.base.get_pin(&format!("D{}", i)) { if let Ok(mut pin_guard) = pin.lock() { let bit_value = (data >> i) & 1; - let pin_value = if bit_value == 1 { PinValue::High } else { PinValue::Low }; + let pin_value = if bit_value == 1 { + PinValue::High + } else { + PinValue::Low + }; pin_guard.set_driver(Some(self.base.get_name().parse().unwrap()), pin_value); } } @@ -293,4 +302,4 @@ mod tests { assert_eq!(cpu.get_program_counter(), 0xFFFC); } -} \ No newline at end of file +} diff --git a/src/components/cpu/wdc_65c02.rs b/src/components/cpu/wdc_65c02.rs index f727e46..7e551a8 100644 --- a/src/components/cpu/wdc_65c02.rs +++ b/src/components/cpu/wdc_65c02.rs @@ -168,4 +168,4 @@ mod tests { assert_eq!(cpu.get_base_cpu().get_accumulator(), 0); assert_eq!(cpu.get_base_cpu().get_x_register(), 0); } -} \ No newline at end of file +} diff --git a/src/components/memory/generic_ram.rs b/src/components/memory/generic_ram.rs index 31da983..16163af 100644 --- a/src/components/memory/generic_ram.rs +++ b/src/components/memory/generic_ram.rs @@ -43,9 +43,9 @@ impl GenericRam { } // Control pins - pin_names.push("CS".parse().unwrap()); // Chip Select - pin_names.push("WE".parse().unwrap()); // Write Enable - pin_names.push("OE".parse().unwrap()); // Output Enable + pin_names.push("CS".parse().unwrap()); // Chip Select + pin_names.push("WE".parse().unwrap()); // Write Enable + pin_names.push("OE".parse().unwrap()); // Output Enable let pin_refs: Vec<&str> = pin_names.iter().map(|s| s.as_str()).collect(); let pins = BaseComponent::create_pin_map(&pin_refs, &name); @@ -70,7 +70,9 @@ impl GenericRam { if offset + data.len() > self.memory.len() { return Err(format!( "Data exceeds RAM capacity: offset {} + data length {} > RAM size {}", - offset, data.len(), self.memory.len() + offset, + data.len(), + self.memory.len() )); } @@ -82,7 +84,9 @@ impl GenericRam { if offset + data.len() > self.memory.len() { return Err(format!( "Data exceeds RAM capacity: offset {} + data length {} > RAM size {}", - offset, data.len(), self.memory.len() + offset, + data.len(), + self.memory.len() )); } @@ -206,7 +210,8 @@ impl GenericRam { for i in 0..self.data_width { if let Ok(pin) = self.base.get_pin(&format!("D{}", i)) { if let Ok(mut pin_guard) = pin.lock() { - pin_guard.set_driver(Some(self.base.get_name().parse().unwrap()), PinValue::HighZ); + pin_guard + .set_driver(Some(self.base.get_name().parse().unwrap()), PinValue::HighZ); } } } @@ -411,4 +416,4 @@ mod tests { let ram = GenericRam::new("TEST_RAM".to_string(), 256, 8, 8); assert!(!ram.is_running()); } -} \ No newline at end of file +} diff --git a/src/components/memory/generic_rom.rs b/src/components/memory/generic_rom.rs index efffc12..708d56d 100644 --- a/src/components/memory/generic_rom.rs +++ b/src/components/memory/generic_rom.rs @@ -25,17 +25,29 @@ impl GenericRom { // Create address pins (A0, A1, A2, ...) for i in 0..address_width { - pins.insert(format!("A{}", i), Arc::new(Mutex::new(Pin::new(format!("{}_A{}", name, i))))); + pins.insert( + format!("A{}", i), + Arc::new(Mutex::new(Pin::new(format!("{}_A{}", name, i)))), + ); } // Create data pins (D0, D1, D2, ...) for i in 0..data_width { - pins.insert(format!("D{}", i), Arc::new(Mutex::new(Pin::new(format!("{}_D{}", name, i))))); + pins.insert( + format!("D{}", i), + Arc::new(Mutex::new(Pin::new(format!("{}_D{}", name, i)))), + ); } // Control pins - pins.insert("CS".to_string(), Arc::new(Mutex::new(Pin::new(format!("{}_CS", name))))); - pins.insert("OE".to_string(), Arc::new(Mutex::new(Pin::new(format!("{}_OE", name))))); + pins.insert( + "CS".to_string(), + Arc::new(Mutex::new(Pin::new(format!("{}_CS", name)))), + ); + pins.insert( + "OE".to_string(), + Arc::new(Mutex::new(Pin::new(format!("{}_OE", name)))), + ); let memory = vec![0u8; size]; @@ -70,7 +82,11 @@ impl GenericRom { Err(_) => Err("Invalid hex data".to_string()), } } - pub fn load_from_binary_file>(&mut self, path: P, offset: usize) -> Result<(), String> { + pub fn load_from_binary_file>( + &mut self, + path: P, + offset: usize, + ) -> Result<(), String> { let path_ref = path.as_ref(); // Check if file exists @@ -80,14 +96,18 @@ impl GenericRom { // Check if offset is within bounds if offset >= self.memory.len() { - return Err(format!("Offset {} exceeds ROM size {}", offset, self.memory.len())); + return Err(format!( + "Offset {} exceeds ROM size {}", + offset, + self.memory.len() + )); } - let mut file = File::open(path_ref) - .map_err(|e| format!("Failed to open file: {}", e))?; + let mut file = File::open(path_ref).map_err(|e| format!("Failed to open file: {}", e))?; // Get file size - let metadata = file.metadata() + let metadata = file + .metadata() .map_err(|e| format!("Failed to get file metadata: {}", e))?; let file_size = metadata.len() as usize; @@ -95,7 +115,9 @@ impl GenericRom { if offset + file_size > self.memory.len() { return Err(format!( "File too large: offset {} + file size {} > ROM size {}", - offset, file_size, self.memory.len() + offset, + file_size, + self.memory.len() )); } @@ -114,7 +136,9 @@ impl GenericRom { if offset + data.len() > self.memory.len() { return Err(format!( "Data exceeds ROM capacity: offset {} + data length {} > ROM size {}", - offset, data.len(), self.memory.len() + offset, + data.len(), + self.memory.len() )); } @@ -122,7 +146,6 @@ impl GenericRom { Ok(()) } - fn read_address(&self) -> u32 { let mut address = 0; @@ -170,7 +193,10 @@ impl GenericRom { for i in 0..self.data_width { if let Ok(pin) = self.base.get_pin(&format!("D{}", i)) { if let Ok(mut pin_guard) = pin.lock() { - pin_guard.set_driver(Some(self.base.get_name().parse().unwrap()), PinValue::HighZ); + pin_guard.set_driver( + Some(self.base.get_name().parse().unwrap()), + PinValue::HighZ, + ); } } } @@ -227,7 +253,10 @@ impl Component for GenericRom { for i in 0..self.data_width { if let Ok(pin) = self.base.get_pin(&format!("D{}", i)) { if let Ok(mut pin_guard) = pin.lock() { - pin_guard.set_driver(Some(self.base.get_name().parse().unwrap()), PinValue::HighZ); + pin_guard.set_driver( + Some(self.base.get_name().parse().unwrap()), + PinValue::HighZ, + ); } } } @@ -237,7 +266,10 @@ impl Component for GenericRom { for i in 0..self.data_width { if let Ok(pin) = self.base.get_pin(&format!("D{}", i)) { if let Ok(mut pin_guard) = pin.lock() { - pin_guard.set_driver(Some(self.base.get_name().parse().unwrap()), PinValue::HighZ); + pin_guard.set_driver( + Some(self.base.get_name().parse().unwrap()), + PinValue::HighZ, + ); } } } @@ -264,7 +296,8 @@ impl Component for GenericRom { for i in 0..self.data_width { if let Ok(pin) = self.base.get_pin(&format!("D{}", i)) { if let Ok(mut pin_guard) = pin.lock() { - pin_guard.set_driver(Some(self.base.get_name().parse().unwrap()), PinValue::HighZ); + pin_guard + .set_driver(Some(self.base.get_name().parse().unwrap()), PinValue::HighZ); } } } @@ -277,9 +310,9 @@ impl Component for GenericRom { #[cfg(test)] mod tests { + use super::*; use std::fs; use tempfile::NamedTempFile; - use super::*; #[test] fn test_rom_creation() { @@ -329,4 +362,4 @@ mod tests { assert_eq!(rom.memory[2], 0x56); assert_eq!(rom.memory[3], 0x78); } -} \ No newline at end of file +} diff --git a/src/components/memory/intel_4001.rs b/src/components/memory/intel_4001.rs index 93fcab5..33683fd 100644 --- a/src/components/memory/intel_4001.rs +++ b/src/components/memory/intel_4001.rs @@ -1,9 +1,8 @@ use std::collections::HashMap; use std::sync::{Arc, Mutex}; -use std::thread; use std::time::{Duration, Instant}; -use crate::component::{BaseComponent, Component}; +use crate::component::{BaseComponent, Component, RunnableComponent}; use crate::pin::{Pin, PinValue}; /// Intel 4001 - 256-byte ROM with integrated I/O @@ -17,12 +16,19 @@ pub struct Intel4001 { output_latch: u8, input_latch: u8, io_mode: IoMode, + // Clock edge detection + prev_phi1: PinValue, + prev_phi2: PinValue, + // Access latency modeling + address_latched: bool, + address_latch_time: Option, + data_available: bool, } #[derive(Debug, Clone, Copy, PartialEq)] enum IoMode { - Input, // I/O pins as inputs - Output, // I/O pins as outputs + Input, // I/O pins as inputs + Output, // I/O pins as outputs Bidirectional, // I/O pins bidirectional } @@ -31,18 +37,26 @@ impl Intel4001 { // Intel 4001 has 256 bytes of ROM let rom_size = 256; - // Intel 4001 pinout: - // - 10 address pins (A0-A9, but only A0-A7 used for 256-byte addressing) + // Intel 4001 pinout (per datasheet): // - 4 data pins (D0-D3) for multiplexed address/data // - 4 I/O pins (IO0-IO3) - // - Control pins: SYNC, CM-ROM, CM-RAM, RESET + // - Control pins: SYNC, RESET, CM, CI + // - Clock pins: Φ1, Φ2 (two-phase clock from 4004 CPU) + // + // Control pin behavior: + // - SYNC: Marks start of instruction cycle + // - RESET: Clears internal state + // - CM: Chip select for ROM vs RAM + // - CI: Distinguishes I/O (LOW) vs ROM access (HIGH) when CM-ROM is HIGH let pin_names = vec![ - "D0", "D1", "D2", "D3", // Data/Address pins - "IO0", "IO1", "IO2", "IO3", // I/O pins - "SYNC", // Sync signal - "CM_ROM", // ROM Chip Select - "CM_RAM", // RAM Chip Select (for system configuration) - "RESET", // Reset + "D0", "D1", "D2", "D3", // Data/Address pins + "IO0", "IO1", "IO2", "IO3", // I/O pins + "SYNC", // Sync signal + "CM", // CM-ROM: ROM/RAM Chip Select + "CI", // CM-RAM: RAM Chip Select (I/O vs ROM access) + "RESET", // Reset + "PHI1", // Clock phase 1 + "PHI2", // Clock phase 2 ]; let pins = BaseComponent::create_pin_map(&pin_names, &name); @@ -57,6 +71,11 @@ impl Intel4001 { output_latch: 0, input_latch: 0, io_mode: IoMode::Input, + prev_phi1: PinValue::Low, + prev_phi2: PinValue::Low, + address_latched: false, + address_latch_time: None, + data_available: false, } } @@ -64,7 +83,9 @@ impl Intel4001 { if offset + data.len() > self.memory.len() { return Err(format!( "Data exceeds ROM capacity: offset {} + data length {} > ROM size {}", - offset, data.len(), self.memory.len() + offset, + data.len(), + self.memory.len() )); } @@ -149,26 +170,87 @@ impl Intel4001 { } fn tri_state_data_bus(&self) { + // CRITICAL: Tri-state data bus to avoid contention with other chips + // The 4001 must be high-Z whenever not actively driving valid data 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(self.base.get_name().parse().unwrap()), PinValue::HighZ); + pin_guard + .set_driver(Some(self.base.get_name().parse().unwrap()), PinValue::HighZ); } } } } + fn should_drive_data_bus(&self) -> bool { + let (sync, cm_rom, cm_ram, _) = self.read_control_pins(); + // ROM drives data bus ONLY when all conditions are met: + sync && cm_rom && cm_ram && self.data_available + } + fn tri_state_io_pins(&self) { for i in 0..4 { if let Ok(pin) = self.base.get_pin(&format!("IO{}", i)) { if let Ok(mut pin_guard) = pin.lock() { - pin_guard.set_driver(Some(self.base.get_name().parse().unwrap()), PinValue::HighZ); + pin_guard + .set_driver(Some(self.base.get_name().parse().unwrap()), PinValue::HighZ); } } } } + 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) + } + + fn is_phi1_rising_edge(&self) -> bool { + let (phi1, _) = self.read_clock_pins(); + phi1 == PinValue::High && self.prev_phi1 == PinValue::Low + } + + fn is_phi1_falling_edge(&self) -> bool { + let (phi1, _) = self.read_clock_pins(); + phi1 == PinValue::Low && self.prev_phi1 == PinValue::High + } + + fn is_phi2_rising_edge(&self) -> bool { + let (_, phi2) = self.read_clock_pins(); + phi2 == PinValue::High && self.prev_phi2 == PinValue::Low + } + + fn is_phi2_falling_edge(&self) -> bool { + let (_, phi2) = self.read_clock_pins(); + phi2 == PinValue::Low && self.prev_phi2 == PinValue::High + } + + fn update_clock_states(&mut self) { + let (phi1, phi2) = self.read_clock_pins(); + self.prev_phi1 = phi1; + self.prev_phi2 = phi2; + } + fn read_control_pins(&self) -> (bool, bool, bool, bool) { + // SYNC: Marks the start of an instruction cycle let sync = if let Ok(pin) = self.base.get_pin("SYNC") { if let Ok(pin_guard) = pin.lock() { pin_guard.read() == PinValue::High @@ -179,7 +261,8 @@ impl Intel4001 { false }; - let cm_rom = if let Ok(pin) = self.base.get_pin("CM_ROM") { + // CM-ROM: Chip select for ROM vs RAM (HIGH = ROM access) + let cm_rom = if let Ok(pin) = self.base.get_pin("CM") { if let Ok(pin_guard) = pin.lock() { pin_guard.read() == PinValue::High } else { @@ -189,7 +272,9 @@ impl Intel4001 { false }; - let cm_ram = if let Ok(pin) = self.base.get_pin("CM_RAM") { + // CM-RAM: Distinguishes I/O vs ROM access when CM-ROM is HIGH + // HIGH = ROM access, LOW = I/O access + let cm_ram = if let Ok(pin) = self.base.get_pin("CI") { if let Ok(pin_guard) = pin.lock() { pin_guard.read() == PinValue::High } else { @@ -213,12 +298,18 @@ impl Intel4001 { } fn handle_reset(&mut self) { - if self.read_control_pins().3 { // RESET is high + let (_, _, _, reset) = self.read_control_pins(); + if reset { + // RESET is high - clear internal state self.output_latch = 0; self.input_latch = 0; self.io_mode = IoMode::Input; self.tri_state_data_bus(); self.tri_state_io_pins(); + // Reset access latency state + self.address_latched = false; + self.address_latch_time = None; + self.data_available = false; } } @@ -247,25 +338,41 @@ impl Intel4001 { fn handle_memory_operation(&mut self) -> bool { let (sync, cm_rom, cm_ram, _) = self.read_control_pins(); - // Memory operations occur when SYNC is high and CM-ROM is high - if sync && cm_rom { - if cm_ram { - // Second cycle of memory read - output data - let address = self.last_address; - if (address as usize) < self.memory.len() { - let data = self.memory[address as usize]; - self.write_data_bus(data); - return true; - } - } else { - // First cycle of memory operation - latch address - let address_low = self.read_data_bus(); - self.last_address = address_low as u16; - // Tri-state during address phase - self.tri_state_data_bus(); + // TRI-STATE RULE: ROM only drives data bus when ALL of these are true: + // - SYNC=1 (instruction cycle active) + // - CM-ROM=1 (ROM chip selected) + // - CM-RAM=1 (data phase, not address phase) + // - data_available=true (access latency has elapsed) + // + // ALL other cases MUST be high-Z to avoid bus contention with CPU/other chips + + if self.should_drive_data_bus() { + // EXACT CONDITIONS: SYNC=1, CM-ROM=1, CM-RAM=1, and data available + // This is the ONLY case where ROM drives the data bus + let address = self.last_address; + if (address as usize) < self.memory.len() { + let data = self.memory[address as usize]; + self.write_data_bus(data); + return true; // Successfully drove the bus } } + // ALL other cases: tri-state the data bus + self.tri_state_data_bus(); + + // Handle address latching when in address phase (but still tri-state) + if sync && cm_rom && !cm_ram { + // First cycle: CPU outputs address, ROM latches it + let address_low = self.read_data_bus(); + self.last_address = address_low as u16; + self.address_latched = true; + self.address_latch_time = Some(Instant::now()); + self.data_available = false; + } else if !self.address_latched { + // Reset data available flag when not in active operation + self.data_available = false; + } + false } } @@ -284,11 +391,28 @@ impl Component for Intel4001 { } fn update(&mut self) { - // Respect access timing - if self.last_access.elapsed() < self.access_time { + // Only update on PHI1 rising edge (synchronous with CPU clock) + if !self.is_phi1_rising_edge() { return; } + // Update clock states for next edge detection + let (phi1, phi2) = self.read_clock_pins(); + self.prev_phi1 = phi1; + self.prev_phi2 = phi2; + + // Check if we have a latched address and need to make data available + if self.address_latched { + if let Some(latch_time) = self.address_latch_time { + if latch_time.elapsed() >= self.access_time { + // Access latency has elapsed, data is now available + self.data_available = true; + self.address_latched = false; + self.address_latch_time = None; + } + } + } + self.handle_reset(); // Handle I/O operations (higher priority than memory operations) @@ -297,23 +421,28 @@ impl Component for Intel4001 { // Handle memory operations let memory_accessed = self.handle_memory_operation(); - // If no memory operation occurred, ensure data bus is tri-stated when not active - if !memory_accessed { - let (sync, cm_rom, _, _) = self.read_control_pins(); - if !sync || !cm_rom { - self.tri_state_data_bus(); - } + // Additional safety: ensure data bus is tri-stated when ROM is not actively driving + // This handles any edge cases not covered in handle_memory_operation + if !memory_accessed && !self.should_drive_data_bus() { + self.tri_state_data_bus(); } self.last_access = Instant::now(); } fn run(&mut self) { + // Time-slice model: run in a loop calling update() each cycle 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(10)); + // Small delay to prevent busy waiting when no clock is present + std::thread::sleep(std::time::Duration::from_micros(1)); } } @@ -323,6 +452,11 @@ impl Component for Intel4001 { // Tri-state all outputs when stopped self.tri_state_data_bus(); self.tri_state_io_pins(); + + // Reset access latency state + self.address_latched = false; + self.address_latch_time = None; + self.data_available = false; } fn is_running(&self) -> bool { @@ -330,6 +464,8 @@ impl Component for Intel4001 { } } +impl RunnableComponent for Intel4001 {} + // Intel 4001 specific methods impl Intel4001 { pub fn get_rom_size(&self) -> usize { @@ -435,4 +571,4 @@ mod tests { assert_eq!(IoMode::Output.to_string(), "Output"); assert_eq!(IoMode::Bidirectional.to_string(), "Bidirectional"); } -} \ No newline at end of file +} diff --git a/src/components/memory/intel_4002.rs b/src/components/memory/intel_4002.rs index 01a1529..e6acca9 100644 --- a/src/components/memory/intel_4002.rs +++ b/src/components/memory/intel_4002.rs @@ -29,12 +29,12 @@ impl Intel4002 { // - 4 output port pins (O0-O3) // - Control pins: SYNC, CM-ROM, CM-RAM, RESET let pin_names = vec![ - "D0", "D1", "D2", "D3", // Data/Address pins - "O0", "O1", "O2", "O3", // Output port pins - "SYNC", // Sync signal - "CM_ROM", // ROM Chip Select - "CM_RAM", // RAM Chip Select - "RESET", // Reset + "D0", "D1", "D2", "D3", // Data/Address pins + "O0", "O1", "O2", "O3", // Output port pins + "SYNC", // Sync signal + "CM_ROM", // ROM Chip Select + "CM_RAM", // RAM Chip Select + "RESET", // Reset ]; let pins = BaseComponent::create_pin_map(&pin_names, &name); @@ -119,7 +119,8 @@ impl Intel4002 { 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(self.base.get_name().parse().unwrap()), PinValue::HighZ); + pin_guard + .set_driver(Some(self.base.get_name().parse().unwrap()), PinValue::HighZ); } } } @@ -231,7 +232,8 @@ impl Intel4002 { let address_instruction = self.read_data_bus(); // Decode the address based on instruction type - let (_bank, ram_address) = self.decode_address(self.last_address, address_instruction); + let (_bank, ram_address) = + self.decode_address(self.last_address, address_instruction); if ram_address < 40 { // Read from RAM and output data @@ -415,7 +417,7 @@ impl Intel4002 { } else if start > 40 { Vec::new() } else { - self.memory[start..40].to_vec() + self.memory[start..40].to_vec() } } } @@ -475,7 +477,7 @@ mod tests { let mut ram = Intel4002::new("RAM_4002".to_string()); // Write test data to different banks - ram.write_ram(0, 0x01).unwrap(); // Bank 0 + ram.write_ram(0, 0x01).unwrap(); // Bank 0 ram.write_ram(16, 0x02).unwrap(); // Bank 1 ram.write_ram(32, 0x03).unwrap(); // Bank 2 @@ -507,4 +509,4 @@ mod tests { assert_eq!(ram.read_ram(0).unwrap(), 0); assert_eq!(ram.read_ram(10).unwrap(), 0); } -} \ No newline at end of file +} diff --git a/src/components/memory/mod.rs b/src/components/memory/mod.rs index 2bf13a2..e60e083 100644 --- a/src/components/memory/mod.rs +++ b/src/components/memory/mod.rs @@ -1,4 +1,4 @@ -pub mod intel_4002; -pub mod intel_4001; +mod generic_ram; pub mod generic_rom; -mod generic_ram; \ No newline at end of file +pub mod intel_4001; +pub mod intel_4002; diff --git a/src/components/mod.rs b/src/components/mod.rs index c869d05..528184b 100644 --- a/src/components/mod.rs +++ b/src/components/mod.rs @@ -1,3 +1,3 @@ -pub mod cpu; pub mod clock; +pub mod cpu; pub mod memory; diff --git a/src/connection.rs b/src/connection.rs index 92916ec..ee50d60 100644 --- a/src/connection.rs +++ b/src/connection.rs @@ -1,6 +1,6 @@ +use crate::pin::Pin; use std::collections::HashMap; use std::sync::{Arc, Mutex}; -use crate::pin::Pin; /// Manages electrical connections between pins pub struct ConnectionManager { @@ -25,35 +25,49 @@ impl ConnectionManager { } /// Connect two pins bidirectionally - pub fn connect_pins(&mut self, pin1: Arc>, pin2: Arc>) -> Result<(), String> { + pub fn connect_pins( + &mut self, + pin1: Arc>, + pin2: Arc>, + ) -> Result<(), String> { let pin1_name = { - let p1 = pin1.lock().map_err(|e| format!("Failed to lock pin1: {}", e))?; + let p1 = pin1 + .lock() + .map_err(|e| format!("Failed to lock pin1: {}", e))?; p1.name().to_string() }; let pin2_name = { - let p2 = pin2.lock().map_err(|e| format!("Failed to lock pin2: {}", e))?; + let p2 = pin2 + .lock() + .map_err(|e| format!("Failed to lock pin2: {}", e))?; p2.name().to_string() }; // Connect pin1 to pin2 { - let mut p1 = pin1.lock().map_err(|e| format!("Failed to lock pin1: {}", e))?; + let mut p1 = pin1 + .lock() + .map_err(|e| format!("Failed to lock pin1: {}", e))?; p1.connect_to(pin2.clone()); } // Connect pin2 to pin1 (bidirectional) { - let mut p2 = pin2.lock().map_err(|e| format!("Failed to lock pin2: {}", e))?; + let mut p2 = pin2 + .lock() + .map_err(|e| format!("Failed to lock pin2: {}", e))?; p2.connect_to(pin1.clone()); } // Update connection graph - self.connections.entry(pin1_name.clone()) + self.connections + .entry(pin1_name.clone()) .or_insert_with(Vec::new) .push(pin2_name.clone()); - self.connections.entry(pin2_name) + self.connections + .entry(pin2_name) .or_insert_with(Vec::new) .push(pin1_name); @@ -67,7 +81,7 @@ impl ConnectionManager { } for i in 0..pins.len() { - for j in i+1..pins.len() { + for j in i + 1..pins.len() { self.connect_pins(pins[i].clone(), pins[j].clone())?; } } @@ -76,26 +90,38 @@ impl ConnectionManager { } /// Disconnect two pins - pub fn disconnect_pins(&mut self, pin1: &Arc>, pin2: &Arc>) -> Result<(), String> { + pub fn disconnect_pins( + &mut self, + pin1: &Arc>, + pin2: &Arc>, + ) -> Result<(), String> { let pin1_name = { - let p1 = pin1.lock().map_err(|e| format!("Failed to lock pin1: {}", e))?; + let p1 = pin1 + .lock() + .map_err(|e| format!("Failed to lock pin1: {}", e))?; p1.name().to_string() }; let pin2_name = { - let p2 = pin2.lock().map_err(|e| format!("Failed to lock pin2: {}", e))?; + let p2 = pin2 + .lock() + .map_err(|e| format!("Failed to lock pin2: {}", e))?; p2.name().to_string() }; // Disconnect pin1 from pin2 { - let mut p1 = pin1.lock().map_err(|e| format!("Failed to lock pin1: {}", e))?; + let mut p1 = pin1 + .lock() + .map_err(|e| format!("Failed to lock pin1: {}", e))?; p1.disconnect_from_pin(pin2); } // Disconnect pin2 from pin1 { - let mut p2 = pin2.lock().map_err(|e| format!("Failed to lock pin2: {}", e))?; + let mut p2 = pin2 + .lock() + .map_err(|e| format!("Failed to lock pin2: {}", e))?; p2.disconnect_from_pin(pin1); } @@ -118,7 +144,8 @@ impl ConnectionManager { /// Check if two pins are connected pub fn are_connected(&self, pin1_name: &str, pin2_name: &str) -> bool { - self.connections.get(pin1_name) + self.connections + .get(pin1_name) .map(|connections| connections.contains(&pin2_name.to_string())) .unwrap_or(false) } @@ -126,12 +153,15 @@ impl ConnectionManager { /// Disconnect all pins from a given pin pub fn disconnect_all(&mut self, pin: &Arc>) -> Result<(), String> { let pin_name = { - let p = pin.lock().map_err(|e| format!("Failed to lock pin: {}", e))?; + let p = pin + .lock() + .map_err(|e| format!("Failed to lock pin: {}", e))?; p.name().to_string() }; // Get all connected pin names before disconnecting - let connected_names: Vec = self.connections + let connected_names: Vec = self + .connections .get(&pin_name) .map(|v| v.clone()) .unwrap_or_default(); @@ -152,7 +182,9 @@ impl ConnectionManager { // Clear the pin's internal connections { - let mut p = pin.lock().map_err(|e| format!("Failed to lock pin: {}", e))?; + let mut p = pin + .lock() + .map_err(|e| format!("Failed to lock pin: {}", e))?; p.clear_connections(); } @@ -278,4 +310,4 @@ mod tests { let p1 = pin1.lock().unwrap(); assert_eq!(p1.get_connection_count(), 0); } -} \ No newline at end of file +} diff --git a/src/lib.rs b/src/lib.rs index 77621ba..32dddce 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,12 +1,12 @@ -pub mod component; -pub mod pin; -pub mod connection; -pub mod components; -pub mod systems; mod bus; +pub mod component; +pub mod components; +pub mod connection; +pub mod pin; +pub mod systems; pub mod types; // Re-export commonly used items for easier importing -pub use component::{Component, BaseComponent}; +pub use component::{BaseComponent, Component}; +pub use connection::connect_pins; pub use pin::{Pin, PinValue}; -pub use connection::connect_pins; \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index f14a300..d51a267 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,5 @@ -use rusty_emu::types::U12; use rusty_emu::systems::intel_mcs_4::IntelMcs4; +use rusty_emu::types::U12; use std::thread; use std::time::{Duration, Instant}; @@ -67,7 +67,7 @@ fn compile_fibonacci_program() -> Vec { 0x31, // SRC 1 0x60, // JUN 0 0x00, // Address - // Pad with zeros + // Pad with zeros ] } @@ -91,7 +91,8 @@ fn run_fibonacci_demo(mcs4: IntelMcs4) { let mut last_fibonacci = 0; let mut iteration = 0; - while iteration < 20 { // Run for 20 iterations + while iteration < 20 { + // Run for 20 iterations thread::sleep(Duration::from_millis(200)); if let Ok(system) = mcs4_arc.lock() { @@ -99,15 +100,21 @@ fn run_fibonacci_demo(mcs4: IntelMcs4) { let current_fibonacci = state.accumulator; if current_fibonacci != last_fibonacci { - println!("{:5} | {:9} | {:11} | {:04X}", - state.cycle_count, current_fibonacci, state.accumulator, state.program_counter); + println!( + "{:5} | {:9} | {:11} | {:04X}", + state.cycle_count, + current_fibonacci, + state.accumulator, + state.program_counter + ); last_fibonacci = current_fibonacci; iteration += 1; } } } - if iteration >= 15 { // Stop after 15 Fibonacci numbers + if iteration >= 15 { + // Stop after 15 Fibonacci numbers if let Ok(mut system) = mcs4_arc.lock() { system.stop(); } @@ -132,4 +139,4 @@ mod tests { let program = compile_fibonacci_program(); assert!(!program.is_empty()); } -} \ No newline at end of file +} diff --git a/src/pin.rs b/src/pin.rs index 3df0b74..91c0e85 100644 --- a/src/pin.rs +++ b/src/pin.rs @@ -92,7 +92,12 @@ impl Pin { self.set_driver_with_strength(driver_name, value, strength); } - pub fn set_driver_with_strength(&mut self, driver_name: Option, value: PinValue, strength: DriveStrength) { + pub fn set_driver_with_strength( + &mut self, + driver_name: Option, + value: PinValue, + strength: DriveStrength, + ) { let driver_id = driver_name.unwrap_or_else(|| "anonymous".to_string()); if value == PinValue::HighZ && strength == DriveStrength::HighImpedance { @@ -140,7 +145,11 @@ impl Pin { } pub fn connect_to(&mut self, other_pin: Arc>) { - if !self.connected_pins.iter().any(|p| Arc::ptr_eq(p, &other_pin)) { + if !self + .connected_pins + .iter() + .any(|p| Arc::ptr_eq(p, &other_pin)) + { self.connected_pins.push(other_pin); } } @@ -190,7 +199,9 @@ impl Pin { } // Get all drivers with the strongest strength - let strong_drivers: Vec = self.drivers.values() + let strong_drivers: Vec = self + .drivers + .values() .filter(|(_, strength)| *strength == max_strength) .map(|(value, _)| *value) .collect(); @@ -216,7 +227,9 @@ impl Pin { } pub fn is_connected_to(&self, other_pin: &Arc>) -> bool { - self.connected_pins.iter().any(|p| Arc::ptr_eq(p, other_pin)) + self.connected_pins + .iter() + .any(|p| Arc::ptr_eq(p, other_pin)) } pub fn get_connection_count(&self) -> usize { @@ -248,7 +261,9 @@ impl std::fmt::Display for Pin { if !self.drivers.is_empty() { write!(f, " [drivers: ")?; for (i, (driver, (value, strength))) in self.drivers.iter().enumerate() { - if i > 0 { write!(f, ", ")?; } + if i > 0 { + write!(f, ", ")?; + } write!(f, "{}={}({})", driver, value.to_char(), *strength as u8)?; } write!(f, "]")?; @@ -301,7 +316,7 @@ mod tests { pin.set_driver_with_strength( Some("weak".to_string()), PinValue::High, - DriveStrength::Weak + DriveStrength::Weak, ); assert_eq!(pin.read(), PinValue::High); @@ -309,7 +324,7 @@ mod tests { pin.set_driver_with_strength( Some("strong".to_string()), PinValue::Low, - DriveStrength::Strong + DriveStrength::Strong, ); assert_eq!(pin.read(), PinValue::Low); } @@ -366,4 +381,4 @@ mod tests { pin.set_driver(Some("driver".to_string()), PinValue::HighZ); assert_eq!(pin.read(), PinValue::HighZ); } -} \ No newline at end of file +} diff --git a/src/systems/intel_mcs_4.rs b/src/systems/intel_mcs_4.rs index 68e9102..5027d7a 100644 --- a/src/systems/intel_mcs_4.rs +++ b/src/systems/intel_mcs_4.rs @@ -3,9 +3,9 @@ use std::sync::{Arc, Mutex}; use std::thread; use std::time::Duration; +use crate::component::Component; use crate::components::clock::generic_clock::GenericClock; use crate::components::cpu::intel_4004::Intel4004; -use crate::component::Component; use crate::components::memory::intel_4001::Intel4001; use crate::components::memory::intel_4002::Intel4002; use crate::pin::Pin; @@ -29,23 +29,29 @@ impl IntelMcs4 { fn initialize_system(&mut self) { self.components.insert( "cpu".to_string(), - Arc::new(Mutex::new(Intel4004::new("CPU_4004".to_string(), 750_000.0))) + Arc::new(Mutex::new(Intel4004::new( + "CPU_4004".to_string(), + 750_000.0, + ))), ); self.components.insert( "clock".to_string(), - Arc::new(Mutex::new(GenericClock::new("SYSTEM_CLOCK".to_string(), 750_000.0))) + Arc::new(Mutex::new(GenericClock::new( + "SYSTEM_CLOCK".to_string(), + 750_000.0, + ))), ); self.components.insert( "ram".to_string(), - Arc::new(Mutex::new(Intel4002::new("RAM_4002".to_string()))) + Arc::new(Mutex::new(Intel4002::new("RAM_4002".to_string()))), ); self.components.insert( "rom1".to_string(), - Arc::new(Mutex::new(Intel4001::new("ROM_4001_1".to_string()))) + Arc::new(Mutex::new(Intel4001::new("ROM_4001_1".to_string()))), ); self.components.insert( "rom2".to_string(), - Arc::new(Mutex::new(Intel4001::new("ROM_4001_2".to_string()))) + Arc::new(Mutex::new(Intel4001::new("ROM_4001_2".to_string()))), ); } @@ -118,7 +124,12 @@ impl IntelMcs4 { Ok(()) } - pub fn load_rom_data(&mut self, rom_chip: usize, data: Vec, offset: usize) -> Result<(), String> { + pub fn load_rom_data( + &mut self, + rom_chip: usize, + data: Vec, + offset: usize, + ) -> Result<(), String> { let rom_key = match rom_chip { 1 => "rom1", 2 => "rom2", @@ -128,7 +139,12 @@ impl IntelMcs4 { if let Some(rom_component) = self.components.get(rom_key) { if let Ok(_rom) = rom_component.lock() { // For now, just log the operation - println!("Loaded {} bytes into ROM{} at offset {}", data.len(), rom_chip, offset); + println!( + "Loaded {} bytes into ROM{} at offset {}", + data.len(), + rom_chip, + offset + ); return Ok(()); } } @@ -167,7 +183,7 @@ impl IntelMcs4 { println!("Resetting MCS-4 system..."); if let Some(cpu_component) = self.components.get_mut("cpu") { if let Some(cpu) = cpu_component.as_any_mut().downcast_mut::() { - cpu.reset(); + cpu.reset(); } } } @@ -181,9 +197,13 @@ impl IntelMcs4 { } pub fn get_connection_graph(&self) -> Vec> { - vec![ - vec!["cpu".to_string(), "clock".to_string(), "ram".to_string(), "rom1".to_string(), "rom2".to_string()], - ] + vec![vec![ + "cpu".to_string(), + "clock".to_string(), + "ram".to_string(), + "rom1".to_string(), + "rom2".to_string(), + ]] } } @@ -244,10 +264,9 @@ impl Component for IntelMcs4 { fn stop(&mut self) { self.stop(); - } fn is_running(&self) -> bool { self.is_running() } -} \ No newline at end of file +} diff --git a/src/systems/mod.rs b/src/systems/mod.rs index 245f27e..f75af90 100644 --- a/src/systems/mod.rs +++ b/src/systems/mod.rs @@ -1 +1 @@ -pub mod intel_mcs_4; \ No newline at end of file +pub mod intel_mcs_4; diff --git a/src/types.rs b/src/types.rs index b9325b0..3ba14f6 100644 --- a/src/types.rs +++ b/src/types.rs @@ -42,4 +42,4 @@ impl From for u16 { fn from(value: U12) -> Self { value.value() } -} \ No newline at end of file +}