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

[#27] Support CMOS Z80 chips. #30

Merged
merged 1 commit into from
Aug 24, 2021
Merged
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
68 changes: 62 additions & 6 deletions tests/tester.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ using z80::fast_u32;
using z80::least_u8;
using z80::reg;
using z80::unreachable;
using z80::unused;
using z80::z80_variant;

static const std::size_t max_line_size = 1024;

Expand Down Expand Up @@ -160,7 +162,7 @@ class test_context {

void handle_end_of_test_entry() {
if(in_skipping_mode)
error("this line is expected, but not found");
input.error("this line is expected, but not found");

in_skipping_mode = false;
}
Expand Down Expand Up @@ -277,6 +279,11 @@ class i8080_disasm : public disasm_base<z80::i8080_disasm<i8080_disasm>> {
bool depends_on_iregp_kind() const {
return false;
}

[[noreturn]] void set_variant(z80_variant v, const test_input &input) {
unused(v);
input.error("unsupported variant");
}
};

class z80_disasm : public disasm_base<z80::z80_disasm<z80_disasm>> {
Expand Down Expand Up @@ -307,8 +314,18 @@ class z80_disasm : public disasm_base<z80::z80_disasm<z80_disasm>> {
base::on_disassemble();
}

void set_variant(z80_variant v, const test_input &input) {
unused(&input);
variant = v;
}

z80_variant on_get_z80_variant() const {
return variant;
}

private:
bool does_depend_on_iregp_kind = false;
z80_variant variant = z80_variant::common;
};

template<typename B>
Expand Down Expand Up @@ -814,6 +831,11 @@ class i8080_machine : public machine_base<z80::i8080_cpu<i8080_machine>> {
base::on_step();
context.match("done", static_cast<unsigned>(get_ticks()));
}

[[noreturn]] void set_variant(z80_variant v, const test_input &input) {
unused(v);
input.error("unsupported variant");
}
};

class z80_machine : public machine_base<z80::z80_cpu<z80_machine>> {
Expand Down Expand Up @@ -851,6 +873,18 @@ class z80_machine : public machine_base<z80::z80_cpu<z80_machine>> {

context.match("done", static_cast<unsigned>(get_ticks()));
}

void set_variant(z80_variant v, const test_input &input) {
unused(&input);
variant = v;
}

z80_variant on_get_z80_variant() const {
return variant;
}

private:
z80_variant variant = z80_variant::common;
};

int translate_hex_digit(char c) {
Expand Down Expand Up @@ -921,13 +955,34 @@ bool parse_set_r_directive(const char *r, fast_u8 &n,
return true;
}

template<typename M>
void handle_directive(const test_input &input, M &mach) {
bool parse_z80_variant_directive(z80_variant &variant,
const test_input &input) {
const char *p = input.get_line();
if(!parse(p, ".z80_variant="))
return false;

if(std::strcmp(p, "common") == 0)
variant = z80_variant::common;
else if(std::strcmp(p, "cmos") == 0)
variant = z80_variant::cmos;
else
input.error("unknown Z80 variant '%s'", p);
return true;
}

template<typename M, typename D>
void handle_directive(M &mach, D &dis, const test_input &input) {
fast_u8 n;
z80_variant variant;
if(parse_set_r_directive("b", n, input))
return mach.set_b(n);
if(parse_set_r_directive("c", n, input))
return mach.set_c(n);
if(parse_z80_variant_directive(variant, input)) {
mach.set_variant(variant, input);
dis.set_variant(variant, input);
return;
}

input.error("unknown directive");
}
Expand All @@ -945,11 +1000,13 @@ void handle_test_entry(test_context &context) {

test_input &input = context.get_input();

// Handle directives.
machine mach(context);
disasm dis(input);

// Handle directives.
const char *p = input.get_line();
while(*p == '.') {
handle_directive(input, mach);
handle_directive(mach, dis, input);
p = input.read_line();
}

Expand All @@ -966,7 +1023,6 @@ void handle_test_entry(test_context &context) {
skip_whitespace(p);

// Test instruction disassembly.
disasm dis(input);
dis.set_encoding(encoding);
dis.on_disassemble();
const char *instr = dis.get_output();
Expand Down
20 changes: 17 additions & 3 deletions tests/tests_z80
Original file line number Diff line number Diff line change
Expand Up @@ -1808,6 +1808,20 @@ dded61 (db 0xdd), out (c), h
16 set_index_rp ix -> hl
16 done

# NMOS and CMOS versions of OUT (C), 0
ed71 out (c), 0x00
...
8 output 00 at 0000
...
12 done

.z80_variant=cmos
ed71 out (c), 0xff
...
8 output ff at 0000
...
12 done

# Block input.
edb2 inir
0 m1_fetch
Expand Down Expand Up @@ -3863,7 +3877,7 @@ dded6d (db 0xdd), xretn 0xed6d
dded6e (db 0xdd), xim 0xed6e, 0
dded6f (db 0xdd), rld
dded70 (db 0xdd), in (c)
dded71 (db 0xdd), out (c), 0
dded71 (db 0xdd), out (c), 0x00
dded72 (db 0xdd), sbc hl, sp
dded730000 (db 0xdd), ld (0x0000), sp
dded74 (db 0xdd), xneg 0xed74
Expand Down Expand Up @@ -4157,7 +4171,7 @@ ed6d xretn 0xed6d
ed6e xim 0xed6e, 0
ed6f rld
ed70 in (c)
ed71 out (c), 0
ed71 out (c), 0x00
ed72 sbc hl, sp
ed730000 ld (0x0000), sp
ed74 xneg 0xed74
Expand Down Expand Up @@ -4927,7 +4941,7 @@ fded6d (db 0xfd), xretn 0xed6d
fded6e (db 0xfd), xim 0xed6e, 0
fded6f (db 0xfd), rld
fded70 (db 0xfd), in (c)
fded71 (db 0xfd), out (c), 0
fded71 (db 0xfd), out (c), 0x00
fded72 (db 0xfd), sbc hl, sp
fded730000 (db 0xfd), ld (0x0000), sp
fded74 (db 0xfd), xneg 0xed74
Expand Down
20 changes: 18 additions & 2 deletions z80.h
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,11 @@ enum class block_out { outi, outd, otir, otdr };

enum class condition { nz, z, nc, c, po, pe, p, m };

enum class z80_variant {
common,
cmos, // Newer chips.
};

// Entities for internal needs of the library.
class internals {
private:
Expand Down Expand Up @@ -507,6 +512,16 @@ class root {
unused(op);
self().on_retn(); }

z80_variant on_get_z80_variant() {
return z80_variant::common; }

fast_u8 on_get_out_c_r_op() {
switch(self().on_get_z80_variant()) {
case z80_variant::common: return 0;
case z80_variant::cmos: return 0xff;
}
unreachable("Unknown Z80 variant."); }

protected:
const derived &self() const{ return static_cast<const derived&>(*this); }
derived &self() { return static_cast<derived&>(*this); }
Expand Down Expand Up @@ -1738,7 +1753,7 @@ class z80_disasm
self().on_format("neg"); }
void on_out_c_r(reg r) {
if(r == reg::at_hl)
self().on_format("out (c), 0");
self().on_format("out (c), N", self().on_get_out_c_r_op());
else
self().on_format("out (c), R", r, iregp::hl, 0); }
void on_out_n_a(fast_u8 n) {
Expand Down Expand Up @@ -3601,7 +3616,8 @@ class z80_executor : public internals::executor_base<B> {
fast_u16 bc = self().on_get_bc();
self().on_set_wz(inc16(bc));
fast_u8 n = (r == reg::at_hl) ?
0 : self().on_get_reg(r, iregp::hl, /* d= */ 0);
self().on_get_out_c_r_op() :
self().on_get_reg(r, iregp::hl, /* d= */ 0);
self().on_output_cycle(bc, n); }
void on_out_n_a(fast_u8 n) {
fast_u8 a = self().on_get_a();
Expand Down