Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Restructure handling of CA1, CA2, CB1, CB2 lines on MOS 652x chips #42

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions src/memory/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,16 @@ mod banked;
mod block;
mod branch;
mod logging;
mod mos6510;
pub mod mos6510;
/// The various interface adapters (6520, 6522, 6526) for the MOS 6502 CPU.
pub mod mos652x;
mod null;
mod ports;

pub use banked::BankedMemory;
pub use block::BlockMemory;
pub use branch::BranchMemory;
pub use logging::LoggingMemory;
pub use mos6510::Mos6510Port;
pub use null::NullMemory;
pub use ports::{NullPort, Port};

/// Represents the state of the interrupts on the system.
#[derive(Debug, PartialEq, Eq)]
Expand Down
19 changes: 11 additions & 8 deletions src/memory/mos6510.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
use super::{ActiveInterrupt, Memory, Port};
use super::{ActiveInterrupt, Memory};

pub trait Mos6510PortInterface {
fn reset(&mut self);
fn read(&mut self) -> u8;
fn write(&mut self, value: u8);
}

/// Represents the port built into a MOS 6510 processor, mapped to memory addresses 0x0000 (for the DDR) and 0x0001 (for the port itself).
pub struct Mos6510Port {
/// The port itself.
port: Box<dyn Port>,
port: Box<dyn Mos6510PortInterface>,

/// If the DDR is write, the current written value.
writes: u8,
Expand All @@ -14,7 +20,7 @@

impl Mos6510Port {
/// Create a new MOS 6510 port with the given port.
pub fn new(port: Box<dyn Port>) -> Self {
pub fn new(port: Box<dyn Mos6510PortInterface>) -> Self {

Check warning on line 23 in src/memory/mos6510.rs

View check run for this annotation

Codecov / codecov/patch

src/memory/mos6510.rs#L23

Added line #L23 was not covered by tests
Self {
port,
writes: 0,
Expand Down Expand Up @@ -50,10 +56,7 @@
self.port.reset();
}

fn poll(&mut self, cycles_since_poll: u64, total_cycle_count: u64) -> ActiveInterrupt {
match self.port.poll(cycles_since_poll, total_cycle_count) {
true => ActiveInterrupt::IRQ,
false => ActiveInterrupt::None,
}
fn poll(&mut self, _cycles_since_poll: u64, _total_cycle_count: u64) -> ActiveInterrupt {
ActiveInterrupt::None

Check warning on line 60 in src/memory/mos6510.rs

View check run for this annotation

Codecov / codecov/patch

src/memory/mos6510.rs#L59-L60

Added lines #L59 - L60 were not covered by tests
}
}
94 changes: 63 additions & 31 deletions src/memory/mos652x/cia.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::memory::{
mos652x::{InterruptRegister, PortRegisters, ShiftRegister, Timer},
ActiveInterrupt, Memory, Port,
mos652x::{InterruptRegister, Port, PortRegisters, ShiftRegister, Timer},
ActiveInterrupt, Memory,
};

struct TimeRegisters {
Expand Down Expand Up @@ -74,10 +74,11 @@ pub struct Cia {
time_clock: TimeClock,
shift_register: ShiftRegister,
interrupts: InterruptRegister,
interrupt_connected: bool,
}

impl Cia {
pub fn new(port_a: Box<dyn Port>, port_b: Box<dyn Port>) -> Self {
pub fn new(port_a: Box<dyn Port>, port_b: Box<dyn Port>, interrupt_connected: bool) -> Self {
Self {
a: PortRegisters::new(port_a),
b: PortRegisters::new(port_b),
Expand All @@ -86,6 +87,7 @@ impl Cia {
time_clock: TimeClock::new(),
shift_register: ShiftRegister::new(),
interrupts: InterruptRegister::new(),
interrupt_connected,
}
}
}
Expand All @@ -111,14 +113,10 @@ impl Memory for Cia {
}
0x0C => self.shift_register.data,
0x0D => {
// TODO: alarm and shift register flags
let value = self
.interrupts
.read_flags((self.timer_a.interrupt as u8) | (self.timer_b.interrupt as u8) << 1);

self.timer_a.interrupt = false;
self.timer_b.interrupt = false;
let value = self.interrupts.read_flags();

// clear the interrupt flags
self.interrupts.clear_flag(value);
value
}
0x0E => {
Expand Down Expand Up @@ -209,37 +207,46 @@ impl Memory for Cia {
}

fn poll(&mut self, cycles_since_poll: u64, total_cycle_count: u64) -> ActiveInterrupt {
if self.timer_a.poll(cycles_since_poll, total_cycle_count)
&& (self.interrupts.interrupt_enable & interrupt_bits::TIMER_A) != 0
{
return ActiveInterrupt::IRQ;
}
let mut active_interrupt = ActiveInterrupt::None;

if self.timer_b.poll(cycles_since_poll, total_cycle_count)
&& (self.interrupts.interrupt_enable & interrupt_bits::TIMER_B) != 0
{
return ActiveInterrupt::IRQ;
if self.timer_a.poll(cycles_since_poll, total_cycle_count) {
self.interrupts.set_flag(interrupt_bits::TIMER_A);

if (self.interrupts.interrupt_enable & interrupt_bits::TIMER_A) != 0 {
active_interrupt = ActiveInterrupt::IRQ;
}
}

if self.a.poll(cycles_since_poll, total_cycle_count)
|| self.b.poll(cycles_since_poll, total_cycle_count)
{
return ActiveInterrupt::IRQ;
if self.timer_b.poll(cycles_since_poll, total_cycle_count) {
self.interrupts.set_flag(interrupt_bits::TIMER_B);

if (self.interrupts.interrupt_enable & interrupt_bits::TIMER_B) != 0 {
active_interrupt = ActiveInterrupt::IRQ;
}
}

ActiveInterrupt::None
let (_ca1, _ca2) = self.a.poll(cycles_since_poll, total_cycle_count);
let (_cb1, _cb2) = self.b.poll(cycles_since_poll, total_cycle_count);

// TODO: stuff based on ca1, ca2, cb1, cb2

if self.interrupt_connected {
active_interrupt
} else {
ActiveInterrupt::None
}
}
}

#[cfg(test)]
mod tests {
use crate::memory::NullPort;
use crate::memory::mos652x::NullPort;

use super::*;

#[test]
fn test_read_write() {
let mut cia = Cia::new(Box::new(NullPort::new()), Box::new(NullPort::new()));
let mut cia = Cia::new(Box::new(NullPort::new()), Box::new(NullPort::new()), true);

// writes without DDR shouldn't be reflected in reads
cia.write(0x00, 0b10101010);
Expand All @@ -265,7 +272,7 @@ mod tests {

#[test]
fn test_timer_a() {
let mut cia = Cia::new(Box::new(NullPort::new()), Box::new(NullPort::new()));
let mut cia = Cia::new(Box::new(NullPort::new()), Box::new(NullPort::new()), true);

// enable timer A interrupts
cia.write(0x0D, interrupt_bits::MASTER | interrupt_bits::TIMER_A);
Expand All @@ -289,9 +296,34 @@ mod tests {
}
}

#[test]
fn test_interrupt_disconnected() {
let mut cia = Cia::new(Box::new(NullPort::new()), Box::new(NullPort::new()), false);

// enable timer A interrupts
cia.write(0x0D, interrupt_bits::MASTER | interrupt_bits::TIMER_A);

// set the timer to count down from 0x10
cia.write(0x04, 0x10);
cia.write(0x05, 0x00);

// start the timer, and disable continuous operation
cia.write(0x0E, 0b0000_1001);

for _ in 0..0x0F {
assert_eq!(ActiveInterrupt::None, cia.poll(1, 0));
}

assert_eq!(ActiveInterrupt::None, cia.poll(1, 0));

for _ in 0..0x20 {
assert_eq!(ActiveInterrupt::None, cia.poll(1, 0));
}
}

#[test]
fn test_timer_b() {
let mut cia = Cia::new(Box::new(NullPort::new()), Box::new(NullPort::new()));
let mut cia = Cia::new(Box::new(NullPort::new()), Box::new(NullPort::new()), true);

// enable timer B interrupts
cia.write(0x0D, interrupt_bits::MASTER | interrupt_bits::TIMER_B);
Expand All @@ -312,7 +344,7 @@ mod tests {

#[test]
fn test_timer_a_continuous() {
let mut cia = Cia::new(Box::new(NullPort::new()), Box::new(NullPort::new()));
let mut cia = Cia::new(Box::new(NullPort::new()), Box::new(NullPort::new()), true);

// enable timer A interrupts
cia.write(0x0D, interrupt_bits::MASTER | interrupt_bits::TIMER_A);
Expand All @@ -335,7 +367,7 @@ mod tests {

#[test]
fn test_ier_timers() {
let mut cia = Cia::new(Box::new(NullPort::new()), Box::new(NullPort::new()));
let mut cia = Cia::new(Box::new(NullPort::new()), Box::new(NullPort::new()), true);

// enable timer 1 interrupts
cia.write(0x0D, interrupt_bits::MASTER | interrupt_bits::TIMER_A);
Expand All @@ -362,7 +394,7 @@ mod tests {

#[test]
fn test_interrupt_flags() {
let mut cia = Cia::new(Box::new(NullPort::new()), Box::new(NullPort::new()));
let mut cia = Cia::new(Box::new(NullPort::new()), Box::new(NullPort::new()), true);

// enable timer 1 interrupts
cia.write(0x0D, interrupt_bits::MASTER | interrupt_bits::TIMER_A);
Expand Down
Loading
Loading