From ac8ebbafe95e3d44f845d1332313d74aa4914a7c Mon Sep 17 00:00:00 2001 From: Jan-Peter von Hunnius Date: Sun, 21 Sep 2025 18:54:27 +0200 Subject: [PATCH] Starting point for MCS-4 emulation and MOS 6502 inheritance --- Cargo.toml | 2 + src/components/clock/generic_clock.rs | 70 ++++++++++ src/components/clock/mod.rs | 1 + src/components/cpu/cmos_65c02.rs | 115 ++++++++++++++++ src/components/cpu/cpu_traits.rs | 138 +++++++++++++++++++ src/components/cpu/intel_4004.rs | 114 ++++++++++++++++ src/components/cpu/mod.rs | 4 + src/components/cpu/mos_6502.rs | 162 +++++++++++++++++++++++ src/components/mod.rs | 2 + src/lib.rs | 182 +++++++++++++++++++++++++- src/main.rs | 4 + src/systems/intel_mcs_4.rs | 32 +++++ src/systems/mod.rs | 1 + 13 files changed, 823 insertions(+), 4 deletions(-) create mode 100644 src/components/clock/generic_clock.rs create mode 100644 src/components/clock/mod.rs create mode 100644 src/components/cpu/cmos_65c02.rs create mode 100644 src/components/cpu/cpu_traits.rs create mode 100644 src/components/cpu/intel_4004.rs create mode 100644 src/components/cpu/mod.rs create mode 100644 src/components/cpu/mos_6502.rs create mode 100644 src/components/mod.rs create mode 100644 src/main.rs create mode 100644 src/systems/intel_mcs_4.rs create mode 100644 src/systems/mod.rs diff --git a/Cargo.toml b/Cargo.toml index 2c17f48..89c7f47 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,3 +4,5 @@ version = "0.1.0" edition = "2021" [dependencies] +serialport = "4.6.0" +connect = "0.2.4" diff --git a/src/components/clock/generic_clock.rs b/src/components/clock/generic_clock.rs new file mode 100644 index 0000000..79e9a78 --- /dev/null +++ b/src/components/clock/generic_clock.rs @@ -0,0 +1,70 @@ +use std::collections::HashMap; +use crate::{PinValue, BaseComponent, Component, Pin}; +use std::sync::{Arc, Mutex}; +use std::thread; +use std::time::Duration; +#[derive(Clone)] +pub struct GenericClock { + base: BaseComponent, + frequency: u64, + half_period: Duration, + last_state: bool, +} +impl GenericClock { + pub fn new(name: String, frequency_hz: u64) -> Self { + let mut base = BaseComponent::new(name); + let out_pin = base.add_pin("out".to_string(), PinValue::Low, true); + + let half_period_ms = 500 / frequency_hz; // Convert to milliseconds + + Self { + base, + frequency: frequency_hz, + half_period: Duration::from_millis(half_period_ms), + last_state: false, + } + } + + pub fn out(&self) -> Option> { + self.base.get_pin("out") + } +} + +impl Component for GenericClock { + fn name(&self) -> &str { + self.base.name() + } + + fn pins(&self) -> &HashMap> { + self.base.pins() + } + + fn get_pin(&self, name: &str) -> Option> { + self.base.get_pin(name) + } + + fn connect_pin(&mut self, pin_name: &str, other_pin: Arc) -> Result<(), String> { + self.base.connect_pin(pin_name, other_pin) + } + + fn update(&mut self) -> Result<(), String> { + let out_pin = self.base.pins.get("out").unwrap(); + + // Toggle clock output + self.last_state = !self.last_state; + let new_value = if self.last_state { PinValue::High } else { PinValue::Low }; + + out_pin.write(new_value, true); + thread::sleep(self.half_period); + + Ok(()) + } + + fn run(&mut self) { + self.base.run(); + } + + fn stop(&mut self) { + self.base.stop(); + } +} \ No newline at end of file diff --git a/src/components/clock/mod.rs b/src/components/clock/mod.rs new file mode 100644 index 0000000..67c6f16 --- /dev/null +++ b/src/components/clock/mod.rs @@ -0,0 +1 @@ +pub(crate) mod generic_clock; \ No newline at end of file diff --git a/src/components/cpu/cmos_65c02.rs b/src/components/cpu/cmos_65c02.rs new file mode 100644 index 0000000..848b1e9 --- /dev/null +++ b/src/components/cpu/cmos_65c02.rs @@ -0,0 +1,115 @@ +use crate::{PinValue, Component, Pin}; +use std::sync::Arc; +use crate::components::cpu::mos_6502::MOS6502; + +pub struct CMOS65C02 { + pub(crate) base_6502: MOS6502, + // 65C02-specific state + stopped: bool, + waiting: bool, +} +impl CMOS65C02 { + pub fn new(name: String) -> Self { + let base_6502 = MOS6502::new(name); + + Self { + base_6502, + stopped: false, + waiting: false, + } + } + + // Inherit methods from MOS6502 + pub fn get_register_a(&self) -> u8 { + self.base_6502.get_register_a() + } + + pub fn set_register_a(&mut self, value: u8) { + self.base_6502.set_register_a(value) + } + + // 65C02-specific instructions + pub fn bra(&mut self, address: u16) { + // Branch always - new in 65C02 + self.base_6502.registers.pc = address; + } + + pub fn phx(&mut self) { + // Push X - new in 65C02 + // Stack push implementation would go here + let x = self.base_6502.registers.x; + println!("PHX: Pushing X register ({:02X}) to stack", x); + } + + pub fn ply(&mut self) { + // Pull Y - new in 65C02 + // Stack pull implementation would go here + println!("PLY: Pulling value from stack to Y register"); + } + + pub fn stp(&mut self) { + // Stop instruction - new in 65C02 + self.stopped = true; + println!("STP: Processor stopped"); + } + + pub fn wai(&mut self) { + // Wait for interrupt - new in 65C02 + self.waiting = true; + println!("WAI: Processor waiting for interrupt"); + } + + // Enhanced addressing modes or modified instructions + pub fn jmp_indirect(&mut self, address: u16) { + // 65C02 fixes the JMP indirect bug + // Implementation would go here + println!("JMP (indirect) to {:04X}", address); + self.base_6502.registers.pc = address; + } + + // Additional 65C02-specific methods + pub fn is_stopped(&self) -> bool { + self.stopped + } + + pub fn is_waiting(&self) -> bool { + self.waiting + } +} + +// Implement Component by delegating to the base 6502 +impl Component for CMOS65C02 { + fn name(&self) -> &str { + self.base_6502.name() + } + + fn pins(&self) -> &std::collections::HashMap> { + self.base_6502.pins() + } + + fn get_pin(&self, name: &str) -> Option> { + self.base_6502.get_pin(name) + } + + fn connect_pin(&mut self, pin_name: &str, other_pin: Arc) -> Result<(), String> { + self.base_6502.connect_pin(pin_name, other_pin) + } + + fn update(&mut self) -> Result<(), String> { + if self.stopped { + // Don't execute instructions if stopped + return Ok(()); + } + + // Delegate to base implementation + self.base_6502.update() + } + + fn run(&mut self) { + self.base_6502.run() + } + + fn stop(&mut self) { + self.base_6502.stop() + } +} \ No newline at end of file diff --git a/src/components/cpu/cpu_traits.rs b/src/components/cpu/cpu_traits.rs new file mode 100644 index 0000000..87da1b3 --- /dev/null +++ b/src/components/cpu/cpu_traits.rs @@ -0,0 +1,138 @@ +use crate::{PinValue, Component}; +use crate::components::cpu::cmos_65c02::CMOS65C02; +use crate::components::cpu::mos_6502::{Registers, MOS6502}; + +pub trait CPU: Component { + fn reset(&mut self); + fn execute_instruction(&mut self); + fn get_registers(&self) -> &Registers; + fn get_registers_mut(&mut self) -> &mut Registers; + fn read_memory(&self, address: u16) -> u8; + fn write_memory(&mut self, address: u16, value: u8); +} + +pub trait MOS6502Family: CPU { + // Common 6502 family methods + fn lda(&mut self, value: u8); + fn sta(&mut self, address: u16); + fn tax(&mut self); + // More common instructions... +} + +pub trait CMOS65C02Extensions: MOS6502Family { + // 65C02-specific methods + fn bra(&mut self, address: u16); + fn phx(&mut self); + fn ply(&mut self); + fn stp(&mut self); + fn wai(&mut self); +} + +impl CPU for MOS6502 { + fn reset(&mut self) { + todo!() + } + + fn execute_instruction(&mut self) { + todo!() + } + + fn get_registers(&self) -> &Registers { + todo!() + } + + fn get_registers_mut(&mut self) -> &mut Registers { + todo!() + } + + fn read_memory(&self, address: u16) -> u8 { + todo!() + } + + fn write_memory(&mut self, address: u16, value: u8) { + todo!() + } +} + +// Implement for both MOS6502 and CMOS65C02 +impl MOS6502Family for MOS6502 { + fn lda(&mut self, value: u8) { + self.lda(value) + } + + fn sta(&mut self, address: u16) { + todo!() + } + + fn tax(&mut self) { + todo!() + } + + // Implement other methods... +} + +impl CPU for CMOS65C02 { + fn reset(&mut self) { + todo!() + } + + fn execute_instruction(&mut self) { + todo!() + } + + fn get_registers(&self) -> &Registers { + todo!() + } + + fn get_registers_mut(&mut self) -> &mut Registers { + todo!() + } + + fn read_memory(&self, address: u16) -> u8 { + todo!() + } + + fn write_memory(&mut self, address: u16, value: u8) { + todo!() + } +} + +impl MOS6502Family for CMOS65C02 { + fn lda(&mut self, value: u8) { + self.base_6502.lda(value) + } + + fn sta(&mut self, address: u16) { + todo!() + } + + fn tax(&mut self) { + todo!() + } + + // Implement other methods... +} + +impl CMOS65C02Extensions for CMOS65C02 { + fn bra(&mut self, address: u16) { + self.bra(address) + } + + fn phx(&mut self) { + todo!() + } + + fn ply(&mut self) { + todo!() + } + + fn stp(&mut self) { + todo!() + } + + fn wai(&mut self) { + todo!() + } + + // 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 new file mode 100644 index 0000000..5813ff4 --- /dev/null +++ b/src/components/cpu/intel_4004.rs @@ -0,0 +1,114 @@ +use std::collections::HashMap; +use crate::{PinValue, BaseComponent, Component, Pin}; +use std::sync::Arc; + +// Simple 4-bit and 12-bit types for the 4004 +#[derive(Debug, Clone, Copy)] +struct u4(u8); +#[derive(Debug, Clone, Copy)] +struct u12(u16); + +impl u4 { + fn wrapping_add(self, other: u4) -> u4 { + u4((self.0 + other.0) & 0xF) + } +} + +impl u12 { + fn wrapping_add(self, other: u12) -> u12 { + u12((self.0 + other.0) & 0xFFF) + } +} + +#[derive(Clone)] +pub struct Intel4004 { + base: BaseComponent, + program_counter: u12, + accumulator: u4, + last_clock_state: PinValue, +} + +impl Intel4004 { + pub fn new(name: String) -> Self { + let mut base = BaseComponent::new(name); + + // Add essential pins + base.add_pin("clk".to_string(), PinValue::Low, false); // Input pin + base.add_pin("reset".to_string(), PinValue::Low, false); // Input pin + base.add_pin("data".to_string(), PinValue::HighZ, false); // Bidirectional + + Self { + base, + program_counter: u12(0), + accumulator: u4(0), + last_clock_state: PinValue::Low, + } + } + + pub fn clk(&self) -> Option> { + self.base.get_pin("clk") + } + + pub fn reset(&self) -> Option> { + self.base.get_pin("reset") + } + + pub fn data(&self) -> Option> { + self.base.get_pin("data") + } +} + +impl Component for Intel4004 { + fn name(&self) -> &str { + self.base.name() + } + + fn pins(&self) -> &HashMap> { + self.base.pins() + } + + fn get_pin(&self, name: &str) -> Option> { + self.base.get_pin(name) + } + + fn connect_pin(&mut self, pin_name: &str, other_pin: Arc) -> Result<(), String> { + self.base.connect_pin(pin_name, other_pin) + } + + fn update(&mut self) -> Result<(), String> { + // Read clock pin (check if any connected component is driving it low) + let clk_pin = self.base.pins.get("clk").unwrap(); + let clk_value = clk_pin.read(); + + // Detect rising edge + if clk_value == PinValue::High && self.last_clock_state == PinValue::Low { + // Simple fetch-execute cycle + self.program_counter = self.program_counter.wrapping_add(u12(1)); + + // Read reset pin + let reset_pin = self.base.pins.get("reset").unwrap(); + let reset_value = reset_pin.read(); + + if reset_value == PinValue::High { + self.program_counter = u12(0); + self.accumulator = u4(0); + println!("CPU {}: RESET", self.name()); + } else { + // For now, just print state + println!("CPU {}: PC={:03X}, ACC={:X}", + self.name(), self.program_counter.0, self.accumulator.0); + } + } + + self.last_clock_state = clk_value; + Ok(()) + } + + fn run(&mut self) { + self.base.run(); + } + + fn stop(&mut self) { + self.base.stop(); + } +} \ No newline at end of file diff --git a/src/components/cpu/mod.rs b/src/components/cpu/mod.rs new file mode 100644 index 0000000..f060142 --- /dev/null +++ b/src/components/cpu/mod.rs @@ -0,0 +1,4 @@ +mod cpu_traits; +pub(crate) mod intel_4004; +mod mos_6502; +mod cmos_65c02; diff --git a/src/components/cpu/mos_6502.rs b/src/components/cpu/mos_6502.rs new file mode 100644 index 0000000..322ac9a --- /dev/null +++ b/src/components/cpu/mos_6502.rs @@ -0,0 +1,162 @@ +use std::collections::HashMap; +use crate::{PinValue, BaseComponent, Component, Pin}; +use std::sync::Arc; + +// 6502 addressing modes +pub enum AddressingMode { + Immediate, + ZeroPage, + ZeroPageX, + ZeroPageY, + Absolute, + AbsoluteX, + AbsoluteY, + Indirect, + IndirectX, + IndirectY, + Implied, + Accumulator, + Relative, +} + +// 6502 registers +#[derive(Clone, Default)] +pub struct Registers { + pub a: u8, // Accumulator + pub x: u8, // X index + pub y: u8, // Y index + pub sp: u8, // Stack pointer + pub pc: u16, // Program counter + pub sr: u8, // Status register +} + +// Bit positions in status register +pub const CARRY_FLAG: u8 = 1 << 0; +pub const ZERO_FLAG: u8 = 1 << 1; +pub const INTERRUPT_DISABLE: u8 = 1 << 2; +pub const DECIMAL_MODE: u8 = 1 << 3; +pub const BREAK_COMMAND: u8 = 1 << 4; +pub const UNUSED_FLAG: u8 = 1 << 5; +pub const OVERFLOW_FLAG: u8 = 1 << 6; +pub const NEGATIVE_FLAG: u8 = 1 << 7; + +pub struct MOS6502 { + base: BaseComponent, + pub(crate) registers: Registers, + cycle_count: u64, + last_clock_state: PinValue, + // Memory interface would be added here +} + +impl MOS6502 { + pub fn new(name: String) -> Self { + let mut base = BaseComponent::new(name); + + // Add 6502 pins + base.add_pin("clk".to_string(), PinValue::Low, false); + base.add_pin("reset".to_string(), PinValue::Low, false); + base.add_pin("irq".to_string(), PinValue::High, false); + base.add_pin("nmi".to_string(), PinValue::High, false); + base.add_pin("rw".to_string(), PinValue::High, true); // Read/Write + base.add_pin("sync".to_string(), PinValue::Low, true); // Sync + // Add address and data pins... + + Self { + base, + registers: Registers::default(), + cycle_count: 0, + last_clock_state: PinValue::Low, + } + } + + // Common 6502 methods that will be inherited + pub fn reset(&mut self) { + self.registers.pc = 0xFFFC; + self.registers.sp = 0xFD; + self.registers.sr = 0x34; // I flag set, others cleared + self.cycle_count = 0; + } + + pub fn get_register_a(&self) -> u8 { + self.registers.a + } + + pub fn set_register_a(&mut self, value: u8) { + self.registers.a = value; + self.update_zero_negative_flags(value); + } + + // Common flag handling + pub fn update_zero_negative_flags(&mut self, value: u8) { + self.set_flag(ZERO_FLAG, value == 0); + self.set_flag(NEGATIVE_FLAG, value & 0x80 != 0); + } + + pub fn set_flag(&mut self, flag: u8, condition: bool) { + if condition { + self.registers.sr |= flag; + } else { + self.registers.sr &= !flag; + } + } + + pub fn get_flag(&self, flag: u8) -> bool { + self.registers.sr & flag != 0 + } + + // Common instruction implementations + pub fn lda(&mut self, value: u8) { + self.set_register_a(value); + } + + pub fn tax(&mut self) { + self.registers.x = self.registers.a; + self.update_zero_negative_flags(self.registers.x); + } + + // More common instructions... +} + +impl Component for MOS6502 { + fn name(&self) -> &str { + todo!() + } + + fn pins(&self) -> &HashMap> { + todo!() + } + + fn get_pin(&self, name: &str) -> Option> { + todo!() + } + + fn connect_pin(&mut self, pin_name: &str, other_pin: Arc) -> Result<(), String> { + todo!() + } + + // Implement Component trait methods... + fn update(&mut self) -> Result<(), String> { + // Clock handling and instruction execution + let clk_pin = self.base.pins.get("clk").unwrap(); + let clk_value = clk_pin.read(); + + // Detect rising edge + if clk_value == PinValue::High && self.last_clock_state == PinValue::Low { + self.cycle_count += 1; + // Instruction execution would happen here + } + + self.last_clock_state = clk_value; + Ok(()) + } + + fn run(&mut self) { + todo!() + } + + fn stop(&mut self) { + todo!() + } + + // Other trait methods... +} \ No newline at end of file diff --git a/src/components/mod.rs b/src/components/mod.rs new file mode 100644 index 0000000..2f5fcc3 --- /dev/null +++ b/src/components/mod.rs @@ -0,0 +1,2 @@ +pub(crate) mod cpu; +pub(crate) mod clock; \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index b93cf3f..b4f5404 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,165 @@ -pub fn add(left: u64, right: u64) -> u64 { - left + right +mod systems; +mod components; + +use std::sync::{Arc, Mutex, RwLock}; +use std::thread; +use std::collections::HashMap; +use std::time::{Duration, Instant}; + +// Pin value representation +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum PinValue { + High, + Low, + HighZ, // High impedance (disconnected) +} +// Pin structure with output enable +#[derive(Clone)] +pub struct Pin { + pub name: String, + pub value: Arc>, // Use RwLock for multiple readers + pub output_enable: Arc>, // Whether this pin is driving the line + pub connections: Arc>>>, +} + +// Component trait +impl Pin { + // Get the effective value considering all connected pins + pub fn read(&self) -> PinValue { + let connections = self.connections.lock().unwrap(); + + // Check if any connected pin is actively driving low + for connected_pin in connections.iter() { + let output_enable = connected_pin.output_enable.lock().unwrap(); + let value = connected_pin.value.read().unwrap(); + + if *output_enable && *value == PinValue::Low { + return PinValue::Low; + } + } + + // If no one is driving low, check if anyone is driving high + for connected_pin in connections.iter() { + let output_enable = connected_pin.output_enable.lock().unwrap(); + let value = connected_pin.value.read().unwrap(); + + if *output_enable && *value == PinValue::High { + return PinValue::High; + } + } + + // If no one is driving, return HighZ + PinValue::HighZ + } + + // Set this pin's value and output enable + pub fn write(&self, value: PinValue, output_enable: bool) { + *self.value.write().unwrap() = value; + *self.output_enable.lock().unwrap() = output_enable; + } +} + +// Component trait +pub trait Component: Send { + fn name(&self) -> &str; + fn pins(&self) -> &HashMap>; + fn get_pin(&self, name: &str) -> Option>; + fn connect_pin(&mut self, pin_name: &str, other_pin: Arc) -> Result<(), String>; + fn update(&mut self) -> Result<(), String>; + fn run(&mut self); + fn stop(&mut self); +} +pub fn connect_pins(source: &Arc, destination: &Arc) -> Result<(), String> { + let mut source_connections = source.connections.lock().unwrap(); + source_connections.push(destination.clone()); + + let mut dest_connections = destination.connections.lock().unwrap(); + dest_connections.push(source.clone()); + + Ok(()) +} +// Helper macro for easy connections +#[macro_export] +macro_rules! connect_pin { + ($source:expr, $dest:expr) => { + crate::connect_pins($source, $dest).unwrap() + }; +}// Base component implementation +#[derive(Clone)] +pub struct BaseComponent { + pub name: String, + pub pins: HashMap>, + pub running: Arc>, +} + +impl BaseComponent { + pub fn new(name: String) -> Self { + Self { + name, + pins: HashMap::new(), + running: Arc::new(Mutex::new(false)), + } + } + + pub fn add_pin(&mut self, name: String, initial_value: PinValue, initial_output_enable: bool) -> Arc { + let pin = Arc::new(Pin { + name: name.clone(), + value: Arc::new(RwLock::new(initial_value)), + output_enable: Arc::new(Mutex::new(initial_output_enable)), + connections: Arc::new(Mutex::new(Vec::new())), + }); + + self.pins.insert(name, pin.clone()); + pin + } +} + +impl Component for BaseComponent { + fn name(&self) -> &str { + &self.name + } + + fn pins(&self) -> &HashMap> { + &self.pins + } + + fn get_pin(&self, name: &str) -> Option> { + self.pins.get(name).cloned() + } + + fn connect_pin(&mut self, pin_name: &str, other_pin: Arc) -> Result<(), String> { + if let Some(pin) = self.pins.get_mut(pin_name) { + let mut connections = pin.connections.lock().unwrap(); + connections.push(other_pin); + Ok(()) + } else { + Err(format!("Pin {} not found", pin_name)) + } + } + + fn update(&mut self) -> Result<(), String> { + // Base implementation does nothing + Ok(()) + } + + fn run(&mut self) { + *self.running.lock().unwrap() = true; + let running = self.running.clone(); + let mut self_clone = self.clone(); + + thread::spawn(move || { + while *running.lock().unwrap() { + if let Err(e) = self_clone.update() { + eprintln!("Error in {}: {}", self_clone.name, e); + } + thread::sleep(Duration::from_micros(10)); + } + }); + } + + fn stop(&mut self) { + *self.running.lock().unwrap() = false; + } } #[cfg(test)] @@ -8,7 +168,21 @@ mod tests { #[test] fn it_works() { - let result = add(2, 2); + let result = 4; assert_eq!(result, 4); } -} + + #[test] + pub fn list_ports() { + let ports = serialport::available_ports().expect("No ports found!"); + for port in ports { + let mut port = serialport::new(port.port_name, 115_200) + .timeout(std::time::Duration::from_millis(10)) + .open().expect("Failed to open port"); + + let output = "This is a test. This is only a test.".as_bytes(); + let result = port.write(output); + assert!(result.is_ok()); + } + } +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..ee0d0dd --- /dev/null +++ b/src/main.rs @@ -0,0 +1,4 @@ +mod systems; +fn main() { + +} \ No newline at end of file diff --git a/src/systems/intel_mcs_4.rs b/src/systems/intel_mcs_4.rs new file mode 100644 index 0000000..f8ee781 --- /dev/null +++ b/src/systems/intel_mcs_4.rs @@ -0,0 +1,32 @@ +use std::thread; +use std::time::Duration; +use crate::Component; +use crate::components::clock::generic_clock::GenericClock; +use crate::components::cpu::intel_4004::Intel4004; + +fn emulation() { + println!("Starting MCS-4 emulation with pin state resolution..."); + + // Create components + let mut clock = GenericClock::new("sys_clock".to_string(), 2); // 2Hz clock + let mut cpu = Intel4004::new("cpu4004".to_string()); + + // Connect clock to CPU using the connection macro + if let (Some(clock_out), Some(cpu_clk)) = (clock.out(), cpu.clk()) { + connect_pin!(&clock_out, &cpu_clk); + println!("Connected clock to CPU"); + } + + // Start components + clock.run(); + cpu.run(); + + // Let it run for a while + thread::sleep(Duration::from_secs(5)); + + // Stop components + clock.stop(); + cpu.stop(); + + println!("Emulation completed"); +} \ No newline at end of file diff --git a/src/systems/mod.rs b/src/systems/mod.rs new file mode 100644 index 0000000..3b90b22 --- /dev/null +++ b/src/systems/mod.rs @@ -0,0 +1 @@ +mod intel_mcs_4; \ No newline at end of file