Skip to main content

Cpu

Struct Cpu 

Source
pub struct Cpu { /* private fields */ }
Expand description

Motorola 6809 CPU emulator.

Implementations§

Source§

impl Cpu

Source

pub fn new() -> Self

Create a new CPU with all state zeroed.

Source

pub fn reset(&mut self, mem: &mut impl Memory)

Hardware reset: read PC from reset vector, set I+F, clear state.

Source

pub fn registers(&self) -> &Registers

Read-only access to the programmer-visible registers.

Source

pub fn registers_mut(&mut self) -> RegistersMut<'_>

Mutable access to the programmer-visible registers via an RAII guard.

The guard implements std::ops::Deref and std::ops::DerefMut for Registers, giving transparent read/write access to all fields. On drop it checks whether the hardware stack pointer (S) changed and, if so, arms the NMI — matching the real 6809 behaviour where the first write to S enables edge-triggered NMI.

Note: the guard detects S changes by comparing the value on entry with the value on drop. Writing S to the value it already holds will not arm NMI, but because nmi_armed is sticky (never cleared) this is inconsequential in practice.

§Example
cpu.registers_mut().s = 0x8000; // arms NMI
{
    let mut r = cpu.registers_mut();
    r.s -= 2;
    mem[r.s as usize] = lo;
} // NMI armed here via Drop
Source

pub fn cycles(&self) -> u64

Total elapsed cycles since the last Self::reset.

Source

pub fn halted(&self) -> bool

true if the CPU has been halted by a halt instruction.

Illegal opcodes do not set this flag; they only set Self::illegal so the host can decide whether to keep running or stop.

Source

pub fn set_halted(&mut self, active: bool)

Assert or de-assert the halted state.

Source

pub fn illegal(&self) -> bool

Sticky flag set when an illegal opcode is executed.

The 6809 keeps running after undefined opcodes, so this flag does not halt the CPU by itself. Hosts that want trap-like behaviour can check this flag after each Self::step and stop on their own policy.

Source

pub fn clear_illegal(&mut self)

Clear the illegal opcode flag.

Source

pub fn set_irq(&mut self, active: bool)

Assert or de-assert the IRQ line (level-triggered).

The CPU samples this each step. Only the peripheral should de-assert it (by calling set_irq(false)); the CPU never clears it internally.

Source

pub fn set_firq(&mut self, active: bool)

Assert or de-assert the FIRQ line (level-triggered).

The CPU samples this each step. Only the peripheral should de-assert it (by calling set_firq(false)); the CPU never clears it internally.

Source

pub fn trigger_nmi(&mut self)

Trigger an NMI (edge-triggered). Only effective if NMI is armed.

Source

pub fn apply_signals(&mut self, signals: BusSignals, prev: BusSignals)

Apply a snapshot of bus signals to the CPU, handling NMI edge detection.

Call this from the host loop whenever BusSignals change. Passing the previous snapshot allows the CPU to detect the NMI rising edge internally, so the caller does not need to track edge transitions for NMI.

IRQ and FIRQ are level-triggered: their state is mirrored directly into the CPU. The CPU will hold the line until the peripheral de-asserts it (i.e. returns a snapshot without IRQ/FIRQ set on a subsequent tick).

RESET is not handled here; the host loop is responsible for calling Cpu::reset when signals contains BusSignals::RESET.

§Host loop pattern
let mut prev_signals = BusSignals::default();
loop {
    let cycles = cpu.step(&mut mem);
    let signals = peripheral.tick(cycles);

    if signals.contains(BusSignals::RESET) {
        cpu.reset(&mut mem);
        prev_signals = BusSignals::default();
        continue;
    }

    if signals != prev_signals {
        cpu.apply_signals(signals, prev_signals);
        prev_signals = signals;
    }

    if cpu.halted() { break; }
}
Source

pub fn step(&mut self, mem: &mut impl Memory) -> u64

Execute a single instruction (or handle a pending interrupt). Returns the number of cycles consumed or ZERO if the CPU is halted.

Warning! Busy-loops in host code that doesn’t check Self::halted can lead to high CPU usage.

If the decoded instruction is illegal, the CPU records that in Self::illegal and continues execution unless the caller chooses to stop.

Source

pub fn run(&mut self, mem: &mut impl Memory, cycle_budget: u64) -> u64

Run until at least cycle_budget cycles have been consumed.

This method stops only when the cycle budget is exhausted or Self::halted becomes true. Illegal opcodes do not stop run; check Self::illegal in the host loop if that policy is desired.

Trait Implementations§

Source§

impl Clone for Cpu

Source§

fn clone(&self) -> Cpu

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Cpu

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for Cpu

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

§

impl Freeze for Cpu

§

impl RefUnwindSafe for Cpu

§

impl Send for Cpu

§

impl Sync for Cpu

§

impl Unpin for Cpu

§

impl UnsafeUnpin for Cpu

§

impl UnwindSafe for Cpu

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.