From fe7e897e5662099f402238931d16a8b1d7b81f31 Mon Sep 17 00:00:00 2001 From: wilbertpol Date: Sat, 26 Oct 2024 22:31:47 +0100 Subject: cpu/upd7810/upd7810.cpp: Improve uPD7801 Mode C handling. (#12914) Fixes banking in SCV Star Speeder. --- src/devices/cpu/upd7810/upd7810.cpp | 111 ++++++++++++++++++---------- src/devices/cpu/upd7810/upd7810.h | 4 + src/devices/cpu/upd7810/upd7810_opcodes.cpp | 5 +- 3 files changed, 82 insertions(+), 38 deletions(-) diff --git a/src/devices/cpu/upd7810/upd7810.cpp b/src/devices/cpu/upd7810/upd7810.cpp index b96ac0a8e7b..0883dd3cc31 100644 --- a/src/devices/cpu/upd7810/upd7810.cpp +++ b/src/devices/cpu/upd7810/upd7810.cpp @@ -623,25 +623,7 @@ uint8_t upd7810_device::RP(offs_t port) data = (m_pb_in & m_mb) | (m_pb_out & ~m_mb); break; case UPD7810_PORTC: - if (m_mc && !m_pc_in_cb.isunset()) // NS20031301 no need to read if the port is set as output - m_pc_in = m_pc_in_cb(0, m_mc); - data = (m_pc_in & m_mc) | (m_pc_out & ~m_mc); - if (m_mcc & 0x01) /* PC0 = TxD output */ - data = (data & ~0x01) | (m_txd & 1 ? 0x01 : 0x00); - if (m_mcc & 0x02) /* PC1 = RxD input */ - data = (data & ~0x02) | (m_rxd & 1 ? 0x02 : 0x00); - if (m_mcc & 0x04) /* PC2 = SCK input/output */ - data = (data & ~0x04) | (m_sck & 1 ? 0x04 : 0x00); - if (m_mcc & 0x08) /* PC3 = TI/INT2 input */ - data = (data & ~0x08) | (m_int2 & 1 ? 0x08 : 0x00); - if (m_mcc & 0x10) /* PC4 = TO output */ - data = (data & ~0x10) | (m_to & 1 ? 0x10 : 0x00); - if (m_mcc & 0x20) /* PC5 = CI input */ - data = (data & ~0x20) | (m_ci & 1 ? 0x20 : 0x00); - if (m_mcc & 0x40) /* PC6 = CO0 output */ - data = (data & ~0x40) | (m_co0 & 1 ? 0x40 : 0x00); - if (m_mcc & 0x80) /* PC7 = CO1 output */ - data = (data & ~0x80) | (m_co1 & 1 ? 0x80 : 0x00); + data = read_pc(); break; case UPD7810_PORTD: if (!m_pd_in_cb.isunset()) @@ -689,6 +671,42 @@ uint8_t upd7810_device::RP(offs_t port) return data; } +uint8_t upd7810_device::read_pc() +{ + if (m_mc && !m_pc_in_cb.isunset()) // NS20031301 no need to read if the port is set as output + m_pc_in = m_pc_in_cb(0, m_mc); + uint8_t data = (m_pc_in & m_mc) | (m_pc_out & ~m_mc); + if (m_mcc & 0x01) /* PC0 = TxD output */ + data = (data & ~0x01) | (m_txd & 1 ? 0x01 : 0x00); + if (m_mcc & 0x02) /* PC1 = RxD input */ + data = (data & ~0x02) | (m_rxd & 1 ? 0x02 : 0x00); + if (m_mcc & 0x04) /* PC2 = SCK input/output */ + data = (data & ~0x04) | (m_sck & 1 ? 0x04 : 0x00); + if (m_mcc & 0x08) /* PC3 = TI/INT2 input */ + data = (data & ~0x08) | (m_int2 & 1 ? 0x08 : 0x00); + if (m_mcc & 0x10) /* PC4 = TO output */ + data = (data & ~0x10) | (m_to & 1 ? 0x10 : 0x00); + if (m_mcc & 0x20) /* PC5 = CI input */ + data = (data & ~0x20) | (m_ci & 1 ? 0x20 : 0x00); + if (m_mcc & 0x40) /* PC6 = CO0 output */ + data = (data & ~0x40) | (m_co0 & 1 ? 0x40 : 0x00); + if (m_mcc & 0x80) /* PC7 = CO1 output */ + data = (data & ~0x80) | (m_co1 & 1 ? 0x80 : 0x00); + return data; +} + +uint8_t upd7801_device::read_pc() +{ + if ((m_mc & 0x87) && !m_pc_in_cb.isunset()) // NS20031301 no need to read if the port is set as output + m_pc_in = m_pc_in_cb(0, 0x84 | (m_mc & 0x03)); + uint8_t data = (m_pc_in & 0x87) | (m_pc_out & ~0x87); + if (!BIT(m_mc, 2)) /* TODO PC2 = -SCS input */ + data = (data & ~0x04) | 0x04; + if (!BIT(m_mc, 7)) /* TODO PC7 = HOLD input */ + data = (data & ~0x80); + return data; +} + void upd7810_device::WP(offs_t port, uint8_t data) { switch (port) @@ -705,24 +723,7 @@ void upd7810_device::WP(offs_t port, uint8_t data) break; case UPD7810_PORTC: m_pc_out = data; - data = (data & ~m_mc) | (m_pc_pullups & m_mc); - if (m_mcc & 0x01) /* PC0 = TxD output */ - data = (data & ~0x01) | (m_txd & 1 ? 0x01 : 0x00); - if (m_mcc & 0x02) /* PC1 = RxD input */ - data = (data & ~0x02) | (m_rxd & 1 ? 0x02 : 0x00); - if (m_mcc & 0x04) /* PC2 = SCK input/output */ - data = (data & ~0x04) | (m_sck & 1 ? 0x04 : 0x00); - if (m_mcc & 0x08) /* PC3 = TI/INT2 input */ - data = (data & ~0x08) | (m_int2 & 1 ? 0x08 : 0x00); - if (m_mcc & 0x10) /* PC4 = TO output */ - data = (data & ~0x10) | (m_to & 1 ? 0x10 : 0x00); - if (m_mcc & 0x20) /* PC5 = CI input */ - data = (data & ~0x20) | (m_ci & 1 ? 0x20 : 0x00); - if (m_mcc & 0x40) /* PC6 = CO0 output */ - data = (data & ~0x40) | (m_co0 & 1 ? 0x40 : 0x00); - if (m_mcc & 0x80) /* PC7 = CO1 output */ - data = (data & ~0x80) | (m_co1 & 1 ? 0x80 : 0x00); - m_pc_out_cb(data); + write_pc(data); break; case UPD7810_PORTD: m_pd_out = data; @@ -763,6 +764,42 @@ void upd7810_device::WP(offs_t port, uint8_t data) } } +void upd7810_device::write_pc(uint8_t data) +{ + data = (data & ~m_mc) | (m_pc_pullups & m_mc); + if (m_mcc & 0x01) /* PC0 = TxD output */ + data = (data & ~0x01) | (m_txd & 1 ? 0x01 : 0x00); + if (m_mcc & 0x02) /* PC1 = RxD input */ + data = (data & ~0x02) | (m_rxd & 1 ? 0x02 : 0x00); + if (m_mcc & 0x04) /* PC2 = SCK input/output */ + data = (data & ~0x04) | (m_sck & 1 ? 0x04 : 0x00); + if (m_mcc & 0x08) /* PC3 = TI/INT2 input */ + data = (data & ~0x08) | (m_int2 & 1 ? 0x08 : 0x00); + if (m_mcc & 0x10) /* PC4 = TO output */ + data = (data & ~0x10) | (m_to & 1 ? 0x10 : 0x00); + if (m_mcc & 0x20) /* PC5 = CI input */ + data = (data & ~0x20) | (m_ci & 1 ? 0x20 : 0x00); + if (m_mcc & 0x40) /* PC6 = CO0 output */ + data = (data & ~0x40) | (m_co0 & 1 ? 0x40 : 0x00); + if (m_mcc & 0x80) /* PC7 = CO1 output */ + data = (data & ~0x80) | (m_co1 & 1 ? 0x80 : 0x00); + m_pc_out_cb(data); +} + +void upd7801_device::write_pc(uint8_t data) +{ + data = (data & 0x78) | (m_pc_pullups & ~0x78); + if (!BIT(m_mc, 3)) /* TODO PC3 = SAK output */ + data = (data & ~0x08); + if (!BIT(m_mc, 4)) /* PC4 = TO output */ + data = (data & ~0x10) | (m_to & 1 ? 0x10 : 0x00); + if (!BIT(m_mc, 5)) /* TODO PC5 = IO/-M input */ + data = (data & ~0x20); + if (!BIT(m_mc, 6)) /* TODO PC6 = HLDA output */ + data = (data & ~0x40); + m_pc_out_cb(data); +} + void upd7810_device::upd7810_take_irq() { uint16_t vector = 0; diff --git a/src/devices/cpu/upd7810/upd7810.h b/src/devices/cpu/upd7810/upd7810.h index 14b6aa29272..9e07c77043b 100644 --- a/src/devices/cpu/upd7810/upd7810.h +++ b/src/devices/cpu/upd7810/upd7810.h @@ -199,6 +199,8 @@ protected: }; virtual void configure_ops(); + virtual uint8_t read_pc(); + virtual void write_pc(uint8_t data); static const struct opcode_s s_op48[256]; static const struct opcode_s s_op4C[256]; @@ -1410,6 +1412,8 @@ protected: virtual void handle_timers(int cycles) override; virtual void upd7810_take_irq() override; virtual void configure_ops() override; + virtual uint8_t read_pc() override; + virtual void write_pc(uint8_t data) override; }; diff --git a/src/devices/cpu/upd7810/upd7810_opcodes.cpp b/src/devices/cpu/upd7810/upd7810_opcodes.cpp index 9b8d481bb3b..892db43bc33 100644 --- a/src/devices/cpu/upd7810/upd7810_opcodes.cpp +++ b/src/devices/cpu/upd7810/upd7810_opcodes.cpp @@ -9474,5 +9474,8 @@ void upd7810_device::MOV_MC_A_7801() /* PC5 Output IO/-M Output */ /* PC6 Output HLDA Output */ /* PC7 Input HOLD Input */ - MC = 0x84 | ( ( A & 0x02 ) ? 0x02 : 0x00 ) | ( ( A & 0x01 ) ? 0x01 : 0x00 ); + if (MC == A) + return; + MC = A; + WP(UPD7810_PORTC, m_pc_out); } -- cgit v1.2.3