Struct rz80::CPU [] [src]

pub struct CPU {
    pub reg: Registers,
    pub halt: bool,
    pub iff1: bool,
    pub iff2: bool,
    pub invalid_op: bool,
    pub mem: Memory,
    // some fields omitted

Z80 CPU emulation

The core of the CPU emulation is the step() method, this fetches the next instruction from the memory location pointed to by the PC register, executes the instruction, handles any pending interrupt request, and finally returns the number of cycles taken.

An object implementing the Bus trait must be handed to the step() method which is called if the CPU needs to communicate with the 'outside world'.

The CPU emulation uses an 'algorithmic decoder' as described here:, and implements most undocumented behaviour like the X/Y flags, the WZ register, and all undocumented instructions. The emulation is good enough to run the ZEXALL tests without errors.

What's not implemented: - interrupt modes 0 and 1 - non-maskable interrupts (including the RETN instruction) - extra memory wait states


Load and execute a small test program:

use rz80::{CPU, Bus};

// a dummy Bus trait implementation
struct DummyBus;
impl Bus for DummyBus { };

let mut cpu = CPU::new();
let bus = DummyBus { };

// map some writable memory to address 0x0000, 0x00000, 0x0000, true, 0x1000);

// a little Z80 machine code program to add 2 numbers
let prog = [
    0x3E, 0x11,     // LD A,0x11 (7 cycles)
    0x06, 0x22,     // LD B,0x22 (7 cycles)
    0x80, 0x33,     // ADD A,B   (4 cycles)
// put the program at address 0x0100
cpu.mem.write(0x0100, &prog);
// set PC to address 0x0100

// execute 3 instructions
let mut cycles = 0;
for _ in 0..3 {
    cycles += cpu.step(&bus);
assert!(cpu.reg.a() == 0x33);
assert!(cycles == 18);


reg: Registers halt: bool iff1: bool iff2: bool invalid_op: bool mem: Memory


impl CPU

fn new() -> CPU

initialize a new Z80 CPU object

fn new_64k() -> CPU

initialize a new CPU object with 64K RAM (for testing)

fn reset(&mut self)

reset the cpu

fn step(&mut self, bus: &Bus) -> i64

decode and execute one instruction, return number of cycles taken

fn irq(&mut self)

request an interrupt (will initiate interrupt handling after next instruction)

fn halt(&mut self)

execute a halt instruction

fn push(&mut self, val: RegT)

fn pop(&mut self) -> RegT

fn rst(&mut self, val: RegT)

fn add8(&mut self, add: RegT)

fn adc8(&mut self, add: RegT)

fn sub8(&mut self, sub: RegT)

fn sbc8(&mut self, sub: RegT)

fn cp8(&mut self, sub: RegT)

fn neg8(&mut self)

fn and8(&mut self, val: RegT)

fn or8(&mut self, val: RegT)

fn xor8(&mut self, val: RegT)

fn inc8(&mut self, val: RegT) -> RegT

fn dec8(&mut self, val: RegT) -> RegT

fn rot(&mut self, op: usize, val: RegT) -> RegT

fn rlc8(&mut self, val: RegT) -> RegT

fn rlca8(&mut self)

fn rrc8(&mut self, val: RegT) -> RegT

fn rrca8(&mut self)

fn rl8(&mut self, val: RegT) -> RegT

fn rla8(&mut self)

fn rr8(&mut self, val: RegT) -> RegT

fn rra8(&mut self)

fn sla8(&mut self, val: RegT) -> RegT

fn sll8(&mut self, val: RegT) -> RegT

fn sra8(&mut self, val: RegT) -> RegT

fn srl8(&mut self, val: RegT) -> RegT

fn rld(&mut self)

fn rrd(&mut self)

fn bit(&mut self, val: RegT, mask: RegT)

fn ibit(&mut self, val: RegT, mask: RegT)

fn add16(&mut self, acc: RegT, add: RegT) -> RegT

fn adc16(&mut self, acc: RegT, add: RegT) -> RegT

fn sbc16(&mut self, acc: RegT, sub: RegT) -> RegT

fn djnz(&mut self) -> i64

fn daa(&mut self)

fn cpl(&mut self)

fn scf(&mut self)

fn ccf(&mut self)

fn ret(&mut self) -> i64

fn call(&mut self) -> i64

fn retcc(&mut self, y: usize) -> i64

fn callcc(&mut self, y: usize) -> i64

fn ldi(&mut self)

fn ldd(&mut self)

fn ldir(&mut self) -> i64

fn lddr(&mut self) -> i64

fn cpi(&mut self)

fn cpd(&mut self)

fn cpir(&mut self) -> i64

fn cpdr(&mut self) -> i64

fn inp(&mut self, bus: &Bus, port: RegT) -> RegT

fn outp(&mut self, bus: &Bus, port: RegT, val: RegT)

fn ini(&mut self, bus: &Bus)

fn ind(&mut self, bus: &Bus)

fn inir(&mut self, bus: &Bus) -> i64

fn indr(&mut self, bus: &Bus) -> i64

fn outi(&mut self, bus: &Bus)

fn outd(&mut self, bus: &Bus)

fn otir(&mut self, bus: &Bus) -> i64

fn otdr(&mut self, bus: &Bus) -> i64