m6801: add input ports ddr override mask

This commit is contained in:
hap 2024-02-22 01:41:31 +01:00
parent 1f53ff94c6
commit 249a6a793f
5 changed files with 79 additions and 60 deletions

View File

@ -434,6 +434,8 @@ m6801_cpu_device::m6801_cpu_device(const machine_config &mconfig, device_type ty
, m_nvram_battery(true) , m_nvram_battery(true)
, m_sclk_divider(8) , m_sclk_divider(8)
{ {
std::fill(std::begin(m_port_ddr_override), std::end(m_port_ddr_override), 0);
// disable nvram by default (set to true if MCU is battery-backed when in standby mode) // disable nvram by default (set to true if MCU is battery-backed when in standby mode)
nvram_enable_backup(false); nvram_enable_backup(false);
} }
@ -498,6 +500,8 @@ hd6301x_cpu_device::hd6301x_cpu_device(const machine_config &mconfig, device_typ
, m_in_portx_func(*this, 0xff) , m_in_portx_func(*this, 0xff)
, m_out_portx_func(*this) , m_out_portx_func(*this)
{ {
std::fill(std::begin(m_portx_ddr_override), std::end(m_portx_ddr_override), 0);
m_sclk_divider = 16; m_sclk_divider = 16;
} }
@ -1221,7 +1225,8 @@ void m6801_cpu_device::execute_set_input(int irqline, int state)
if (!m_port3_latched && (m_p3csr & M6801_P3CSR_LE)) if (!m_port3_latched && (m_p3csr & M6801_P3CSR_LE))
{ {
// latch input data to port 3 // latch input data to port 3
m_port_data[2] = (m_in_port_func[2]() & (m_port_ddr[2] ^ 0xff)) | (m_port_data[2] & m_port_ddr[2]); u8 ddr = m_port_ddr[2] & ~m_port_ddr_override[2];
m_port_data[2] = (m_in_port_func[2]() & ~ddr) | (m_port_data[2] & ddr);
m_port3_latched = 1; m_port3_latched = 1;
LOGPORT("Latched Port 3 Data: %02x\n", m_port_data[2]); LOGPORT("Latched Port 3 Data: %02x\n", m_port_data[2]);
@ -1322,6 +1327,7 @@ void m6801_cpu_device::device_start()
save_item(NAME(m_nvram_battery)); save_item(NAME(m_nvram_battery));
save_item(NAME(m_port_ddr)); save_item(NAME(m_port_ddr));
save_item(NAME(m_port_data)); save_item(NAME(m_port_data));
save_item(NAME(m_port_ddr_override));
save_item(NAME(m_p3csr)); save_item(NAME(m_p3csr));
save_item(NAME(m_tcsr)); save_item(NAME(m_tcsr));
save_item(NAME(m_pending_tcsr)); save_item(NAME(m_pending_tcsr));
@ -1392,6 +1398,7 @@ void hd6301x_cpu_device::device_start()
save_item(NAME(m_portx_ddr)); save_item(NAME(m_portx_ddr));
save_item(NAME(m_portx_data)); save_item(NAME(m_portx_data));
save_item(NAME(m_portx_ddr_override));
save_item(NAME(m_tcsr2)); save_item(NAME(m_tcsr2));
save_item(NAME(m_pending_tcsr2)); save_item(NAME(m_pending_tcsr2));
save_item(NAME(m_output_compare[1].d)); save_item(NAME(m_output_compare[1].d));
@ -1680,10 +1687,12 @@ void hd6301y_cpu_device::p1_ddr_1bit_w(u8 data)
u8 m6801_cpu_device::p1_data_r() u8 m6801_cpu_device::p1_data_r()
{ {
if (m_port_ddr[0] == 0xff) u8 ddr = m_port_ddr[0] & ~m_port_ddr_override[0];
if (ddr == 0xff)
return m_port_data[0]; return m_port_data[0];
else else
return (m_in_port_func[0]() & (m_port_ddr[0] ^ 0xff)) | (m_port_data[0] & m_port_ddr[0]); return (m_in_port_func[0]() & ~ddr) | (m_port_data[0] & ddr);
} }
void m6801_cpu_device::p1_data_w(u8 data) void m6801_cpu_device::p1_data_w(u8 data)
@ -1763,10 +1772,12 @@ void hd6301x_cpu_device::p2_ddr_2bit_w(u8 data)
u8 m6801_cpu_device::p2_data_r() u8 m6801_cpu_device::p2_data_r()
{ {
if (m_port_ddr[1] == 0xff) u8 ddr = m_port_ddr[1] & ~m_port_ddr_override[1];
if (ddr == 0xff)
return m_port_data[1]; return m_port_data[1];
else else
return (m_in_port_func[1]() & (m_port_ddr[1] ^ 0xff)) | (m_port_data[1] & m_port_ddr[1]); return (m_in_port_func[1]() & ~ddr) | (m_port_data[1] & ddr);
} }
void m6801_cpu_device::p2_data_w(u8 data) void m6801_cpu_device::p2_data_w(u8 data)
@ -1805,8 +1816,6 @@ void hd6301x_cpu_device::p3_ddr_1bit_w(u8 data)
u8 m6801_cpu_device::p3_data_r() u8 m6801_cpu_device::p3_data_r()
{ {
u8 data;
if (!machine().side_effects_disabled()) if (!machine().side_effects_disabled())
{ {
if (m_pending_isf_clear) if (m_pending_isf_clear)
@ -1822,10 +1831,12 @@ u8 m6801_cpu_device::p3_data_r()
} }
} }
if ((m_p3csr & M6801_P3CSR_LE) || (m_port_ddr[2] == 0xff)) u8 data, ddr = m_port_ddr[2] & ~m_port_ddr_override[2];
if ((m_p3csr & M6801_P3CSR_LE) || (ddr == 0xff))
data = m_port_data[2]; data = m_port_data[2];
else else
data = (m_in_port_func[2]() & (m_port_ddr[2] ^ 0xff)) | (m_port_data[2] & m_port_ddr[2]); data = (m_in_port_func[2]() & ~ddr) | (m_port_data[2] & ddr);
if (!machine().side_effects_disabled()) if (!machine().side_effects_disabled())
{ {
@ -1836,6 +1847,7 @@ u8 m6801_cpu_device::p3_data_r()
set_os3(CLEAR_LINE); set_os3(CLEAR_LINE);
} }
} }
return data; return data;
} }
@ -1867,10 +1879,12 @@ void m6801_cpu_device::p3_data_w(u8 data)
u8 hd6301x_cpu_device::p3_data_r() u8 hd6301x_cpu_device::p3_data_r()
{ {
// no handshaking protocol // no handshaking protocol
if (m_port_ddr[2] == 0xff) u8 ddr = m_port_ddr[2] & ~m_port_ddr_override[2];
if (ddr == 0xff)
return m_port_data[2]; return m_port_data[2];
else else
return (m_in_port_func[2]() & (m_port_ddr[2] ^ 0xff)) | (m_port_data[2] & m_port_ddr[2]); return (m_in_port_func[2]() & ~ddr) | (m_port_data[2] & ddr);
} }
void hd6301x_cpu_device::p3_data_w(u8 data) void hd6301x_cpu_device::p3_data_w(u8 data)
@ -1913,10 +1927,12 @@ void m6801_cpu_device::p4_ddr_w(u8 data)
u8 m6801_cpu_device::p4_data_r() u8 m6801_cpu_device::p4_data_r()
{ {
if (m_port_ddr[3] == 0xff) u8 ddr = m_port_ddr[3] & ~m_port_ddr_override[3];
if (ddr == 0xff)
return m_port_data[3]; return m_port_data[3];
else else
return (m_in_port_func[3]() & (m_port_ddr[3] ^ 0xff)) | (m_port_data[3] & m_port_ddr[3]); return (m_in_port_func[3]() & ~ddr) | (m_port_data[3] & ddr);
} }
void m6801_cpu_device::p4_data_w(u8 data) void m6801_cpu_device::p4_data_w(u8 data)
@ -1954,7 +1970,9 @@ u8 hd6301x_cpu_device::p5_data_r()
u8 hd6301y_cpu_device::p5_data_r() u8 hd6301y_cpu_device::p5_data_r()
{ {
if (m_portx_ddr[0] == 0xff) u8 ddr = m_portx_ddr[0] & ~m_portx_ddr_override[0];
if (ddr == 0xff)
return m_portx_data[0]; return m_portx_data[0];
else else
{ {
@ -1963,7 +1981,7 @@ u8 hd6301y_cpu_device::p5_data_r()
if (m_irq_state[M6801_IS3_LINE]) if (m_irq_state[M6801_IS3_LINE])
data |= 0x10; data |= 0x10;
return (data & (m_portx_ddr[0] ^ 0xff)) | (m_portx_data[0] & m_portx_ddr[0]); return (data & ~ddr) | (m_portx_data[0] & ddr);
} }
} }
@ -1989,10 +2007,12 @@ void hd6301x_cpu_device::p6_ddr_w(u8 data)
u8 hd6301x_cpu_device::p6_data_r() u8 hd6301x_cpu_device::p6_data_r()
{ {
if (m_portx_ddr[1] == 0xff) u8 ddr = m_portx_ddr[1] & ~m_portx_ddr_override[1];
if (ddr == 0xff)
return m_portx_data[1]; return m_portx_data[1];
else else
return (m_in_portx_func[1]() & (m_portx_ddr[1] ^ 0xff)) | (m_portx_data[1] & m_portx_ddr[1]); return (m_in_portx_func[1]() & ~ddr) | (m_portx_data[1] & ddr);
} }
void hd6301x_cpu_device::p6_data_w(u8 data) void hd6301x_cpu_device::p6_data_w(u8 data)

View File

@ -52,6 +52,12 @@ public:
auto in_p4_cb() { return m_in_port_func[3].bind(); } auto in_p4_cb() { return m_in_port_func[3].bind(); }
auto out_p4_cb() { return m_out_port_func[3].bind(); } auto out_p4_cb() { return m_out_port_func[3].bind(); }
// a connected device can pull the voltage enough to force pin(s) to input, overriding DDR
void in_p1_override_mask(u8 mask) { m_port_ddr_override[0] = mask; }
void in_p2_override_mask(u8 mask) { m_port_ddr_override[1] = mask; }
void in_p3_override_mask(u8 mask) { m_port_ddr_override[2] = mask; }
void in_p4_override_mask(u8 mask) { m_port_ddr_override[3] = mask; }
auto out_sc2_cb() { return m_out_sc2_func.bind(); } auto out_sc2_cb() { return m_out_sc2_func.bind(); }
auto out_ser_tx_cb() { return m_out_sertx_func.bind(); } auto out_ser_tx_cb() { return m_out_sertx_func.bind(); }
@ -142,12 +148,13 @@ protected:
int m_sclk_divider; int m_sclk_divider;
// internal registers // internal registers
u8 m_port_ddr[4]; u8 m_port_ddr[4];
u8 m_port_data[4]; u8 m_port_data[4];
u8 m_p3csr; // Port 3 Control/Status Register u8 m_port_ddr_override[4];
u8 m_tcsr; // Timer Control and Status Register u8 m_p3csr; // Port 3 Control/Status Register
u8 m_pending_tcsr; // pending IRQ flag for clear IRQflag process u8 m_tcsr; // Timer Control and Status Register
u8 m_ram_ctrl; u8 m_pending_tcsr; // pending IRQ flag for clear IRQflag process
u8 m_ram_ctrl;
PAIR m_counter; // free running counter PAIR m_counter; // free running counter
PAIR m_output_compare[3]; // output compare (MC6801U4 and HD6301X have more than one) PAIR m_output_compare[3]; // output compare (MC6801U4 and HD6301X have more than one)
u16 m_input_capture; // input capture u16 m_input_capture; // input capture
@ -155,11 +162,11 @@ protected:
int m_port3_latched; int m_port3_latched;
bool m_port2_written; bool m_port2_written;
u8 m_trcsr, m_rmcr, m_rdr, m_tdr, m_rsr, m_tshr; u8 m_trcsr, m_rmcr, m_rdr, m_tdr, m_rsr, m_tshr;
int m_rxbits, m_txbits, m_txstate, m_trcsr_read_tdre, m_trcsr_read_orfe, m_trcsr_read_rdrf, m_tx, m_ext_serclock; int m_rxbits, m_txbits, m_txstate, m_trcsr_read_tdre, m_trcsr_read_orfe, m_trcsr_read_rdrf, m_tx, m_ext_serclock;
bool m_use_ext_serclock; bool m_use_ext_serclock;
u8 m_latch09; u8 m_latch09;
int m_is3_state; int m_is3_state;
PAIR m_timer_over; PAIR m_timer_over;
@ -339,6 +346,9 @@ public:
auto out_p6_cb() { return m_out_portx_func[1].bind(); } auto out_p6_cb() { return m_out_portx_func[1].bind(); }
auto out_p7_cb() { return m_out_portx_func[2].bind(); } auto out_p7_cb() { return m_out_portx_func[2].bind(); }
void in_p5_override_mask(u8 mask) { m_portx_ddr_override[0] = mask; }
void in_p6_override_mask(u8 mask) { m_portx_ddr_override[1] = mask; }
protected: protected:
hd6301x_cpu_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, address_map_constructor internal, int nvram_bytes); hd6301x_cpu_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, address_map_constructor internal, int nvram_bytes);
@ -398,6 +408,7 @@ protected:
u8 m_portx_ddr[2]; u8 m_portx_ddr[2];
u8 m_portx_data[3]; u8 m_portx_data[3];
u8 m_portx_ddr_override[2];
u8 m_tcsr2; u8 m_tcsr2;
u8 m_pending_tcsr2; u8 m_pending_tcsr2;

View File

@ -1129,15 +1129,15 @@ void pic16c5x_device::state_string_export(const device_state_entry &entry, std::
case STATE_GENFLAGS: case STATE_GENFLAGS:
str = string_format("%01x%c%c%c%c%c %c%c%c%03x", str = string_format("%01x%c%c%c%c%c %c%c%c%03x",
(m_STATUS & 0xe0) >> 5, (m_STATUS & 0xe0) >> 5,
m_STATUS & 0x10 ? '.':'O', // WDT Overflow m_STATUS & 0x10 ? '.':'O', // WDT Overflow
m_STATUS & 0x08 ? 'P':'D', // Power/Down m_STATUS & 0x08 ? 'P':'D', // Power/Down
m_STATUS & 0x04 ? 'Z':'.', // Zero m_STATUS & 0x04 ? 'Z':'.', // Zero
m_STATUS & 0x02 ? 'c':'b', // Nibble Carry/Borrow m_STATUS & 0x02 ? 'c':'b', // Nibble Carry/Borrow
m_STATUS & 0x01 ? 'C':'B', // Carry/Borrow m_STATUS & 0x01 ? 'C':'B', // Carry/Borrow
m_OPTION & 0x20 ? 'C':'T', // Counter/Timer m_OPTION & 0x20 ? 'C':'T', // Counter/Timer
m_OPTION & 0x10 ? 'N':'P', // Negative/Positive m_OPTION & 0x10 ? 'N':'P', // Negative/Positive
m_OPTION & 0x08 ? 'W':'T', // WatchDog/Timer m_OPTION & 0x08 ? 'W':'T', // WatchDog/Timer
m_OPTION & 0x08 ? (1<<(m_OPTION&7)) : (2<<(m_OPTION&7))); m_OPTION & 0x08 ? (1<<(m_OPTION&7)) : (2<<(m_OPTION&7)));
break; break;
} }

View File

@ -15,18 +15,19 @@ Hardware notes:
- piezo, 16+4 LEDs, 8*8 chessboard buttons - piezo, 16+4 LEDs, 8*8 chessboard buttons
TODO: TODO:
- It expects P63 input to be 0 even though that pin is set to output, otherwise
the piezo is very slow. There's a workaround in p6_w. This is the 2nd time I
saw a situation like this, perhaps external devices can override DDR?
- is Novag Amigo the same ROM? MCU label is also "892A", but QFP, ROM serial M44 - is Novag Amigo the same ROM? MCU label is also "892A", but QFP, ROM serial M44
BTANB:
- piezo sounds glitchy/fast (which is weird when compared against other Novag
chesscomputers), verified with 2 videos
*******************************************************************************/ *******************************************************************************/
#include "emu.h" #include "emu.h"
#include "cpu/m6800/m6801.h" #include "cpu/m6800/m6801.h"
#include "machine/sensorboard.h" #include "machine/sensorboard.h"
#include "sound/dac.h" #include "sound/spkrdev.h"
#include "video/pwm.h" #include "video/pwm.h"
#include "speaker.h" #include "speaker.h"
@ -66,7 +67,7 @@ private:
required_device<sensorboard_device> m_board; required_device<sensorboard_device> m_board;
required_device<pwm_display_device> m_led_pwm; required_device<pwm_display_device> m_led_pwm;
required_device<pwm_display_device> m_lcd_pwm; required_device<pwm_display_device> m_lcd_pwm;
required_device<dac_2bit_ones_complement_device> m_dac; required_device<speaker_sound_device> m_dac;
required_ioport_array<2> m_inputs; required_ioport_array<2> m_inputs;
output_finder<4, 16> m_out_lcd; output_finder<4, 16> m_out_lcd;
output_finder<8> m_out_digit; output_finder<8> m_out_digit;
@ -153,8 +154,7 @@ void mentor16_state::lcd_pwm_w(offs_t offset, u8 data)
void mentor16_state::update_lcd() void mentor16_state::update_lcd()
{ {
for (int i = 0; i < 4; i++) m_lcd_pwm->matrix(m_lcd_com >> 4, (m_lcd_com & 1) ? ~m_lcd_segs : m_lcd_segs);
m_lcd_pwm->write_row(i, BIT(m_lcd_com, i + 4) ? ((m_lcd_com & 1) ? ~m_lcd_segs : m_lcd_segs) : 0);
} }
template <int N> template <int N>
@ -214,14 +214,11 @@ u8 mentor16_state::p6_r()
void mentor16_state::p6_w(u8 data) void mentor16_state::p6_w(u8 data)
{ {
// P62,P63: speaker out // P62: speaker out (P63 too, but forced low)
m_dac->write(~data >> 2 & 3); m_dac->level_w(BIT(~data, 2));
// P64-P66: led select // P64-P66: led select
m_led_pwm->write_my(~data >> 4 & 7); m_led_pwm->write_my(~data >> 4 & 7);
// HACK: force DDR6 to be 0x74
m_maincpu->space(AS_PROGRAM).write_byte(0x16, 0x74);
} }
@ -274,6 +271,7 @@ void mentor16_state::mentor16(machine_config &config)
m_maincpu->out_p4_cb().set(FUNC(mentor16_state::lcd_segs_w<1>)); m_maincpu->out_p4_cb().set(FUNC(mentor16_state::lcd_segs_w<1>));
m_maincpu->in_p5_cb().set(FUNC(mentor16_state::p5_r)); m_maincpu->in_p5_cb().set(FUNC(mentor16_state::p5_r));
m_maincpu->in_p6_cb().set(FUNC(mentor16_state::p6_r)); m_maincpu->in_p6_cb().set(FUNC(mentor16_state::p6_r));
m_maincpu->in_p6_override_mask(0x08); // P23 forced low, slow piezo otherwise
m_maincpu->out_p6_cb().set(FUNC(mentor16_state::p6_w)); m_maincpu->out_p6_cb().set(FUNC(mentor16_state::p6_w));
SENSORBOARD(config, m_board).set_type(sensorboard_device::BUTTONS); SENSORBOARD(config, m_board).set_type(sensorboard_device::BUTTONS);
@ -290,7 +288,7 @@ void mentor16_state::mentor16(machine_config &config)
// sound hardware // sound hardware
SPEAKER(config, "speaker").front_center(); SPEAKER(config, "speaker").front_center();
DAC_2BIT_ONES_COMPLEMENT(config, m_dac).add_route(ALL_OUTPUTS, "speaker", 0.25); SPEAKER_SOUND(config, m_dac).add_route(ALL_OUTPUTS, "speaker", 0.25);
} }

View File

@ -14,8 +14,6 @@ NVRAM won't save properly.
TODO: TODO:
- dump/add other MCU revisions, SX8 for tmate/conquist is known to exist - dump/add other MCU revisions, SX8 for tmate/conquist is known to exist
- verify if QFP SX5A has the same ROM contents as DIP SX5A - verify if QFP SX5A has the same ROM contents as DIP SX5A
- SX4A and SX5A read from port 2 bits 3 and 7 while DDR is 0xff, why does it work?
I added a simple workaround for it in p2_w
- what is t1850's official title? "1850 Deluxe Table Chess" is from the back of - what is t1850's official title? "1850 Deluxe Table Chess" is from the back of
the computer. The manual can't make up its mind and says "1850 Chess Computer", the computer. The manual can't make up its mind and says "1850 Chess Computer",
"1850 Chess: 16 Level Program", or "1850 Sensory Chess Game". The box disagrees "1850 Chess: 16 Level Program", or "1850 Sensory Chess Game". The box disagrees
@ -125,7 +123,6 @@ protected:
template <int N> void leds1_w(u8 data); template <int N> void leds1_w(u8 data);
template <int N> void leds2_w(u8 data); template <int N> void leds2_w(u8 data);
void p2_w(u8 data);
void p2l_w(u8 data); void p2l_w(u8 data);
virtual void p3_w(u8 data); virtual void p3_w(u8 data);
virtual u8 p5_r(); virtual u8 p5_r();
@ -205,15 +202,6 @@ void turbo16k_state::leds2_w(u8 data)
m_display->write_row(N + 3, ~data); m_display->write_row(N + 3, ~data);
} }
void turbo16k_state::p2_w(u8 data)
{
// P24,P25: status leds
leds2_w<0>(data);
// HACK: force DDR2 to be 0x77
m_maincpu->space(AS_PROGRAM).write_byte(0x01, 0x77);
}
void turbo16k_state::p3_w(u8 data) void turbo16k_state::p3_w(u8 data)
{ {
// P30-P37: input mux // P30-P37: input mux
@ -283,7 +271,8 @@ void turbo16k_state::lcd_enable(u8 enable)
void turbo16k_state::p2l_w(u8 data) void turbo16k_state::p2l_w(u8 data)
{ {
p2_w(data); // P24,P25: status leds
leds2_w<0>(data);
// P20,P21: LCD clocks enabled // P20,P21: LCD clocks enabled
lcd_enable(~data & 3); lcd_enable(~data & 3);
@ -425,7 +414,8 @@ void turbo16k_state::compan3(machine_config &config)
m_maincpu->standby_cb().append([this](int state) { if (state) m_display->clear(); }); m_maincpu->standby_cb().append([this](int state) { if (state) m_display->clear(); });
m_maincpu->out_p1_cb().set(FUNC(turbo16k_state::leds1_w<0>)); m_maincpu->out_p1_cb().set(FUNC(turbo16k_state::leds1_w<0>));
m_maincpu->in_p2_cb().set_ioport("FREQ"); m_maincpu->in_p2_cb().set_ioport("FREQ");
m_maincpu->out_p2_cb().set(FUNC(turbo16k_state::p2_w)); m_maincpu->in_p2_override_mask(0x88); // SX4A and SX5A rely on this
m_maincpu->out_p2_cb().set(FUNC(turbo16k_state::leds2_w<0>));
m_maincpu->out_p3_cb().set(FUNC(turbo16k_state::p3_w)); m_maincpu->out_p3_cb().set(FUNC(turbo16k_state::p3_w));
m_maincpu->out_p4_cb().set(FUNC(turbo16k_state::leds1_w<1>)); m_maincpu->out_p4_cb().set(FUNC(turbo16k_state::leds1_w<1>));
m_maincpu->in_p5_cb().set(FUNC(turbo16k_state::p5_r)); m_maincpu->in_p5_cb().set(FUNC(turbo16k_state::p5_r));