diff --git a/scripts/src/machine.lua b/scripts/src/machine.lua index d831ac381ca..9188507cce4 100644 --- a/scripts/src/machine.lua +++ b/scripts/src/machine.lua @@ -1895,6 +1895,18 @@ if (MACHINES["MC6843"]~=null) then } end +--------------------------------------------------- +-- +--@src/devices/machine/mc6844.h,MACHINES["MC6844"] = true +--------------------------------------------------- + +if (MACHINES["MC6844"]~=null) then + files { + MAME_DIR .. "src/devices/machine/mc6844.cpp", + MAME_DIR .. "src/devices/machine/mc6844.h", + } +end + --------------------------------------------------- -- --@src/devices/machine/mc6846.h,MACHINES["MC6846"] = true diff --git a/scripts/target/mame/mess.lua b/scripts/target/mame/mess.lua index 85b6ee9c86e..7e3e127fc1b 100644 --- a/scripts/target/mame/mess.lua +++ b/scripts/target/mame/mess.lua @@ -545,6 +545,7 @@ MACHINES["MC14411"] = true MACHINES["MC146818"] = true MACHINES["MC2661"] = true MACHINES["MC6843"] = true +MACHINES["MC6844"] = true MACHINES["MC6846"] = true MACHINES["MC6852"] = true MACHINES["MC6854"] = true @@ -2240,6 +2241,9 @@ files { MAME_DIR .. "src/mame/drivers/eispc.cpp", MAME_DIR .. "src/mame/machine/eispc_kb.cpp", MAME_DIR .. "src/mame/machine/eispc_kb.h", + MAME_DIR .. "src/mame/drivers/alfaskop41xx.cpp", + MAME_DIR .. "src/mame/machine/alfaskop_s41_kb.cpp", + MAME_DIR .. "src/mame/machine/alfaskop_s41_kb.h", } createMESSProjects(_target, _subtarget, "exidy") diff --git a/src/devices/machine/6821pia.cpp b/src/devices/machine/6821pia.cpp index 3f5c52188ae..1392166081b 100644 --- a/src/devices/machine/6821pia.cpp +++ b/src/devices/machine/6821pia.cpp @@ -17,7 +17,8 @@ #define LOG_SETUP 0x02 #define LOG_CA1 0x08 -//#define VERBOSE (LOG_SETUP | LOG_GENERAL) +//#define VERBOSE (LOG_SETUP | LOG_GENERAL | LOG_CA1) +//#define LOG_OUTPUT_STREAM std::cout #include "logmacro.h" #define LOGSETUP(...) LOGMASKED(LOG_SETUP, __VA_ARGS__) @@ -596,7 +597,7 @@ void pia6821_device::send_to_out_a_func(const char* message) // input pins are pulled high const uint8_t data = get_out_a_value(); - LOG("PIA %s = %02X\n", message, data); + LOG("PIA %s = %02X DDRA=%02x\n", message, data, m_ddr_a); if (!m_out_a_handler.isnull()) { @@ -621,7 +622,7 @@ void pia6821_device::send_to_out_b_func(const char* message) // input pins are high-impedance - we just send them as zeros for backwards compatibility const uint8_t data = get_out_b_value(); - LOG("PIA %s = %02X\n", message, data); + LOG("PIA %s = %02X DDRB=%02x\n", message, data, m_ddr_b); if (!m_out_b_handler.isnull()) { @@ -646,6 +647,7 @@ void pia6821_device::port_a_w(uint8_t data) // buffer the output value m_out_a = data; + LOGSETUP("PIA "); send_to_out_a_func("port A write"); } @@ -720,6 +722,9 @@ void pia6821_device::control_a_w(uint8_t data) data &= 0x3f; LOGSETUP("PIA control A write = %02X\n", data); + LOGSETUP(" - CA1 interrupts %s\n", (data & 0x01) ? "enabled" : "disabled"); + LOGSETUP(" - CA1 interrupts active on %s transition\n", (data & 0x02) ? "low-to-high" : "high-to-low"); + LOGSETUP(" - Port A %s register selected\n", (data & 0x04) ? "Data" : "DDR"); // update the control register m_ctl_a = data; @@ -729,10 +734,17 @@ void pia6821_device::control_a_w(uint8_t data) { bool temp; if (c2_set_mode(m_ctl_a)) + { + LOGSETUP(" - CA2 set/reset mode: "); temp = c2_set(m_ctl_a); // set/reset mode - bit value determines the new output + } else + { + LOGSETUP(" - CA2 strobe mode: "); temp = true; // strobe mode - output is always high unless strobed + } + LOGSETUP("%d\n", temp); set_out_ca2(temp); } @@ -751,16 +763,26 @@ void pia6821_device::control_b_w(uint8_t data) data &= 0x3f; LOGSETUP("PIA control B write = %02X\n", data); + LOGSETUP(" - CB1 interrupts %s\n", (data & 0x01) ? "enabled" : "disabled"); + LOGSETUP(" - CB1 interrupts active on %s transition\n", (data & 0x02) ? "low-to-high" : "high-to-low"); + LOGSETUP(" - Port B %s register selected\n", (data & 0x04) ? "Data" : "DDR"); // update the control register m_ctl_b = data; bool temp; if (c2_set_mode(m_ctl_b)) + { + LOGSETUP(" - CB2 set/reset mode: "); temp = c2_set(m_ctl_b); // set/reset mode - bit value determines the new output + } else + { + LOGSETUP(" - CB2 strobe mode: "); temp = true; // strobe mode - output is always high unless strobed + } + LOGSETUP("%d\n", temp); set_out_cb2(temp); // update externals diff --git a/src/devices/machine/6850acia.cpp b/src/devices/machine/6850acia.cpp index b7a7de81e4b..ed763825b59 100644 --- a/src/devices/machine/6850acia.cpp +++ b/src/devices/machine/6850acia.cpp @@ -16,10 +16,15 @@ MACROS ***************************************************************************/ -//#define VERBOSE 1 +#define LOG_SETUP (1U << 1) + +//#define VERBOSE (LOG_GENERAL | LOG_SETUP) //#define LOG_OUTPUT_STREAM std::cout + #include "logmacro.h" +#define LOGSETUP(...) LOGMASKED(LOG_SETUP, __VA_ARGS__) + /*************************************************************************** LOCAL VARIABLES ***************************************************************************/ @@ -177,12 +182,14 @@ void acia6850_device::control_w(uint8_t data) // CR0 & CR1 int counter_divide_select_bits = (data >> 0) & 3; m_divide = counter_divide_select[counter_divide_select_bits]; + LOGSETUP(" - Divide: x%d\n", counter_divide_select[counter_divide_select_bits]); // CR2, CR3 & CR4 int word_select_bits = (data >> 2) & 7; m_bits = word_select[word_select_bits][0]; m_parity = word_select[word_select_bits][1]; m_stopbits = word_select[word_select_bits][2]; + LOGSETUP(" - %d%c%d\n", m_bits, m_parity == PARITY_NONE ? 'N' : (m_parity == PARITY_ODD ? 'O' : 'E'), m_stopbits); // CR5 & CR6 int transmitter_control_bits = (data >> 5) & 3; @@ -192,6 +199,7 @@ void acia6850_device::control_w(uint8_t data) // CR7 m_rx_irq_enable = (data >> 7) & 1; + LOGSETUP(" - RTS:%d BRK:%d TxIE:%d RxIE:%d\n", rts, m_brk, m_tx_irq_enable, m_rx_irq_enable); if (m_divide == 0) { diff --git a/src/devices/machine/mc6844.cpp b/src/devices/machine/mc6844.cpp new file mode 100644 index 00000000000..c5fdb21c870 --- /dev/null +++ b/src/devices/machine/mc6844.cpp @@ -0,0 +1,561 @@ +// license:BSD-3-Clause +// copyright-holders: Joakim Larsson Edström +/********************************************************************** + + Motorola 6844 emulation. This code is not yet ready for general use, see TODO list below + + "MC6844 — Direct Memory Access Controller + + This DMAC works with an M6800 MPU Clock Pulse Generator and an I/O Peripheral Controller, + such as the units described here, to facilitate direct access to the computer memory by + the peripheral, thus by passing MPU interactive time delay. + + General Description + + The MC6844 is operable in three modes: HALT Burst, Cycle Steal and TSC Steal. + In the Burst Mode, the MPU is halted by the first transfer request (TxRQ) input and + is restarted when the Byte Count Register (BCR) is zero. Each data transfer is synchronized + by a pulse input of TxRQ. In the Cycle Steal Mode, the MPU is halted by each TxRQ and + is restarted after each one byte of data transferred. In the TSC Steal Mode, DMAC uses the + three-state control function of the MPU to control the system bus. One byte of data is + transferred during each DMA cycle. + + The DMAC has four channels. A Priority Control Register determines which of the channels + is enabled. While data is being transferred on one channel, the other channels are inhibited. + When one channel completes transferring, the next will become valid for DMA transfer. The PCR + also utilizes a Rotate Control bit. Priority of DMA transfer is normally fixed in sequential + order. The highest priority is in #0 Channel and the lowest is in #3. When this bit is in high + level, channel priority is rotated such that the just-serviced channel has the lowest priority + in the next DMA transfer." + + Source: https://en.wikipedia.org/wiki/File:Motorola_Microcomputer_Components_1978_pg13.jpg + + CREDITS & Prior Work: + The base code was ripped out of swtpc09.cpp and deviceified but similar code is also to be found + in exidy440.cpp so copyrigt is probably shared among the authors there: Robert Justice, 68bit and + Aaron Giles. + + TODO: + - Memory to Device transfers + +**********************************************************************/ + +#include "emu.h" +#include "mc6844.h" + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** +#define LOG_SETUP (1U << 1) +#define LOG_INT (1U << 2) +#define LOG_STATE (1U << 3) +#define LOG_TFR (1U << 4) + +//#define VERBOSE (LOG_GENERAL|LOG_SETUP | LOG_INT | LOG_STATE |LOG_TFR) +//#define LOG_OUTPUT_STREAM std::cout + +#include "logmacro.h" + +#define LOGSETUP(...) LOGMASKED(LOG_SETUP, __VA_ARGS__) +#define LOGINT(...) LOGMASKED(LOG_INT, __VA_ARGS__) +#define LOGSTATE(...) LOGMASKED(LOG_STATE, __VA_ARGS__) +#define LOGTFR(...) LOGMASKED(LOG_TFR, __VA_ARGS__) + +#ifdef _MSC_VER +#define FUNCNAME __func__ +#else +#define FUNCNAME __PRETTY_FUNCTION__ +#endif + +// device type definition +DEFINE_DEVICE_TYPE(MC6844, mc6844_device, "mc6844", "MC6844 DMA") + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// mc6844_device - constructor +//------------------------------------------------- +mc6844_device::mc6844_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, MC6844, tag, owner, clock) + , device_execute_interface(mconfig, *this) + , m_out_int_cb(*this) + , m_out_txak_cb(*this) + , m_out_drq1_cb(*this) + , m_out_drq2_cb(*this) + , m_in_memr_cb(*this) + , m_out_memw_cb(*this) + , m_in_ior_cb{ { *this },{ *this },{ *this },{ *this } } + , m_out_iow_cb{ { *this },{ *this },{ *this },{ *this } } + , m_state(STATE_S0) + , m_icount(0) +{ +} + +//------------------------------------------------- +// device_resolve_objects - device-specific setup +//------------------------------------------------- +void mc6844_device::device_resolve_objects() +{ + m_out_int_cb.resolve_safe(); + m_out_txak_cb.resolve_safe(); + m_out_drq1_cb.resolve_safe(); + m_out_drq2_cb.resolve_safe(); + m_in_memr_cb.resolve_safe(0); + m_out_memw_cb.resolve_safe(); + + for (auto &cb : m_in_ior_cb) + cb.resolve_safe(0); + for (auto &cb : m_out_iow_cb) + cb.resolve_safe(); +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void mc6844_device::device_start() +{ + // set our instruction counter + set_icountptr(m_icount); + + save_item(NAME(m_m6844_priority)); + save_item(NAME(m_m6844_interrupt)); + save_item(NAME(m_m6844_chain)); + save_item(NAME(m_state)); + save_item(NAME(m_icount)); + save_item(NAME(m_current_channel)); + save_item(NAME(m_last_channel)); + save_item(NAME(m_dgrnt)); + save_item(NAME(m_dreq)); + + save_item(STRUCT_MEMBER( m_m6844_channel, active)); + save_item(STRUCT_MEMBER( m_m6844_channel, address)); + save_item(STRUCT_MEMBER( m_m6844_channel, counter)); + save_item(STRUCT_MEMBER( m_m6844_channel, control)); + save_item(STRUCT_MEMBER( m_m6844_channel, start_address)); + save_item(STRUCT_MEMBER( m_m6844_channel, start_counter)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void mc6844_device::device_reset() +{ + // reset the 6844 + for (int i = 0; i < 4; i++) + { + m_m6844_channel[i].active = 0; + m_m6844_channel[i].control = 0x00; + } + m_m6844_priority = 0x00; + m_m6844_interrupt = 0x00; + m_m6844_chain = 0x00; + m_state = STATE_SI; +} + +//------------------------------------------------- +// dma_request - +//------------------------------------------------- + +void mc6844_device::dma_request(int channel, int state) +{ + LOG("MC6844 Channel %u DMA Request: %u\n", channel, state); + + m_dreq[channel & 3] = state; + + LOGSTATE("Trigger(1)\n"); + trigger(1); +} + +//------------------------------------------------- +// execute_run - +//------------------------------------------------- + +void mc6844_device::execute_run() +{ + do + { + switch (m_state) + { + case STATE_SI: // IDLE state, will suspend until a DMA request comes through + { // Hi ------> Lo + int const priorities[][4] = {{ 1, 2, 3, 0 }, + { 2, 3, 0, 1 }, + { 3, 0, 1, 2 }, + { 0, 1, 2, 3 }}; + + LOGSTATE("DMA state SI\n"); + for (int prio = 0; prio < 4; prio++) + { + // Rotating or static channel prioritizations + int current_channel = priorities[((m_m6844_priority & 0x80) ? m_last_channel : 3) & 3][prio]; + + if (m_m6844_channel[current_channel].active == 1 && m_dreq[current_channel] == ASSERT_LINE) + { + m_current_channel = m_last_channel = current_channel; + m_state = STATE_S0; + break; + } + } + } + if(m_state == STATE_SI) + { + LOGSTATE("Suspend in SI\n"); + suspend_until_trigger(1, true); + m_icount = 0; + } + break; + case STATE_S0: // Wait for BCR != 0 and Tx EN == 1 + LOGSTATE("DMA state S0\n"); + if (m_m6844_channel[m_current_channel].active == 1 && + m_m6844_channel[m_current_channel].counter != 0) + { + m_state = STATE_S1; + } + else + { + LOGSTATE("Suspend in S0\n"); + suspend_until_trigger(1, true); + m_icount = 0; + } + break; + case STATE_S1: // Wait for Tx RQ == 1 + LOGSTATE("DMA state S1\n"); + if (m_dreq[m_current_channel] == ASSERT_LINE) + { + m_state = STATE_S2; + switch(m_m6844_channel[m_current_channel].control & 0x06) + { + case 0x00: // Mode 2 - single-byte transfer HALT steal mode + case 0x02: // Mode 3 - block transfer mode + m_out_drq2_cb(ASSERT_LINE); + break; + case 0x04: // Mode 1 - single-byte transfer TSC steal mode + m_out_drq1_cb(ASSERT_LINE); + break; + default: + m_out_drq1_cb(CLEAR_LINE); + m_out_drq2_cb(CLEAR_LINE); + break; + } + } + else + { + LOGSTATE("Suspend in S1\n"); + suspend_until_trigger(1, true); + m_icount = 0; + } + break; + case STATE_S2: // Wait for DGRNT == 1 + LOGSTATE("DMA state S2\n"); + if (m_dgrnt == ASSERT_LINE && m_dreq[m_current_channel] == ASSERT_LINE) + { + m_out_txak_cb(m_current_channel); + + if (m_m6844_channel[m_current_channel].active == 1) //active dma transfer + { + if (!(m_m6844_channel[m_current_channel].control & 0x01)) + { + uint8_t data = m_in_ior_cb[m_current_channel](); + LOGTFR("DMA%d from device to memory location %04x: <- %02x\n", m_current_channel, m_m6844_channel[m_current_channel].address, data ); + m_out_memw_cb(m_m6844_channel[m_current_channel].address, data); + } + else // dma write to device from memory + { + uint8_t data = 0; + //uint8_t data = m_in_memr_cb(m_m6844_channel[m_current_channel].address); + LOGTFR("DMA from memory location to device %04x: -> %02x\n", m_m6844_channel[m_current_channel].address, data ); + //m_out_iow_cb[m_current_channel](data); + } + + if (m_m6844_channel[m_current_channel].control & 0x08) + { + m_m6844_channel[m_current_channel].address--; + } + else + { + m_m6844_channel[m_current_channel].address++; + } + + m_m6844_channel[m_current_channel].counter--; + + if (m_m6844_channel[m_current_channel].counter == 0) + { + m_out_drq1_cb(CLEAR_LINE); + m_out_drq2_cb(CLEAR_LINE); + m_m6844_channel[m_current_channel].control |= 0x80; + m6844_update_interrupt(); + m_state = STATE_SI; + } + else + { + switch(m_m6844_channel[m_current_channel].control & 0x06) + { + case 0x00: + LOGTFR("Mode 2 - single-byte transfer HALT steal mode\n"); + m_state = STATE_S1; + m_out_drq2_cb(CLEAR_LINE); + break; + case 0x02: + LOGTFR("Mode 3 - block transfer mode\n"); + m_state = STATE_S2; // Just for clarity, we are still in STATE_S2 + break; + case 0x04: + LOGTFR("Mode 1 - single-byte transfer TSC steal mode\n"); + m_state = STATE_S1; + m_out_drq1_cb(CLEAR_LINE); + break; + default: // Undefined - needs verification on real hardware + logerror("MC6844: undefined transfer mode, clearing DMA request\n"); + m_state = STATE_SI; + m_out_drq1_cb(CLEAR_LINE); + m_out_drq2_cb(CLEAR_LINE); + break; + } + } + } + } + else + { + LOGSTATE("Suspend in S2\n"); + suspend_until_trigger(1, true); + m_icount = 0; + } + break; + default: + logerror("MC6844: bad state, please report error\n"); + break; + } + m_icount--; + } while (m_icount > 0); +} + +//************************************************************************** +// READ/WRITE HANDLERS +//************************************************************************** + +//------------------------------------------------- +// read handler +//------------------------------------------------- + +uint8_t mc6844_device::read(offs_t offset) +{ + uint8_t result = 0; + + // switch off the offset we were given + switch (offset) + { + // upper byte of address + case 0x00: + case 0x04: + case 0x08: + case 0x0c: + result = m_m6844_channel[offset / 4].address >> 8; + break; + + // lower byte of address + case 0x01: + case 0x05: + case 0x09: + case 0x0d: + result = m_m6844_channel[offset / 4].address & 0xff; + break; + + // upper byte of counter + case 0x02: + case 0x06: + case 0x0a: + case 0x0e: + result = m_m6844_channel[offset / 4].counter >> 8; + break; + + // lower byte of counter + case 0x03: + case 0x07: + case 0x0b: + case 0x0f: + result = m_m6844_channel[offset / 4].counter & 0xff; + break; + + // channel control + case 0x10: + case 0x11: + case 0x12: + case 0x13: + result = m_m6844_channel[offset - 0x10].control; + + // A read here clears the 'DMA end' flag of the + // associated channel. + if (!machine().side_effects_disabled()) + { + m_m6844_channel[offset - 0x10].control &= ~0x80; + if (m_m6844_interrupt & 0x80) + m6844_update_interrupt(); + } + break; + + // priority control + case 0x14: + result = m_m6844_priority; + break; + + // interrupt control + case 0x15: + result = m_m6844_interrupt; + break; + + // chaining control + case 0x16: + result = m_m6844_chain; + break; + + // 0x17-0x1f not used + default: break; + } + + return result & 0xff; +} + +//------------------------------------------------- +// write() handler +//------------------------------------------------- + +void mc6844_device::write(offs_t offset, uint8_t data) +{ + int i; + LOGSETUP("DMA write %02x: %02x\n", offset, data); + // switch off the offset we were given + switch (offset) + { + // upper byte of address + case 0x00: + case 0x04: + case 0x08: + case 0x0c: + LOGSETUP(" - upper address byte ch %d: %02x\n", offset / 4, data); + m_m6844_channel[offset / 4].address = (m_m6844_channel[offset / 4].address & 0xff) | (data << 8); + break; + + // lower byte of address + case 0x01: + case 0x05: + case 0x09: + case 0x0d: + LOGSETUP(" - lower address byte ch %d: %02x\n", offset / 4, data); + m_m6844_channel[offset / 4].address = (m_m6844_channel[offset / 4].address & 0xff00) | (data & 0xff); + break; + + // upper byte of counter + case 0x02: + case 0x06: + case 0x0a: + case 0x0e: + LOGSETUP(" - upper counter byte ch %d: %02x\n", offset / 4, data); + m_m6844_channel[offset / 4].counter = (m_m6844_channel[offset / 4].counter & 0xff) | (data << 8); + break; + + // lower byte of counter + case 0x03: + case 0x07: + case 0x0b: + case 0x0f: + LOGSETUP(" - lower counter byte ch %d: %02x\n", offset / 4, data); + m_m6844_channel[offset / 4].counter = (m_m6844_channel[offset / 4].counter & 0xff00) | (data & 0xff); + break; + + // channel control + case 0x10: + case 0x11: + case 0x12: + case 0x13: + LOGSETUP(" - control byte ch %d: %02x\n", offset / 4, data); + m_m6844_channel[offset - 0x10].control = (m_m6844_channel[offset - 0x10].control & 0xc0) | (data & 0x3f); + break; + + // priority control + case 0x14: + LOGSETUP(" - priority byte: %02x\n", data); + m_m6844_priority = data; + + // update each channel + for (i = 0; i < 4; i++) + { + // if we're going active... + if (!m_m6844_channel[i].active && (data & (1 << i))) + { + // mark us active + m_m6844_channel[i].active = 1; + + // set the DMA busy bit and clear the DMA end bit + m_m6844_channel[i].control |= 0x40; + m_m6844_channel[i].control &= ~0x80; + + // set the starting address, counter, and time + m_m6844_channel[i].start_address = m_m6844_channel[i].address; + m_m6844_channel[i].start_counter = m_m6844_channel[i].counter; + } + + // if we're going inactive... + else if (m_m6844_channel[i].active && !(data & (1 << i))) + { + //mark us inactive + m_m6844_channel[i].active = 0; + } + } + break; + + // interrupt control + case 0x15: + LOGSETUP(" - interrupt control: %02x\n", data); + m_m6844_interrupt = (m_m6844_interrupt & 0x80) | (data & 0x7f); + m6844_update_interrupt(); + break; + + // chaining control + case 0x16: + LOGSETUP(" - chaining control: %02x\n", data); + m_m6844_chain = data; + break; + + // 0x17-0x1f not used + default: break; + } + LOGSTATE("Trigger(1)\n"); + trigger(1); +} + +//------------------------------------------------- +// m6844_update_interrupt() +//------------------------------------------------- + +void mc6844_device::m6844_update_interrupt() +{ + uint8_t interrupt = 0; + + interrupt |= BIT(m_m6844_channel[0].control, 7) & BIT(m_m6844_interrupt, 0); + interrupt |= BIT(m_m6844_channel[1].control, 7) & BIT(m_m6844_interrupt, 1); + interrupt |= BIT(m_m6844_channel[2].control, 7) & BIT(m_m6844_interrupt, 2); + interrupt |= BIT(m_m6844_channel[3].control, 7) & BIT(m_m6844_interrupt, 3); + + if (interrupt) + { + if (!(m_m6844_interrupt & 0x80)) + { + // Set interrupt indication bit 7. + m_m6844_interrupt |= 0x80; + m_out_int_cb(ASSERT_LINE); + } + } + else + { + if (m_m6844_interrupt & 0x80) + { + // Clear interrupt indication bit 7. + m_m6844_interrupt &= 0x7f; + m_out_int_cb(CLEAR_LINE); + } + } +} diff --git a/src/devices/machine/mc6844.h b/src/devices/machine/mc6844.h new file mode 100644 index 00000000000..e2db601e8e7 --- /dev/null +++ b/src/devices/machine/mc6844.h @@ -0,0 +1,148 @@ +// license:BSD-3-Clause +// copyright-holders: Joakim Larsson Edström +/*************************************************************************** + + Motorola 6844 emulation + +**************************************************************************** + _____ _____ + VSS 1 |* \_/ | 40 E + *CS / Tx AKBW 2 | | 39 *RESET + R / *W 3 | | 38 DGRNT + A0 4 | | 37 *DRQ1 + A1 5 | | 36 *DRQ2 + A2 6 | | 35 Tx AKA + A3 7 | | 34 *TX STB + A4 8 | | 33 *IRQ / *DEND + A5 9 | | 32 Tx RQ0 + A6 10 | MC6844 | 31 Tx RQ1 + A7 11 | | 30 Tx RQ2 + A8 12 | | 29 Tx RQ3 + A9 13 | | 28 D0 + A10 14 | | 27 D1 + A11 15 | | 26 D2 + A12 16 | | 25 D3 + A13 17 | | 24 D4 + A14 18 | | 23 D5 + A15 19 | | 22 D6 + VCC 20 |_____________| 21 D7 + +***************************************************************************/ + +#ifndef MAME_MACHINE_MC6844_H +#define MAME_MACHINE_MC6844_H + +#pragma once + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> mc6844_device + +class mc6844_device : public device_t, public device_execute_interface +{ +public: + // construction/destruction + mc6844_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + auto out_int_callback() { return m_out_int_cb.bind(); } + auto out_txak_callback() { return m_out_txak_cb.bind(); } + auto out_drq1_callback() { return m_out_drq1_cb.bind(); } + auto out_drq2_callback() { return m_out_drq2_cb.bind(); } + auto in_memr_callback() { return m_in_memr_cb.bind(); } + auto out_memw_callback() { return m_out_memw_cb.bind(); } + + // I/O operations + void write(offs_t offset, uint8_t data); + uint8_t read(offs_t offset); + template auto in_ior_callback() { return m_in_ior_cb[CH].bind(); } + template auto out_iow_callback() { return m_out_iow_cb[CH].bind(); } + + template DECLARE_WRITE_LINE_MEMBER( dreq_w ) { dma_request(CH, state); } + + DECLARE_WRITE_LINE_MEMBER( dgrnt_w ){ m_dgrnt = state; trigger(1); } + +protected: + // device-level overrides + //virtual void device_validity_check(validity_checker &valid) const override; + virtual void device_resolve_objects() override; + virtual void device_start() override; + virtual void device_reset() override; + virtual void execute_run() override; + + devcb_write_line m_out_int_cb; + devcb_write8 m_out_txak_cb; + devcb_write_line m_out_drq1_cb; + devcb_write_line m_out_drq2_cb; + devcb_read8 m_in_memr_cb; + devcb_write8 m_out_memw_cb; + devcb_read8 m_in_ior_cb[4]; + devcb_write8 m_out_iow_cb[4]; + + /* channel_data structure holds info about each 6844 DMA channel */ + struct m6844_channel_data + { + int active; + int address; + int counter; + // Channel control register. + // bit 0: Read / Write mode + // bit 1: Mode control B + // bit 2: Mode control A + // bit 3: Address up (0) / down (1). + // bit 4: Not used + // bit 5: Not used + // bit 6: Busy / Ready. Read only. Set when request + // made. Cleared when transfer completed. + // bit 7: DMA end flag. Read only? Set when transfer + // completed. Cleared when control register + // read. Sets IRQ. + // Mode control A,B: 0,0 Mode2; 0,1 Mode 3; 1,0 Mode 0; + // 1,1 Undefined. + uint8_t control; + int start_address; + int start_counter; + }; + + /* 6844 description */ + m6844_channel_data m_m6844_channel[4]; + uint8_t m_m6844_priority; + // Interrupt control register. + // Bit 0-3: channel interrupt enable, 1 enabled, 0 masked. + // Bit 4-6: unused + // Bit 7: Read only. Set to 1 when IRQ asserted. Clear when the + // control register associated with the channel that caused the + // interrut is read. + uint8_t m_m6844_interrupt; + uint8_t m_m6844_chain; + void m6844_update_interrupt(); + + // State machine + enum { + STATE_SI, + STATE_S0, + STATE_S1, + STATE_S2 + }; + + int m_state; + int m_icount; + int m_current_channel; + int m_last_channel; + + // input states + bool m_dgrnt; + bool m_dreq[4]; +private: + void dma_request(int channel, int state); +}; + +// device type definition +DECLARE_DEVICE_TYPE(MC6844, mc6844_device) + +#endif // MAME_MACHINE_MC6844_H diff --git a/src/devices/machine/mc6846.cpp b/src/devices/machine/mc6846.cpp index 31e562fd849..ecae29b48c3 100644 --- a/src/devices/machine/mc6846.cpp +++ b/src/devices/machine/mc6846.cpp @@ -24,6 +24,8 @@ #include "mc6846.h" //#define VERBOSE 1 +//#define LOG_OUTPUT_STREAM std::cout + #include "logmacro.h" @@ -47,7 +49,6 @@ DEFINE_DEVICE_TYPE(MC6846, mc6846_device, "mc6846", "MC6846 Programmable Timer") mc6846_device::mc6846_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : device_t(mconfig, MC6846, tag, owner, clock), m_out_port_cb(*this), - m_out_cp1_cb(*this), m_out_cp2_cb(*this), m_in_port_cb(*this), m_out_cto_cb(*this), @@ -65,7 +66,6 @@ void mc6846_device::device_start() m_one_shot = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(mc6846_device::timer_one_shot), this)); m_out_port_cb.resolve(); /* 8-bit output */ - m_out_cp1_cb.resolve_safe(); /* 1-bit output */ m_out_cp2_cb.resolve(); /* 1-bit output */ /* CPU read from the outside through chip */ @@ -354,6 +354,7 @@ READ8_MEMBER(mc6846_device::read) WRITE8_MEMBER(mc6846_device::write) { + switch ( offset ) { case 0: diff --git a/src/devices/machine/mc6846.h b/src/devices/machine/mc6846.h index 1b960ae1ef3..81633923adc 100644 --- a/src/devices/machine/mc6846.h +++ b/src/devices/machine/mc6846.h @@ -21,7 +21,6 @@ public: auto out_port() { return m_out_port_cb.bind(); } auto in_port() { return m_in_port_cb.bind(); } - auto cp1() { return m_out_cp1_cb.bind(); } auto cp2() { return m_out_cp2_cb.bind(); } auto cto() { return m_out_cto_cb.bind(); } auto irq() { return m_irq_cb.bind(); } @@ -78,7 +77,6 @@ private: /* CPU write to the outside through chip */ devcb_write8 m_out_port_cb; /* 8-bit output */ - devcb_write_line m_out_cp1_cb; /* 1-bit output */ devcb_write_line m_out_cp2_cb; /* 1-bit output */ /* CPU read from the outside through chip */ diff --git a/src/devices/machine/mc6854.cpp b/src/devices/machine/mc6854.cpp index 488d3872745..ed5eb02b8b5 100644 --- a/src/devices/machine/mc6854.cpp +++ b/src/devices/machine/mc6854.cpp @@ -22,7 +22,6 @@ TODO: - CRC - - DMA mode - loop mode - status prioritization - NRZI vs. NRZ coding @@ -34,9 +33,18 @@ #include "emu.h" #include "mc6854.h" -//#define VERBOSE 1 +#define LOG_SETUP ( 1U << 1 ) +#define LOG_BITS ( 1U << 2 ) +#define LOG_IRQ ( 1U << 3 ) + +//#define VERBOSE (LOG_IRQ | LOG_BITS | LOG_GENERAL | LOG_SETUP) +//#define LOG_OUTPUT_STREAM std::cout + #include "logmacro.h" +#define LOGSETUP(...) LOGMASKED(LOG_SETUP, __VA_ARGS__) +#define LOGBITS(...) LOGMASKED(LOG_BITS, __VA_ARGS__) +#define LOGIRQ(...) LOGMASKED(LOG_IRQ, __VA_ARGS__) /******************* parameters ******************/ @@ -66,6 +74,9 @@ constexpr unsigned mc6854_device::MAX_FRAME_LENGTH; #define RIE ( m_cr1 & 2 ) /* interrupt enable */ #define TIE ( m_cr1 & 4 ) +#define RDSR ( m_cr1 & 8 ) /* DMA mode */ +#define TDSR ( m_cr1 & 0x10 ) + #define DISCONTINUE ( m_cr1 & 0x20 ) /* discontinue received frame */ @@ -131,6 +142,8 @@ DEFINE_DEVICE_TYPE(MC6854, mc6854_device, "mc6854", "Motorola MC6854 ADLC") mc6854_device::mc6854_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : device_t(mconfig, MC6854, tag, owner, clock), m_out_irq_cb(*this), + m_out_rdsr_cb(*this), + m_out_tdsr_cb(*this), m_out_txd_cb(*this), m_out_frame_cb(*this), m_out_rts_cb(*this), @@ -150,6 +163,8 @@ mc6854_device::mc6854_device(const machine_config &mconfig, const char *tag, dev m_rreg(0), m_rones(0), m_rsize(0), + m_rxd(0), + m_rxc(0), m_flen(0), m_fpos(0) { @@ -172,6 +187,8 @@ mc6854_device::mc6854_device(const machine_config &mconfig, const char *tag, dev void mc6854_device::device_start() { m_out_irq_cb.resolve_safe(); + m_out_rdsr_cb.resolve_safe(); + m_out_tdsr_cb.resolve_safe(); m_out_txd_cb.resolve(); m_out_frame_cb.resolve(); m_out_rts_cb.resolve_safe(); @@ -391,6 +408,7 @@ TIMER_CALLBACK_MEMBER(mc6854_device::tfifo_cb) /* data underrun => abort */ logerror( "%f mc6854_tfifo_cb: FIFO underrun\n", machine().time().as_double() ); m_sr1 |= TU; + update_sr1(); m_tstate = 0; send_bits( 0xffff, ABTEX ? 16 : 8, 0 ); m_flen = 0; @@ -514,10 +532,10 @@ void mc6854_device::rfifo_push( uint8_t d ) } m_rsize -= blen; + update_sr1( ); } - void mc6854_device::rfifo_terminate( ) { /* mark most recently pushed byte as the last one of the frame */ @@ -526,7 +544,7 @@ void mc6854_device::rfifo_terminate( ) { if ( m_rfifo[ i ] & 0x100 ) { - m_tfifo[ i ] |= 0x200; + m_rfifo[ i ] |= 0x200; break; } @@ -537,7 +555,6 @@ void mc6854_device::rfifo_terminate( ) } - /* CPU pops the FIFO */ uint8_t mc6854_device::rfifo_pop( ) { @@ -566,70 +583,9 @@ uint8_t mc6854_device::rfifo_pop( ) } -/* MC6854 makes fields from bits */ WRITE_LINE_MEMBER( mc6854_device::set_rx ) { - int fieldlen = ( m_rstate < 6 ) ? 8 : RWL; - - if ( RRESET || (m_sr2 & DCD) ) - return; - - if ( state ) - { - m_rones++; - m_rreg = (m_rreg >> 1) | 0x80000000; - if ( m_rones >= 8 ) - { - /* abort */ - m_rstate = 0; - m_rsize = 0; - if ( m_rstate > 1 ) - { - /* only in-frame abort */ - m_sr2 |= RABT; - LOG( "%f mc6854_receive_bit: abort\n", machine().time().as_double() ); - } - } - else - { - m_rsize++; - if ( m_rstate && m_rsize >= fieldlen + 24 ) - rfifo_push( m_rreg ); - } - } - else if ( m_rones == 5 ) - { - /* discards '0' inserted after 5 '1' */ - m_rones = 0; - return; - } - else if ( m_rones == 6 ) - { - /* flag */ - if ( FDSE ) - m_sr1 |= FD; - - if ( m_rstate > 1 ) - { - /* end of frame */ - m_rreg >>= 1; - m_rsize++; - if ( m_rsize >= fieldlen + 24 ) /* last field */ - rfifo_push( m_rreg ); - rfifo_terminate( ); - LOG( "%f mc6854_receive_bit: end of frame\n", machine().time().as_double() ); - } - m_rones = 0; - m_rstate = 1; - m_rsize = 0; - } else - { - m_rones = 0; - m_rreg >>= 1; - m_rsize++; - if ( m_rstate && m_rsize >= fieldlen + 24 ) - rfifo_push( m_rreg ); - } + m_rxd = state; } @@ -663,7 +619,10 @@ int mc6854_device::send_frame( uint8_t* data, int len ) } memcpy( m_frame, data, len ); if ( FDSE ) + { m_sr1 |= FD; + update_sr1(); + } m_flen = len; m_fpos = 0; rfifo_push( m_frame[ m_fpos++ ] ); @@ -689,6 +648,7 @@ WRITE_LINE_MEMBER( mc6854_device::set_cts ) m_sr1 |= CTS; else m_sr1 &= ~CTS; + update_sr1(); } @@ -715,7 +675,7 @@ void mc6854_device::update_sr2( ) m_sr2 |= RDA2; if ( ! (m_rfifo[ FIFO_SIZE - 1 ] & 0x100) ) m_sr2 &= ~RDA2; - else if ( TWOBYTES && ! (m_tfifo[ FIFO_SIZE - 2 ] & 0x100) ) + else if ( TWOBYTES && ! (m_rfifo[ FIFO_SIZE - 2 ] & 0x100) ) m_sr2 &= ~RDA2; /* update AP */ @@ -737,7 +697,7 @@ void mc6854_device::update_sr1( ) else m_sr1 &= ~S2RQ; - /* update TRDA (always prioritized by CTS) */ + /* update TDRA (always prioritized by CTS) */ if ( TRESET || ( m_sr1 & CTS ) ) m_sr1 &= ~TDRA; else @@ -756,18 +716,28 @@ void mc6854_device::update_sr1( ) m_sr1 &= ~RDA; /* update IRQ */ + LOGIRQ("\nUpdate IRQ in: %d\n", (m_sr1 & IRQ) ? 1 : 0); m_sr1 &= ~IRQ; - if ( RIE && (m_sr1 & (TU | TDRA) ) ) - m_sr1 |= IRQ; if ( TIE ) { - if ( m_sr1 & (S2RQ | RDA | CTS) ) - m_sr1 |= IRQ; - if ( m_sr2 & (ERR | FV | DCD | OVRN | RABT | RIDLE | AP) ) - m_sr1 |= IRQ; + if ( m_sr1 & TU ) m_sr1 |= IRQ; + LOGIRQ(" - Update IRQ TU: %d\n", (m_sr1 & IRQ) ? 1 : 0); + if ( ( m_sr1 & TDRA ) && !TDSR ) m_sr1 |= IRQ; // TDRA will not cause interrupt if in DMA mode + LOGIRQ(" - Update IRQ TDRA: %d\n", (m_sr1 & IRQ) ? 1 : 0); + } + if ( RIE ) + { + if ( m_sr1 & (S2RQ | CTS) ) m_sr1 |= IRQ; + LOGIRQ(" - Update IRQ S2RQ(%02x)|CTS(%d): %d\n", (m_sr2 & 0x7f), (m_sr1 & CTS) ? 1 : 0, (m_sr1 & IRQ) ? 1 : 0); + if ( ( m_sr1 & RDA ) && !RDSR ) m_sr1 |= IRQ; // RDA will not cause interrupt if in DMA mode + LOGIRQ(" - Update IRQ RDA(%d) && !RDSR(%d): %d\n", (m_sr1 & RDA) ? 1 : 0, RDSR ? 1 : 0, (m_sr1 & IRQ) ? 1 : 0); + if ( m_sr2 & (ERR | FV | DCD | OVRN | RABT | RIDLE | AP) ) m_sr1 |= IRQ; + LOGIRQ(" - Update IRQ ERR: %d\n", (m_sr1 & IRQ) ? 1 : 0); } m_out_irq_cb((m_sr1 & IRQ) ? ASSERT_LINE : CLEAR_LINE); + m_out_rdsr_cb((m_sr1 & RDA) ? ASSERT_LINE : CLEAR_LINE); + m_out_tdsr_cb((m_sr1 & TDRA) ? ASSERT_LINE : CLEAR_LINE); } @@ -777,7 +747,7 @@ uint8_t mc6854_device::read(offs_t offset) switch ( offset ) { case 0: /* status register 1 */ - update_sr1( ); + //update_sr1( ); LOG( "%f %s mc6854_r: get SR1=$%02X (rda=%i,s2rq=%i,fd=%i,cts=%i,tu=%i,tdra=%i,irq=%i)\n", machine().time().as_double(), machine().describe_context(), m_sr1, ( m_sr1 & RDA) ? 1 : 0, ( m_sr1 & S2RQ) ? 1 : 0, @@ -787,7 +757,7 @@ uint8_t mc6854_device::read(offs_t offset) return m_sr1; case 1: /* status register 2 */ - update_sr2( ); + //update_sr2( ); LOG( "%f %s mc6854_r: get SR2=$%02X (ap=%i,fv=%i,ridle=%i,rabt=%i,err=%i,dcd=%i,ovrn=%i,rda2=%i)\n", machine().time().as_double(), machine().describe_context(), m_sr2, ( m_sr2 & AP ) ? 1 : 0, ( m_sr2 & FV ) ? 1 : 0, @@ -802,6 +772,7 @@ uint8_t mc6854_device::read(offs_t offset) uint8_t data = rfifo_pop( ); LOG( "%f %s mc6854_r: get data $%02X\n", machine().time().as_double(), machine().describe_context(), data ); + m_out_rdsr_cb(CLEAR_LINE); // Deactive DMA request line regardless of mode return data; } @@ -819,15 +790,13 @@ void mc6854_device::write(offs_t offset, uint8_t data) { case 0: /* control register 1 */ m_cr1 = data; - LOG( "%f %s mc6854_w: set CR1=$%02X (ac=%i,irq=%c%c,%sreset=%c%c)\n", + LOGSETUP( "%f %s mc6854_w: set CR1=$%02X (ac=%i,irq=%c%c,%sreset=%c%c)\n", machine().time().as_double(), machine().describe_context(), m_cr1, AC ? 1 : 0, RIE ? 'r' : '-', TIE ? 't' : '-', DISCONTINUE ? "discontinue," : "", RRESET ? 'r' : '-', TRESET ? 't' : '-' ); - if ( m_cr1 & 0xc ) - logerror( "%s mc6854 DMA not handled (CR1=$%02X)\n", - machine().describe_context(), m_cr1 ); + if ( DISCONTINUE ) { /* abort receive FIFO but keeps shift register & synchro */ @@ -841,12 +810,14 @@ void mc6854_device::write(offs_t offset, uint8_t data) m_sr1 &= ~FD; m_sr2 &= ~(AP | FV | RIDLE | RABT | ERR | OVRN | DCD); if ( m_dcd ) m_sr2 |= DCD; + update_sr1( ); } if ( TRESET ) { tfifo_clear( ); m_sr1 &= ~(TU | TDRA | CTS); if ( m_cts ) m_sr1 |= CTS; + update_sr1( ); } break; @@ -855,7 +826,7 @@ void mc6854_device::write(offs_t offset, uint8_t data) { /* control register 3 */ m_cr3 = data; - LOG( "%f %s mc6854_w: set CR3=$%02X (lcf=%i,aex=%i,idl=%i,fdse=%i,loop=%i,tst=%i,dtr=%i)\n", + LOGSETUP( "%f %s mc6854_w: set CR3=$%02X (lcf=%i,aex=%i,idl=%i,fdse=%i,loop=%i,tst=%i,dtr=%i)\n", machine().time().as_double(), machine().describe_context(), m_cr3, LCF ? (CEX ? 16 : 8) : 0, AEX ? 1 : 0, IDL0 ? 0 : 1, FDSE ? 1 : 0, LOOP ? 1 : 0, @@ -872,7 +843,7 @@ void mc6854_device::write(offs_t offset, uint8_t data) { /* control register 2 */ m_cr2 = data; - LOG( "%f %s mc6854_w: set CR2=$%02X (pse=%i,bytes=%i,fmidle=%i,%s,tlast=%i,clr=%c%c,rts=%i)\n", + LOGSETUP( "%f %s mc6854_w: set CR2=$%02X (pse=%i,bytes=%i,fmidle=%i,%s,tlast=%i,clr=%c%c,rts=%i)\n", machine().time().as_double(), machine().describe_context(), m_cr2, PSE ? 1 : 0, TWOBYTES ? 2 : 1, FMIDLE ? 1 : 0, FCTDRA ? "fc" : "tdra", TLAST ? 1 : 0, @@ -889,6 +860,7 @@ void mc6854_device::write(offs_t offset, uint8_t data) m_sr2 &= ~(AP | FV | RIDLE | RABT | ERR | OVRN | DCD); if ( m_dcd ) m_sr2 |= DCD; + update_sr1( ); } if ( data & 0x40 ) { @@ -896,6 +868,7 @@ void mc6854_device::write(offs_t offset, uint8_t data) m_sr1 &= ~(TU | TDRA | CTS); if ( m_cts ) m_sr1 |= CTS; + update_sr1( ); } m_out_rts_cb( RTS ? 1 : 0 ); @@ -903,7 +876,7 @@ void mc6854_device::write(offs_t offset, uint8_t data) break; case 2: /* transmitter data: continue data */ - LOG( "%f %smc6854_w: push data=$%02X\n", machine().time().as_double(), machine().describe_context(), data ); + LOGSETUP( "%f %smc6854_w: push data=$%02X\n", machine().time().as_double(), machine().describe_context(), data ); tfifo_push( data ); break; @@ -912,7 +885,7 @@ void mc6854_device::write(offs_t offset, uint8_t data) { /* control register 4 */ m_cr4 = data; - LOG( "%f %s mc6854_w: set CR4=$%02X (interframe=%i,tlen=%i,rlen=%i,%s%s)\n", machine().time().as_double(), machine().describe_context(), m_cr4, + LOGSETUP( "%f %s mc6854_w: set CR4=$%02X (interframe=%i,tlen=%i,rlen=%i,%s%s)\n", machine().time().as_double(), machine().describe_context(), m_cr4, TWOINTER ? 2 : 1, TWL, RWL, ABT ? ( ABTEX ? "abort-ext," : "abort,") : "", @@ -927,7 +900,7 @@ void mc6854_device::write(offs_t offset, uint8_t data) else { /* transmitter data: last data */ - LOG( "%f %s mc6854_w: push last-data=$%02X\n", machine().time().as_double(), machine().describe_context(), data ); + LOGSETUP( "%f %s mc6854_w: push last-data=$%02X\n", machine().time().as_double(), machine().describe_context(), data ); tfifo_push( data ); tfifo_terminate( ); } @@ -938,9 +911,82 @@ void mc6854_device::write(offs_t offset, uint8_t data) } } +inline bool mc6854_device::receive_allowed() const +{ + return (!RRESET && !(m_sr2 & DCD)); +} + +/* MC6854 makes fields from bits */ WRITE_LINE_MEMBER( mc6854_device::rxc_w ) { - // TODO + if (receive_allowed() && state && !m_rxc) + { + int fieldlen = ( m_rstate < 6 ) ? 8 : RWL; + + if ( m_rxd ) + { + LOGBITS("I "); + m_rones++; + m_rreg = (m_rreg >> 1) | 0x80000000; + if ( m_rones >= 8 ) + { + /* abort */ + m_rstate = 0; + m_rsize = 0; + if ( m_rstate > 1 ) + { + /* only in-frame abort */ + m_sr2 |= RABT; + LOG( "%f mc6854_receive_bit: abort\n", machine().time().as_double() ); + } + } + else + { + m_rsize++; + if ( m_rstate && m_rsize >= fieldlen + 24 ) + rfifo_push( m_rreg ); + } + } + else if ( m_rones == 5 ) + { + /* discards '0' inserted after 5 '1' */ + LOGBITS("A zero is discarded\n"); + m_rones = 0; + return; + } + else if ( m_rones == 6 ) + { + /* flag */ + if ( FDSE ) + { + m_sr1 |= FD; + update_sr1( ); + } + + if ( m_rstate > 1 ) + { + /* end of frame */ + m_rreg >>= 1; + m_rsize++; + if ( m_rsize >= fieldlen + 24 ) /* last field */ + rfifo_push( m_rreg ); + rfifo_terminate( ); + LOG( "%f mc6854_receive_bit: end of frame\n", machine().time().as_double() ); + } + m_rones = 0; + m_rstate = 1; + m_rsize = 0; + } else + { + LOGBITS("O "); + m_rones = 0; + m_rreg >>= 1; + m_rsize++; + if ( m_rstate && m_rsize >= fieldlen + 24 ) + rfifo_push( m_rreg ); + } + } + m_rxc = state; } WRITE_LINE_MEMBER( mc6854_device::txc_w ) diff --git a/src/devices/machine/mc6854.h b/src/devices/machine/mc6854.h index defd3aa76c1..2e2fe6fa663 100644 --- a/src/devices/machine/mc6854.h +++ b/src/devices/machine/mc6854.h @@ -23,16 +23,19 @@ public: mc6854_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0); - auto out_irq_cb() { return m_out_irq_cb.bind(); } - auto out_txd_cb() { return m_out_txd_cb.bind(); } - auto out_rts_cb() { return m_out_rts_cb.bind(); } - auto out_dtr_cb() { return m_out_dtr_cb.bind(); } + auto out_irq_cb() { return m_out_irq_cb.bind(); } + auto out_rdsr_cb() { return m_out_rdsr_cb.bind(); } + auto out_tdsr_cb() { return m_out_tdsr_cb.bind(); } + auto out_txd_cb() { return m_out_txd_cb.bind(); } + auto out_rts_cb() { return m_out_rts_cb.bind(); } + auto out_dtr_cb() { return m_out_dtr_cb.bind(); } template void set_out_frame_callback(T &&... args) { m_out_frame_cb.set(std::forward(args)...); } /* interface to CPU via address/data bus*/ uint8_t read(offs_t offset); void write(offs_t offset, uint8_t data); + uint8_t dma_r(){ return read(2); } /* low-level, bit-based interface */ DECLARE_WRITE_LINE_MEMBER( set_rx ); @@ -52,12 +55,15 @@ protected: // device-level overrides virtual void device_start() override; virtual void device_reset() override; + bool receive_allowed() const; private: static constexpr unsigned FIFO_SIZE = 3; // hardcoded size of the 6854 FIFO (this is a hardware limit) // internal state devcb_write_line m_out_irq_cb; /* interrupt request */ + devcb_write_line m_out_rdsr_cb; /* Rx fifo DMA request */ + devcb_write_line m_out_tdsr_cb; /* Tx fifo DMA request */ /* low-level, bit-based interface */ devcb_write_line m_out_txd_cb; /* transmit bit */ @@ -87,6 +93,8 @@ private: uint8_t m_rones; /* count '1 bits */ uint8_t m_rsize; /* bits in the shift register */ uint16_t m_rfifo[FIFO_SIZE]; /* X x 8-bit FIFO + full & addr marker bits */ + bool m_rxd; + bool m_rxc; /* frame-based interface*/ uint8_t m_frame[MAX_FRAME_LENGTH]; @@ -132,6 +140,7 @@ DECLARE_DEVICE_TYPE(MC6854, mc6854_device) The frame-based interface is higher-level and faster. It passes bytes directly from one end to the other without bothering with the actual bit-encoding, synchronization, and CRC. + Once completed, a frame is sent through out_frame. Aborted frames are not transmitted at all. No start flag, stop flag, or crc bits are transmitted. send_frame makes a frame available to the CPU through the 6854 (it may diff --git a/src/devices/machine/pla.cpp b/src/devices/machine/pla.cpp index 44db6a4ed10..463ccc334cc 100644 --- a/src/devices/machine/pla.cpp +++ b/src/devices/machine/pla.cpp @@ -12,9 +12,11 @@ #include "plaparse.h" #define LOG_TERMS (1 << 0U) -//#define VERBOSE (LOG_TERMS) -#include "logmacro.h" +//#define VERBOSE (LOG_TERMS) +//#define LOG_OUTPUT_STREAM std::cout + +#include "logmacro.h" DEFINE_DEVICE_TYPE(PLA, pla_device, "pla", "PLA") DEFINE_DEVICE_TYPE(PLS100, pls100_device, "pls100", "82S100-series PLA") @@ -123,6 +125,8 @@ void pla_device::parse_fusemap() return; } + LOGMASKED(LOG_TERMS, "PLA read and parsed, %d fuses in %s format\n", jed.numfuses, jed.binfmt == MAXLOADER ? "Maxloader" : "DataIO" ); + // parse it uint32_t fusenum = 0; @@ -135,11 +139,21 @@ void pla_device::parse_fusemap() for (int i = 0; i < m_inputs; i++) { - // complement - term->and_mask |= (uint64_t)jed_get_fuse(&jed, fusenum++) << (i + 32); - - // true - term->and_mask |= (uint64_t)jed_get_fuse(&jed, fusenum++) << i; + if (jed.binfmt == MAXLOADER) + { + term->and_mask |= (uint64_t)jed_get_fuse(&jed, fusenum++) << (i + 32); // complement + term->and_mask |= (uint64_t)jed_get_fuse(&jed, fusenum++) << i; // true + } + else if (jed.binfmt == DATAIO) + { + term->and_mask |= (uint64_t)jed_get_fuse(&jed, fusenum++) << i; // true + term->and_mask |= (uint64_t)jed_get_fuse(&jed, fusenum++) << (i + 32); // complement + } + else + { + logerror("PLA parser: Unknown JED format\n"); + break; + } } // OR mask diff --git a/src/lib/util/jedparse.cpp b/src/lib/util/jedparse.cpp index d25b35c3328..14cc503f18f 100644 --- a/src/lib/util/jedparse.cpp +++ b/src/lib/util/jedparse.cpp @@ -391,9 +391,24 @@ int jedbin_parse(const void *data, size_t length, jed_data *result) /* first unpack the number of fuses */ result->numfuses = (cursrc[0] << 24) | (cursrc[1] << 16) | (cursrc[2] << 8) | cursrc[3]; cursrc += 4; + if (result->numfuses == 0 || result->numfuses > JED_MAX_FUSES) return JEDERR_INVALID_DATA; + /* Detect DataIO binary format and prepare for conversion. This transformation is based on observation of an 82S100 dump */ + if (result->numfuses == ((cursrc[0] << 24) | (cursrc[1] << 16) | (cursrc[2] << 8) | cursrc[3])) + { + result->numfuses = (result->numfuses - 9) * 8; // Double 32 bit byte file size header + trailing byte to Single 32 byte fuse count + cursrc = cursrc + 4; // Adjust start of buffer, trailing byte will not be copied below + result->binfmt = DATAIO; // DataIO also has swapped inverted/non-inverted line fuses so remember origin + if (LOG_PARSE) printf("DATAIO format detected\n"); + } + else + { + result->binfmt = MAXLOADER; // This is the old format just set for completeness. + if (LOG_PARSE) printf("MAXLOADER format detected\n"); + } + /* now make sure we have enough data in the source */ if (length < 4 + (result->numfuses + 7) / 8) return JEDERR_INVALID_DATA; diff --git a/src/lib/util/jedparse.h b/src/lib/util/jedparse.h index f12101ca154..adb9010de1c 100644 --- a/src/lib/util/jedparse.h +++ b/src/lib/util/jedparse.h @@ -29,7 +29,9 @@ #define JEDERR_BAD_XMIT_SUM 2 #define JEDERR_BAD_FUSE_SUM 3 - +/* binary file formats */ +#define MAXLOADER 0 +#define DATAIO 1 /*************************************************************************** TYPE DEFINITIONS @@ -37,8 +39,9 @@ struct jed_data { - uint32_t numfuses; /* number of defined fuses */ - uint8_t fusemap[JED_MAX_FUSES / 8];/* array of bit-packed data */ + uint32_t numfuses; /* number of defined fuses */ + uint8_t fusemap[JED_MAX_FUSES / 8]; /* array of bit-packed data */ + uint8_t binfmt; /* file format MAXLOADER or DATAIO */ }; diff --git a/src/mame/drivers/alfaskop41xx.cpp b/src/mame/drivers/alfaskop41xx.cpp index 9c41981c322..63d461631f8 100644 --- a/src/mame/drivers/alfaskop41xx.cpp +++ b/src/mame/drivers/alfaskop41xx.cpp @@ -5,7 +5,7 @@ Alfaskop 41 series This driver is a part of a revivel project for Alfaskop 41 series where -no known working system exists today because of the distributed nature. +no known working system exists today because of its distributed nature. All parts network boots over SS3 (SDLC) from a Floppy Disk unit and nothing works unless there is a floppy in that unit. These floppies are rare and many parts have been discarded because they are useless stand alone. @@ -25,18 +25,31 @@ Dansk Datahistorisk Forening - http://datamuseum.dk/ #include "cpu/m6800/m6800.h" #include "machine/6850acia.h" #include "machine/6821pia.h" +#include "machine/mc6854.h" +#include "machine/mc6844.h" +#include "machine/pla.h" #include "video/mc6845.h" #include "screen.h" +#include "machine/input_merger.h" +#include "machine/output_latch.h" +#include "machine/alfaskop_s41_kb.h" //#include "bus/rs232/rs232.h" -//#include "machine/clock.h" +#include "machine/clock.h" #define LOG_IO (1U << 1) #define LOG_NVRAM (1U << 2) #define LOG_MIC (1U << 3) #define LOG_DIA (1U << 4) +#define LOG_DMA (1U << 5) +#define LOG_IRQ (1U << 6) +#define LOG_ADLC (1U << 7) +#define LOG_KBD (1U << 8) +#define LOG_AM (1U << 9) +#define LOG_LEDS (1U << 10) +#define LOG_BITS (1U << 11) -//#define VERBOSE (LOG_IO|LOG_NVRAM|LOG_MIC|LOG_DIA) +//#define VERBOSE (LOG_MIC) //#define LOG_OUTPUT_STREAM std::cout #include "logmacro.h" @@ -45,6 +58,15 @@ Dansk Datahistorisk Forening - http://datamuseum.dk/ #define LOGNVRAM(...) LOGMASKED(LOG_NVRAM, __VA_ARGS__) #define LOGMIC(...) LOGMASKED(LOG_MIC, __VA_ARGS__) #define LOGDIA(...) LOGMASKED(LOG_DIA, __VA_ARGS__) +#define LOGDMA(...) LOGMASKED(LOG_DMA, __VA_ARGS__) +#define LOGIRQ(...) LOGMASKED(LOG_IRQ, __VA_ARGS__) +#define LOGADLC(...) LOGMASKED(LOG_ADLC, __VA_ARGS__) +#define LOGKBD(...) LOGMASKED(LOG_KBD, __VA_ARGS__) +#define LOGAM(...) LOGMASKED(LOG_AM, __VA_ARGS__) +#define LOGLEDS(...) LOGMASKED(LOG_LEDS, __VA_ARGS__) +#define LOGBITS(...) LOGMASKED(LOG_BITS, __VA_ARGS__) + +#define PLA1_TAG "ic50" class alfaskop4110_state : public driver_device { @@ -52,30 +74,96 @@ public: alfaskop4110_state(const machine_config &mconfig, device_type type, const char *tag) : driver_device(mconfig, type, tag) , m_maincpu(*this, "maincpu") - , m_kbdacia(*this, "kbdacia") - , m_micpia(*this, "micpia") - , m_diapia(*this, "diapia") + , m_kbd_acia(*this, "kbd_acia") + , m_mic_pia(*this, "mic_pia") + , m_dia_pia(*this, "dia_pia") , m_crtc(*this, "crtc") , m_screen(*this, "screen") , m_vram(*this, "vram") + , m_pla(*this, PLA1_TAG) + , m_kbd(*this, "keyboard") , m_chargen(*this, "chargen") + , m_tia_adlc(*this, "tia_adlc") + , m_tia_dma(*this, "tia_dma") + , m_irq(0) + , m_imsk(0) { } void alfaskop4110(machine_config &config); private: + virtual void machine_start() override; + virtual void machine_reset() override; + void mem_map(address_map &map); required_device m_maincpu; - required_device m_kbdacia; - required_device m_micpia; - required_device m_diapia; + required_device m_kbd_acia; + required_device m_mic_pia; + required_device m_dia_pia; required_device m_crtc; required_device m_screen; required_shared_ptr m_vram; + required_device m_pla; + required_device m_kbd; /* Video controller */ required_region_ptr m_chargen; MC6845_UPDATE_ROW(crtc_update_row); + + /* TIA */ + required_device m_tia_adlc; + required_device m_tia_dma; + + /* Interrupt handling */ + template DECLARE_WRITE_LINE_MEMBER(irq_w); + uint8_t m_irq; + uint8_t m_imsk; + + /* Kbd communications */ + uint8_t m_txd; + + /* Debug stuff */ + /* Timer */ + enum + { + TIMER_POLL_START, + TIMER_POLL_BIT + }; + void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override; + + // DEBUG stuff, will be removed when hooked up towards remote peer +#if 1 + /* zero extended SDLC poll message frame to feed into receiver as a test + 0 1 1 1 1 1 1 0 ; opening flag 0x7e + 0 0 0 0 0 0 0 0 ; 0x00 + 1 1 1 1 1 0 1 1 1 ; 0xff <- a zero needs to be inserted, done by test code + 0 0 0 0 0 0 1 1 ; 0xc0 + 0 0 0 0 0 1 0 1 ; 0xa0 + 1 0 1 1 0 0 0 1 ; CRC 0x8d + 1 0 1 0 1 0 1 0 ; CRC 0x55 + 0 1 1 1 1 1 1 0 ; closing flag 0x7e + */ + uint8_t txBuf[10] = {0x7e, 0x00, 0xff, 0xc0, 0xa0, 0x8d, 0x55, 0x7e}; + +#else // Alternative poll message body wih faulty CRC, CRC isn't checked yet by the ADLC + + /* zero extended SDLC poll message frame to feed into receiver as a test + 0 1 1 1 1 1 1 0 ; opening flag 0x7e + 0 0 0 0 0 0 0 0 ; 0x00 + 0 0 0 0 0 0 0 0 ; 0x00 + 1 1 1 1 1 0 1 1 0 ; 0xfe <- a zero needs to be inserted, done by test code + 1 1 1 0 1 0 0 1 ; 0xe9 + 1 0 1 1 0 0 0 1 ; CRC 0x8d - wrong + 1 0 1 0 1 0 1 0 ; CRC 0x55 - wrong + 0 1 1 1 1 1 1 0 ; closing flag 0x7e + */ + uint8_t txBuf[10] = {0x7e, 0x00, 0x00, 0xfe, 0xe9, 0x8d, 0x55, 0x7e}; +#endif + + int index = 0; + int pos = 0; + int ones = 0; + bool flank = false; }; class alfaskop4120_state : public driver_device @@ -84,8 +172,8 @@ public: alfaskop4120_state(const machine_config &mconfig, device_type type, const char *tag) : driver_device(mconfig, type, tag) , m_maincpu(*this, "maincpu") - , m_micpia(*this, "micpia") - , m_fdapia(*this, "diapia") + , m_mic_pia(*this, "mic_pia") + , m_fdapia(*this, "dia_pia") { } void alfaskop4120(machine_config &config); @@ -93,7 +181,7 @@ private: void mem_map(address_map &map); required_device m_maincpu; - required_device m_micpia; + required_device m_mic_pia; required_device m_fdapia; }; @@ -103,7 +191,7 @@ public: alfaskop4101_state(const machine_config &mconfig, device_type type, const char *tag) : driver_device(mconfig, type, tag) , m_maincpu(*this, "maincpu") - , m_micpia(*this, "micpia") + , m_mic_pia(*this, "mic_pia") { } void alfaskop4101(machine_config &config); @@ -111,31 +199,77 @@ private: void mem_map(address_map &map); required_device m_maincpu; - required_device m_micpia; + required_device m_mic_pia; }; void alfaskop4110_state::mem_map(address_map &map) { map.unmap_value_high(); map(0x0000, 0x7fff).ram(); - map(0x7800, 0x7fff).ram().share(m_vram); + map(0x7800, 0x7fff).ram().share(m_vram); // TODO: Video RAM base address is configurable via NVRAM - this is the default map(0x8000, 0xefff).ram(); - map(0xf600, 0xf6ff).lrw8(NAME([this](offs_t offset) -> uint8_t { LOGNVRAM("nvram_r %04x: %02x\n", offset, 0); return (uint8_t) 0; }),// TODO: Move to MRO board - NAME( [this](offs_t offset, uint8_t data) { LOGNVRAM("nvram_w %04x: %02x\n", offset, data); })); + // NVRAM + map(0xf600, 0xf6ff).lrw8(NAME([this](offs_t offset) -> uint8_t + { + LOGNVRAM("nvram_r %04x: %02x\n", offset, 0); return (uint8_t) 0; + }), + NAME([this](offs_t offset, uint8_t data) + { + LOGNVRAM("nvram_w %04x: %02x\n", offset, data); + })); + // TIA board + map(0xf700, 0xf71f).mirror(0x00).lrw8(NAME([this](offs_t offset) -> uint8_t { LOGDMA("TIA DMA_r %04x: %02x\n", offset, 0); return m_tia_dma->read(offset); }), + NAME([this](offs_t offset, uint8_t data) { LOGDMA("TIA DMA_w %04x: %02x\n", offset, data); m_tia_dma->write(offset, data); })); + map(0xf720, 0xf723).mirror(0x04).lrw8(NAME([this](offs_t offset) -> uint8_t { LOGADLC("TIA ADLC_r %04x: %02x\n", offset, 0); return m_tia_adlc->read(offset); }), + NAME([this](offs_t offset, uint8_t data) { LOGADLC("TIA ADLC_w %04x: %02x\n", offset, data); m_tia_adlc->write(offset, data); })); + + // Main PCB map(0xf7d9, 0xf7d9).mirror(0x06).lrw8(NAME([this](offs_t offset) -> uint8_t { LOGIO("CRTC reg r %04x: %02x\n", offset, 0); return m_crtc->register_r(); }), - NAME([this](offs_t offset, uint8_t data) { LOGIO("CRTC reg w %04x: %02x\n", offset, data); m_crtc->register_w(data);})); + NAME([this](offs_t offset, uint8_t data) { LOGIO("CRTC reg w %04x: %02x\n", offset, data); m_crtc->register_w(data);})); map(0xf7d8, 0xf7d8).mirror(0x06).lw8(NAME([this](offs_t offset, uint8_t data) { LOGIO("CRTC adr w %04x: %02x\n", offset, data); m_crtc->address_w(data); })); - map(0xf7d0, 0xf7d3).mirror(0x04).lrw8(NAME([this](offs_t offset) -> uint8_t { LOGIO("DIA pia_r %04x: %02x\n", offset, 0); return m_diapia->read(offset & 3); }), - NAME([this](offs_t offset, uint8_t data) { LOGIO("DIA pia_w %04x: %02x\n", offset, data); m_diapia->write(offset & 3, data); })); - map(0xf7c4, 0xf7c7).mirror(0x00).lrw8(NAME([this](offs_t offset) -> uint8_t { LOGIO("MIC pia_r %04x: %02x\n", offset, 0); return m_micpia->read(offset & 3); }), - NAME( [this](offs_t offset, uint8_t data) { LOGIO("MIC pia_w %04x: %02x\n", offset, data); m_micpia->write(offset & 3, data); })); - map(0xf7c0, 0xf7c1).mirror(0x02).lrw8(NAME([this](offs_t offset) -> uint8_t { LOGIO("KBD acia_r %04x: %02x\n", offset, 0); return m_kbdacia->read(offset & 1); }), - NAME( [this](offs_t offset, uint8_t data) { LOGIO("KBD acia_w %04x: %02x\n", offset, data); m_kbdacia->write(offset & 1, data); })); + map(0xf7d0, 0xf7d3).mirror(0x04).lrw8(NAME([this](offs_t offset) -> uint8_t { LOGDIA("DIA pia_r %04x: %02x\n", offset, 0); return m_dia_pia->read(offset & 3); }), + NAME([this](offs_t offset, uint8_t data) { LOGDIA("DIA pia_w %04x: %02x\n", offset, data); m_dia_pia->write(offset & 3, data); })); + map(0xf7c4, 0xf7c7).mirror(0x00).lrw8(NAME([this](offs_t offset) -> uint8_t { uint8_t tmp = m_mic_pia->read(offset & 3); LOGMIC("\nMIC pia_r %04x: %02x\n", offset, tmp); return tmp; }), + NAME([this](offs_t offset, uint8_t data) { LOGMIC("\nMIC pia_w %04x: %02x\n", offset, data); m_mic_pia->write(offset & 3, data); })); + map(0xf7c0, 0xf7c1).mirror(0x02).lrw8(NAME([this](offs_t offset) -> uint8_t { LOGKBD("KBD acia_r %04x: %02x\n", offset, 0); return m_kbd_acia->read(offset & 1); }), + NAME([this](offs_t offset, uint8_t data) { LOGKBD("KBD acia_w %04x: %02x\n", offset, data); m_kbd_acia->write(offset & 1, data); })); - map(0xf7fc, 0xf7fc).mirror(0x00).lr8(NAME([this](offs_t offset) -> uint8_t { LOGIO("Address Switch 0-7\n"); return 0; })); + map(0xf7fc, 0xf7fc).mirror(0x00).lr8(NAME([this](offs_t offset) -> uint8_t { LOGIO("Address Switch 0-7\n"); return 0; })); - map(0xf800, 0xffff).rom().region("roms", 0); + map(0xf800, 0xffe7).rom().region("roms", 0); + + // IRQ mask setting + map(0xffe8, 0xfff7).rom().lrw8( NAME([this](offs_t offset) -> uint8_t + { + if (!machine().side_effects_disabled()) LOGAM("AMSK read set %04x\n", offset >> 1); + m_imsk = (offset >> 1) & 7; + return ((uint8_t *) memregion("roms")->base() + 0x7e8)[offset]; + }), + NAME([this](offs_t offset, uint8_t data) + { + if (!machine().side_effects_disabled()) LOGAM("AMSK write set %04x\n", offset); + m_imsk = (offset >> 1) & 7; + })); + + // Address modification + map(0xfff8, 0xfff9).rom().lrw8( NAME([this](offs_t offset) -> uint8_t + { + uint16_t ploffs = (~m_irq & 0xff) | ((m_imsk & 0x07) << 8) | 0x000 | (0x18 << 11); + uint8_t tmp = ((uint8_t *) memregion("roms")->base())[0x7e0 | offset | ((m_pla->read(ploffs) & 0xf0) >> 3)]; + if (!machine().side_effects_disabled()) + { + LOGAM("AMOD read %04x: %02x\n", offset, tmp); + LOGAM("AMOD pla read %04x: %02x ==> %04x\n", ploffs, m_pla->read(ploffs), (0xffe0 | offset | ((m_pla->read(ploffs) & 0xf0) >> 3))); + } + return tmp; + }), + NAME([this](offs_t offset, uint8_t data) // TODO: Check what a write does if anything + { + if (!machine().side_effects_disabled()) LOGAM("AMOD write %04x\n", offset); + })); + + map(0xfffa, 0xffff).rom().region("roms", 0x7fa); } void alfaskop4120_state::mem_map(address_map &map) @@ -145,9 +279,9 @@ void alfaskop4120_state::mem_map(address_map &map) map(0xf600, 0xf6ff).lrw8(NAME([this](offs_t offset) -> uint8_t { LOGNVRAM("nvram_r %04x: %02x\n", offset, 0); return (uint8_t) 0; }), // TODO: Move to MRO board NAME([this](offs_t offset, uint8_t data) { LOGNVRAM("nvram_w %04x: %02x\n", offset, data); })); map(0xf740, 0xf743).mirror(0x0c).lrw8(NAME([this](offs_t offset) -> uint8_t { LOGIO("FDA pia_r %04x: %02x\n", offset, 0); return m_fdapia->read(offset & 3); }), - NAME([this](offs_t offset, uint8_t data) { LOGIO("FDA pia_w %04x: %02x\n", offset, data); m_fdapia->write(offset & 3, data); })); - map(0xf7c4, 0xf7c7).mirror(0x00).lrw8(NAME([this](offs_t offset) -> uint8_t { LOGIO("MIC pia_r %04x: %02x\n", offset, 0); return m_micpia->read(offset & 3); }), - NAME([this](offs_t offset, uint8_t data) { LOGIO("MIC pia_w %04x: %02x\n", offset, data); m_micpia->write(offset & 3, data); })); + NAME([this](offs_t offset, uint8_t data) { LOGIO("FDA pia_w %04x: %02x\n", offset, data); m_fdapia->write(offset & 3, data); })); + map(0xf7c4, 0xf7c7).mirror(0x00).lrw8(NAME([this](offs_t offset) -> uint8_t { LOGMIC("MIC pia_r %04x: %02x\n", offset, 0); return m_mic_pia->read(offset & 3); }), + NAME([this](offs_t offset, uint8_t data) { LOGMIC("MIC pia_w %04x: %02x\n", offset, data); m_mic_pia->write(offset & 3, data); })); map(0xf800, 0xffff).rom().region("roms", 0); } @@ -157,8 +291,8 @@ void alfaskop4101_state::mem_map(address_map &map) map(0x0000, 0xefff).ram(); map(0xf600, 0xf6ff).lrw8(NAME([this](offs_t offset) -> uint8_t { LOGNVRAM("nvram_r %04x: %02x\n", offset, 0); return (uint8_t) 0; }), NAME([this](offs_t offset, uint8_t data) { LOGNVRAM("nvram_w %04x: %02x\n", offset, data); })); - map(0xf7c4, 0xf7c7).mirror(0x00).lrw8(NAME([this](offs_t offset) -> uint8_t { LOGIO("MIC pia_r %04x: %02x\n", offset, 0); return m_micpia->read(offset & 3); }), - NAME([this](offs_t offset, uint8_t data) { LOGIO("MIC pia_w %04x: %02x\n", offset, data); m_micpia->write(offset & 3, data); })); + map(0xf7c4, 0xf7c7).mirror(0x00).lrw8(NAME([this](offs_t offset) -> uint8_t { LOGMIC("MIC pia_r %04x: %02x\n", offset, 0); return m_mic_pia->read(offset & 3); }), + NAME([this](offs_t offset, uint8_t data) { LOGMIC("MIC pia_w %04x: %02x\n", offset, data); m_mic_pia->write(offset & 3, data); })); map(0xf800, 0xffff).rom().region("roms", 0); } @@ -172,6 +306,14 @@ INPUT_PORTS_END static INPUT_PORTS_START( alfaskop4101 ) INPUT_PORTS_END +/* Interrupt handling - vector address modifyer, irq prioritizer and irq mask */ +template WRITE_LINE_MEMBER( alfaskop4110_state::irq_w ) +{ + m_irq = (m_irq & ~(1 << N)) | ((state ? 1 : 0) << N); + LOGIRQ("4110 IRQ %d: %d ==> %02x\n", N, state, m_irq); + m_maincpu->set_input_line(M6800_IRQ_LINE, state); +} + /* Simplified chargen, no attributes or special formats/features yet */ MC6845_UPDATE_ROW( alfaskop4110_state::crtc_update_row ) { @@ -197,38 +339,256 @@ void alfaskop4110_state::alfaskop4110(machine_config &config) M6800(config, m_maincpu, XTAL(19'170'000) / 18); // Verified from service manual m_maincpu->set_addrmap(AS_PROGRAM, &alfaskop4110_state::mem_map); + // TTL-level serial keyboard callback + ALFASKOP_S41_KB(config, m_kbd); + m_kbd->txd_cb().set([this](bool state) + { + LOGBITS("KBD->4110: %d\n", state); + m_kbd_acia->write_rxd(state); + }); + m_kbd->leds_cb().set([this] (uint8_t data) + { + LOGLEDS("LEDS: write %02x to LEDs\n", data); + }); + + + /* Interrupt controller and address modifier PLA */ + /* + * 82S100 data sheet + * ----------------- + * + * The 82S100 is a bipolar, fuse-link programmable logic array. It uses the + * standard AND/OR/invert architecture to directly implement custom + * um-of-product logic equations. + * + * Each device consists of 16 dedicated inputs and 8 dedicated outputs. Each + * output is capable of being actively controlled by any or all of the 48 + * product terms. The true, complement, or don't care condition of each of the + * 16 inputs ANDed together comprise one P-Term. All 48 P-Terms are then OR-d + * to each output. The user must then only select which P-Terms will activate + * an output by disconnecting terms which do not affect the output. In addition, + * each output can be fused as active high or active low. + * + * The 82S100 is fully TTL compatible and includes chip-enable control for + * expansion of input variables and output inhibit. It features three state + * outputs. + * + * Field programmable Ni-Cr links + * 16 inputs + * 8 outputs + * 48 product terms + * Commercial verion - N82S100 - 50ns max address access time + * Power dissipation - 600mW typ + * Input loading - 100uA max + * Chip enable input + * Three state outputs + * + * + */ + /* _____ _____ + * nc FE 1 |* \_/ | 28 Vcc + * IRQ7 I7 2 | | 27 I8 mask 1 + * IRQ6 I6 3 | | 26 I9 mask 2 + * IRQ5 I5 4 | | 25 I10 mask 3 + * IRQ4 I4 5 | | 24 I11 Address &== 1111 1111 111x xxxx + * IRQ3 I3 6 | 82S100 | 23 I12 AI 1 A1 + * IRQ2 I2 7 | | 22 I13 AI 2 A2 + * IRQ1 I1 8 | IC50 | 21 I14 AI 3 A3 + * IRQ0 I0 9 | | 20 I15 AI 4 A4 + * P4 F7 10 | Interrupt | 19 _CE + * mask P3 F6 11 | Controller | 18 F0 IRQ + * mask P2 F5 12 | PLA | 17 F1 mask register + * mask P1 F4 13 | | 16 F2 interrupt latch + * GND 14 |_____________| 15 F3 nc + */ + PLS100(config, m_pla); + MC6845(config, m_crtc, XTAL(19'170'000) / 9); m_crtc->set_screen("screen"); m_crtc->set_show_border_area(false); m_crtc->set_char_width(8); m_crtc->set_update_row_callback(FUNC(alfaskop4110_state::crtc_update_row)); + // VSYNC should goto IRQ1 through some logic involving MIC PIA CRA bits 0 ( 1 == enable) & 1 (1 == positive edge) + //m_crtc->out_vsync_callback().set(FUNC(alfaskop4110_state::crtc_vsync); + //m_crtc->out_vsync_callback().set([this](bool state) { LOGIRQ("CRTC VSYNC: %d\n", state); }); + //m_crtc->out_vsync_callback().set("irq1", FUNC(input_merger_device::in_w<1>)); SCREEN(config, m_screen, SCREEN_TYPE_RASTER); m_screen->set_raw(19'170'000, 80 * 8, 0, 80 * 8, 400, 0, 400); m_screen->set_screen_update("crtc", FUNC(mc6845_device::screen_update)); - PIA6821(config, m_micpia, 0); // Main board PIA - m_micpia->readcb1_handler().set([this](offs_t offset) -> uint8_t { LOGMIC("MIC PIA: CB1_r\n"); return 0;}); - m_micpia->cb2_handler().set([this](offs_t offset, uint8_t data) { LOGMIC("MIC PIA: CB2_w\n"); }); - m_micpia->writepa_handler().set([this](offs_t offset, uint8_t data) { LOGMIC("MIC PIA: PA_w\n"); }); - m_micpia->writepb_handler().set([this](offs_t offset, uint8_t data) { LOGMIC("MIC PIA: PB_w\n"); }); - m_micpia->readpa_handler().set([this](offs_t offset) -> uint8_t { LOGMIC("MIC PIA: PA_r\n"); return 0;}); - m_micpia->readpb_handler().set([this](offs_t offset) -> uint8_t { LOGMIC("MIC PIA: PB_r\n"); return 0;}); - m_micpia->readca1_handler().set([this](offs_t offset) -> uint8_t { LOGMIC("MIC PIA: CA1_r\n"); return 0;}); - m_micpia->readca2_handler().set([this](offs_t offset) -> uint8_t { LOGMIC("MIC PIA: CA2_r\n"); return 0;}); + PIA6821(config, m_mic_pia, 0); // Main board PIA + m_mic_pia->readcb1_handler().set([this](offs_t offset) -> uint8_t { LOGMIC("<-MIC PIA: CB1 read\n"); return 0;}); + m_mic_pia->cb2_handler().set([this](offs_t offset, uint8_t data) { LOGMIC("->MIC PIA: CB2 write %d\n", data); }); - PIA6821(config, m_diapia, 0); // Display PIA, controls how the CRTC accesses memory etc - m_diapia->readcb1_handler().set([this](offs_t offset) -> uint8_t { LOGDIA("DIA PIA: CB1_r\n"); return 0;}); - m_diapia->cb2_handler().set([this](offs_t offset, uint8_t data) { LOGDIA("DIA PIA: CB2_w\n"); }); - m_diapia->writepa_handler().set([this](offs_t offset, uint8_t data) { LOGDIA("DIA PIA: PA_w\n"); }); - m_diapia->writepb_handler().set([this](offs_t offset, uint8_t data) { LOGDIA("DIA PIA: PB_w\n"); }); - m_diapia->readpa_handler().set([this](offs_t offset) -> uint8_t { LOGDIA("DIA PIA: PA_r\n"); return 0;}); - m_diapia->readpb_handler().set([this](offs_t offset) -> uint8_t { LOGDIA("DIA PIA: PB_r\n"); return 0;}); - m_diapia->readca1_handler().set([this](offs_t offset) -> uint8_t { LOGDIA("DIA PIA: CA1_r\n"); return 0;}); - m_diapia->readca2_handler().set([this](offs_t offset) -> uint8_t { LOGDIA("DIA PIA: CA2_r\n"); return 0;}); + /* + * MIC PIA interface + * + * Port A (DDRA=0x7a) + * 0 - PA0 input - not used + * 1 - PA1 output - KB reset P11 pin 23 at connector 1 == KB reset 0 == no KB reset + * 2 - PA2 input - MCP test mode 1 == no test mode 0 == in test mode, + * 3 - PA3 output - not used (in DTC) + * 4 - PA4 output - not used (in DTC) + * 5 - PA5 output - Interrupt enable 1 == Int. out on P1:7 0 == no Int. out + * 6 - PA6 output - I4 latch enable 1 == I4 will be latched 0 == no I4 latch + * 7 - PA7 input - Button/MCP NMI 1 == NMI from DU button 0 == NMI from MCP P4:1=low + * Note: At initialization a KB reset pulse will be sent as DDRA contains all zeros: PA I functions as a + * high impedance input: "active level" for KB reset generation. + * + * Port B (DDRB=0xff) + * 0 - PB0 output - Reset PC-error 1 == Reset PC error FF 0 == Memory PC used + * or PC not used + * 1 - PB1 output - VMAX/VMA 1 MPU 1 == VMAX gen by MPU 0 == VMA 1 gen by MPU + * 2 - PB2 output - VMAX/VMA 1 DMA 1 == VMAX gen by DMA 0 == VMA 1 gen by DMA + * 3 - PB3 output - Display Memory 1 == 4KB Display Memory 0 == 8KB Display Memory + * 4 - PB4 output - Option Character Generator 1 == Enabled to MIC bus 0 == Disabled from MIC bus + * 5 - PB5 output - MPU Addr 1 == Mode 1 0 == Mode 0 + * 6 - PB6 output - Reset 1 == Reset all but MPU 0 == No reset + * and MIC PIA + * 7 - PB7 output - not used + */ + m_mic_pia->writepa_handler().set([this](offs_t offset, uint8_t data) + { + LOGMIC("->MIC PIA: Port A write %02x\n", data); + LOGKBD(" PA1 - KBD reset %s\n", BIT(data, 1) ? "active" : "inactive"); + m_kbd->rst_line_w(BIT(data, 1) ? ASSERT_LINE : CLEAR_LINE); + LOGMIC(" PA5 - Int out %s\n", BIT(data, 5) ? "enabled": "disabled"); + LOGMIC(" PA6 - I4 latch %s\n", BIT(data, 6) ? "enabled": "disabled"); + }); - ACIA6850(config, m_kbdacia, 0); - //CLOCK(config, "acia_clock", ACIA_CLOCK).signal_handler().set(FUNC(alfaskop4110_state::write_acia_clock)); + m_mic_pia->writepb_handler().set([this](offs_t offset, uint8_t data) + { + LOGMIC("->MIC PIA: Port B write %02x\n", data); + LOGMIC(" PB0 - Reset PC-error %s\n", BIT(data, 0) ? "active" : "inactive"); + LOGMIC(" PB1 - %s generated by MPU\n", BIT(data, 1) ? "VMAX" : "VMA 1"); + LOGMIC(" PB2 - %s generated by DMA\n", BIT(data, 2) ? "VMAX" : "VMA 1"); + LOGMIC(" PB3 - %sKB Display Memory\n", BIT(data, 3) ? "4" : "8"); + LOGMIC(" PB4 - Option Char Generator %s\n", BIT(data, 4) ? "enabled" : "disabled"); + LOGMIC(" PB5 - MPU Address Mode %s\n", BIT(data, 5) ? "1" : "0"); + LOGMIC(" PB6 - Reset of devices %s\n", BIT(data, 6) ? "active" : "inactive"); + }); + + m_mic_pia->readpa_handler().set([this](offs_t offset) -> uint8_t + { + uint8_t data = (1U << 2); // MCU is not in test mode + LOGMIC("<-MIC PIA: Port A read\n"); + LOGMIC(" PA2 - MCU test mode %s\n", BIT(data, 2) ? "inactive" : "active"); + return 0; + }); + m_mic_pia->readpb_handler().set([this](offs_t offset) -> uint8_t { LOGMIC("<-MIC PIA: Port B read\n"); return 0;}); + m_mic_pia->readca1_handler().set([this](offs_t offset) -> uint8_t { LOGMIC("<-MIC PIA: CA1 read\n"); return 0;}); + m_mic_pia->readca2_handler().set([this](offs_t offset) -> uint8_t { LOGMIC("<-MIC PIA: CA2 read\n"); return 0;}); + + PIA6821(config, m_dia_pia, 0); // Display PIA, controls how the CRTC accesses memory etc + m_dia_pia->readcb1_handler().set([this](offs_t offset) -> uint8_t { LOGDIA("DIA PIA: CB1_r\n"); return 0;}); + m_dia_pia->cb2_handler().set([this](offs_t offset, uint8_t data) { LOGDIA("DIA PIA: CB2_w %d\n", data); }); + m_dia_pia->writepa_handler().set([this](offs_t offset, uint8_t data) { LOGDIA("DIA PIA: PA_w %02x\n", data); }); + m_dia_pia->writepb_handler().set([this](offs_t offset, uint8_t data) { LOGDIA("DIA PIA: PB_w %02x\n", data); }); + m_dia_pia->readpa_handler().set([this](offs_t offset) -> uint8_t { LOGDIA("DIA PIA: PA_r\n"); return 0;}); + m_dia_pia->readpb_handler().set([this](offs_t offset) -> uint8_t { LOGDIA("DIA PIA: PB_r\n"); return 0;}); + m_dia_pia->readca1_handler().set([this](offs_t offset) -> uint8_t { LOGDIA("DIA PIA: CA1_r\n"); return 0;}); + m_dia_pia->readca2_handler().set([this](offs_t offset) -> uint8_t { LOGDIA("DIA PIA: CA2_r\n"); return 0;}); + + /* The ACIA RxC and TxC are fed from the systemclock divided through a by 14 dividing 74163, from the tech manual: + "A clock of 76 kHz is provided for the ACIA by the timing logic. ACIA divides this clock by 64 (Bit transfer rate 1188 Hz) and + synchronizes internally to received data. Furthermore ACIA may provide interrupt (at level 3) when transmit register is empty, + receive register is full or an error has occured. */ + ACIA6850(config, m_kbd_acia, XTAL(19'170'000) / 18); + CLOCK(config, "acia_clock", (XTAL(19'170'000) / 18) / 14 ).signal_handler().set([this](int state) { m_kbd_acia->write_txc(state); m_kbd_acia->write_rxc(state); }); + m_kbd_acia->irq_handler().set("irq3", FUNC(input_merger_device::in_w<3>)); + m_kbd_acia->txd_handler().set([this](bool state) + { + if (m_txd != state) + { + LOGBITS("4110->KBD: %d\n", state); + m_txd = state; + m_kbd->rxd_w(m_txd); + } + }); + + MC6854(config, m_tia_adlc, XTAL(19'170'000) / 18); + m_tia_adlc->out_irq_cb().set("irq7", FUNC(input_merger_device::in_w<7>)); + m_tia_adlc->out_rdsr_cb().set([this](bool state){ LOGDMA("TIA ADLC RDSR: %d\n", state); m_tia_dma->dreq_w<1>(state); }); + m_tia_adlc->out_tdsr_cb().set([this](bool state){ LOGDMA("TIA ADLC TDSR: %d\n", state); m_tia_dma->dreq_w<0>(state); }); + + MC6844(config, m_tia_dma, XTAL(19'170'000) / 18); + //m_tia_dma->out_int_callback().set([this](bool state){ LOGDMA("TIA DMA IRQ: %d\n", state); }); // Used as DEND (end of dma) towards the ADLC through some logic + m_tia_dma->out_drq1_callback().set([this](bool state){ LOGDMA("TIA DMA DRQ1: %d\n", state); m_tia_dma->dgrnt_w(state); }); + //m_tia_dma->out_drq2_callback().set([this](bool state){ LOGDMA("TIA DMA DRQ2: %d\n", state); }); // Not connected + m_tia_dma->in_ior_callback<1>().set([this](offs_t offset) -> uint8_t { return m_tia_adlc->dma_r(); }); + m_tia_dma->out_memw_callback().set([this](offs_t offset, uint8_t data) { m_maincpu->space(AS_PROGRAM).write_byte(offset, data); }); + + /* 74LS273 latch inputs of interruptt sources */ + INPUT_MERGER_ANY_HIGH(config, "irq0").output_handler().set(FUNC(alfaskop4110_state::irq_w<0>)); + INPUT_MERGER_ANY_HIGH(config, "irq1").output_handler().set(FUNC(alfaskop4110_state::irq_w<1>)); + INPUT_MERGER_ANY_HIGH(config, "irq2").output_handler().set(FUNC(alfaskop4110_state::irq_w<2>)); + INPUT_MERGER_ANY_HIGH(config, "irq3").output_handler().set(FUNC(alfaskop4110_state::irq_w<3>)); + INPUT_MERGER_ANY_HIGH(config, "irq4").output_handler().set(FUNC(alfaskop4110_state::irq_w<4>)); + INPUT_MERGER_ANY_HIGH(config, "irq5").output_handler().set(FUNC(alfaskop4110_state::irq_w<5>)); + INPUT_MERGER_ANY_HIGH(config, "irq6").output_handler().set(FUNC(alfaskop4110_state::irq_w<6>)); + INPUT_MERGER_ANY_HIGH(config, "irq7").output_handler().set(FUNC(alfaskop4110_state::irq_w<7>)); +} + +void alfaskop4110_state::machine_start() +{ + save_item(NAME(m_irq)); + save_item(NAME(m_imsk)); + timer_set(attotime::from_msec(5000), TIMER_POLL_START); + + // Hard wired inputs + m_kbd_acia->write_cts(0); + m_kbd_acia->write_dcd(0); +} + +void alfaskop4110_state::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + // Debug feature, inserts a poll SDLC frame through the ADLC, it ends up at address 0x140 in RAM through DMA + switch (id) + { + case TIMER_POLL_START: + /* The serial transfer of 8 bits is complete. Now trigger INT7. */ + LOGADLC("Starting poll message\n"); + m_tia_adlc->set_rx(0); + timer_set(attotime::from_hz(300000), TIMER_POLL_BIT); + break; + case TIMER_POLL_BIT: + if (flank) + { + if (index != 0 && index != 7 && BIT(txBuf[index], (pos % 8)) && ones == 5) + { + LOGADLC("%d%c", 2, (pos % 8) == 7 ? '\n' : ' '); + m_tia_adlc->set_rx(0); + ones = 0; + } + else + { + LOGADLC("%d%c", BIT(txBuf[index], (pos % 8)), (pos % 8) == 7 ? '\n' : ' '); + m_tia_adlc->set_rx(BIT(txBuf[index], (pos % 8))); + if (index != 0 && index != 7 && BIT(txBuf[index], (pos % 8))) + ones++; + else + ones = 0; + pos++; + index = pos / 8; + } + } + m_tia_adlc->rxc_w(flank ? 1 : 0); + if (index < 8) + timer_set(attotime::from_hz(300000) / 2, TIMER_POLL_BIT); + flank = !flank; + break; + } +} + +void alfaskop4110_state::machine_reset() +{ + m_irq = 0x00; + m_kbd->rst_line_w(ASSERT_LINE); + + // Hard wired inputs + m_kbd_acia->write_cts(0); + m_kbd_acia->write_dcd(0); } void alfaskop4120_state::alfaskop4120(machine_config &config) @@ -237,7 +597,7 @@ void alfaskop4120_state::alfaskop4120(machine_config &config) M6800(config, m_maincpu, XTAL(19'170'000) / 18); // Verified from service manual m_maincpu->set_addrmap(AS_PROGRAM, &alfaskop4120_state::mem_map); - PIA6821(config, m_micpia, 0); // Main board PIA + PIA6821(config, m_mic_pia, 0); // Main Board PIA PIA6821(config, m_fdapia, 0); // Floppy Disk PIA } @@ -247,7 +607,7 @@ void alfaskop4101_state::alfaskop4101(machine_config &config) M6800(config, m_maincpu, XTAL(19'170'000) / 18); // Verified from service manual m_maincpu->set_addrmap(AS_PROGRAM, &alfaskop4101_state::mem_map); - PIA6821(config, m_micpia, 0); // Main board PIA + PIA6821(config, m_mic_pia, 0); // Main board PIA } /* ROM definitions */ @@ -257,6 +617,9 @@ ROM_START( alfaskop4110 ) // Display Unit ROM_REGION( 0x800, "chargen", ROMREGION_ERASEFF ) ROM_LOAD( "e3405972067500.bin", 0x0000, 0x0400, CRC(fb12b549) SHA1(53783f62c5e51320a53e053fbcf8b3701d8a805f)) ROM_LOAD( "e3405972067600.bin", 0x0400, 0x0400, CRC(c7069d65) SHA1(587efcbee036d4c0c5b936cc5d7b1f97b6fe6dba)) + ROM_REGION( 0xff, PLA1_TAG, 0 ) + //ROM_LOAD( "dtc_a_e34062_0100_ic50_e3405970303601_ml.bin", 0x00, 0xf5, CRC(b37395f2) SHA1(a00dc77d4bef084c0ddceef618986d83c69b1d65) ) // Signetics_N82S100N.bin MAXLOADER format + ROM_LOAD( "dtc_a_e34062_0100_ic50_e3405970303601.bin", 0x00, 0xfa, CRC(16339b7a) SHA1(9b313a7526460dc9bcedfda25bece91c924f0ddc) ) // Signetics_N82S100N.bin DATAIO format ROM_END ROM_START( alfaskop4120 ) // Flexible Disk Unit @@ -271,7 +634,7 @@ ROM_END /* Driver(S) */ -// Only 4101 may exist as a driver in the end making the 4110 and 4120 as slots devices on the SS3 bus, time will tell +// Only 4101 should exist as a driver in the end, making the 4110 and 4120 as slots devices on the SS3 bus, time will tell // YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS COMP( 1984, alfaskop4110, 0, 0, alfaskop4110, alfaskop4110, alfaskop4110_state, empty_init, "Ericsson", "Alfaskop Display Unit 4110", MACHINE_IS_SKELETON) diff --git a/src/mame/machine/alfaskop_s41_kb.cpp b/src/mame/machine/alfaskop_s41_kb.cpp new file mode 100644 index 00000000000..733914d636e --- /dev/null +++ b/src/mame/machine/alfaskop_s41_kb.cpp @@ -0,0 +1,397 @@ +// license:BSD-3-Clause +// copyright-holders: Joakim Larsson Edström +/********************************************************************** + + Alfaskop 4110 keyboard, emulation of the KeyBoard Unit KBU 4140. which often + was attached to the numerical Keyboard eXpansion Unit KXE 4141 which is not + emulated yet. There is also an optional Magnetic Identification Device MID 4131 + + TTL-level bi-directional serial matrix keyboard + + The KBU 4140 keyboard is controlled by a MC6802@3'579'000Hz in combo with a MC6846. + The key matrix is scanned with the help of two 74LS164 which is also extended to the + KXE 4141. The columns are read through a 74LS240. There are 8 LEDs which are + latched by a 74LS374. The I/O port on the MC6846 is connected to a magnet strip + reader through a MIA interface + + The keyboard serial interface line is interpreted and generated by the timer in + the MC6846 where both TX and Rx shares the same line on the keyboard side. The + keyboard remains silent until spoken to by the host computer to avoid collisions. + + Credits + ------- + The MC6846 ROM and address decoder ROM were dumped by Dalby Datormuseum whom + also provided documentation and schematics of the keyboard + + https://sites.google.com/site/dalbydatormuseum/home + + **********************************************************************/ + +#include "emu.h" +#include "alfaskop_s41_kb.h" +#include "cpu/m6800/m6800.h" + +//************************************************************************** +// CONFIGURABLE LOGGING +//************************************************************************** +#define LOG_IRQ (1U << 1) +#define LOG_RESET (1U << 2) +#define LOG_BITS (1U << 3) +#define LOG_UI (1U << 4) +#define LOG_LEDS (1U << 5) +#define LOG_ROM (1U << 6) +#define LOG_ADEC (1U << 7) +#define LOG_IO (1U << 8) + +//#define VERBOSE (LOG_GENERAL|LOG_IO|LOG_IRQ|LOG_LEDS|LOG_BITS|LOG_RESET) +//#define LOG_OUTPUT_STREAM std::cout + +#include "logmacro.h" + +#define LOGIRQ(...) LOGMASKED(LOG_IRQ, __VA_ARGS__) +#define LOGRST(...) LOGMASKED(LOG_RESET, __VA_ARGS__) +#define LOGBITS(...) LOGMASKED(LOG_BITS, __VA_ARGS__) +#define LOGUI(...) LOGMASKED(LOG_UI, __VA_ARGS__) +#define LOGLEDS(...) if (!machine().side_effects_disabled()) LOGMASKED(LOG_LEDS, __VA_ARGS__) +#define LOGROM(...) if (!machine().side_effects_disabled()) LOGMASKED(LOG_ROM, __VA_ARGS__) +#define LOGADEC(...) if (!machine().side_effects_disabled()) LOGMASKED(LOG_ADEC, __VA_ARGS__) +#define LOGIO(...) if (!machine().side_effects_disabled()) LOGMASKED(LOG_IO, __VA_ARGS__) + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define M6800_TAG "mcu" + +namespace { + +INPUT_PORTS_START(alfaskop_s41_kb) + PORT_START("P15") + PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("KP 6") PORT_CODE(KEYCODE_6_PAD) PORT_CODE(KEYCODE_RIGHT) PORT_CHAR('6') PORT_CHAR(UCHAR_MAMEKEY(RIGHT)) // 77 + PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("KP +") PORT_CODE(KEYCODE_PLUS_PAD) PORT_CHAR('+') // 78 + PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("KP 5") PORT_CODE(KEYCODE_5_PAD) PORT_CHAR('5') // 76 + PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("* PRINT") PORT_CODE(KEYCODE_TILDE) PORT_CHAR('*') PORT_CHAR(UCHAR_MAMEKEY(PRTSCR)) // 55 + PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("R Shift") PORT_CODE(KEYCODE_RSHIFT) PORT_CHAR(UCHAR_SHIFT_1) // 54 + PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') PORT_CHAR('_') // 53 + PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME(". :") PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR(':') // 52 + PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F5") PORT_CODE(KEYCODE_F5) PORT_CHAR(UCHAR_MAMEKEY(F5)) // 63 + PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F6") PORT_CODE(KEYCODE_F6) PORT_CHAR(UCHAR_MAMEKEY(F6)) // 64 + PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_UNUSED ) // no scancode is sent + PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("CTRL") PORT_CODE(KEYCODE_LCONTROL) PORT_CHAR(UCHAR_MAMEKEY(LCONTROL)) // 29 + PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME(", ;") PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR(';') // 51 + PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_D) PORT_CHAR('D') PORT_CHAR('d') // 32 + PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_X) PORT_CHAR('X') PORT_CHAR('x') // 45 + PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_C) PORT_CHAR('C') PORT_CHAR('c') // 46 + PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_J) PORT_CHAR('J') PORT_CHAR('j') // 36 + + PORT_START("P14") + PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_UNUSED ) // 00 - keyboard error + PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("BREAK") PORT_CODE(KEYCODE_PAUSE) PORT_CHAR(UCHAR_MAMEKEY(PAUSE)) // 70 + PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("KP 7") PORT_CODE(KEYCODE_7_PAD) PORT_CHAR('7') PORT_CHAR(UCHAR_MAMEKEY(HOME)) // 71 + PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_UNUSED ) // ff - keyboard error + PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_TILDE) PORT_CHAR('^') PORT_CHAR('~') PORT_CHAR(']') // 27 + PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR(0x00e5) PORT_CHAR(0x00c5) PORT_CHAR('[') // 26 å Å + PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_P) PORT_CHAR('P') PORT_CHAR('p') // 25 + PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F1") PORT_CODE(KEYCODE_F1) PORT_CHAR(UCHAR_MAMEKEY(F1)) // 59 + PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F2") PORT_CODE(KEYCODE_F2) PORT_CHAR(UCHAR_MAMEKEY(F2)) // 60 + PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_W) PORT_CHAR('w') PORT_CHAR('W') // 17 + PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_E) PORT_CHAR('e') PORT_CHAR('E') // 18 + PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_O) PORT_CHAR('o') PORT_CHAR('O') // 24 + PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_R) PORT_CHAR('r') PORT_CHAR('R') // 19 + PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_T) PORT_CHAR('t') PORT_CHAR('T') // 20 + PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Y) PORT_CHAR('y') PORT_CHAR('Y') // 21 + PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_I) PORT_CHAR('i') PORT_CHAR('I') // 23 + + PORT_START("P13") + PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_NUMLOCK) PORT_CHAR(UCHAR_MAMEKEY(NUMLOCK)) // 69 + PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_UNUSED ) // ff - keyboard error + PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("BS DEL") PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(8) PORT_CHAR(UCHAR_MAMEKEY(DEL)) // 14 + PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('=') PORT_CHAR('+') // 13 + PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') PORT_CHAR('_') // 12 + PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHAR(')') // 11 + PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR('(') // 10 + PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!') // 02 + PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("ESC") PORT_CODE(KEYCODE_ESC) PORT_CHAR(UCHAR_MAMEKEY(ESC)) // 01 + PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('@') // 03 + PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('#') // 04 + PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('*') // 09 + PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$') // 05 + PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%') // 06 + PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('^') // 07 + PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('&') // 08 + + PORT_START("P12") + PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("KP 9") PORT_CODE(KEYCODE_9_PAD) PORT_CHAR('9') PORT_CHAR(UCHAR_MAMEKEY(PGUP)) // 73 + PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("KP -") PORT_CODE(KEYCODE_MINUS_PAD) PORT_CHAR(UCHAR_MAMEKEY(MINUS_PAD)) // 74 + PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("KP 8") PORT_CODE(KEYCODE_8_PAD) PORT_CODE(KEYCODE_UP) PORT_CHAR('8') PORT_CHAR(UCHAR_MAMEKEY(UP)) // 72 + PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_TILDE) PORT_CHAR('`') PORT_CHAR('~') // 41 + PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_QUOTE) PORT_CHAR('\'') PORT_CHAR('"') // 40 + PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_COLON) PORT_CHAR(';') PORT_CHAR(':') // 39 + PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_L) PORT_CHAR('l') PORT_CHAR('L') // 38 + PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F3") PORT_CODE(KEYCODE_F3) PORT_CHAR(UCHAR_MAMEKEY(F3)) // 61 + PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F4") PORT_CODE(KEYCODE_F4) PORT_CHAR(UCHAR_MAMEKEY(F4)) // 62 + PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Q) PORT_CHAR('q') PORT_CHAR('Q') // 16 + PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("TAB") PORT_CODE(KEYCODE_TAB) PORT_CHAR(9) // 15 + PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_K) PORT_CHAR('k') PORT_CHAR('K') // 37 + PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F) PORT_CHAR('f') PORT_CHAR('F') // 33 + PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_G) PORT_CHAR('g') PORT_CHAR('G') // 34 + PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_H) PORT_CHAR('h') PORT_CHAR('H') // 35 + PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_U) PORT_CHAR('u') PORT_CHAR('U') // 22 + + PORT_START("P11") + PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_DEL_PAD) PORT_CHAR(UCHAR_MAMEKEY(COMMA_PAD)) // 83 + PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("RETURN") PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13) // 28 + PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("KP 0") PORT_CODE(KEYCODE_0_PAD) PORT_CHAR('0') PORT_CHAR(UCHAR_MAMEKEY(INSERT)) // 82 + PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_UNUSED ) // 89 - no key + PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_UNUSED ) // 86 - no key + PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_UNUSED ) // 87 - no key + PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_UNUSED ) // 88 - no key + PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F9") PORT_CODE(KEYCODE_F9) PORT_CHAR(UCHAR_MAMEKEY(F9)) // 67 + PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F10") PORT_CODE(KEYCODE_F10) PORT_CHAR(UCHAR_MAMEKEY(F10)) // 68 + PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_UNUSED ) // scan code ff - keyboard error + PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR('\\') // 43 + PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("CAPS LOCK") PORT_CODE(KEYCODE_CAPSLOCK) PORT_CHAR(UCHAR_MAMEKEY(CAPSLOCK)) // 58 + PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("SHIFT LOCK") PORT_CODE(KEYCODE_LALT) // 56 + PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_UNUSED ) // 85 - no key + PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_V) PORT_CHAR('v') PORT_CHAR('V') // 47 + PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ') // 57 + + PORT_START("P10") + PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("KP 3") PORT_CODE(KEYCODE_3_PAD) PORT_CODE(KEYCODE_PGDN) // 81 + PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_UNUSED ) // ff - keyboard error + PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("KP 2") PORT_CODE(KEYCODE_2_PAD) PORT_CODE(KEYCODE_DOWN) PORT_CHAR(UCHAR_MAMEKEY(2_PAD)) // 80 + PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("NEW LINE") PORT_CODE(KEYCODE_ENTER_PAD) PORT_CHAR(UCHAR_MAMEKEY(ENTER_PAD)) // 84 (programmable, default is 28) + PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("KP 1") PORT_CODE(KEYCODE_1_PAD) PORT_CHAR(UCHAR_MAMEKEY(1_PAD)) // 79 + PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("KP 4") PORT_CODE(KEYCODE_4_PAD) PORT_CODE(KEYCODE_LEFT) PORT_CHAR('4') PORT_CHAR(UCHAR_MAMEKEY(LEFT)) // 75 + PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_UNUSED ) // ff - keyboard error + PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F7") PORT_CODE(KEYCODE_F7) PORT_CHAR(UCHAR_MAMEKEY(F7)) // 65 + PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F8") PORT_CODE(KEYCODE_F8) PORT_CHAR(UCHAR_MAMEKEY(F8)) // 66 + PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_LSHIFT) PORT_CHAR(UCHAR_SHIFT_1) // 42 + PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Z) PORT_CHAR('z') PORT_CHAR('Z') // 44 + PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_M) PORT_CHAR('m') PORT_CHAR('M') // 50 + PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_A) PORT_CHAR('a') PORT_CHAR('A') // 30 + PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_S) PORT_CHAR('s') PORT_CHAR('S') // 31 + PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_B) PORT_CHAR('b') PORT_CHAR('B') // 48 + PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_N) PORT_CHAR('n') PORT_CHAR('N') // 49 +INPUT_PORTS_END + + +//------------------------------------------------- +// ROM( alfaskop_s41_kb ) +//------------------------------------------------- + +ROM_START( alfaskop_s41_kb ) + ROM_REGION( 0x800, M6800_TAG, 0 ) + ROM_LOAD( "kbc_e34066_0000_ic3.bin", 0x000, 0x800, CRC(a1232241) SHA1(45d1b038bfbd04e1b7e3718a27202280c5257989) ) + ROM_REGION( 0x20, "ad_rom", 0 ) // Address decoder + ROM_LOAD( "kbc_e34066_0000_ic4_e3405970280400.bin", 0x00, 0x20, CRC(f26acca3) SHA1(ac8c607d50bb588c1da4ad1602665c785ebd29b3) ) +ROM_END + +} // anonymous namespace + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +DEFINE_DEVICE_TYPE(ALFASKOP_S41_KB, alfaskop_s41_keyboard_device, "alfaskop_s41_kb", "Alfaskop 4110 keyboard") + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// alfaskop_s41_keyboard_device - constructor +//------------------------------------------------- + +alfaskop_s41_keyboard_device::alfaskop_s41_keyboard_device( + machine_config const &mconfig, + char const *tag, + device_t *owner, + uint32_t clock) + : device_t(mconfig, ALFASKOP_S41_KB, tag, owner, clock) + , m_mcu(*this, M6800_TAG) + , m_mc6846(*this, "mc6846") + , m_rows(*this, "P1%u", 0) + , m_txd_cb(*this) + , m_leds_cb(*this) + , m_rxd_high(true) + , m_txd_high(true) + , m_hold(true) + , m_col_select(0) + , m_p1(0) + , m_leds(0) +{ +} + +WRITE_LINE_MEMBER(alfaskop_s41_keyboard_device::rxd_w) +{ + LOGBITS("KBD bit presented: %d\n", state); + //m_rxd_high = CLEAR_LINE != state; +} + +// WRITE_LINE_MEMBER(alfaskop_s41_keyboard_device::hold_w) +// { +// m_hold = CLEAR_LINE == state; +// } + +WRITE_LINE_MEMBER(alfaskop_s41_keyboard_device::rst_line_w) +{ + if (state == CLEAR_LINE) + { + m_mcu->set_input_line(INPUT_LINE_RESET, CLEAR_LINE); + LOGRST("KBD: Keyboard mcu reset line is cleared\n"); + } + else + { + m_mcu->set_input_line(INPUT_LINE_RESET, ASSERT_LINE); + LOGRST("KBD: Keyboard mcu reset line is asserted\n"); + } +} + +//------------------------------------------------- +// device_start - device specific startup +//------------------------------------------------- + +void alfaskop_s41_keyboard_device::device_start() +{ + m_txd_cb.resolve_safe(); + m_leds_cb.resolve_safe(); + + save_item(NAME(m_rxd_high)); + save_item(NAME(m_txd_high)); + save_item(NAME(m_col_select)); + + m_rxd_high = true; + m_txd_high = true; + m_col_select = 0; +} + + + +//------------------------------------------------- +// device_add_mconfig - add device configuration +//------------------------------------------------- + +void alfaskop_s41_keyboard_device::device_add_mconfig(machine_config &config) +{ + M6802(config, m_mcu, XTAL(3'579'545)); // Crystal verified from schematics + m_mcu->set_addrmap(AS_PROGRAM, &alfaskop_s41_keyboard_device::alfaskop_s41_kb_mem); + + MC6846(config, m_mc6846, XTAL(3'579'545) / 4); // Driven by E from 6802 == XTAL / 4 + m_mc6846->irq().set([this](bool state) + { + LOGIRQ(" [timer IRQ: %s] ", state == ASSERT_LINE ? "asserted" : "cleared"); + m_mcu->set_input_line(M6802_IRQ_LINE, state); + }); + m_mc6846->cp2().set([this](bool state){ LOG("CP2:%d\n", state); }); + // MIA ID interrupt: m_mc6846->set_input_cp1(1); + m_mc6846->cto().set([this](bool state){ LOG("CTO:%d\n", state); }); // Not connected to anything +} + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor alfaskop_s41_keyboard_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( alfaskop_s41_kb ); +} + +//------------------------------------------------- +// ADDRESS_MAP( alfaskop_s41_kb_mem ) +//------------------------------------------------- + +void alfaskop_s41_keyboard_device::alfaskop_s41_kb_mem(address_map &map) +{ + map(0x0000, 0x007f).ram(); // Internal RAM + /* A 32 byte decoder ROM connects A0-A4 to A11, A12, A13, A15 and to an external port pin, A14 is not decoded! + * c3 c3 c3 c3 c3 c3 c3 c3 c3 c3 c3 c3 c3 c3 c3 c3 - if external port pin is low + * c3 c3 c3 c3 c5 c6 cb c3 d3 c3 c3 c3 c3 c3 43 f3 - if external port pin is high - normal operation + * + * Decoder rom byte bits as follows + * 0 - 0x01 Start scanning + * 1 - 0x02 read col + * 2 - 0x04 shift col clock + * 3 - 0x08 set lamp data + * 4 - 0x10 CS1 mc6846 I/O access - active low + * 5 - 0x20 CS0 mc6846 ROM access - active high + * 6 - 0x40 n/c? + * 7 - 0x80 to KBX + * + * F3 <- 0x0f <- 1-11 1 == b800-bfff, f800-ffff // 1111 0011 MC6846 Internal ROM access (CS0 - active high) + * 43 <- 0x0e <- 1-11 0 == b000-b7ff, f000-f7ff // 0100 0011 + * c3 <- 0x0d <- 1-10 1 == a800-afff, e800-efff // 1100 0011 + * c3 <- 0x0c <- 1-10 0 == a000-a7ff, e000-e7ff // 1100 0011 + * c3 <- 0x0b <- 1-01 1 == 9800-9fff, d800-dfff // 1100 0011 + * c3 <- 0x0a <- 1-01 0 == 9000-97ff, d000-d7ff // 1100 0011 + * c3 <- 0x09 <- 1-00 1 == 8800-8fff, c800-cfff // 1100 0011 + * d3 <- 0x08 <- 1-00 0 == 8000-87ff, c000-c7ff // 1101 0011 MC6846 Internal I/O access (CS1 - active high) + + * c3 <- 0x07 <- 0-11 1 == 3800-3fff, 7800-7fff // 1100 0011 + * cb <- 0x06 <- 0-11 0 == 3000-37ff, 7000-77ff // 1100 1011 Set lamp data + * c6 <- 0x05 <- 0-10 1 == 2800-2fff, 6800-6fff // 1100 0110 start scan + * c5 <- 0x04 <- 0-10 0 == 2000-27ff, 6000-67ff // 1100 0101 read col + * c3 <- 0x03 <- 0-01 1 == 1800-1fff, 5800-5fff // 1100 0011 + * c3 <- 0x02 <- 0-01 0 == 1000-17ff, 5000-57ff // 1100 0011 + * c3 <- 0x01 <- 0-00 1 == 0800-0fff, 4800-4fff // 1100 0011 + * c3 <- 0x00 <- 0-00 0 == 0000-07ff, 4000-47ff // 1100 0011 + */ + map(0x0080, 0xffff).lrw8(NAME([this](address_space &space, offs_t offset) -> uint8_t + { + uint16_t addr = offset + 0x80; + uint8_t index = 0x10 | ((((addr & 0x8000) | ((addr & 0x3800) << 1)) >> 12) & 0x000f); // 0x10 | (((A15 | A13 | A12 | A11) >> 12) + uint8_t ret = 0; + LOGADEC("address_r %04x -> index %02x: %02x\n", offset + 0x80, index, memregion("ad_rom")->base ()[index]); + switch (memregion("ad_rom")->base ()[index]) + { + case 0xf3: + ret = memregion(M6800_TAG)->base ()[addr & 0x07ff]; + LOGROM(" - ROM %04x: %02x\n", addr & 0x7ff, ret); + break; + case 0xd3: + LOGIO(" - I/O read mc6846 %04x", addr & 0x07); + ret = m_mc6846->read(space, (offs_t)(addr & 0x07)); + LOGIO(": %02x\n", ret); + break; + case 0xc3: + break; // Idle + default: + logerror(" - unmapped read access at %04x through %02x\n", addr, memregion("ad_rom")->base ()[index]); + } + return ret; + }), + NAME( [this](address_space &space, offs_t offset, uint8_t data) + { + uint16_t addr = offset + 0x80; + uint8_t index = 0x10 | ((((addr & 0x8000) | ((addr & 0x3800) << 1)) >> 12) & 0x000f); // 0x10 | (((A15 | A13 | A12 | A11) >> 12) + LOGADEC("address_w %04x -> index %02x: %02x\n", offset + 0x80, index, memregion("ad_rom")->base ()[index]); + switch (memregion("ad_rom")->base ()[index]) + { + case 0xd3: + LOGIO(" - I/O write mc6846 %04x, %02x\n", addr & 0x07, data); + m_mc6846->write(space, (offs_t)(addr & 0x07), data); + break; + case 0xcb: // Leds + if (m_leds != data) + { + m_leds_cb(data); m_leds = data; + LOGLEDS(" - I/O write LEDs %04x, %02x\n", addr, data); + } + break; + case 0xc3: + break; // Idle + default: + logerror(" - unmapped write access at %04x, %02x through %02x\n", addr, data, memregion("ad_rom")->base ()[index]); + } + })); + // map(0xf800, 0xffff).rom().region(M6800_TAG,0); +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const tiny_rom_entry *alfaskop_s41_keyboard_device::device_rom_region() const +{ + return ROM_NAME( alfaskop_s41_kb ); +} diff --git a/src/mame/machine/alfaskop_s41_kb.h b/src/mame/machine/alfaskop_s41_kb.h new file mode 100644 index 00000000000..8ac29df5f40 --- /dev/null +++ b/src/mame/machine/alfaskop_s41_kb.h @@ -0,0 +1,48 @@ +// license:BSD-3-Clause +// copyright-holders:Joakim Larsson Edström +#ifndef MAME_MACHINE_ALFASKOP_S41_KB_H +#define MAME_MACHINE_ALFASKOP_S41_KB_H + +#pragma once + +#include "cpu/m6800/m6800.h" +#include "machine/mc6846.h" + +DECLARE_DEVICE_TYPE(ALFASKOP_S41_KB, alfaskop_s41_keyboard_device) + +class alfaskop_s41_keyboard_device : public device_t +{ +public: + auto txd_cb() { return m_txd_cb.bind(); } + auto leds_cb() { return m_leds_cb.bind(); } + + alfaskop_s41_keyboard_device(machine_config const &mconfig, char const *tag, device_t *owner, uint32_t clock = 0); + + DECLARE_INPUT_CHANGED_MEMBER(key); + DECLARE_WRITE_LINE_MEMBER(rxd_w); + //DECLARE_WRITE_LINE_MEMBER(hold_w); + DECLARE_WRITE_LINE_MEMBER(rst_line_w); + +protected: + virtual void device_start() override; + virtual void device_add_mconfig(machine_config &config) override; + virtual ioport_constructor device_input_ports() const override; + virtual tiny_rom_entry const *device_rom_region() const override; + + required_device m_mcu; + required_device m_mc6846; + required_ioport_array<6> m_rows; + devcb_write_line m_txd_cb; // Callback for KBD-> S41 + devcb_write8 m_leds_cb; // Callback for all 8 leds -> layout + + bool m_rxd_high; // state of Rx input line + bool m_txd_high; // state of Tx output line + bool m_hold; + uint16_t m_col_select; + uint8_t m_p1; + uint8_t m_leds; + + void alfaskop_s41_kb_mem(address_map &map); +}; + +#endif // MAME_MACHINE_ALFASKOP_S41_KB_H diff --git a/src/tools/jedutil.cpp b/src/tools/jedutil.cpp index 49b5d00cd38..b500e689785 100644 --- a/src/tools/jedutil.cpp +++ b/src/tools/jedutil.cpp @@ -7429,9 +7429,19 @@ static int command_convert(int argc, char *argv[]) /* read the binary data */ err = jedbin_parse(srcbuf, srcbuflen, &jed); - switch (err) + + if (err == JEDERR_INVALID_DATA) { - case JEDERR_INVALID_DATA: fprintf(stderr, "Fatal error: Invalid binary JEDEC file\n"); free(srcbuf); return 1; + fprintf(stderr, "Fatal error: Invalid binary JEDEC file\n"); + free(srcbuf); + return 1; + } + + if (jed.binfmt == DATAIO) // DATAIO is detected and not supported yet, it has swapped inverted/non-inverted line fuses + { + fprintf(stderr, "Fatal error: Unsupported DATAIO PLA format detected\n"); + free(srcbuf); + return 1; } /* print out data */