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_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)
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_out_portx_func(*this)
{
std::fill(std::begin(m_portx_ddr_override), std::end(m_portx_ddr_override), 0);
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))
{
// 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;
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_port_ddr));
save_item(NAME(m_port_data));
save_item(NAME(m_port_ddr_override));
save_item(NAME(m_p3csr));
save_item(NAME(m_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_data));
save_item(NAME(m_portx_ddr_override));
save_item(NAME(m_tcsr2));
save_item(NAME(m_pending_tcsr2));
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()
{
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];
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)
@ -1763,10 +1772,12 @@ void hd6301x_cpu_device::p2_ddr_2bit_w(u8 data)
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];
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)
@ -1805,8 +1816,6 @@ void hd6301x_cpu_device::p3_ddr_1bit_w(u8 data)
u8 m6801_cpu_device::p3_data_r()
{
u8 data;
if (!machine().side_effects_disabled())
{
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];
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())
{
@ -1836,6 +1847,7 @@ u8 m6801_cpu_device::p3_data_r()
set_os3(CLEAR_LINE);
}
}
return data;
}
@ -1867,10 +1879,12 @@ void m6801_cpu_device::p3_data_w(u8 data)
u8 hd6301x_cpu_device::p3_data_r()
{
// 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];
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)
@ -1913,10 +1927,12 @@ void m6801_cpu_device::p4_ddr_w(u8 data)
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];
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)
@ -1954,7 +1970,9 @@ u8 hd6301x_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];
else
{
@ -1963,7 +1981,7 @@ u8 hd6301y_cpu_device::p5_data_r()
if (m_irq_state[M6801_IS3_LINE])
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()
{
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];
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)

View File

@ -52,6 +52,12 @@ public:
auto in_p4_cb() { return m_in_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_ser_tx_cb() { return m_out_sertx_func.bind(); }
@ -142,12 +148,13 @@ protected:
int m_sclk_divider;
// internal registers
u8 m_port_ddr[4];
u8 m_port_data[4];
u8 m_p3csr; // Port 3 Control/Status Register
u8 m_tcsr; // Timer Control and Status Register
u8 m_pending_tcsr; // pending IRQ flag for clear IRQflag process
u8 m_ram_ctrl;
u8 m_port_ddr[4];
u8 m_port_data[4];
u8 m_port_ddr_override[4];
u8 m_p3csr; // Port 3 Control/Status Register
u8 m_tcsr; // Timer Control and Status Register
u8 m_pending_tcsr; // pending IRQ flag for clear IRQflag process
u8 m_ram_ctrl;
PAIR m_counter; // free running counter
PAIR m_output_compare[3]; // output compare (MC6801U4 and HD6301X have more than one)
u16 m_input_capture; // input capture
@ -155,11 +162,11 @@ protected:
int m_port3_latched;
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;
bool m_use_ext_serclock;
u8 m_latch09;
u8 m_latch09;
int m_is3_state;
PAIR m_timer_over;
@ -339,6 +346,9 @@ public:
auto out_p6_cb() { return m_out_portx_func[1].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:
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_data[3];
u8 m_portx_ddr_override[2];
u8 m_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:
str = string_format("%01x%c%c%c%c%c %c%c%c%03x",
(m_STATUS & 0xe0) >> 5,
m_STATUS & 0x10 ? '.':'O', // WDT Overflow
m_STATUS & 0x08 ? 'P':'D', // Power/Down
m_STATUS & 0x04 ? 'Z':'.', // Zero
m_STATUS & 0x02 ? 'c':'b', // Nibble Carry/Borrow
m_STATUS & 0x01 ? 'C':'B', // Carry/Borrow
m_STATUS & 0x10 ? '.':'O', // WDT Overflow
m_STATUS & 0x08 ? 'P':'D', // Power/Down
m_STATUS & 0x04 ? 'Z':'.', // Zero
m_STATUS & 0x02 ? 'c':'b', // Nibble Carry/Borrow
m_STATUS & 0x01 ? 'C':'B', // Carry/Borrow
m_OPTION & 0x20 ? 'C':'T', // Counter/Timer
m_OPTION & 0x10 ? 'N':'P', // Negative/Positive
m_OPTION & 0x08 ? 'W':'T', // WatchDog/Timer
m_OPTION & 0x20 ? 'C':'T', // Counter/Timer
m_OPTION & 0x10 ? 'N':'P', // Negative/Positive
m_OPTION & 0x08 ? 'W':'T', // WatchDog/Timer
m_OPTION & 0x08 ? (1<<(m_OPTION&7)) : (2<<(m_OPTION&7)));
break;
}

View File

@ -15,18 +15,19 @@ Hardware notes:
- piezo, 16+4 LEDs, 8*8 chessboard buttons
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
BTANB:
- piezo sounds glitchy/fast (which is weird when compared against other Novag
chesscomputers), verified with 2 videos
*******************************************************************************/
#include "emu.h"
#include "cpu/m6800/m6801.h"
#include "machine/sensorboard.h"
#include "sound/dac.h"
#include "sound/spkrdev.h"
#include "video/pwm.h"
#include "speaker.h"
@ -66,7 +67,7 @@ private:
required_device<sensorboard_device> m_board;
required_device<pwm_display_device> m_led_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;
output_finder<4, 16> m_out_lcd;
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()
{
for (int i = 0; i < 4; i++)
m_lcd_pwm->write_row(i, BIT(m_lcd_com, i + 4) ? ((m_lcd_com & 1) ? ~m_lcd_segs : m_lcd_segs) : 0);
m_lcd_pwm->matrix(m_lcd_com >> 4, (m_lcd_com & 1) ? ~m_lcd_segs : m_lcd_segs);
}
template <int N>
@ -214,14 +214,11 @@ u8 mentor16_state::p6_r()
void mentor16_state::p6_w(u8 data)
{
// P62,P63: speaker out
m_dac->write(~data >> 2 & 3);
// P62: speaker out (P63 too, but forced low)
m_dac->level_w(BIT(~data, 2));
// P64-P66: led select
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->in_p5_cb().set(FUNC(mentor16_state::p5_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));
SENSORBOARD(config, m_board).set_type(sensorboard_device::BUTTONS);
@ -290,7 +288,7 @@ void mentor16_state::mentor16(machine_config &config)
// sound hardware
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:
- 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
- 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
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
@ -125,7 +123,6 @@ protected:
template <int N> void leds1_w(u8 data);
template <int N> void leds2_w(u8 data);
void p2_w(u8 data);
void p2l_w(u8 data);
virtual void p3_w(u8 data);
virtual u8 p5_r();
@ -205,15 +202,6 @@ void turbo16k_state::leds2_w(u8 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)
{
// P30-P37: input mux
@ -283,7 +271,8 @@ void turbo16k_state::lcd_enable(u8 enable)
void turbo16k_state::p2l_w(u8 data)
{
p2_w(data);
// P24,P25: status leds
leds2_w<0>(data);
// P20,P21: LCD clocks enabled
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->out_p1_cb().set(FUNC(turbo16k_state::leds1_w<0>));
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_p4_cb().set(FUNC(turbo16k_state::leds1_w<1>));
m_maincpu->in_p5_cb().set(FUNC(turbo16k_state::p5_r));