Fixes for 6502 CPUs.
They are not complete yet
This commit is contained in:
parent
2a78581a2d
commit
4d1a87e2af
4 changed files with 437 additions and 212 deletions
|
|
@ -1,106 +0,0 @@
|
||||||
use std::sync::Arc;
|
|
||||||
use crate::component::Component;
|
|
||||||
use crate::pin::Pin;
|
|
||||||
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<String, Arc<Pin>> {
|
|
||||||
self.base_6502.pins()
|
|
||||||
}
|
|
||||||
fn get_pin(&self, name: &str) -> Option<Arc<Pin>> {
|
|
||||||
self.base_6502.get_pin(name)
|
|
||||||
}
|
|
||||||
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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,4 +1,9 @@
|
||||||
pub mod cpu_traits;
|
// CPU components module
|
||||||
|
pub mod mos_6502;
|
||||||
|
pub mod wdc_65c02;
|
||||||
pub mod intel_4004;
|
pub mod intel_4004;
|
||||||
mod mos_6502;
|
|
||||||
mod cmos_65c02;
|
// Re-export the CPU types
|
||||||
|
pub use mos_6502::MOS6502;
|
||||||
|
pub use wdc_65c02::WDC65C02;
|
||||||
|
pub use intel_4004::Intel4004;
|
||||||
|
|
@ -1,141 +1,296 @@
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::Arc;
|
use std::sync::{Arc, Mutex};
|
||||||
|
use std::thread;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
use crate::component::{BaseComponent, Component};
|
use crate::component::{BaseComponent, Component};
|
||||||
use crate::pin::{Pin, PinValue};
|
use crate::pin::{Pin, PinValue};
|
||||||
|
|
||||||
// 6502 addressing modes
|
/// MOS Technology 6502 CPU - 8-bit microprocessor
|
||||||
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 {
|
pub struct MOS6502 {
|
||||||
base: BaseComponent,
|
base: BaseComponent,
|
||||||
pub(crate) registers: Registers,
|
// Registers
|
||||||
|
accumulator: u8,
|
||||||
|
x_register: u8,
|
||||||
|
y_register: u8,
|
||||||
|
stack_pointer: u8,
|
||||||
|
program_counter: u16,
|
||||||
|
status_register: u8,
|
||||||
|
|
||||||
|
// Internal state
|
||||||
cycle_count: u64,
|
cycle_count: u64,
|
||||||
last_clock_state: PinValue,
|
is_reset: bool,
|
||||||
// Memory interface would be added here
|
is_running: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MOS6502 {
|
impl MOS6502 {
|
||||||
pub fn new(name: String) -> Self {
|
pub fn new(name: String) -> Self {
|
||||||
let mut base = BaseComponent::new(name);
|
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
|
||||||
|
"SYNC", // Sync
|
||||||
|
"RDY", // Ready
|
||||||
|
];
|
||||||
|
|
||||||
// Add 6502 pins
|
let pins = BaseComponent::create_pin_map(&pin_names, &name);
|
||||||
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 {
|
MOS6502 {
|
||||||
base,
|
base: BaseComponent::new(name, pins),
|
||||||
registers: Registers::default(),
|
accumulator: 0,
|
||||||
|
x_register: 0,
|
||||||
|
y_register: 0,
|
||||||
|
stack_pointer: 0xFD,
|
||||||
|
program_counter: 0xFFFC, // Reset vector location
|
||||||
|
status_register: 0x20, // Always set bit 5
|
||||||
cycle_count: 0,
|
cycle_count: 0,
|
||||||
last_clock_state: PinValue::Low,
|
is_reset: false,
|
||||||
|
is_running: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Common 6502 methods that will be inherited
|
|
||||||
pub fn reset(&mut self) {
|
pub fn reset(&mut self) {
|
||||||
self.registers.pc = 0xFFFC;
|
self.accumulator = 0;
|
||||||
self.registers.sp = 0xFD;
|
self.x_register = 0;
|
||||||
self.registers.sr = 0x34; // I flag set, others cleared
|
self.y_register = 0;
|
||||||
self.cycle_count = 0;
|
self.stack_pointer = 0xFD;
|
||||||
|
self.program_counter = 0xFFFC;
|
||||||
|
self.status_register = 0x20;
|
||||||
|
self.is_reset = true;
|
||||||
|
|
||||||
|
// Set initial pin states
|
||||||
|
self.set_address_bus(0xFFFC);
|
||||||
|
self.set_data_bus(0xFF);
|
||||||
|
self.set_rw_pin(true); // Start in read mode
|
||||||
}
|
}
|
||||||
pub fn get_register_a(&self) -> u8 {
|
|
||||||
self.registers.a
|
fn set_address_bus(&self, address: u16) {
|
||||||
|
for i in 0..16 {
|
||||||
|
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 };
|
||||||
|
pin_guard.set_driver(Some(self.base.get_name().parse().unwrap()), pin_value);
|
||||||
}
|
}
|
||||||
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;
|
fn set_data_bus(&self, data: u8) {
|
||||||
|
for i in 0..8 {
|
||||||
|
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 };
|
||||||
|
pin_guard.set_driver(Some(self.base.get_name().parse().unwrap()), pin_value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_rw_pin(&self, read: bool) {
|
||||||
|
if let Ok(pin) = self.base.get_pin("RW") {
|
||||||
|
if let Ok(mut pin_guard) = pin.lock() {
|
||||||
|
let pin_value = if read { PinValue::High } else { PinValue::Low };
|
||||||
|
pin_guard.set_driver(Some(self.base.get_name().parse().unwrap()), pin_value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_data_bus(&self) -> u8 {
|
||||||
|
let mut data = 0;
|
||||||
|
|
||||||
|
for i in 0..8 {
|
||||||
|
if let Ok(pin) = self.base.get_pin(&format!("D{}", i)) {
|
||||||
|
if let Ok(pin_guard) = pin.lock() {
|
||||||
|
if pin_guard.read() == PinValue::High {
|
||||||
|
data |= 1 << i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn read_control_pins(&self) -> (bool, bool, bool, bool) {
|
||||||
|
let irq = if let Ok(pin) = self.base.get_pin("IRQ") {
|
||||||
|
if let Ok(pin_guard) = pin.lock() {
|
||||||
|
pin_guard.read() == PinValue::Low // IRQ is active low
|
||||||
} else {
|
} else {
|
||||||
self.registers.sr &= !flag;
|
false
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
};
|
||||||
|
|
||||||
|
let nmi = if let Ok(pin) = self.base.get_pin("NMI") {
|
||||||
|
if let Ok(pin_guard) = pin.lock() {
|
||||||
|
pin_guard.read() == PinValue::Low // NMI is active low
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
};
|
||||||
|
|
||||||
|
let reset = if let Ok(pin) = self.base.get_pin("RES") {
|
||||||
|
if let Ok(pin_guard) = pin.lock() {
|
||||||
|
pin_guard.read() == PinValue::Low // RESET is active low
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
};
|
||||||
|
|
||||||
|
let rdy = if let Ok(pin) = self.base.get_pin("RDY") {
|
||||||
|
if let Ok(pin_guard) = pin.lock() {
|
||||||
|
pin_guard.read() == PinValue::High // RDY is active high
|
||||||
|
} else {
|
||||||
|
true // Default to ready if pin doesn't exist
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
};
|
||||||
|
|
||||||
|
(irq, nmi, reset, rdy)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_flag(&self, flag: u8) -> bool {
|
fn execute_instruction(&mut self) {
|
||||||
self.registers.sr & flag != 0
|
// Simplified instruction execution - just increment PC for compilation
|
||||||
}
|
self.program_counter = self.program_counter.wrapping_add(1);
|
||||||
|
self.cycle_count += 1;
|
||||||
|
|
||||||
// Common instruction implementations
|
// Minimal implementation to satisfy compilation
|
||||||
pub fn lda(&mut self, value: u8) {
|
self.set_address_bus(self.program_counter);
|
||||||
self.set_register_a(value);
|
self.set_rw_pin(true); // Always reading for now
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
impl Component for MOS6502 {
|
||||||
fn name(&self) -> &str {
|
fn name(&self) -> String {
|
||||||
todo!()
|
self.base.name()
|
||||||
}
|
}
|
||||||
fn pins(&self) -> &HashMap<String, Arc<Pin>> {
|
|
||||||
todo!()
|
fn pins(&self) -> &HashMap<String, Arc<Mutex<Pin>>> {
|
||||||
|
self.base.pins()
|
||||||
}
|
}
|
||||||
fn get_pin(&self, _name: &str) -> Option<Arc<Pin>> {
|
|
||||||
todo!()
|
fn get_pin(&self, name: &str) -> Result<Arc<Mutex<Pin>>, String> {
|
||||||
|
self.base.get_pin(name)
|
||||||
}
|
}
|
||||||
// Implement Component trait methods...
|
|
||||||
fn update(&mut self) -> Result<(), String> {
|
fn update(&mut self) {
|
||||||
// Clock handling and instruction execution
|
if !self.is_running {
|
||||||
let clk_pin = self.base.pins.get("clk").unwrap();
|
return;
|
||||||
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(())
|
let (irq, nmi, reset, rdy) = self.read_control_pins();
|
||||||
|
|
||||||
|
if reset && !self.is_reset {
|
||||||
|
self.reset();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.is_reset = reset;
|
||||||
|
|
||||||
|
if rdy {
|
||||||
|
self.execute_instruction();
|
||||||
|
}
|
||||||
|
// If RDY is low, the CPU waits
|
||||||
|
}
|
||||||
|
|
||||||
fn run(&mut self) {
|
fn run(&mut self) {
|
||||||
todo!()
|
self.is_running = true;
|
||||||
|
self.reset();
|
||||||
|
|
||||||
|
while self.is_running {
|
||||||
|
self.update();
|
||||||
|
thread::sleep(Duration::from_micros(1));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn stop(&mut self) {
|
fn stop(&mut self) {
|
||||||
todo!()
|
self.is_running = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_running(&self) -> bool {
|
||||||
|
self.is_running
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 6502-specific methods
|
||||||
|
impl MOS6502 {
|
||||||
|
pub fn get_program_counter(&self) -> u16 {
|
||||||
|
self.program_counter
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_program_counter(&mut self, address: u16) {
|
||||||
|
self.program_counter = address;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_accumulator(&self) -> u8 {
|
||||||
|
self.accumulator
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_x_register(&self) -> u8 {
|
||||||
|
self.x_register
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_y_register(&self) -> u8 {
|
||||||
|
self.y_register
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_stack_pointer(&self) -> u8 {
|
||||||
|
self.stack_pointer
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_status_register(&self) -> u8 {
|
||||||
|
self.status_register
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_cycle_count(&self) -> u64 {
|
||||||
|
self.cycle_count
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_6502_creation() {
|
||||||
|
let cpu = MOS6502::new("CPU_6502".to_string());
|
||||||
|
assert_eq!(cpu.name(), "CPU_6502");
|
||||||
|
assert!(!cpu.is_running());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_6502_registers() {
|
||||||
|
let mut cpu = MOS6502::new("CPU_6502".to_string());
|
||||||
|
|
||||||
|
cpu.set_program_counter(0x1234);
|
||||||
|
assert_eq!(cpu.get_program_counter(), 0x1234);
|
||||||
|
|
||||||
|
assert_eq!(cpu.get_accumulator(), 0);
|
||||||
|
assert_eq!(cpu.get_x_register(), 0);
|
||||||
|
assert_eq!(cpu.get_y_register(), 0);
|
||||||
|
assert_eq!(cpu.get_stack_pointer(), 0xFD);
|
||||||
|
assert_eq!(cpu.get_status_register(), 0x20);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_6502_reset() {
|
||||||
|
let mut cpu = MOS6502::new("CPU_6502".to_string());
|
||||||
|
|
||||||
|
cpu.set_program_counter(0x1000);
|
||||||
|
cpu.reset();
|
||||||
|
|
||||||
|
assert_eq!(cpu.get_program_counter(), 0xFFFC);
|
||||||
}
|
}
|
||||||
// Other trait methods...
|
|
||||||
}
|
}
|
||||||
171
src/components/cpu/wdc_65c02.rs
Normal file
171
src/components/cpu/wdc_65c02.rs
Normal file
|
|
@ -0,0 +1,171 @@
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
|
use crate::component::Component;
|
||||||
|
use crate::components::cpu::MOS6502;
|
||||||
|
use crate::pin::Pin;
|
||||||
|
|
||||||
|
/// WDC 65C02 - CMOS version of 6502 with additional instructions
|
||||||
|
pub struct WDC65C02 {
|
||||||
|
base: MOS6502,
|
||||||
|
// 65C02-specific state
|
||||||
|
stop_mode: bool,
|
||||||
|
wait_mode: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WDC65C02 {
|
||||||
|
pub fn new(name: String) -> Self {
|
||||||
|
WDC65C02 {
|
||||||
|
base: MOS6502::new(name),
|
||||||
|
stop_mode: false,
|
||||||
|
wait_mode: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 65C02 specific methods
|
||||||
|
pub fn enter_stop_mode(&mut self) {
|
||||||
|
self.stop_mode = true;
|
||||||
|
self.wait_mode = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn enter_wait_mode(&mut self) {
|
||||||
|
self.wait_mode = true;
|
||||||
|
self.stop_mode = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn exit_low_power_modes(&mut self) {
|
||||||
|
self.stop_mode = false;
|
||||||
|
self.wait_mode = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_in_stop_mode(&self) -> bool {
|
||||||
|
self.stop_mode
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_in_wait_mode(&self) -> bool {
|
||||||
|
self.wait_mode
|
||||||
|
}
|
||||||
|
|
||||||
|
// 65C02 additional instructions would be implemented here
|
||||||
|
fn execute_65c02_instruction(&mut self) {
|
||||||
|
if self.stop_mode {
|
||||||
|
// CPU is stopped - no operation
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.wait_mode {
|
||||||
|
// CPU is waiting for interrupt - no operation
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For compilation, just call the base 6502 implementation
|
||||||
|
// In a full implementation, this would handle 65C02-specific instructions
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Component for WDC65C02 {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update(&mut self) {
|
||||||
|
if self.stop_mode || self.wait_mode {
|
||||||
|
// In low-power modes, only check for interrupts
|
||||||
|
let (irq, nmi, reset, _) = self.base.read_control_pins();
|
||||||
|
|
||||||
|
if nmi || reset || (irq && !self.base.get_status_register() & 0x04 == 0) {
|
||||||
|
// Exit low-power modes on interrupt or reset
|
||||||
|
self.exit_low_power_modes();
|
||||||
|
} else {
|
||||||
|
return; // Stay in low-power mode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delegate to base 6502 implementation
|
||||||
|
self.base.update();
|
||||||
|
|
||||||
|
// 65C02-specific processing would go here
|
||||||
|
self.execute_65c02_instruction();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(&mut self) {
|
||||||
|
self.base.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn stop(&mut self) {
|
||||||
|
self.base.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_running(&self) -> bool {
|
||||||
|
self.base.is_running()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 65C02-specific enhancements
|
||||||
|
impl WDC65C02 {
|
||||||
|
pub fn get_base_cpu(&self) -> &MOS6502 {
|
||||||
|
&self.base
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_base_cpu_mut(&mut self) -> &mut MOS6502 {
|
||||||
|
&mut self.base
|
||||||
|
}
|
||||||
|
|
||||||
|
// Additional 65C02 functionality can be added here
|
||||||
|
// - New addressing modes
|
||||||
|
// - Additional instructions (STZ, BRA, etc.)
|
||||||
|
// - Improved interrupt handling
|
||||||
|
// - Low-power mode control
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_65c02_creation() {
|
||||||
|
let cpu = WDC65C02::new("CPU_65C02".to_string());
|
||||||
|
assert_eq!(cpu.name(), "CPU_65C02");
|
||||||
|
assert!(!cpu.is_running());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_65c02_low_power_modes() {
|
||||||
|
let mut cpu = WDC65C02::new("CPU_65C02".to_string());
|
||||||
|
|
||||||
|
assert!(!cpu.is_in_stop_mode());
|
||||||
|
assert!(!cpu.is_in_wait_mode());
|
||||||
|
|
||||||
|
cpu.enter_stop_mode();
|
||||||
|
assert!(cpu.is_in_stop_mode());
|
||||||
|
assert!(!cpu.is_in_wait_mode());
|
||||||
|
|
||||||
|
cpu.enter_wait_mode();
|
||||||
|
assert!(!cpu.is_in_stop_mode());
|
||||||
|
assert!(cpu.is_in_wait_mode());
|
||||||
|
|
||||||
|
cpu.exit_low_power_modes();
|
||||||
|
assert!(!cpu.is_in_stop_mode());
|
||||||
|
assert!(!cpu.is_in_wait_mode());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_65c02_inheritance() {
|
||||||
|
let mut cpu = WDC65C02::new("CPU_65C02".to_string());
|
||||||
|
|
||||||
|
// Verify that 65C02 inherits 6502 functionality
|
||||||
|
cpu.get_base_cpu_mut().set_program_counter(0x1000);
|
||||||
|
assert_eq!(cpu.get_base_cpu().get_program_counter(), 0x1000);
|
||||||
|
|
||||||
|
assert_eq!(cpu.get_base_cpu().get_accumulator(), 0);
|
||||||
|
assert_eq!(cpu.get_base_cpu().get_x_register(), 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue