Skip to content

Commit

Permalink
Cycle counting
Browse files Browse the repository at this point in the history
  • Loading branch information
ivanizag committed Jul 27, 2023
1 parent 3940766 commit 2c6a2c8
Show file tree
Hide file tree
Showing 18 changed files with 600 additions and 291 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
[![Crates](https://img.shields.io/crates/v/iz80.svg)](https://crates.io/crates/iz80)
[![Documentation](https://docs.rs/iz80/badge.svg)](https://docs.rs/iz80)

Zilog Z80 and Intel 8080 emulator library for RUST. It passes all the tests of the ZEXALL suite. No cycle emulation accuracy, runs as fast as it can.
Zilog Z80 and Intel 8080 emulator library for RUST. It passes all the tests of the ZEXALL suite. Instruction based accuracy.

To run the ZEXALL test suite for Zilog Z80:

Expand Down Expand Up @@ -202,7 +202,7 @@ Tests complete

### Pre-commit tests

Note that some of the Zexall tests takes very long and is disabled for continuouos integrations. To run it, execute:
Note that the Zexall test suite is very long and is disabled for continuouos integration. To run it, execute:

```
cargo test --release -- --nocapture --ignored --test zexall
Expand Down
10 changes: 8 additions & 2 deletions src/bin/cpuville.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,16 @@ use std::time::Duration;

use iz80::Cpu;
use iz80::Machine;
use iz80::TimedRunner;

static TINY_BASIC: &[u8] = include_bytes!("rom/tinybasic2dms.bin");
const MHZ: f64 = 4.0;

fn main() {
let mut machine = VilleMachine::new();
let mut cpu = Cpu::new();
let mut timed_runner = TimedRunner::new();
timed_runner.set_mhz(&cpu, MHZ, 1000);

// Init console
let mut stdout = stdout();
Expand All @@ -35,7 +39,7 @@ fn main() {
machine.in_values[3] = 1; // TX Ready

loop {
cpu.execute_instruction(&mut machine);
timed_runner.execute(&mut cpu, &mut machine);

if let Some(port) = machine.out_port {
match port {
Expand All @@ -60,7 +64,9 @@ fn main() {
machine.in_port = None;

// Avoid 100% CPU usage waiting for input.
thread::sleep(Duration::from_millis(1));
if MHZ == 0.0 {
thread::sleep(Duration::from_millis(1));
}
}

if !in_char_waiting {
Expand Down
15 changes: 12 additions & 3 deletions src/cpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,11 +93,14 @@ impl Cpu {
if self.trace {
print!("==> {:04x}: {:20}", pc, opcode.disasm(&env));
}

env.clear_branch_taken();
opcode.execute(&mut env);
env.advance_cycles(opcode);
env.clear_index();

if self.trace {
print!(" PC:{:04x} AF:{:04x} BC:{:04x} DE:{:04x} HL:{:04x} SP:{:04x} IX:{:04x} IY:{:04x} Flags:{:08b}",
print!(" PC:{:04x} AF:{:04x} BC:{:04x} DE:{:04x} HL:{:04x} SP:{:04x} IX:{:04x} IY:{:04x} Flags:{:08b} Cycle:{:04}",
self.state.reg.pc(),
self.state.reg.get16(Reg16::AF),
self.state.reg.get16(Reg16::BC),
Expand All @@ -106,14 +109,15 @@ impl Cpu {
self.state.reg.get16(Reg16::SP),
self.state.reg.get16(Reg16::IX),
self.state.reg.get16(Reg16::IY),
self.state.reg.get8(Reg8::F)
self.state.reg.get8(Reg8::F),
self.state.cycle
);
println!(" [{:02x} {:02x} {:02x}]", sys.peek(pc),
sys.peek(pc.wrapping_add(1)), sys.peek(pc.wrapping_add(2)));
}
}

/// Returns the instrction in PC disassembled. PC is advanced.
/// Returns the instruction in PC disassembled. PC is advanced.
///
/// # Arguments
///
Expand Down Expand Up @@ -159,6 +163,11 @@ impl Cpu {
pub fn signal_reset(&mut self) {
self.state.reset_pending = true
}

/// Returns the current cycle count
pub fn cycle_count(&self) -> u64 {
self.state.cycle
}
}


72 changes: 64 additions & 8 deletions src/decoder_8080.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ impl Decoder8080 {
]
};
decoder.load_no_prefix();
decoder.load_cycle_information();
decoder
}

Expand Down Expand Up @@ -157,6 +158,39 @@ impl Decoder8080 {
self.no_prefix[c as usize] = opcode;
}
}

fn load_cycle_information(&mut self) {

// Load cycle information
for c in 0..=255 {
if let Some(opcode) = &mut self.no_prefix[c as usize] {
opcode.cycles = NO_PREFIX_CYCLES[c];
opcode.cycles_conditional = opcode.cycles;
}
}

//Load cycle information for conditional cases
if let Some(opcode) = &mut self.no_prefix[0xc0] { opcode.cycles_conditional = 5; }
if let Some(opcode) = &mut self.no_prefix[0xc4] { opcode.cycles_conditional = 11; }
if let Some(opcode) = &mut self.no_prefix[0xc8] { opcode.cycles_conditional = 5; }
if let Some(opcode) = &mut self.no_prefix[0xcc] { opcode.cycles_conditional = 11; }

if let Some(opcode) = &mut self.no_prefix[0xd0] { opcode.cycles_conditional = 5; }
if let Some(opcode) = &mut self.no_prefix[0xd4] { opcode.cycles_conditional = 11; }
if let Some(opcode) = &mut self.no_prefix[0xd8] { opcode.cycles_conditional = 5; }
if let Some(opcode) = &mut self.no_prefix[0xdc] { opcode.cycles_conditional = 11; }

if let Some(opcode) = &mut self.no_prefix[0xe0] { opcode.cycles_conditional = 5; }
if let Some(opcode) = &mut self.no_prefix[0xe4] { opcode.cycles_conditional = 11; }
if let Some(opcode) = &mut self.no_prefix[0xe8] { opcode.cycles_conditional = 5; }
if let Some(opcode) = &mut self.no_prefix[0xec] { opcode.cycles_conditional = 11; }

if let Some(opcode) = &mut self.no_prefix[0xf0] { opcode.cycles_conditional = 5; }
if let Some(opcode) = &mut self.no_prefix[0xf4] { opcode.cycles_conditional = 11; }
if let Some(opcode) = &mut self.no_prefix[0xf8] { opcode.cycles_conditional = 5; }
if let Some(opcode) = &mut self.no_prefix[0xfc] { opcode.cycles_conditional = 11; }
// Note that on the 8080 the conditional jumps use always the same number of cycles
}
}

#[derive(Debug)]
Expand All @@ -181,12 +215,11 @@ impl DecodingHelper {
}
}

const RP: [Reg16; 4] = [Reg16::BC, Reg16::DE, Reg16::HL, Reg16::SP];
const RP2: [Reg16; 4] = [Reg16::BC, Reg16::DE, Reg16::HL, Reg16::AF];
const R: [Reg8; 8] = [Reg8::B, Reg8::C, Reg8::D, Reg8::E, Reg8::H, Reg8::L, Reg8::_HL, Reg8::A];

pub const RP: [Reg16; 4] = [Reg16::BC, Reg16::DE, Reg16::HL, Reg16::SP];
pub const RP2: [Reg16; 4] = [Reg16::BC, Reg16::DE, Reg16::HL, Reg16::AF];
pub const R: [Reg8; 8] = [Reg8::B, Reg8::C, Reg8::D, Reg8::E, Reg8::H, Reg8::L, Reg8::_HL, Reg8::A];

pub const CC: [(Flag, bool, &str); 8] = [
const CC: [(Flag, bool, &str); 8] = [
(Flag::Z, false, "NZ"),
(Flag::Z, true, "Z"),
(Flag::C, false, "NC"),
Expand All @@ -197,7 +230,7 @@ pub const CC: [(Flag, bool, &str); 8] = [
(Flag::S, true, "N")
];

pub const ROT: [(ShiftDir, ShiftMode, &str); 8] = [
const ROT: [(ShiftDir, ShiftMode, &str); 8] = [
(ShiftDir::Left, ShiftMode::RotateCarry, "RLC"),
(ShiftDir::Right, ShiftMode::RotateCarry, "RRC"),
(ShiftDir::Left, ShiftMode::Rotate, "RL" ),
Expand All @@ -208,8 +241,7 @@ pub const ROT: [(ShiftDir, ShiftMode, &str); 8] = [
(ShiftDir::Right, ShiftMode::Logical, "SRL"),
];

//pub const ALU: [(fn(&mut State, u8, u8) -> u8, &'static str); 8] = [
pub const ALU: [(Operator, &str); 8] = [
const ALU: [(Operator, &str); 8] = [
(operator_add, "ADD"),
(operator_adc, "ADC"),
(operator_sub, "SUB"),
Expand All @@ -219,3 +251,27 @@ pub const ALU: [(Operator, &str); 8] = [
(operator_or, "OR"),
(operator_cp, "CP")
];

// From https://pastraiser.com/cpu/i8080/i8080_opcodes.html
// From https://tobiasvl.github.io/optable/intel-8080/
const NO_PREFIX_CYCLES: [u8; 256] = [
4, 10, 7, 5, 5, 5, 7, 4, 4, 10, 7, 5, 5, 5, 7, 4,
4, 10, 7, 5, 5, 5, 7, 4, 4, 10, 7, 5, 5, 5, 7, 4,
4, 10, 16, 5, 5, 5, 7, 4, 4, 10, 16, 5, 5, 5, 7, 4,
4, 10, 13, 5, 10, 10, 10, 4, 4, 10, 13, 5, 5, 5, 7, 4,

5, 5, 5, 5, 5, 5, 7, 5, 5, 5, 5, 5, 5, 5, 7, 5,
5, 5, 5, 5, 5, 5, 7, 5, 5, 5, 5, 5, 5, 5, 7, 5,
5, 5, 5, 5, 5, 5, 7, 5, 5, 5, 5, 5, 5, 5, 7, 5,
7, 7, 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, 7, 5,

4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4,
4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4,
4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4,
7, 7, 7, 7, 7, 7, 4, 7, 4, 4, 4, 4, 4, 4, 7, 4,

11, 10, 10, 10, 17, 11, 7, 11, 11, 10, 10, 10, 17, 17, 7, 11,
11, 10, 10, 10, 17, 11, 7, 11, 11, 10, 10, 10, 17, 17, 7, 11,
11, 10, 10, 18, 17, 11, 7, 11, 11, 5, 10, 5, 17, 17, 7, 11,
11, 10, 10, 4, 17, 11, 7, 11, 11, 5, 10, 4, 17, 17, 7, 11,
];
Loading

0 comments on commit 2c6a2c8

Please sign in to comment.