From 8fb5044e87e8c8f1b53b432637565599384139d3 Mon Sep 17 00:00:00 2001 From: tim lindner Date: Sat, 3 Dec 2022 10:12:00 -0800 Subject: 6x09 TFR / EXG Improvement (#10572) Remove tuple implementation used by the EXG and TFR instructions of the 6809, 6309 and Konami CPUs. It was unnecessary because fundamentally these are implemented with a single, 16 bit wide temporary register. Changed how the 6809 CPU processes the invalid 8 to/from 16 bit register combinations. Their behavior now matches actual hardware. I used page 66 and 138 of Darren Atkinson's 6x09 manual [1] for reference. I also double checked with my own hardware [2]. Checked for regressions using NitrOS-9 (6809 and 6309) on the CoCo, And Aliens and 88Games (Konami). --- src/devices/cpu/m6809/hd6309.cpp | 73 +++++++++++++++++++------------------- src/devices/cpu/m6809/hd6309.h | 4 +-- src/devices/cpu/m6809/hd6309.ops | 6 ++-- src/devices/cpu/m6809/konami.cpp | 33 +++++++++--------- src/devices/cpu/m6809/konami.h | 4 +-- src/devices/cpu/m6809/konami.ops | 6 ++-- src/devices/cpu/m6809/m6809.cpp | 75 ++++++++++++++++++++++++++-------------- src/devices/cpu/m6809/m6809.h | 12 ++----- src/devices/cpu/m6809/m6809.ops | 27 ++++++++++----- 9 files changed, 132 insertions(+), 108 deletions(-) diff --git a/src/devices/cpu/m6809/hd6309.cpp b/src/devices/cpu/m6809/hd6309.cpp index 03eb11336e2..54f97096d29 100644 --- a/src/devices/cpu/m6809/hd6309.cpp +++ b/src/devices/cpu/m6809/hd6309.cpp @@ -446,35 +446,32 @@ inline void hd6309_device::bittest_set(bool result) // read_exgtfr_register //------------------------------------------------- -inline m6809_base_device::exgtfr_register hd6309_device::read_exgtfr_register(uint8_t reg) +inline uint16_t hd6309_device::read_exgtfr_register(uint8_t reg) { - uint16_t value; + uint16_t result; switch(reg & 0x0F) { - case 0: value = m_q.r.d; break; // D - case 1: value = m_x.w; break; // X - case 2: value = m_y.w; break; // Y - case 3: value = m_u.w; break; // U - case 4: value = m_s.w; break; // S - case 5: value = m_pc.w; break; // PC - case 6: value = m_q.r.w; break; // W - case 7: value = m_v.w; break; // V - case 8: value = ((uint16_t) m_q.r.a) << 8 | m_q.r.a; break; // A - case 9: value = ((uint16_t) m_q.r.b) << 8 | m_q.r.b; break; // B - case 10: value = ((uint16_t) m_cc) << 8 | m_cc; break; // CC - case 11: value = ((uint16_t) m_dp) << 8 | m_dp; break; // DP - case 12: value = 0; break; // 0 - case 13: value = 0; break; // 0 - case 14: value = ((uint16_t) m_q.r.e) << 8 | m_q.r.e; break; // E - case 15: value = ((uint16_t) m_q.r.f) << 8 | m_q.r.f; break; // F + case 0: result = m_q.r.d; break; // D + case 1: result = m_x.w; break; // X + case 2: result = m_y.w; break; // Y + case 3: result = m_u.w; break; // U + case 4: result = m_s.w; break; // S + case 5: result = m_pc.w; break; // PC + case 6: result = m_q.r.w; break; // W + case 7: result = m_v.w; break; // V + case 8: result = ((uint16_t) m_q.r.a) << 8 | m_q.r.a; break; // A + case 9: result = ((uint16_t) m_q.r.b) << 8 | m_q.r.b; break; // B + case 10: result = ((uint16_t) m_cc) << 8 | m_cc; break; // CC + case 11: result = ((uint16_t) m_dp) << 8 | m_dp; break; // DP + case 12: result = 0; break; // 0 + case 13: result = 0; break; // 0 + case 14: result = ((uint16_t) m_q.r.e) << 8 | m_q.r.e; break; // E + case 15: result = ((uint16_t) m_q.r.f) << 8 | m_q.r.f; break; // F default: fatalerror("Should not reach here"); } - exgtfr_register result; - result.byte_value = (uint8_t)value; - result.word_value = value; return result; } @@ -484,26 +481,26 @@ inline m6809_base_device::exgtfr_register hd6309_device::read_exgtfr_register(ui // write_exgtfr_register //------------------------------------------------- -inline void hd6309_device::write_exgtfr_register(uint8_t reg, m6809_base_device::exgtfr_register value) +inline void hd6309_device::write_exgtfr_register(uint8_t reg, uint16_t value) { switch(reg & 0x0F) { - case 0: m_q.r.d = value.word_value; break; // D - case 1: m_x.w = value.word_value; break; // X - case 2: m_y.w = value.word_value; break; // Y - case 3: m_u.w = value.word_value; break; // U - case 4: m_s.w = value.word_value; break; // S - case 5: m_pc.w = value.word_value; break; // PC - case 6: m_q.r.w = value.word_value; break; // W - case 7: m_v.w = value.word_value; break; // V - case 8: m_q.r.a = (uint8_t) (value.word_value >> 8); break; // A - case 9: m_q.r.b = (uint8_t) (value.word_value >> 0); break; // B - case 10: m_cc = (uint8_t) (value.word_value >> 0); break; // CC - case 11: m_dp = (uint8_t) (value.word_value >> 8); break; // DP - case 12: break; // 0 - case 13: break; // 0 - case 14: m_q.r.e = (uint8_t) (value.word_value >> 8); break; // E - case 15: m_q.r.f = (uint8_t) (value.word_value >> 0); break; // F + case 0: m_q.r.d = value; break; // D + case 1: m_x.w = value; break; // X + case 2: m_y.w = value; break; // Y + case 3: m_u.w = value; break; // U + case 4: m_s.w = value; break; // S + case 5: m_pc.w = value; break; // PC + case 6: m_q.r.w = value; break; // W + case 7: m_v.w = value; break; // V + case 8: m_q.r.a = (uint8_t) (value >> 8); break; // A + case 9: m_q.r.b = (uint8_t) (value >> 0); break; // B + case 10: m_cc = (uint8_t) (value >> 0); break; // CC + case 11: m_dp = (uint8_t) (value >> 8); break; // DP + case 12: break; // 0 + case 13: break; // 0 + case 14: m_q.r.e = (uint8_t) (value >> 8); break; // E + case 15: m_q.r.f = (uint8_t) (value >> 0); break; // F default: fatalerror("Should not reach here"); } diff --git a/src/devices/cpu/m6809/hd6309.h b/src/devices/cpu/m6809/hd6309.h index 99065882116..c23ee66203f 100644 --- a/src/devices/cpu/m6809/hd6309.h +++ b/src/devices/cpu/m6809/hd6309.h @@ -108,8 +108,8 @@ private: void set_e() { m_addressing_mode = ADDRESSING_MODE_REGISTER_E; } void set_f() { m_addressing_mode = ADDRESSING_MODE_REGISTER_F; } void set_w() { m_addressing_mode = ADDRESSING_MODE_REGISTER_W; } - exgtfr_register read_exgtfr_register(uint8_t reg); - void write_exgtfr_register(uint8_t reg, exgtfr_register value); + uint16_t read_exgtfr_register(uint8_t reg); + void write_exgtfr_register(uint8_t reg, uint16_t value); bool tfr_read(uint8_t opcode, uint8_t arg, uint8_t &data); bool tfr_write(uint8_t opcode, uint8_t arg, uint8_t data); bool add8_sets_h() { return (m_opcode & 0xFE) != 0x30; } diff --git a/src/devices/cpu/m6809/hd6309.ops b/src/devices/cpu/m6809/hd6309.ops index e8e1a53f78f..39e7ddb405b 100644 --- a/src/devices/cpu/m6809/hd6309.ops +++ b/src/devices/cpu/m6809/hd6309.ops @@ -797,8 +797,8 @@ INDEXED: EXG: { uint8_t param = read_opcode_arg(); - exgtfr_register reg1 = read_exgtfr_register(param >> 4); - exgtfr_register reg2 = read_exgtfr_register(param >> 0); + uint16_t reg1 = read_exgtfr_register(param >> 4); + uint16_t reg2 = read_exgtfr_register(param >> 0); write_exgtfr_register(param >> 4, reg2); write_exgtfr_register(param >> 0, reg1); } @@ -808,7 +808,7 @@ EXG: TFR: { uint8_t param = read_opcode_arg(); - exgtfr_register reg = read_exgtfr_register(param >> 4); + uint16_t reg = read_exgtfr_register(param >> 4); write_exgtfr_register(param >> 0, reg); } eat(hd6309_native_mode() ? 2 : 4); diff --git a/src/devices/cpu/m6809/konami.cpp b/src/devices/cpu/m6809/konami.cpp index 95bd6765526..84553c8dbb9 100644 --- a/src/devices/cpu/m6809/konami.cpp +++ b/src/devices/cpu/m6809/konami.cpp @@ -193,21 +193,20 @@ inline uint16_t &konami_cpu_device::ireg() // read_exgtfr_register //------------------------------------------------- -inline m6809_base_device::exgtfr_register konami_cpu_device::read_exgtfr_register(uint8_t reg) +inline uint16_t konami_cpu_device::read_exgtfr_register(uint8_t reg) { - exgtfr_register result; - result.word_value = 0x00FF; + uint16_t result = 0x00FF; switch(reg & 0x07) { - case 0: result.word_value = m_q.r.a; break; // A - case 1: result.word_value = m_q.r.b; break; // B - case 2: result.word_value = m_x.w; break; // X - case 3: result.word_value = m_y.w; break; // Y - case 4: result.word_value = m_s.w; break; // S - case 5: result.word_value = m_u.w; break; // U + case 0: result = m_q.r.a; break; // A + case 1: result = m_q.r.b; break; // B + case 2: result = m_x.w; break; // X + case 3: result = m_y.w; break; // Y + case 4: result = m_s.w; break; // S + case 5: result = m_u.w; break; // U } - result.byte_value = (uint8_t) result.word_value; + return result; } @@ -216,16 +215,16 @@ inline m6809_base_device::exgtfr_register konami_cpu_device::read_exgtfr_registe // write_exgtfr_register //------------------------------------------------- -inline void konami_cpu_device::write_exgtfr_register(uint8_t reg, m6809_base_device::exgtfr_register value) +inline void konami_cpu_device::write_exgtfr_register(uint8_t reg, uint16_t value) { switch(reg & 0x07) { - case 0: m_q.r.a = value.byte_value; break; // A - case 1: m_q.r.b = value.byte_value; break; // B - case 2: m_x.w = value.word_value; break; // X - case 3: m_y.w = value.word_value; break; // Y - case 4: m_s.w = value.word_value; break; // S - case 5: m_u.w = value.word_value; break; // U + case 0: m_q.r.a = value; break; // A + case 1: m_q.r.b = value; break; // B + case 2: m_x.w = value; break; // X + case 3: m_y.w = value; break; // Y + case 4: m_s.w = value; break; // S + case 5: m_u.w = value; break; // U } } diff --git a/src/devices/cpu/m6809/konami.h b/src/devices/cpu/m6809/konami.h index edb595d771e..2106bcae31e 100644 --- a/src/devices/cpu/m6809/konami.h +++ b/src/devices/cpu/m6809/konami.h @@ -56,8 +56,8 @@ private: uint8_t read_operand(int ordinal); void write_operand(uint8_t data); void write_operand(int ordinal, uint8_t data); - exgtfr_register read_exgtfr_register(uint8_t reg); - void write_exgtfr_register(uint8_t reg, exgtfr_register value); + uint16_t read_exgtfr_register(uint8_t reg); + void write_exgtfr_register(uint8_t reg, uint16_t value); // instructions void lmul(); diff --git a/src/devices/cpu/m6809/konami.ops b/src/devices/cpu/m6809/konami.ops index 76c5c6c5229..01103e29678 100644 --- a/src/devices/cpu/m6809/konami.ops +++ b/src/devices/cpu/m6809/konami.ops @@ -435,8 +435,8 @@ EXG: { // konami's EXG instruction differs enough from 6809 to fork the code uint8_t param = read_opcode_arg(); - exgtfr_register reg1 = read_exgtfr_register(param >> 0); - exgtfr_register reg2 = read_exgtfr_register(param >> 4); + uint16_t reg1 = read_exgtfr_register(param >> 0); + uint16_t reg2 = read_exgtfr_register(param >> 4); write_exgtfr_register(param >> 0, reg2); write_exgtfr_register(param >> 4, reg1); } @@ -447,7 +447,7 @@ TFR: { // konami's TFR instruction differs enough from 6809 to fork the code uint8_t param = read_opcode_arg(); - exgtfr_register reg = read_exgtfr_register(param >> 0); + uint16_t reg = read_exgtfr_register(param >> 0); write_exgtfr_register(param >> 4, reg); } eat(hd6309_native_mode() ? 2 : 4); diff --git a/src/devices/cpu/m6809/m6809.cpp b/src/devices/cpu/m6809/m6809.cpp index 52ddfa433c6..dabdac7e74c 100644 --- a/src/devices/cpu/m6809/m6809.cpp +++ b/src/devices/cpu/m6809/m6809.cpp @@ -490,28 +490,51 @@ const char *m6809_base_device::inputnum_string(int inputnum) //------------------------------------------------- -// read_exgtfr_register +// read_tfr_register //------------------------------------------------- -m6809_base_device::exgtfr_register m6809_base_device::read_exgtfr_register(uint8_t reg) +uint16_t m6809_base_device::read_tfr_exg_816_register(uint8_t reg) { - exgtfr_register result; - result.byte_value = 0xFF; - result.word_value = 0x00FF; + uint16_t result; switch(reg & 0x0F) { - case 0: result.word_value = m_q.r.d; break; // D - case 1: result.word_value = m_x.w; break; // X - case 2: result.word_value = m_y.w; break; // Y - case 3: result.word_value = m_u.w; break; // U - case 4: result.word_value = m_s.w; break; // S - case 5: result.word_value = m_pc.w; break; // PC - case 8: result.byte_value = m_q.r.a; break; // A - case 9: result.byte_value = m_q.r.b; break; // B - case 10: result.byte_value = m_cc; break; // CC - case 11: result.byte_value = m_dp; break; // DP + case 0: result = m_q.r.d; break; // D + case 1: result = m_x.w; break; // X + case 2: result = m_y.w; break; // Y + case 3: result = m_u.w; break; // U + case 4: result = m_s.w; break; // S + case 5: result = m_pc.w; break; // PC + case 8: result = ((uint16_t)0xff00) | m_q.r.a; break; // A + case 9: result = ((uint16_t)0xff00) | m_q.r.b; break; // B + case 10: result = ((uint16_t)m_cc) << 8 | m_cc; break; // CC + case 11: result = ((uint16_t)m_dp) << 8 | m_dp; break; // DP + default: result = 0xffff; break; } + + return result; +} + + +uint16_t m6809_base_device::read_exg_168_register(uint8_t reg) +{ + uint16_t result; + + switch(reg & 0x0F) + { + case 0: result = m_q.r.d; break; // D + case 1: result = m_x.w; break; // X + case 2: result = m_y.w; break; // Y + case 3: result = m_u.w; break; // U + case 4: result = m_s.w; break; // S + case 5: result = m_pc.w; break; // PC + case 8: result = ((uint16_t)0xff00) | m_q.r.a; break; // A + case 9: result = ((uint16_t)0xff00) | m_q.r.b; break; // B + case 10: result = ((uint16_t)0xff00) | m_cc; break; // CC + case 11: result = ((uint16_t)0xff00) | m_dp; break; // DP + default: result = 0xffff; break; + } + return result; } @@ -520,20 +543,20 @@ m6809_base_device::exgtfr_register m6809_base_device::read_exgtfr_register(uint8 // write_exgtfr_register //------------------------------------------------- -void m6809_base_device::write_exgtfr_register(uint8_t reg, m6809_base_device::exgtfr_register value) +void m6809_base_device::write_exgtfr_register(uint8_t reg, uint16_t value) { switch(reg & 0x0F) { - case 0: m_q.r.d = value.word_value; break; // D - case 1: m_x.w = value.word_value; break; // X - case 2: m_y.w = value.word_value; break; // Y - case 3: m_u.w = value.word_value; break; // U - case 4: m_s.w = value.word_value; break; // S - case 5: m_pc.w = value.word_value; break; // PC - case 8: m_q.r.a = value.byte_value; break; // A - case 9: m_q.r.b = value.byte_value; break; // B - case 10: m_cc = value.byte_value; break; // CC - case 11: m_dp = value.byte_value; break; // DP + case 0: m_q.r.d = value; break; // D + case 1: m_x.w = value; break; // X + case 2: m_y.w = value; break; // Y + case 3: m_u.w = value; break; // U + case 4: m_s.w = value; break; // S + case 5: m_pc.w = value; break; // PC + case 8: m_q.r.a = (uint8_t)value; break; // A + case 9: m_q.r.b = (uint8_t)value; break; // B + case 10: m_cc = (uint8_t)value; break; // CC + case 11: m_dp = (uint8_t)value; break; // DP } } diff --git a/src/devices/cpu/m6809/m6809.h b/src/devices/cpu/m6809/m6809.h index 3fc0b8bae1d..6f7f9f5f03d 100644 --- a/src/devices/cpu/m6809/m6809.h +++ b/src/devices/cpu/m6809/m6809.h @@ -91,13 +91,6 @@ protected: ADDRESSING_MODE_REGISTER_D = 4 }; - // register transfer - struct exgtfr_register - { - uint8_t byte_value; - uint16_t word_value; - }; - // flag bits in the cc register enum { @@ -272,8 +265,9 @@ protected: uint16_t entire_state_registers() { return 0xFF; } // miscellaneous - inline exgtfr_register read_exgtfr_register(uint8_t reg); - inline void write_exgtfr_register(uint8_t reg, exgtfr_register value); + inline uint16_t read_tfr_exg_816_register(uint8_t reg); + inline uint16_t read_exg_168_register(uint8_t reg); + inline void write_exgtfr_register(uint8_t reg, uint16_t value); bool is_register_addressing_mode(); bool is_ea_addressing_mode() { return m_addressing_mode == ADDRESSING_MODE_EA; } uint16_t get_pending_interrupt(); diff --git a/src/devices/cpu/m6809/m6809.ops b/src/devices/cpu/m6809/m6809.ops index e07f02d4b24..93ac3c2c014 100644 --- a/src/devices/cpu/m6809/m6809.ops +++ b/src/devices/cpu/m6809/m6809.ops @@ -266,7 +266,7 @@ MAIN: case 0xFD: set_regop16(m_q.p.d); %EXTENDED; %ST16; return; case 0xFE: set_regop16(m_u); %EXTENDED; %LD16; return; case 0xFF: set_regop16(m_u); %EXTENDED; %ST16; return; - default: %ILLEGAL; return; + default: %ILLEGAL; return; } return; @@ -319,7 +319,7 @@ DISPATCH10: case 0xFE: set_regop16(m_s); %EXTENDED; %LD16; return; case 0xFF: set_regop16(m_s); %EXTENDED; %ST16; return; - default: %ILLEGAL; return; + default: %ILLEGAL; return; } return; @@ -336,10 +336,10 @@ DISPATCH11: case 0xAC: set_regop16(m_s); %INDEXED; %CMP16; return; case 0xB3: set_regop16(m_u); %EXTENDED; %CMP16; return; case 0xBC: set_regop16(m_s); %EXTENDED; %CMP16; return; - default: %ILLEGAL; return; + default: %ILLEGAL; return; } return; - + #include "base6x09.ops" PUSH_REGISTERS: @@ -568,10 +568,21 @@ INDEXED: EXG: { uint8_t param = read_opcode_arg(); - exgtfr_register reg1 = read_exgtfr_register(param >> 4); - exgtfr_register reg2 = read_exgtfr_register(param >> 0); - write_exgtfr_register(param >> 4, reg2); + uint16_t reg1, reg2; + + // Exchange differs if 16 bit register or 8 bit register is first + if (BIT(param, 7)) + { + reg1 = read_tfr_exg_816_register(param >> 4); + reg2 = read_tfr_exg_816_register(param >> 0); + } + else + { + reg1 = read_exg_168_register(param >> 4); + reg2 = read_exg_168_register(param >> 0); + } write_exgtfr_register(param >> 0, reg1); + write_exgtfr_register(param >> 4, reg2); } @dummy_vma(hd6309_native_mode() ? 3 : 6); return; @@ -579,7 +590,7 @@ EXG: TFR: { uint8_t param = read_opcode_arg(); - exgtfr_register reg = read_exgtfr_register(param >> 4); + uint16_t reg = read_tfr_exg_816_register(param >> 4); write_exgtfr_register(param >> 0, reg); if ((param & 0x0F) == 4) { m_lds_encountered = true; -- cgit v1.2.3