diff --git a/src/mame/ussr/1515xm031.cpp b/src/mame/ussr/1515xm031.cpp new file mode 100644 index 0000000000000..8044e403ab076 --- /dev/null +++ b/src/mame/ussr/1515xm031.cpp @@ -0,0 +1,452 @@ +// license:BSD-3-Clause +// copyright-holders:Sergey Svishchev +/********************************************************************** + + 1515XM1-031 Gate Array emulation + + Keyboard controller and programmable timer for UKNC + +**********************************************************************/ + +#include "emu.h" +#include "1515xm031.h" +#include "machine/keyboard.ipp" + +//#define VERBOSE (LOG_GENERAL) +#include "logmacro.h" + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +DEFINE_DEVICE_TYPE(K1515XM031_PRI, k1515xm031_pri_device, "1515xm1_031_pri", "1515XM1-031 keyboard") +DEFINE_DEVICE_TYPE(K1515XM031_SUB, k1515xm031_sub_device, "1515xm1_031_sub", "1515XM1-031 timer") + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +INPUT_PORTS_START(ms7007) + PORT_START("Y4") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("") PORT_CODE(KEYCODE_F10) PORT_CHAR(UCHAR_MAMEKEY(F10)) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("Y5") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Keypad ,") PORT_CODE(KEYCODE_ASTERISK) PORT_CHAR(UCHAR_MAMEKEY(ASTERISK)) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Keypad -") PORT_CODE(KEYCODE_MINUS_PAD) PORT_CHAR(UCHAR_MAMEKEY(MINUS_PAD)) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Left Shift") PORT_CODE(KEYCODE_LSHIFT) PORT_CODE(KEYCODE_RSHIFT) PORT_CHAR(UCHAR_SHIFT_1) + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Keypad 7") PORT_CODE(KEYCODE_7_PAD) PORT_CHAR(UCHAR_MAMEKEY(7_PAD)) + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Keypad 8") PORT_CODE(KEYCODE_8_PAD) PORT_CHAR(UCHAR_MAMEKEY(8_PAD)) + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Keypad 9") PORT_CODE(KEYCODE_9_PAD) PORT_CHAR(UCHAR_MAMEKEY(9_PAD)) + + PORT_START("Y6") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("AR2 (Esc)") PORT_CODE(KEYCODE_ESC) PORT_CHAR(UCHAR_MAMEKEY(ESC)) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Tab") PORT_CODE(KEYCODE_TAB) PORT_CHAR('\t') + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Ctrl") PORT_CODE(KEYCODE_LCONTROL) PORT_CHAR(UCHAR_MAMEKEY(LCONTROL)) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Graf") PORT_CODE(KEYCODE_LALT) PORT_CHAR(UCHAR_MAMEKEY(LALT)) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Alf") PORT_CODE(KEYCODE_RALT) PORT_CHAR(UCHAR_MAMEKEY(RALT)) + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Keypad 0") PORT_CODE(KEYCODE_0_PAD) PORT_CHAR(UCHAR_MAMEKEY(0_PAD)) + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Keypad .") PORT_CODE(KEYCODE_DEL_PAD) PORT_CHAR(UCHAR_MAMEKEY(DEL_PAD)) + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Keypad Enter") PORT_CODE(KEYCODE_ENTER_PAD) PORT_CHAR(UCHAR_MAMEKEY(ENTER_PAD)) + + PORT_START("Y7") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_COLON) PORT_CHAR(';') PORT_CHAR('+') + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_J) PORT_CHAR('j') PORT_CHAR('J') PORT_CHAR(0x0a) PORT_CHAR(0x0a) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F) PORT_CHAR('f') PORT_CHAR('F') PORT_CHAR(0x06) PORT_CHAR(0x06) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Q) PORT_CHAR('q') PORT_CHAR('Q') PORT_CHAR(0x11) PORT_CHAR(0x11) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Lock") PORT_CODE(KEYCODE_CAPSLOCK) PORT_CHAR(UCHAR_MAMEKEY(CAPSLOCK)) + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Keypad 1") PORT_CODE(KEYCODE_1_PAD) PORT_CHAR(UCHAR_MAMEKEY(1_PAD)) + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Keypad 2") PORT_CODE(KEYCODE_2_PAD) PORT_CHAR(UCHAR_MAMEKEY(2_PAD)) + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Keypad 3") PORT_CODE(KEYCODE_3_PAD) PORT_CHAR(UCHAR_MAMEKEY(3_PAD)) + + PORT_START("Y8") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("K1") PORT_CODE(KEYCODE_F1) PORT_CHAR(UCHAR_MAMEKEY(F1)) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!') + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_C) PORT_CHAR('c') PORT_CHAR('C') PORT_CHAR(0x03) PORT_CHAR(0x03) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Y) PORT_CHAR('y') PORT_CHAR('Y') PORT_CHAR(0x19) PORT_CHAR(0x19) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Ch") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Keypad 4") PORT_CODE(KEYCODE_4_PAD) PORT_CHAR(UCHAR_MAMEKEY(4_PAD)) + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Keypad 5") PORT_CODE(KEYCODE_5_PAD) PORT_CHAR(UCHAR_MAMEKEY(5_PAD)) + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Keypad 6") PORT_CODE(KEYCODE_6_PAD) PORT_CHAR(UCHAR_MAMEKEY(6_PAD)) + + PORT_START("Y9") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("K2") PORT_CODE(KEYCODE_F2) PORT_CHAR(UCHAR_MAMEKEY(F2)) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('@') + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_U) PORT_CHAR('u') PORT_CHAR('U') PORT_CHAR(0x15) PORT_CHAR(0x15) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_W) PORT_CHAR('w') PORT_CHAR('W') PORT_CHAR(0x17) PORT_CHAR(0x17) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_S) PORT_CHAR('s') PORT_CHAR('S') PORT_CHAR(0x13) PORT_CHAR(0x13) + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Keypad +") PORT_CODE(KEYCODE_PLUS_PAD) PORT_CHAR(UCHAR_MAMEKEY(PLUS_PAD)) + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME(" (Go)") PORT_CODE(KEYCODE_F8) PORT_CHAR(UCHAR_MAMEKEY(F6)) + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME(" (Reset)") PORT_CODE(KEYCODE_F9) PORT_CHAR(UCHAR_MAMEKEY(F7)) + + PORT_START("Y10") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("K3") PORT_CODE(KEYCODE_F3) PORT_CHAR(UCHAR_MAMEKEY(F3)) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('#') + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_K) PORT_CHAR('k') PORT_CHAR('K') PORT_CHAR(0x0b) PORT_CHAR(0x0b) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_A) PORT_CHAR('a') PORT_CHAR('A') PORT_CHAR(0x01) PORT_CHAR(0x01) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_M) PORT_CHAR('m') PORT_CHAR('M') PORT_CHAR(0x0d) PORT_CHAR(0x0d) + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("UTF8_LEFT") PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(8) + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME(" (Setup)") PORT_CODE(KEYCODE_F7) PORT_CHAR(UCHAR_MAMEKEY(F8)) + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME(" (Help)") PORT_CODE(KEYCODE_F6) PORT_CHAR(UCHAR_MAMEKEY(F9)) + + PORT_START("Y11") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$') + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_E) PORT_CHAR('e') PORT_CHAR('E') PORT_CHAR(0x05) PORT_CHAR(0x05) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_P) PORT_CHAR('p') PORT_CHAR('P') PORT_CHAR(0x10) PORT_CHAR(0x10) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_I) PORT_CHAR('i') PORT_CHAR('I') PORT_CHAR(0x09) PORT_CHAR(0x09) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Space") PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ') + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Cursor right") PORT_CODE(KEYCODE_RIGHT) PORT_CHAR(UCHAR_MAMEKEY(RIGHT)) + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Enter") PORT_CODE(KEYCODE_ENTER) PORT_CHAR('\r') + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') PORT_CHAR('?') + + PORT_START("Y12") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("K4") PORT_CODE(KEYCODE_F4) PORT_CHAR(UCHAR_MAMEKEY(F4)) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%') + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_N) PORT_CHAR('n') PORT_CHAR('N') PORT_CHAR(0x0e) PORT_CHAR(0x0e) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_R) PORT_CHAR('r') PORT_CHAR('R') PORT_CHAR(0x12) PORT_CHAR(0x12) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_T) PORT_CHAR('t') PORT_CHAR('T') PORT_CHAR(0x14) PORT_CHAR(0x14) + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Cursor down") PORT_CODE(KEYCODE_DOWN) PORT_CHAR(UCHAR_MAMEKEY(DOWN)) + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Cursor up") PORT_CODE(KEYCODE_UP) PORT_CHAR(UCHAR_MAMEKEY(UP)) + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_QUOTE) PORT_CHAR(':') PORT_CHAR('*') + + PORT_START("Y13") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("K5") PORT_CODE(KEYCODE_F5) PORT_CHAR(UCHAR_MAMEKEY(F5)) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('^') + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_G) PORT_CHAR('g') PORT_CHAR('G') PORT_CHAR(0x07) PORT_CHAR(0x07) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_O) PORT_CHAR('o') PORT_CHAR('O') PORT_CHAR(0x0f) PORT_CHAR(0x0f) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_X) PORT_CHAR('x') PORT_CHAR('X') PORT_CHAR(0x18) PORT_CHAR(0x18) + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR('>') + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME(": hardsign") PORT_CODE(KEYCODE_TILDE) PORT_CHAR('`') PORT_CHAR('~') + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') PORT_CHAR('_') + + PORT_START("Y14") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('&') + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('[') PORT_CHAR('{') + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_L) PORT_CHAR('l') PORT_CHAR('L') PORT_CHAR(0x0c) PORT_CHAR(0x0c) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_B) PORT_CHAR('b') PORT_CHAR('B') PORT_CHAR(0x02) PORT_CHAR(0x02) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Cursor left") PORT_CODE(KEYCODE_LEFT) PORT_CHAR(UCHAR_MAMEKEY(LEFT)) + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR('\\') PORT_CHAR('|') + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_H) PORT_CHAR('h') PORT_CHAR('H') PORT_CHAR(0x08) PORT_CHAR(0x08) + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHAR(')') + + PORT_START("Y15") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('*') + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR(']') PORT_CHAR('}') + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_D) PORT_CHAR('d') PORT_CHAR('D') PORT_CHAR(0x04) PORT_CHAR(0x04) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME(": @") PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('=') PORT_CHAR('+') + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR('<') + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_V) PORT_CHAR('v') PORT_CHAR('V') PORT_CHAR(0x16) PORT_CHAR(0x16) + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Z) PORT_CHAR('z') PORT_CHAR('Z') PORT_CHAR(0x1a) PORT_CHAR(0x1a) + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR('(') +INPUT_PORTS_END + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor k1515xm031_pri_device::device_input_ports() const +{ + return INPUT_PORTS_NAME(ms7007); +} + +//------------------------------------------------- +// k1515xm031_pri_device - constructor +//------------------------------------------------- + +k1515xm031_pri_device::k1515xm031_pri_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, K1515XM031_PRI, tag, owner, clock) + , device_z80daisy_interface(mconfig, *this) + , device_matrix_keyboard_interface(mconfig, *this, "Y4", "Y5", "Y6", "Y7", "Y8", "Y9", "Y10", "Y11", "Y12", "Y13", "Y14", "Y15") + , m_write_virq(*this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void k1515xm031_pri_device::device_start() +{ + // register for state saving + save_item(NAME(m_csr)); + save_item(NAME(m_buf)); + + m_buf = 0; +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void k1515xm031_pri_device::device_reset() +{ + m_csr = 0; + + reset_key_state(); + start_processing(attotime::from_hz(16'000)); +} + +//------------------------------------------------- +// daisy chained interrupts +//------------------------------------------------- + +int k1515xm031_pri_device::z80daisy_irq_state() +{ + if (m_rxrdy == ASSERT_LINE) + return Z80_DAISY_INT; + else + return 0; +} + +int k1515xm031_pri_device::z80daisy_irq_ack() +{ + int vec = -1; + + if (m_rxrdy == ASSERT_LINE) + { + m_rxrdy = CLEAR_LINE; + vec = 0300; + } + + return vec; +} + + +//------------------------------------------------- +// read - register read +//------------------------------------------------- + +uint16_t k1515xm031_pri_device::read(offs_t offset) +{ + uint16_t data = 0; + + switch (offset) + { + case 0: + data = m_csr & KBDCSR_RD; + break; + + case 1: + data = m_buf; + if (!machine().side_effects_disabled()) + { + m_csr &= ~CSR_DONE; + clear_virq(m_write_virq, m_csr, CSR_IE, m_rxrdy); + start_processing(attotime::from_hz(16'000)); + } + break; + + case 2: // KBD_BUS + data = 010000; // indicate that 80-track floppy drive is installed + break; + } + + if (offset) + LOG("%s R %06o == %06o\n", machine().describe_context(), 0177700 + (offset << 1), data); + + return data; +} + + +//------------------------------------------------- +// write - register write +//------------------------------------------------- + +void k1515xm031_pri_device::write(offs_t offset, uint16_t data, uint16_t mem_mask) +{ + switch (offset & 3) + { + case 0: + if ((data & CSR_IE) == 0) + clear_virq(m_write_virq, 1, 1, m_rxrdy); + else if ((m_csr & (CSR_DONE + CSR_IE)) == CSR_DONE) + raise_virq(m_write_virq, 1, 1, m_rxrdy); + m_csr = ((m_csr & ~KBDCSR_WR) | (data & KBDCSR_WR)); + break; + } +} + +void k1515xm031_pri_device::key_make(uint8_t row, uint8_t column) +{ + m_buf = column * 16 + row + 4; + m_csr |= CSR_DONE; + raise_virq(m_write_virq, m_csr, CSR_IE, m_rxrdy); + stop_processing(); +} + +void k1515xm031_pri_device::key_break(uint8_t row, uint8_t column) +{ + m_buf = 128 + row + 4; + m_csr |= CSR_DONE; + raise_virq(m_write_virq, m_csr, CSR_IE, m_rxrdy); + stop_processing(); +} + + +//------------------------------------------------- +// k1515xm031_sub_device - constructor +//------------------------------------------------- + +k1515xm031_sub_device::k1515xm031_sub_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, K1515XM031_SUB, tag, owner, clock) + , device_z80daisy_interface(mconfig, *this) + , m_write_virq(*this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void k1515xm031_sub_device::device_start() +{ + // register for state saving + save_item(NAME(m_csr)); + save_item(NAME(m_buf)); + save_item(NAME(m_value)); + save_item(NAME(m_counter)); + + m_timer = timer_alloc(FUNC(k1515xm031_sub_device::timer_tick), this); + m_timer->adjust(attotime::never, 0, attotime::never); + + m_buf = m_csr = m_value = m_counter = 0; +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void k1515xm031_sub_device::device_reset() +{ + m_csr &= ~(TMRCSR_MODE | TMRCSR_EVNT); +} + +//------------------------------------------------- +// daisy chained interrupts +//------------------------------------------------- + +int k1515xm031_sub_device::z80daisy_irq_state() +{ + if (m_rxrdy == ASSERT_LINE) + return Z80_DAISY_INT; + else + return 0; +} + +int k1515xm031_sub_device::z80daisy_irq_ack() +{ + int vec = -1; + + if (m_rxrdy == ASSERT_LINE) + { + m_rxrdy = CLEAR_LINE; + vec = 0304; + } + + return vec; +} + + +//------------------------------------------------- +// read - register read +//------------------------------------------------- + +uint16_t k1515xm031_sub_device::read(offs_t offset) +{ + uint16_t data = 0; + + switch (offset) + { + case 0: + data = m_csr & TMRCSR_RD; + if (!machine().side_effects_disabled()) + m_csr &= ~TMRCSR_OVF; + break; + + case 2: + data = m_value & TMRBUF_RDWR; + if (!machine().side_effects_disabled()) + { + m_csr &= ~CSR_DONE; + clear_virq(m_write_virq, m_csr, CSR_IE, m_rxrdy); + } + break; + } + + return data; +} + +//------------------------------------------------- +// write - register write +//------------------------------------------------- + +void k1515xm031_sub_device::write(offs_t offset, uint16_t data, uint16_t mem_mask) +{ + LOG("%s W %06o <- %06o & %06o\n", machine().describe_context(), 0177710 + (offset << 1), data, mem_mask); + + switch (offset) + { + case 0: + if (BIT(data, 0)) + { + int period = (data >> 1) & 3; + m_timer->adjust(attotime::from_usec(2 << period), 0, attotime::from_usec(2 << period)); // FIXME 1.92, not 2 usec + LOG("timer set %d usec\n", 2 << period); + } + else + { + m_timer->adjust(attotime::never, 0, attotime::never); + LOG("timer stopped\n"); + } + + if ((data & CSR_IE) == 0) + clear_virq(m_write_virq, 1, 1, m_rxrdy); + else if ((m_csr & (CSR_DONE + CSR_IE)) == CSR_DONE) + raise_virq(m_write_virq, 1, 1, m_rxrdy); + + m_csr = ((m_csr & ~TMRCSR_WR) | (data & TMRCSR_WR)); + break; + + case 1: + m_buf = data & TMRBUF_RDWR; + if (!BIT(m_csr, 0)) + m_value = m_counter = m_buf; + break; + } +} + +TIMER_CALLBACK_MEMBER(k1515xm031_sub_device::timer_tick) +{ + if (m_counter) + { + if (--m_counter == 0) + { + if (m_csr & CSR_DONE) + { + m_csr |= TMRCSR_OVF; + } + m_csr |= CSR_DONE; + LOG("timer done ovf %d irq %d\n", m_csr & TMRCSR_OVF, m_csr & CSR_IE); + raise_virq(m_write_virq, m_csr, CSR_IE, m_rxrdy); + m_value = m_counter = m_buf; + } + else + { + m_value = m_counter; + } + } +} diff --git a/src/mame/ussr/1515xm031.h b/src/mame/ussr/1515xm031.h new file mode 100644 index 0000000000000..3ce31aa7c9b2e --- /dev/null +++ b/src/mame/ussr/1515xm031.h @@ -0,0 +1,114 @@ +// license:BSD-3-Clause +// copyright-holders:Sergey Svishchev +/********************************************************************** + + 1515XM1-031 Gate Array emulation + +**********************************************************************/ + +#ifndef MAME_USSR_1515XM031_H +#define MAME_USSR_1515XM031_H + +#pragma once + +#include "machine/keyboard.h" +#include "machine/pdp11.h" +#include "machine/z80daisy.h" + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> k1515xm031_device + +class k1515xm031_pri_device : public device_t, + public device_z80daisy_interface, + protected device_matrix_keyboard_interface<12U> +{ +public: + // construction/destruction + k1515xm031_pri_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + auto virq_wr_callback() { return m_write_virq.bind(); } + + uint16_t read(offs_t offset); + void write(offs_t offset, uint16_t data, uint16_t mem_mask); + +protected: + // device-level overrides + virtual void device_start() override ATTR_COLD; + virtual void device_reset() override ATTR_COLD; + virtual ioport_constructor device_input_ports() const override ATTR_COLD; + + // device_z80daisy_interface overrides + virtual int z80daisy_irq_state() override; + virtual int z80daisy_irq_ack() override; + virtual void z80daisy_irq_reti() override {}; + + virtual void key_make(uint8_t row, uint8_t column) override; + virtual void key_break(uint8_t row, uint8_t column) override; + +private: + static constexpr uint16_t KBDCSR_RD = CSR_DONE | CSR_IE; + static constexpr uint16_t KBDCSR_WR = CSR_IE; + + devcb_write_line m_write_virq; + line_state m_rxrdy; + + uint16_t m_csr; + uint16_t m_buf; +}; + + +class k1515xm031_sub_device : public device_t, + public device_z80daisy_interface +{ +public: + // construction/destruction + k1515xm031_sub_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + auto virq_wr_callback() { return m_write_virq.bind(); } + + uint16_t read(offs_t offset); + void write(offs_t offset, uint16_t data, uint16_t mem_mask = ~0); + +protected: + // device-level overrides + virtual void device_start() override ATTR_COLD; + virtual void device_reset() override ATTR_COLD; + + // device_z80daisy_interface overrides + virtual int z80daisy_irq_state() override; + virtual int z80daisy_irq_ack() override; + virtual void z80daisy_irq_reti() override {}; + +private: + static constexpr uint16_t TMRCSR_MODE = 0001; + static constexpr uint16_t TMRCSR_FREQ = 0002; + static constexpr uint16_t TMRCSR_OVF = 0010; + static constexpr uint16_t TMRCSR_EIE = 0020; + static constexpr uint16_t TMRCSR_EVNT = 0040; + static constexpr uint16_t TMRCSR_RD = 0377; + static constexpr uint16_t TMRCSR_WR = (CSR_IE | TMRCSR_EIE | TMRCSR_FREQ | TMRCSR_MODE); + + static constexpr uint16_t TMRBUF_RDWR = 07777; + + devcb_write_line m_write_virq; + + line_state m_rxrdy; + uint16_t m_csr; + uint16_t m_buf; + uint16_t m_value; + uint16_t m_counter; + + emu_timer *m_timer; + TIMER_CALLBACK_MEMBER(timer_tick); +}; + + +// device type definition +DECLARE_DEVICE_TYPE(K1515XM031_PRI, k1515xm031_pri_device) +DECLARE_DEVICE_TYPE(K1515XM031_SUB, k1515xm031_sub_device) + +#endif // MAME_USSR_1515XM031_H diff --git a/src/mame/ussr/1801vp120.cpp b/src/mame/ussr/1801vp120.cpp new file mode 100644 index 0000000000000..c9348f27d7c1c --- /dev/null +++ b/src/mame/ussr/1801vp120.cpp @@ -0,0 +1,410 @@ +// license:BSD-3-Clause +// copyright-holders:Sergey Svishchev +/********************************************************************** + + 1801VP1-120 Gate Array emulation + + Inter-processor bridge for UKNC + + https://github.com/1801BM1/k1801/blob/master/120 + +**********************************************************************/ + +#include "emu.h" +#include "1801vp120.h" + +//#define VERBOSE (LOG_GENERAL) +#include "logmacro.h" + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +DEFINE_DEVICE_TYPE(K1801VP120_PRI, k1801vp120_pri_device, "1801vp1_120_pri", "1801VP1-120 maincpu") +DEFINE_DEVICE_TYPE(K1801VP120_SUB, k1801vp120_sub_device, "1801vp1_120_sub", "1801VP1-120 subcpu") + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// k1801vp120_pri_device - constructor +//------------------------------------------------- + +k1801vp120_pri_device::k1801vp120_pri_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, K1801VP120_PRI, tag, owner, clock) + , device_z80daisy_interface(mconfig, *this) + , m_write_reset(*this) + , m_write_virq(*this) + , m_write_ack(*this) + , m_write_out(*this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void k1801vp120_pri_device::device_start() +{ + // register for state saving FIXME + save_item(NAME(m_channel[0].rcsr)); + save_item(NAME(m_channel[0].rbuf)); + save_item(NAME(m_channel[0].tcsr)); + save_item(NAME(m_channel[0].tbuf)); + save_item(NAME(m_channel[1].rcsr)); + save_item(NAME(m_channel[1].rbuf)); + save_item(NAME(m_channel[1].tcsr)); + save_item(NAME(m_channel[1].tbuf)); + save_item(NAME(m_channel[2].tcsr)); + save_item(NAME(m_channel[2].tbuf)); + + memset(m_channel, 0, sizeof(m_channel)); + m_channel[1].channel = 1; + m_channel[2].channel = 2; +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void k1801vp120_pri_device::device_reset() +{ + m_channel[0].tcsr = m_channel[1].tcsr = m_channel[2].tcsr = CSR_DONE; + m_channel[0].rcsr = m_channel[1].rcsr = m_channel[2].rcsr = 0; + + m_write_reset(ASSERT_LINE); +} + +//------------------------------------------------- +// daisy chained interrupts +//------------------------------------------------- + +int k1801vp120_pri_device::z80daisy_irq_state() +{ + if ((m_channel[0].rxrdy | m_channel[1].rxrdy | m_channel[0].txrdy | m_channel[1].txrdy | + m_channel[2].txrdy) == ASSERT_LINE) + return Z80_DAISY_INT; + else + return 0; +} + +int k1801vp120_pri_device::z80daisy_irq_ack() +{ + int vec = -1; + + if (m_channel[0].rxrdy == ASSERT_LINE) + { + m_channel[0].rxrdy = CLEAR_LINE; + vec = 060; + } + else if (m_channel[0].txrdy == ASSERT_LINE) + { + m_channel[0].txrdy = CLEAR_LINE; + vec = 064; + } + else if (m_channel[1].rxrdy == ASSERT_LINE) + { + m_channel[1].rxrdy = CLEAR_LINE; + vec = 0460; + } + else if (m_channel[1].txrdy == ASSERT_LINE) + { + m_channel[1].txrdy = CLEAR_LINE; + vec = 0464; + } + else if (m_channel[2].txrdy == ASSERT_LINE) + { + m_channel[2].txrdy = CLEAR_LINE; + vec = 0474; + } + + return vec; +} + + +//------------------------------------------------- +// read - register read +//------------------------------------------------- + +uint16_t k1801vp120_pri_device::channel_read(struct xchannel *ch, offs_t offset) +{ + uint16_t data = 0; + + switch (offset) + { + case DLRCSR: + data = ch->rcsr & DLxCSR_RD; + break; + + case DLRBUF: + data = ch->rbuf; + if (!machine().side_effects_disabled()) + { + ch->rcsr &= ~CSR_DONE; + clear_virq(m_write_virq, ch->rcsr, CSR_IE, ch->rxrdy); + if (ch->channel == 0 || ch->channel == 1) + m_write_ack[ch->channel](ASSERT_LINE); + } + break; + + case DLTCSR: + data = ch->tcsr & DLxCSR_RD; + break; + } + + LOG("%s R ch %d %06o == %06o\n", machine().describe_context(), ch->channel, (offset << 1), data); + + return data; +} + +//------------------------------------------------- +// write - register write +//------------------------------------------------- + +void k1801vp120_pri_device::channel_write(struct xchannel *ch, offs_t offset, uint16_t data, uint16_t mem_mask) +{ + LOG("%s W ch %d %06o <- %06o & %06o\n", machine().describe_context(), ch->channel, (offset << 1), data, mem_mask); + + switch (offset) + { + case DLRCSR: + if ((data & CSR_IE) == 0) + { + clear_virq(m_write_virq, 1, 1, ch->rxrdy); + } + else if ((ch->rcsr & (CSR_DONE + CSR_IE)) == CSR_DONE) + { + raise_virq(m_write_virq, 1, 1, ch->rxrdy); + } + ch->rcsr = ((ch->rcsr & ~DLxCSR_WR) | (data & DLxCSR_WR)); + break; + + case DLTCSR: + if ((data & CSR_IE) == 0) + { + clear_virq(m_write_virq, 1, 1, ch->txrdy); + } + else if ((ch->tcsr & (CSR_DONE + CSR_IE)) == CSR_DONE) + { + raise_virq(m_write_virq, 1, 1, ch->txrdy); + } + ch->tcsr = ((ch->tcsr & ~DLxCSR_WR) | (data & DLxCSR_WR)); + break; + + case DLTBUF: + ch->tcsr &= ~CSR_DONE; + clear_virq(m_write_virq, ch->tcsr, CSR_IE, ch->txrdy); + m_write_out[ch->channel](data); + break; + } +} + +//------------------------------------------------- +// k1801vp120_sub_device - constructor +//------------------------------------------------- + +k1801vp120_sub_device::k1801vp120_sub_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, K1801VP120_SUB, tag, owner, clock) + , device_z80daisy_interface(mconfig, *this) + , m_ppi(*this, "ppi") + , m_write_virq(*this) + , m_write_ack(*this) + , m_write_out(*this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void k1801vp120_sub_device::device_start() +{ + // register for state saving + save_item(NAME(m_channel[0].rbuf)); + save_item(NAME(m_channel[0].tbuf)); + save_item(NAME(m_channel[1].rbuf)); + save_item(NAME(m_channel[1].tbuf)); + save_item(NAME(m_channel[2].rbuf)); + + m_reset = CLEAR_LINE; +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void k1801vp120_sub_device::device_reset() +{ + memset(m_channel, 0, sizeof(m_channel)); + + m_rcsr = 0; + m_tcsr = PPTCSR_1DONE | PPTCSR_0DONE; +} + +//------------------------------------------------- +// device_add_mconfig - add device configuration +//------------------------------------------------- +void k1801vp120_sub_device::device_add_mconfig(machine_config &config) +{ + // FIXME has to be byte-addressable without byte-wide insns + I8255(config, m_ppi); + m_ppi->out_pa_callback().set("printdata", FUNC(output_latch_device::write)); + m_ppi->in_pb_callback().set("printctrl", FUNC(input_buffer_device::read)); + m_ppi->out_pc_callback().set("centronics", FUNC(centronics_device::write_strobe)); + + centronics_device ¢ronics(CENTRONICS(config, "centronics", centronics_devices, "printer")); + centronics.set_output_latch(OUTPUT_LATCH(config, "printdata")); + centronics.set_data_input_buffer(INPUT_BUFFER(config, "printctrl")); + centronics.perror_handler().set("printctrl", FUNC(input_buffer_device::write_bit0)); + centronics.select_handler().set("printctrl", FUNC(input_buffer_device::write_bit1)); + centronics.fault_handler().set("printctrl", FUNC(input_buffer_device::write_bit3)); + centronics.busy_handler().set("printctrl", FUNC(input_buffer_device::write_bit7)); +} + +//------------------------------------------------- +// daisy chained interrupts +//------------------------------------------------- + +int k1801vp120_sub_device::z80daisy_irq_state() +{ + if ((m_channel[0].rxrdy | m_channel[1].rxrdy | m_channel[2].rxrdy | m_channel[0].txrdy | + m_channel[1].txrdy | m_reset) == ASSERT_LINE) + return Z80_DAISY_INT; + else + return 0; +} + +int k1801vp120_sub_device::z80daisy_irq_ack() +{ + int vec = -1; + + if (m_reset == ASSERT_LINE) + { + m_reset = CLEAR_LINE; + vec = 0314; + } + else if (m_channel[0].rxrdy == ASSERT_LINE) + { + m_channel[0].rxrdy = CLEAR_LINE; + vec = 0320; + } + else if (m_channel[0].txrdy == ASSERT_LINE) + { + m_channel[0].txrdy = CLEAR_LINE; + vec = 0324; + } + else if (m_channel[1].rxrdy == ASSERT_LINE) + { + m_channel[1].rxrdy = CLEAR_LINE; + vec = 0330; + } + else if (m_channel[1].txrdy == ASSERT_LINE) + { + m_channel[1].txrdy = CLEAR_LINE; + vec = 0334; + } + else if (m_channel[2].rxrdy == ASSERT_LINE) + { + m_channel[2].rxrdy = CLEAR_LINE; + vec = 0340; + } + + return vec; +} + + +//------------------------------------------------- +// read - register read +//------------------------------------------------- + +uint16_t k1801vp120_sub_device::read(offs_t offset) +{ + uint16_t data = 0; + + switch (offset) + { + case 0: case 1: case 2: + data = m_channel[offset].rbuf; + if (!machine().side_effects_disabled()) + { + clear_virq(m_write_virq, m_rcsr, (PPRCSR_0IE << offset), m_channel[offset].rxrdy); + m_write_ack[offset](ASSERT_LINE); + m_rcsr &= ~(PPRCSR_0RDY << offset); + } + break; + + case 3: + data = m_rcsr & PPRCSR_RD; + break; + + case 7: + data = m_tcsr & PPTCSR_RD; + break; + } + + LOG("%s R %06o == %06o\n", machine().describe_context(), 0177060 + (offset << 1), data); + + return data; +} + +//------------------------------------------------- +// write - register write +//------------------------------------------------- + +void k1801vp120_sub_device::write(offs_t offset, uint16_t data, uint16_t mem_mask) +{ + LOG("%s W %06o <- %06o & %06o\n", machine().describe_context(), 0177060 + (offset << 1), data, mem_mask); + + switch (offset) + { + case 3: + if ((data & PPRCSR_0IE) == 0) + clear_virq(m_write_virq, 1, 1, m_channel[0].rxrdy); + else if ((m_rcsr & (PPRCSR_0RDY + PPRCSR_0IE)) == PPRCSR_0RDY) + m_channel[0].rxrdy = (ASSERT_LINE); + + if ((data & PPRCSR_1IE) == 0) + clear_virq(m_write_virq, 1, 1, m_channel[1].rxrdy); + else if ((m_rcsr & (PPRCSR_1RDY + PPRCSR_1IE)) == PPRCSR_1RDY) + m_channel[1].rxrdy = (ASSERT_LINE); + + if ((data & PPRCSR_2IE) == 0) + clear_virq(m_write_virq, 1, 1, m_channel[2].rxrdy); + else if ((m_rcsr & (PPRCSR_2RDY + PPRCSR_2IE)) == PPRCSR_2RDY) + m_channel[2].rxrdy = (ASSERT_LINE); + + m_rcsr = ((m_rcsr & ~PPRCSR_WR) | (data & PPRCSR_WR)); + break; + + case 4: + m_write_out[0](data); + clear_virq(m_write_virq, m_tcsr, PPTCSR_0IE, m_channel[0].txrdy); + break; + + case 5: + m_write_out[1](data); + clear_virq(m_write_virq, m_tcsr, PPTCSR_1IE, m_channel[1].txrdy); + break; + + case 7: + if ((data & PPTCSR_0IE) == 0) + clear_virq(m_write_virq, 1, 1, m_channel[0].txrdy); + else if ((m_tcsr & (PPTCSR_0DONE + PPTCSR_0IE)) == PPTCSR_0DONE) + raise_virq(m_write_virq, 1, 1, m_channel[0].txrdy); + + if ((data & PPTCSR_1IE) == 0) + clear_virq(m_write_virq, 1, 1, m_channel[1].txrdy); + else if ((m_tcsr & (PPTCSR_1DONE + PPTCSR_1IE)) == PPTCSR_1DONE) + raise_virq(m_write_virq, 1, 1, m_channel[1].txrdy); + + m_tcsr = ((m_tcsr & ~PPTCSR_WR) | (data & PPTCSR_WR)); + break; + } +} diff --git a/src/mame/ussr/1801vp120.h b/src/mame/ussr/1801vp120.h new file mode 100644 index 0000000000000..f5bbe1119e962 --- /dev/null +++ b/src/mame/ussr/1801vp120.h @@ -0,0 +1,176 @@ +// license:BSD-3-Clause +// copyright-holders:Sergey Svishchev +/********************************************************************** + + 1801VP1-120 Gate Array emulation + +**********************************************************************/ + +#ifndef MAME_USSR_1801VP120_H +#define MAME_USSR_1801VP120_H + +#pragma once + +#include "bus/centronics/ctronics.h" +#include "machine/i8255.h" +#include "machine/pdp11.h" +#include "machine/z80daisy.h" + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> k1801vp120_device + +class k1801vp120_pri_device : public device_t, + public device_z80daisy_interface +{ +public: + // construction/destruction + k1801vp120_pri_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + auto virq_wr_callback() { return m_write_virq.bind(); } + auto reset_wr_callback() { return m_write_reset.bind(); } + template auto ack_wr_callback() { return m_write_ack[ch].bind(); } + template auto out_wr_callback() { return m_write_out[ch].bind(); } + + template auto write_data(uint8_t data) + { + m_channel[ch].rbuf = data; m_channel[ch].rcsr |= CSR_DONE; + raise_virq(m_write_virq, m_channel[ch].rcsr, CSR_IE, m_channel[ch].rxrdy); + } + template auto write_ack(int state) + { + m_channel[ch].tcsr |= CSR_DONE; + raise_virq(m_write_virq, m_channel[ch].tcsr, CSR_IE, m_channel[ch].txrdy); + } + + template uint16_t read(offs_t offset) { return channel_read(&m_channel[ch], offset & 3); } + template void write(offs_t offset, uint16_t data, uint16_t mem_mask = ~0) { channel_write(&m_channel[ch], offset & 3, data, mem_mask); } + +protected: + // device-level overrides + virtual void device_start() override ATTR_COLD; + virtual void device_reset() override ATTR_COLD; + + // device_z80daisy_interface overrides + virtual int z80daisy_irq_state() override; + virtual int z80daisy_irq_ack() override; + virtual void z80daisy_irq_reti() override {}; + +private: + enum + { + DLRCSR = 0, + DLRBUF, + DLTCSR, + DLTBUF + }; + + static constexpr uint16_t DLxCSR_RD = CSR_DONE | CSR_IE; + static constexpr uint16_t DLxCSR_WR = CSR_IE; + + struct xchannel + { + int channel; + uint16_t rcsr; + uint16_t rbuf; + uint16_t tcsr; + uint16_t tbuf; + line_state rxrdy; + line_state txrdy; + } m_channel[3]; + + devcb_write_line m_write_reset; + devcb_write_line m_write_virq; + devcb_write_line::array<2> m_write_ack; + devcb_write8::array<3> m_write_out; + + uint16_t channel_read(struct xchannel *ch, offs_t offset); + void channel_write(struct xchannel *ch, offs_t offset, uint16_t data, uint16_t mem_mask); +}; + + +class k1801vp120_sub_device : public device_t, + public device_z80daisy_interface +{ +public: + // construction/destruction + k1801vp120_sub_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + auto virq_wr_callback() { return m_write_virq.bind(); } + template auto ack_wr_callback() { return m_write_ack[ch].bind(); } + template auto out_wr_callback() { return m_write_out[ch].bind(); } + + auto write_reset(int state) { raise_virq(m_write_virq, m_rcsr, PPRCSR_RIE, m_reset); } + template auto write_data(uint8_t data) + { + m_channel[ch].rbuf = data; m_rcsr |= (PPRCSR_0RDY << ch); + raise_virq(m_write_virq, m_rcsr, (PPRCSR_0IE << ch), m_channel[ch].rxrdy); + } + template auto write_ack(int state) + { + m_tcsr |= (PPTCSR_0DONE << ch); + raise_virq(m_write_virq, m_tcsr, (PPTCSR_0IE << ch), m_channel[ch].txrdy); + } + + uint16_t read(offs_t offset); + void write(offs_t offset, uint16_t data, uint16_t mem_mask = ~0); + +protected: + // device-level overrides + virtual void device_start() override ATTR_COLD; + virtual void device_reset() override ATTR_COLD; + virtual void device_add_mconfig(machine_config &config) override ATTR_COLD; + + // device_z80daisy_interface overrides + virtual int z80daisy_irq_state() override; + virtual int z80daisy_irq_ack() override; + virtual void z80daisy_irq_reti() override {}; + +private: + static constexpr uint16_t PPTCSR_1DONE = 0000020; + static constexpr uint16_t PPTCSR_0DONE = 0000010; + static constexpr uint16_t PPTCSR_0UNMAP = 0000004; + static constexpr uint16_t PPTCSR_1IE = 0000002; + static constexpr uint16_t PPTCSR_0IE = 0000001; + static constexpr uint16_t PPTCSR_RD = (PPTCSR_1DONE | PPTCSR_0DONE | PPTCSR_1IE | PPTCSR_0IE); + static constexpr uint16_t PPTCSR_WR = (PPTCSR_0UNMAP | PPTCSR_1IE | PPTCSR_0IE); + + static constexpr uint16_t PPRCSR_RIE = 0000100; + static constexpr uint16_t PPRCSR_2RDY = 0000040; + static constexpr uint16_t PPRCSR_1RDY = 0000020; + static constexpr uint16_t PPRCSR_0RDY = 0000010; + static constexpr uint16_t PPRCSR_2IE = 0000004; + static constexpr uint16_t PPRCSR_1IE = 0000002; + static constexpr uint16_t PPRCSR_0IE = 0000001; + static constexpr uint16_t PPRCSR_RD = (PPRCSR_RIE | PPRCSR_2RDY | PPRCSR_1RDY | PPRCSR_0RDY | PPRCSR_2IE | PPRCSR_1IE | PPRCSR_0IE); + static constexpr uint16_t PPRCSR_WR = (PPRCSR_RIE | PPRCSR_2IE | PPRCSR_1IE | PPRCSR_0IE); + + struct xchannel + { + uint16_t rbuf; + uint16_t tbuf; + line_state rxrdy; + line_state txrdy; + } m_channel[3]; + + required_device m_ppi; + + devcb_write_line m_write_virq; + devcb_write_line::array<3> m_write_ack; + devcb_write8::array<2> m_write_out; + + line_state m_reset; + + uint16_t m_rcsr; + uint16_t m_tcsr; +}; + + +// device type definition +DECLARE_DEVICE_TYPE(K1801VP120_PRI, k1801vp120_pri_device) +DECLARE_DEVICE_TYPE(K1801VP120_SUB, k1801vp120_sub_device) + +#endif // MAME_USSR_1801VP120_H diff --git a/src/mame/ussr/orion.cpp b/src/mame/ussr/orion.cpp index a54cd7b03ae17..b764eb196cddc 100644 --- a/src/mame/ussr/orion.cpp +++ b/src/mame/ussr/orion.cpp @@ -372,9 +372,9 @@ ROM_END // YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS COMP( 1990, orion128, 0, 0, orion128, radio86, orion_state, empty_init, "", "Orion 128", MACHINE_SUPPORTS_SAVE ) -COMP( 1990, orionms, orion128, 0, orion128ms, ms7007, orion_state, empty_init, "", "Orion 128 (MS7007)", MACHINE_SUPPORTS_SAVE ) +COMP( 1990, orionms, orion128, 0, orion128ms, rk7007, orion_state, empty_init, "", "Orion 128 (MS7007)", MACHINE_SUPPORTS_SAVE ) COMP( 1990, orionz80, orion128, 0, orionz80, radio86, orion_z80_state, empty_init, "", "Orion 128 + Z80 Card II", MACHINE_SUPPORTS_SAVE ) COMP( 1990, orionide, orion128, 0, orionz80, radio86, orion_z80_state, empty_init, "", "Orion 128 + Z80 Card II + IDE", MACHINE_SUPPORTS_SAVE ) -COMP( 1990, orionzms, orion128, 0, orionz80ms, ms7007, orion_z80_state, empty_init, "", "Orion 128 + Z80 Card II (MS7007)", MACHINE_SUPPORTS_SAVE ) -COMP( 1990, orionidm, orion128, 0, orionz80ms, ms7007, orion_z80_state, empty_init, "", "Orion 128 + Z80 Card II + IDE (MS7007)", MACHINE_SUPPORTS_SAVE ) +COMP( 1990, orionzms, orion128, 0, orionz80ms, rk7007, orion_z80_state, empty_init, "", "Orion 128 + Z80 Card II (MS7007)", MACHINE_SUPPORTS_SAVE ) +COMP( 1990, orionidm, orion128, 0, orionz80ms, rk7007, orion_z80_state, empty_init, "", "Orion 128 + Z80 Card II + IDE (MS7007)", MACHINE_SUPPORTS_SAVE ) COMP( 1994, orionpro, orion128, 0, orionpro, radio86, orion_pro_state, empty_init, "", "Orion Pro", MACHINE_SUPPORTS_SAVE ) diff --git a/src/mame/ussr/radio86.cpp b/src/mame/ussr/radio86.cpp index a6d31ed570151..a85f2ace97cab 100644 --- a/src/mame/ussr/radio86.cpp +++ b/src/mame/ussr/radio86.cpp @@ -304,7 +304,8 @@ INPUT_PORTS_START( kr03 ) PORT_BIT(0x00, IP_ACTIVE_LOW, IPT_UNUSED) INPUT_PORTS_END -INPUT_PORTS_START( ms7007 ) +// keyboard module is MS7007, originally designed for UKNC +INPUT_PORTS_START( rk7007 ) PORT_START("LINE0") PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_0) PORT_CHAR(' ') PORT_CHAR('0') PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_9) PORT_CHAR(')') PORT_CHAR('9') @@ -697,7 +698,7 @@ COMP( 1986, radio4k, radio86, 0, radio86, radio86, radio86_state, init_ra COMP( 1986, radiorom, radio86, 0, radiorom, radio86, radio86_state, init_radio86, "", "Radio-86RK (ROM-Disk)", MACHINE_SUPPORTS_SAVE ) COMP( 1986, radioram, radio86, 0, radioram, radio86, radio86_state, init_radioram, "", "Radio-86RK (ROM/RAM Disk)", MACHINE_SUPPORTS_SAVE ) COMP( 1986, spektr01, radio86, 0, radio86, radio86, radio86_state, init_radio86, "", "Spektr-001", MACHINE_SUPPORTS_SAVE ) -COMP( 1986, rk7007, radio86, 0, rk7007, ms7007, radio86_state, init_radio86, "", "Radio-86RK (MS7007)", MACHINE_SUPPORTS_SAVE ) -COMP( 1986, rk700716, radio86, 0, rk700716, ms7007, radio86_state, init_radio86, "", "Radio-86RK (MS7007 16K RAM)", MACHINE_SUPPORTS_SAVE ) +COMP( 1986, rk7007, radio86, 0, rk7007, rk7007, radio86_state, init_radio86, "", "Radio-86RK (MS7007)", MACHINE_SUPPORTS_SAVE ) +COMP( 1986, rk700716, radio86, 0, rk700716, rk7007, radio86_state, init_radio86, "", "Radio-86RK (MS7007 16K RAM)", MACHINE_SUPPORTS_SAVE ) COMP( 1986, mikron2, radio86, 0, mikron2, radio86, radio86_state, init_radio86, "", "Mikron-2", MACHINE_SUPPORTS_SAVE ) COMP( 1986, impuls03, radio86, 0, impuls03, radio86, radio86_state, init_radio86, "", "Impuls-03", MACHINE_SUPPORTS_SAVE ) diff --git a/src/mame/ussr/radio86.h b/src/mame/ussr/radio86.h index c8942e276f7ce..0f5bdf00a0e6d 100644 --- a/src/mame/ussr/radio86.h +++ b/src/mame/ussr/radio86.h @@ -115,6 +115,6 @@ class radio86_state : public driver_device /*----------- defined in drivers/radio86.c -----------*/ INPUT_PORTS_EXTERN( radio86 ); -INPUT_PORTS_EXTERN( ms7007 ); +INPUT_PORTS_EXTERN( rk7007 ); #endif // MAME_USSR_RADIO86_H diff --git a/src/mame/ussr/uknc.cpp b/src/mame/ussr/uknc.cpp index 115ada27fc3da..97b64bf2b48c2 100644 --- a/src/mame/ussr/uknc.cpp +++ b/src/mame/ussr/uknc.cpp @@ -1,29 +1,78 @@ // license:BSD-3-Clause -// copyright-holders:Miodrag Milanovic +// copyright-holders:Miodrag Milanovic, Sergey Svishchev /*************************************************************************** UKNC (Educational Computer by Scientific Centre) PDP-11 clone. Also known as Elektronika MS-0511. -RAM = 192K (CPU 1 = 64K, CPU 2 = 32K, Videoram = 96K), ROM = 32K. +RAM = 192K (CPU 1 = 128K, CPU 2 = 64K), ROM = 32K. Graphics 640x288 pixels. 2009-05-12 Skeleton driver. -Status: both CPUs start in the weeds. +First half of each CPU's memory is mapped into address space for use by OS; +and second is reachable via register I/O, for use as VRAM. + +CPU 1 memory is treated as bit plane 0, CPU 2 -- as planes 1 and 2. + ****************************************************************************/ #include "emu.h" + +#include "1515xm031.h" +#include "1801vp120.h" #include "bus/qbus/qbus.h" +#include "bus/rs232/rs232.h" #include "cpu/t11/t11.h" #include "imagedev/cassette.h" +#include "imagedev/floppy.h" +#include "machine/bankdev.h" +#include "machine/dl11.h" +#include "machine/timer.h" +#include "sound/dac.h" +#include "speaker.h" #include "emupal.h" #include "screen.h" +#define LOG_VRAM (1U << 1) +#define LOG_DEBUG (1U << 2) + +//#define VERBOSE (LOG_GENERAL) +#include "logmacro.h" + +#define LOGVRAM(...) LOGMASKED(LOG_VRAM, __VA_ARGS__) +#define LOGDBG(...) LOGMASKED(LOG_DEBUG, __VA_ARGS__) + + namespace { +// video parameters +static constexpr int UKNC_TOTAL_HORZ = 800; +static constexpr int UKNC_DISP_HORZ = 640; +static constexpr int UKNC_HORZ_START = 80; + +static constexpr int UKNC_TOTAL_VERT = 312; +static constexpr int UKNC_DISP_VERT = 288; // 12 top sysline + 24*11 text area + 12 bottom sysline +static constexpr int UKNC_VERT_START = 19; +static constexpr int UKNC_MAX_VERT = 288 + 19; + + +typedef struct +{ + uint16_t addr; + bool cursor; + uint32_t aux; + bool color; + bool control; + bool cursor_type; + int cursor_color; + int cursor_octet; + int cursor_pixel; +} uknc_scanline; + + class uknc_state : public driver_device { public: @@ -31,9 +80,23 @@ class uknc_state : public driver_device : driver_device(mconfig, type, tag) , m_maincpu(*this, "maincpu") , m_subcpu(*this, "subcpu") + , m_channel(*this, "channel") + , m_subchan(*this, "subchan") + , m_keyboard(*this, "keyboard") + , m_timer(*this, "timer") , m_qbus(*this, "qbus") + , m_s2(*this, "s2") + , m_rs232(*this, "rs232") , m_cart(*this, "cart") , m_cassette(*this, "cassette") + , m_dac(*this, "dac") + , m_yrgb(*this, "yrgb") + , m_palette(*this, "palette") + , m_screen(*this, "screen") + , m_ram(*this, "maincpu") + , m_view_main(*this, "view_main") + , m_view_cart(*this, "view_cart") + , m_view_rom(*this, "view_rom") { } void uknc(machine_config &config); @@ -42,64 +105,861 @@ class uknc_state : public driver_device virtual void machine_reset() override ATTR_COLD; virtual void machine_start() override ATTR_COLD; uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); + + void screen_vblank(int state); + TIMER_DEVICE_CALLBACK_MEMBER(scanline_callback); + + void uknc_mem(address_map &map) ATTR_COLD; + void uknc_sub_mem(address_map &map) ATTR_COLD; + + void reset_w(int state); + void reset_sub_w(int state); + + uint16_t trap_r(offs_t offset); + void trap_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0); + + uint16_t maincpu_vram_addr_r(); + void maincpu_vram_addr_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0); + uint16_t maincpu_vram_data_r(); + void maincpu_vram_data_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0); + + uint16_t bcsr_r(); + void bcsr_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0); + uint16_t scsr_r(); + void scsr_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0); + + uint16_t vram_addr_r(); + void vram_addr_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0); + uint16_t vram_data_pl0_r(); + void vram_data_pl0_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0); + uint16_t vram_data_p12_r(); + void vram_data_p12_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0); + uint16_t sprite_r(offs_t offset); + void sprite_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0); + + // subcpu registers + uint16_t m_bcsr; // 177054 + uint16_t m_scsr; // 177716 + + // video + struct + { + uint16_t vram_addr; + uint16_t vram_data_pl0; + uint16_t vram_data_p12; + uint16_t maincpu_vram_addr; + uint16_t maincpu_vram_data; + uint8_t foreground; // 177016 + uint32_t background; // 177020 + uint8_t sprite_mask; // 177024 + uint8_t plane_mask; // 177026 + uint32_t control; + uint32_t palette; + } m_video; + std::unique_ptr m_scanlines; + bitmap_rgb32 m_tmpbmp; + int m_odt_map; + + void uknc_palette(palette_device &palette) const; + void set_palette_yrgb(uint32_t aux); + void set_palette_ygrb(uint32_t aux); + void set_palette__rgb(uint32_t aux); + void set_palette_gray(uint32_t aux); + void update_displaylist(); + void draw_scanline(uint32_t *p, uknc_scanline *scanline); + +protected: required_device m_maincpu; required_device m_subcpu; + required_device m_channel; + required_device m_subchan; + required_device m_keyboard; + required_device m_timer; required_device m_qbus; + optional_device m_s2; + optional_device m_rs232; required_device m_cart; required_device m_cassette; - - void uknc_mem(address_map &map) ATTR_COLD; - void uknc_sub_mem(address_map &map) ATTR_COLD; + required_device m_dac; + required_ioport m_yrgb; + required_device m_palette; + required_device m_screen; + required_region_ptr m_ram; + + memory_view m_view_main, m_view_cart, m_view_rom; + std::unique_ptr m_subram; }; void uknc_state::uknc_mem(address_map &map) { - map.unmap_value_high(); - map(0x0000, 0x7fff).ram(); + map(0000000, 0177777).view(m_view_main); + // USER mode + m_view_main[0](0000000, 0177777).rw(FUNC(uknc_state::trap_r), FUNC(uknc_state::trap_w)); + m_view_main[0](0000000, 0157777).ram().region("maincpu", 0); + m_view_main[0](0176570, 0176577).rw(m_s2, FUNC(k1801vp065_device::read), FUNC(k1801vp065_device::write)); + m_view_main[0](0176640, 0176641).rw(FUNC(uknc_state::maincpu_vram_addr_r), FUNC(uknc_state::maincpu_vram_addr_w)); + m_view_main[0](0176642, 0176643).rw(FUNC(uknc_state::maincpu_vram_data_r), FUNC(uknc_state::maincpu_vram_data_w)); + m_view_main[0](0176644, 0176647).noprw(); // hardware breakpoint + m_view_main[0](0176660, 0176667).rw(m_channel, FUNC(k1801vp120_pri_device::read<1>), FUNC(k1801vp120_pri_device::write<1>)); // printer + m_view_main[0](0176670, 0176677).rw(m_channel, FUNC(k1801vp120_pri_device::read<2>), FUNC(k1801vp120_pri_device::write<2>)); // RPC + m_view_main[0](0177560, 0177567).rw(m_channel, FUNC(k1801vp120_pri_device::read<0>), FUNC(k1801vp120_pri_device::write<0>)); // terminal emulator + // HALT mode + m_view_main[1](0000000, 0177777).ram().region("maincpu", 0); } +static const z80_daisy_config daisy_chain[] = +{ + { "channel" }, +// { "bp" }, + { "s2" }, + { "qbus" }, + { nullptr } +}; + void uknc_state::uknc_sub_mem(address_map &map) { - map.unmap_value_high(); - map(0x0000, 0x7fff).ram(); - map(0x8000, 0xffff).rom().region("subcpu",0); + map(0000000, 0077777).bankrw("plane0bank0_3"); + + map(0100000, 0117777).view(m_view_cart); + m_view_cart[0](0100000, 0117777).bankr("plane0bank4").nopw(); + m_view_cart[1](0100000, 0117777).rom().region("subcpu", 0).nopw(); + m_view_cart[2](0100000, 0117777).bankrw("plane0bank4"); + m_view_cart[3](0100000, 0117777).rom().region("subcpu", 0).bankw("plane0bank4"); + + map(0120000, 0176777).view(m_view_rom); + for (int v = 0; v < 8; v++) + { + if (v & 1) + m_view_rom[v](0120000, 0137777).rom().region("subcpu", 020000).bankw("plane0bank5"); + else + m_view_rom[v](0120000, 0137777).rom().region("subcpu", 020000); + if (v & 2) + m_view_rom[v](0140000, 0157777).rom().region("subcpu", 040000).bankw("plane0bank6"); + else + m_view_rom[v](0140000, 0157777).rom().region("subcpu", 040000); + if (v & 4) + m_view_rom[v](0160000, 0176777).rom().region("subcpu", 060000).bankw("plane0bank7"); + else + m_view_rom[v](0160000, 0176777).rom().region("subcpu", 060000); + } + + map(0177010, 0177011).rw(FUNC(uknc_state::vram_addr_r), FUNC(uknc_state::vram_addr_w)); + map(0177012, 0177013).rw(FUNC(uknc_state::vram_data_pl0_r), FUNC(uknc_state::vram_data_pl0_w)); + map(0177014, 0177015).rw(FUNC(uknc_state::vram_data_p12_r), FUNC(uknc_state::vram_data_p12_w)); + map(0177016, 0177027).rw(FUNC(uknc_state::sprite_r), FUNC(uknc_state::sprite_w)); + map(0177054, 0177055).rw(FUNC(uknc_state::bcsr_r), FUNC(uknc_state::bcsr_w)); + map(0177060, 0177103).rw(m_subchan, FUNC(k1801vp120_sub_device::read), FUNC(k1801vp120_sub_device::write)); + // 1515XM1-031 system controller + map(0177700, 0177707).rw(m_keyboard, FUNC(k1515xm031_pri_device::read), FUNC(k1515xm031_pri_device::write)); + map(0177710, 0177715).rw(m_timer, FUNC(k1515xm031_sub_device::read), FUNC(k1515xm031_sub_device::write)); + map(0177716, 0177717).rw(FUNC(uknc_state::scsr_r), FUNC(uknc_state::scsr_w)); } +static const z80_daisy_config sub_daisy_chain[] = +{ +// { "event" }, + { "timer" }, + { "keyboard" }, +// { "reset" }, + { "subchan" }, + { "cart" }, + { nullptr } +}; + /* Input ports */ + +// some models had R and G outputs swapped and others had no Y (intensity) output static INPUT_PORTS_START( uknc ) + PORT_START("yrgb") + PORT_DIPNAME(0x03, 0x00, "variant") + PORT_DIPSETTING(0x00, "Color, YRGB") + PORT_DIPSETTING(0x01, "Color, YGRB") + PORT_DIPSETTING(0x02, "Color, xRGB") + PORT_DIPSETTING(0x03, "Grayscale") INPUT_PORTS_END void uknc_state::machine_reset() { + m_odt_map = 1; m_view_main.select(1); + bcsr_w(0, 01401, 0xffff); + scsr_w(0, 0, 0xffff); } void uknc_state::machine_start() { + m_subram = make_unique_clear(0200000); + m_scanlines = std::make_unique(UKNC_MAX_VERT); + m_tmpbmp.allocate(UKNC_DISP_HORZ, UKNC_DISP_VERT); + memset(&m_video, 0, sizeof(m_video)); + + membank("plane0bank0_3")->set_base(&m_subram[0]); + membank("plane0bank4")->set_base(&m_subram[0100000]); + membank("plane0bank5")->set_base(&m_subram[0120000]); + membank("plane0bank6")->set_base(&m_subram[0140000]); + membank("plane0bank7")->set_base(&m_subram[0160000]); + + machine_reset(); +} + +void uknc_state::reset_w(int state) +{ + if (state == ASSERT_LINE) + { + m_channel->reset(); + // breakpoint + m_s2->reset(); + m_qbus->init_w(); + } +} + +void uknc_state::reset_sub_w(int state) +{ + if (state == ASSERT_LINE) + { + // event + m_timer->reset(); + m_keyboard->reset(); + // reset + m_subchan->reset(); + m_cart->init_w(); + } +} + + +void uknc_state::uknc_palette(palette_device &palette) const +{ + // for debugging only, will be overwritten by firmware + for (int i = 0; i < 8; i++) + { + palette.set_pen_color(i, rgb_t(pal3bit(i), pal3bit(i), pal3bit(i))); + } +} + + +void uknc_state::screen_vblank(int state) +{ +// FIXME not synced to vblank? + if (!BIT(m_bcsr, 8)) + m_subcpu->set_input_line(t11_device::CP2_LINE, state); + else + m_subcpu->set_input_line(t11_device::CP2_LINE, CLEAR_LINE); + if (!BIT(m_bcsr, 9)) + m_maincpu->set_input_line(t11_device::CP2_LINE, state); + else + m_maincpu->set_input_line(t11_device::CP2_LINE, CLEAR_LINE); +} + +// VRAM access from maincpu + +uint16_t uknc_state::maincpu_vram_addr_r() +{ + return m_video.maincpu_vram_addr; +} + +void uknc_state::maincpu_vram_addr_w(offs_t offset, uint16_t data, uint16_t mem_mask) +{ + m_video.maincpu_vram_addr = data; + m_video.maincpu_vram_data = m_ram[data]; +} + +uint16_t uknc_state::maincpu_vram_data_r() +{ + return m_video.maincpu_vram_data; +} + +void uknc_state::maincpu_vram_data_w(offs_t offset, uint16_t data, uint16_t mem_mask) +{ + COMBINE_DATA(&m_video.maincpu_vram_data); + m_ram[m_video.maincpu_vram_addr] = m_video.maincpu_vram_data; +} + +// VRAM access from subcpu + +uint16_t uknc_state::vram_addr_r() +{ + return m_video.vram_addr; +} + +void uknc_state::vram_addr_w(offs_t offset, uint16_t data, uint16_t mem_mask) +{ + m_video.vram_addr = data; + m_video.vram_data_p12 = m_ram[data]; + m_video.vram_data_pl0 = m_subram[data]; +} + +uint16_t uknc_state::vram_data_pl0_r() +{ + return m_video.vram_data_pl0; +} + +uint16_t uknc_state::vram_data_p12_r() +{ + return m_video.vram_data_p12; +} + +void uknc_state::vram_data_pl0_w(offs_t offset, uint16_t data, uint16_t mem_mask) +{ + COMBINE_DATA(&m_video.vram_data_pl0); + m_subram[m_video.vram_addr] = m_video.vram_data_pl0; +} + +void uknc_state::vram_data_p12_w(offs_t offset, uint16_t data, uint16_t mem_mask) +{ + COMBINE_DATA(&m_video.vram_data_p12); + m_ram[m_video.vram_addr] = m_video.vram_data_p12; +} + +uint16_t uknc_state::sprite_r(offs_t offset) +{ + uint16_t data = 0; + + switch (offset) + { + case 0: + data = m_video.foreground; + break; + + case 1: + data = m_video.background; + break; + + case 2: + data = (m_video.background >> 16); + break; + + case 3: + // vram read + { + uint8_t vdata; + + // plane 0 + vdata = m_subram[m_video.vram_addr]; + m_video.background = BIT(vdata, 0); + m_video.background |= BIT(vdata, 1) << 4; + m_video.background |= BIT(vdata, 2) << 8; + m_video.background |= BIT(vdata, 3) << 12; + m_video.background |= BIT(vdata, 4) << 16; + m_video.background |= BIT(vdata, 5) << 20; + m_video.background |= BIT(vdata, 6) << 24; + m_video.background |= BIT(vdata, 7) << 28; + + // plane 1 + vdata = m_ram[m_video.vram_addr]; + m_video.background |= BIT(vdata, 0) << 1; + m_video.background |= BIT(vdata, 1) << 5; + m_video.background |= BIT(vdata, 2) << 9; + m_video.background |= BIT(vdata, 3) << 13; + m_video.background |= BIT(vdata, 4) << 17; + m_video.background |= BIT(vdata, 5) << 21; + m_video.background |= BIT(vdata, 6) << 25; + m_video.background |= BIT(vdata, 7) << 29; + + // plane 2 + vdata = m_ram[m_video.vram_addr] >> 8; + m_video.background |= BIT(vdata, 0) << 2; + m_video.background |= BIT(vdata, 1) << 6; + m_video.background |= BIT(vdata, 2) << 10; + m_video.background |= BIT(vdata, 3) << 14; + m_video.background |= BIT(vdata, 4) << 18; + m_video.background |= BIT(vdata, 5) << 22; + m_video.background |= BIT(vdata, 6) << 26; + m_video.background |= BIT(vdata, 7) << 30; + } + break; + + case 4: + data = m_video.plane_mask; + break; + } + + return data; +} + +void uknc_state::sprite_w(offs_t offset, uint16_t data, uint16_t mem_mask) +{ + switch (offset) + { + case 0: // 177016 + m_video.foreground = data & 7; + break; + + case 1: // 177020 + m_video.background &= ~0xffff; + m_video.background |= data & 0x7777; + break; + + case 2: // 177022 + m_video.background &= 0xffff; + m_video.background |= (data & 0x7777) << 16; + break; + + case 3: // 177024 + m_video.sprite_mask = data; + if (!BIT(m_video.plane_mask, 0)) + { + uint8_t vdata; + + vdata = (BIT(data, 0) ? BIT(m_video.foreground, 0) : BIT(m_video.background, 0)); + vdata |= (BIT(data, 1) ? BIT(m_video.foreground, 0) : BIT(m_video.background, 4)) << 1; + vdata |= (BIT(data, 2) ? BIT(m_video.foreground, 0) : BIT(m_video.background, 8)) << 2; + vdata |= (BIT(data, 3) ? BIT(m_video.foreground, 0) : BIT(m_video.background, 12)) << 3; + vdata |= (BIT(data, 4) ? BIT(m_video.foreground, 0) : BIT(m_video.background, 16)) << 4; + vdata |= (BIT(data, 5) ? BIT(m_video.foreground, 0) : BIT(m_video.background, 20)) << 5; + vdata |= (BIT(data, 6) ? BIT(m_video.foreground, 0) : BIT(m_video.background, 24)) << 6; + vdata |= (BIT(data, 7) ? BIT(m_video.foreground, 0) : BIT(m_video.background, 28)) << 7; + m_subram[m_video.vram_addr] = vdata; + } + if (!BIT(m_video.plane_mask, 1)) + { + uint8_t vdata; + + vdata = (BIT(data, 0) ? BIT(m_video.foreground, 1) : BIT(m_video.background, 1)); + vdata |= (BIT(data, 1) ? BIT(m_video.foreground, 1) : BIT(m_video.background, 5)) << 1; + vdata |= (BIT(data, 2) ? BIT(m_video.foreground, 1) : BIT(m_video.background, 9)) << 2; + vdata |= (BIT(data, 3) ? BIT(m_video.foreground, 1) : BIT(m_video.background, 13)) << 3; + vdata |= (BIT(data, 4) ? BIT(m_video.foreground, 1) : BIT(m_video.background, 17)) << 4; + vdata |= (BIT(data, 5) ? BIT(m_video.foreground, 1) : BIT(m_video.background, 21)) << 5; + vdata |= (BIT(data, 6) ? BIT(m_video.foreground, 1) : BIT(m_video.background, 25)) << 6; + vdata |= (BIT(data, 7) ? BIT(m_video.foreground, 1) : BIT(m_video.background, 29)) << 7; + m_ram[m_video.vram_addr] &= 0xff00; + m_ram[m_video.vram_addr] |= vdata; + } + if (!BIT(m_video.plane_mask, 2)) + { + uint8_t vdata; + + vdata = (BIT(data, 0) ? BIT(m_video.foreground, 2) : BIT(m_video.background, 2)); + vdata |= (BIT(data, 1) ? BIT(m_video.foreground, 2) : BIT(m_video.background, 6)) << 1; + vdata |= (BIT(data, 2) ? BIT(m_video.foreground, 2) : BIT(m_video.background, 10)) << 2; + vdata |= (BIT(data, 3) ? BIT(m_video.foreground, 2) : BIT(m_video.background, 14)) << 3; + vdata |= (BIT(data, 4) ? BIT(m_video.foreground, 2) : BIT(m_video.background, 18)) << 4; + vdata |= (BIT(data, 5) ? BIT(m_video.foreground, 2) : BIT(m_video.background, 22)) << 5; + vdata |= (BIT(data, 6) ? BIT(m_video.foreground, 2) : BIT(m_video.background, 26)) << 6; + vdata |= (BIT(data, 7) ? BIT(m_video.foreground, 2) : BIT(m_video.background, 30)) << 7; + m_ram[m_video.vram_addr] &= 0xff; + m_ram[m_video.vram_addr] |= (vdata << 8); + } + break; + + case 4: // 177026 + m_video.plane_mask = data & 7; + break; + } +} + +// system registers + +uint16_t uknc_state::trap_r(offs_t offset) +{ + if (!machine().side_effects_disabled()) + m_maincpu->pulse_input_line(t11_device::BUS_ERROR, attotime::zero); + return 0xffff; +} + +void uknc_state::trap_w(offs_t offset, uint16_t data, uint16_t mem_mask) +{ + m_maincpu->pulse_input_line(t11_device::BUS_ERROR, attotime::zero); +} + +/* + * 00 R cassette data in. if b2=1 and b3=0, interrupts at vector 0310 on data change. + * 01 RW cassette data out + * 02 RW cassette data/ext gate. 1: cassette 0: ext (always reads as 1) + * 03 RW cassette data/ext/index gate. 0: cassette/ext 1: index + * 04 RW maincpu USER/HALT mode. 0: USER, 1: HALT + * 05 RW maincpu DCLO pin + * 06 - + * 07 RW sound data out, if 08-12 == 0 + * 12:08 sound frequency matrix + * 13 RW reserved + * 14 - + * 15 RW maincpu ACLO pin + */ +uint16_t uknc_state::scsr_r() +{ + double tap_val = m_cassette->input(); + + m_scsr = (m_scsr & ~1) | (tap_val < 0 ? 1 : 0); + + return m_scsr | 4; +} + +void uknc_state::scsr_w(offs_t offset, uint16_t data, uint16_t mem_mask) +{ + COMBINE_DATA(&m_scsr); + + if ((m_scsr & 017400) == 0) m_dac->write(!BIT(m_scsr, 7)); + if (BIT(m_scsr, 2)) m_cassette->output(BIT(m_scsr, 1) ? -1 : 1); + + m_maincpu->set_input_line(t11_device::HLT_LINE, BIT(m_scsr, 4)); + + if (BIT(m_scsr, 15) && m_maincpu->suspended(SUSPEND_REASON_DISABLE)) + { + LOG("starting maincpu\n"); + m_maincpu->resume(SUSPEND_REASON_DISABLE); + } + else if (!BIT(m_scsr, 15) && !m_maincpu->suspended(SUSPEND_REASON_DISABLE)) + { + LOG("stopping maincpu\n"); + m_maincpu->set_input_line(t11_device::PF_LINE, ASSERT_LINE); + } +} + +/* + * 0-3 CE0..CE3 bus signals + * CE0 mapping at 100000: 0 - read from VRAM plane 0, 1 - read from ROM (reset to 1) + * CE1-2 ROM carts: bank selector + * CE3 slot number + * 4-7 ROM banks replacement: 0 - writes ignored, 1 - writes go to VRAM plane 0 + * 4 100000..117777 + * 5 120000..137777 + * 6 140000..157777 + * 7 160000..177777 + * 8 line clock interrupt (subcpu): 0 - enable + * 9 line clock interrupt (maincpu): 0 - enable + */ +uint16_t uknc_state::bcsr_r() +{ + return m_bcsr; +} + +void uknc_state::bcsr_w(offs_t offset, uint16_t data, uint16_t mem_mask) +{ + int bank1, bank2; + + bank1 = bitswap<2>(data, 4, 0); + bank2 = (data >> 5) & 7; + LOG("bcsr W banks %d,%d\n", bank1, bank2); + +#if 0 + // order matters: ROM on device may unmap itself and we restore the mapping + m_cart->ce0_ce3_w(data & 15); + address_space *subspace = &m_subcpu->space(AS_PROGRAM); + + if (BIT(m_bcsr ^ data, 0) && BIT(data, 0)) + { + subspace->unmap_readwrite(0100000, 0117777); + subspace->install_readwrite_handler(0100000, 0117777, + read16s_delegate(m_bankdev1, FUNC(address_map_bank_device::read16)), + write16s_delegate(m_bankdev1, FUNC(address_map_bank_device::write16))); + } +#endif + m_view_cart.select(bank1); + m_view_rom.select(bank2); + + m_bcsr = data; +} + +// video + +#define YRGB(rgb, y, p) ((rgb)*42 * (3 + (p) + (y)*2)) + +void uknc_state::set_palette_yrgb(uint32_t aux) +{ + for (int i = 0; i < 8; i++) + { + m_palette->set_pen_color(i, rgb_t( + YRGB(BIT(aux, i * 4 + 2), BIT(aux, i * 4 + 3), BIT(m_video.control, 18)), + YRGB(BIT(aux, i * 4 + 1), BIT(aux, i * 4 + 3), BIT(m_video.control, 17)), + YRGB(BIT(aux, i * 4 ), BIT(aux, i * 4 + 3), BIT(m_video.control, 16))) + ); + } +} + +void uknc_state::set_palette_ygrb(uint32_t aux) +{ + for (int i = 0; i < 8; i++) + { + m_palette->set_pen_color(i, rgb_t( + YRGB(BIT(aux, i * 4 + 1), BIT(aux, i * 4 + 3), BIT(m_video.control, 17)), + YRGB(BIT(aux, i * 4 + 2), BIT(aux, i * 4 + 3), BIT(m_video.control, 18)), + YRGB(BIT(aux, i * 4 ), BIT(aux, i * 4 + 3), BIT(m_video.control, 16))) + ); + } +} + +void uknc_state::set_palette__rgb(uint32_t aux) +{ + for (int i = 0; i < 8; i++) + { + m_palette->set_pen_color(i, rgb_t( + YRGB(BIT(aux, i * 4 + 2), !BIT(aux, i * 4 + 3), 1), + YRGB(BIT(aux, i * 4 + 1), !BIT(aux, i * 4 + 3), 1), + YRGB(BIT(aux, i * 4 ), !BIT(aux, i * 4 + 3), 1)) + ); + } +} + +void uknc_state::set_palette_gray(uint32_t aux) +{ + for (int i = 0; i < 8; i++) + { + m_palette->set_pen_color(i, rgb_t(pal3bit(i), pal3bit(i), pal3bit(i))); + } +} + +#undef YGRB + + +void uknc_state::update_displaylist() +{ + int wide = 0; + uint16_t addr = 0270, nextaddr; + bool cursor = false, cursor_type = false; + int cursor_color = 0, cursor_octet = 0, cursor_pixel = 0; + uknc_scanline *scanline; + + for (int row = 0; row < UKNC_MAX_VERT; row++) + { + scanline = &m_scanlines[row]; + scanline->addr = m_subcpu->space(AS_PROGRAM).read_word(addr); + nextaddr = m_subcpu->space(AS_PROGRAM).read_word(addr + 2); + + if (BIT(nextaddr, 0)) + cursor = !cursor; + + scanline->control = scanline->color = false; + scanline->cursor = cursor; + + if (wide) + { + scanline->aux = m_subcpu->space(AS_PROGRAM).read_word(addr - 4) | + (m_subcpu->space(AS_PROGRAM).read_word(addr - 2) << 16); + if (wide == 1) + { + scanline->control = true; + cursor_type = BIT(scanline->aux, 4); + cursor_color = scanline->aux & 15; + cursor_pixel = (scanline->aux >> 4) & 3; + cursor_octet = (scanline->aux >> 8) & 127; + } + else + { + scanline->color = true; + } + } + + if (row < 0) + { + LOGVRAM("dl row %d addr %06o px %06o wide %d\n", row, addr, scanline->addr, wide); + if (wide) LOGVRAM("aux %08x (%s)\n", scanline->aux, wide == 1 ? "ctl" : "color"); + } + + scanline->cursor_type = cursor_type; + scanline->cursor_color = cursor_color; + scanline->cursor_pixel = cursor_pixel; + scanline->cursor_octet = cursor_octet; + + if (BIT(nextaddr, 1)) + { + wide = BIT(nextaddr, 2) + 1; + nextaddr &= ~7; + nextaddr += 4; + } + else + { + wide = 0; + nextaddr &= ~3; + } + + addr = nextaddr; + } +} + +/* + * aux bits, word 0: + * + * 0-3 cursor color, YRGB + * 4 cursor type, 0: character, 1: graphics + * 5-7 graphics cursor position in octet + * 8-14 cursor position in line + * 15 - + * + * aux bits, word 1: + * + * 16-18 RGB intensity + * 19 - + * 20-21 scaling + */ +void uknc_state::draw_scanline(uint32_t *p, uknc_scanline *scanline) +{ + if (scanline->color) + { + m_video.palette = scanline->aux; + } + else if (scanline->control) + { + m_video.control = scanline->aux; + } + + if (scanline->color || scanline->control) + { + switch (m_yrgb->read()) + { + case 0: + set_palette_yrgb(m_video.palette); + break; + + case 1: + set_palette_ygrb(m_video.palette); + break; + + case 2: + set_palette__rgb(m_video.palette); + break; + + case 3: + set_palette_gray(m_video.palette); + break; + } + } + + if (!p) return; + + const pen_t *pen = m_palette->pens(); + int wide = (m_video.control >> 20) & 3; + + for (int i = 0; i < (80 >> wide); i++) + { + uint8_t bit_plane_0 = m_subram[scanline->addr + i]; + uint8_t bit_plane_1 = m_ram[scanline->addr + i]; + uint8_t bit_plane_2 = m_ram[scanline->addr + i] >> 8; + + if (scanline->cursor && (i << wide) == scanline->cursor_octet) + { + // graphics cursor + if (scanline->cursor_type) + { + bit_plane_0 &= ~(1 << scanline->cursor_pixel); + bit_plane_1 &= ~(1 << scanline->cursor_pixel); + bit_plane_2 &= ~(1 << scanline->cursor_pixel); + bit_plane_0 |= (BIT(scanline->cursor_color, 0) << scanline->cursor_pixel); + bit_plane_1 |= (BIT(scanline->cursor_color, 1) << scanline->cursor_pixel); + bit_plane_2 |= (BIT(scanline->cursor_color, 2) << scanline->cursor_pixel); + } + // text cursor + else + { + bit_plane_0 = (BIT(scanline->cursor_color, 0)) ? 255 : 0; + bit_plane_1 = (BIT(scanline->cursor_color, 1)) ? 255 : 0; + bit_plane_2 = (BIT(scanline->cursor_color, 2)) ? 255 : 0; + } + } + + for (int pixel_x = 0; pixel_x < 8; pixel_x++) + { + int pen_selected = BIT(bit_plane_0, pixel_x) | + BIT(bit_plane_1, pixel_x) << 1 | BIT(bit_plane_2, pixel_x) << 2; + + *p++ = pen[pen_selected]; + if (wide) *p++ = pen[pen_selected]; + if (wide > 1) *p++ = pen[pen_selected]; + if (wide > 2) *p++ = pen[pen_selected]; + } + } +} + + +TIMER_DEVICE_CALLBACK_MEMBER(uknc_state::scanline_callback) +{ + uint16_t y = m_screen->vpos(); + + if (y < UKNC_VERT_START || y >= UKNC_MAX_VERT) + draw_scanline(NULL, &m_scanlines[y]); + else + draw_scanline(&m_tmpbmp.pix(y - UKNC_VERT_START), &m_scanlines[y]); } uint32_t uknc_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) { + copybitmap(bitmap, m_tmpbmp, 0, 0, UKNC_HORZ_START, UKNC_VERT_START, cliprect); + update_displaylist(); return 0; } + void uknc_state::uknc(machine_config &config) { - /* basic machine hardware */ K1801VM2(config, m_maincpu, XTAL(16'000'000)/4); // external clock is /2 + internal divider /2 - m_maincpu->set_initial_mode(0x8000); m_maincpu->set_addrmap(AS_PROGRAM, &uknc_state::uknc_mem); + m_maincpu->set_initial_mode(0160000); + m_maincpu->set_daisy_config(daisy_chain); + m_maincpu->out_reset().set(FUNC(uknc_state::reset_w)); +#if 0 // not yet + m_maincpu->out_bankswitch().set([this] (int state) { + if (m_odt_map != state) { m_view_main.select(state); m_odt_map = state; } + LOGDBG("%s HALT mode changed: %d\n", machine().describe_context(), state); + }); +#endif m_maincpu->set_disable(); + K1801VM2(config, m_subcpu, XTAL(12'500'000)/4); + m_subcpu->set_addrmap(AS_PROGRAM, &uknc_state::uknc_sub_mem); + m_subcpu->set_initial_mode(0160000); + m_subcpu->set_daisy_config(sub_daisy_chain); + m_subcpu->out_reset().set(FUNC(uknc_state::reset_sub_w)); + + /* video hardware */ + SCREEN(config, m_screen, SCREEN_TYPE_RASTER); + m_screen->set_screen_update(FUNC(uknc_state::screen_update)); + m_screen->set_raw(XTAL(12'500'000), UKNC_TOTAL_HORZ, UKNC_HORZ_START, UKNC_HORZ_START+UKNC_DISP_HORZ, + UKNC_TOTAL_VERT, UKNC_VERT_START, UKNC_VERT_START+UKNC_DISP_VERT); + m_screen->screen_vblank().set(FUNC(uknc_state::screen_vblank)); + + TIMER(config, "scantimer").configure_scanline(FUNC(uknc_state::scanline_callback), "screen", 0, 1); + + PALETTE(config, m_palette, FUNC(uknc_state::uknc_palette), 8); + + /* + * devices on the main cpu + */ + + K1801VP120_PRI(config, m_channel, 0); + m_channel->virq_wr_callback().set_inputline(m_maincpu, t11_device::VEC_LINE); + m_channel->reset_wr_callback().set(m_subchan, FUNC(k1801vp120_sub_device::write_reset)); + m_channel->out_wr_callback<0>().set(m_subchan, FUNC(k1801vp120_sub_device::write_data<0>)); + m_channel->out_wr_callback<1>().set(m_subchan, FUNC(k1801vp120_sub_device::write_data<1>)); + m_channel->out_wr_callback<2>().set(m_subchan, FUNC(k1801vp120_sub_device::write_data<2>)); + m_channel->ack_wr_callback<0>().set(m_subchan, FUNC(k1801vp120_sub_device::write_ack<0>)); + m_channel->ack_wr_callback<1>().set(m_subchan, FUNC(k1801vp120_sub_device::write_ack<1>)); + + K1801VP065(config, m_s2, XTAL(4'608'000)); + m_s2->set_rxc(9600); + m_s2->set_txc(9600); + m_s2->set_rxvec(0370); + m_s2->set_txvec(0374); + m_s2->txd_wr_callback().set(m_rs232, FUNC(rs232_port_device::write_txd)); + m_s2->rts_wr_callback().set(m_rs232, FUNC(rs232_port_device::write_rts)); + m_s2->txrdy_wr_callback().set_inputline(m_maincpu, t11_device::VEC_LINE); + m_s2->rxrdy_wr_callback().set_inputline(m_maincpu, t11_device::VEC_LINE); + + RS232_PORT(config, m_rs232, default_rs232_devices, "null_modem"); + m_rs232->rxd_handler().set(m_s2, FUNC(k1801vp065_device::rx_w)); + QBUS(config, m_qbus, 0); m_qbus->set_space(m_maincpu, AS_PROGRAM); m_qbus->birq4().set_inputline(m_maincpu, t11_device::VEC_LINE); QBUS_SLOT(config, "qbus" ":1", qbus_cards, nullptr); - K1801VM2(config, m_subcpu, XTAL(12'500'000)/4); - m_subcpu->set_addrmap(AS_PROGRAM, &uknc_state::uknc_sub_mem); - m_subcpu->set_initial_mode(0x8000); + /* + * devices on the sub cpu + */ + + K1515XM031_PRI(config, m_keyboard, 0); + m_keyboard->virq_wr_callback().set_inputline(m_subcpu, t11_device::VEC_LINE); + + K1515XM031_SUB(config, m_timer, 0); + m_timer->virq_wr_callback().set_inputline(m_subcpu, t11_device::VEC_LINE); + + K1801VP120_SUB(config, m_subchan, 0); + m_subchan->virq_wr_callback().set_inputline(m_subcpu, t11_device::VEC_LINE); + m_subchan->out_wr_callback<0>().set(m_channel, FUNC(k1801vp120_pri_device::write_data<0>)); + m_subchan->out_wr_callback<1>().set(m_channel, FUNC(k1801vp120_pri_device::write_data<1>)); + m_subchan->ack_wr_callback<0>().set(m_channel, FUNC(k1801vp120_pri_device::write_ack<0>)); + m_subchan->ack_wr_callback<1>().set(m_channel, FUNC(k1801vp120_pri_device::write_ack<1>)); + m_subchan->ack_wr_callback<2>().set(m_channel, FUNC(k1801vp120_pri_device::write_ack<2>)); QBUS(config, m_cart, 0); m_cart->set_space(m_subcpu, AS_PROGRAM); @@ -110,21 +970,16 @@ void uknc_state::uknc(machine_config &config) CASSETTE(config, m_cassette); m_cassette->set_default_state(CASSETTE_STOPPED | CASSETTE_MOTOR_ENABLED | CASSETTE_SPEAKER_ENABLED); - /* video hardware */ - screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER)); - screen.set_refresh_hz(50); - screen.set_vblank_time(ATTOSECONDS_IN_USEC(2500)); /* not accurate */ - screen.set_size(640, 480); - screen.set_visarea(0, 640-1, 0, 480-1); - screen.set_screen_update(FUNC(uknc_state::screen_update)); - - PALETTE(config, "palette", palette_device::MONOCHROME); + // built-in piezo + SPEAKER(config, "mono").front_center(); + DAC_1BIT(config, m_dac, 0).add_route(ALL_OUTPUTS, "mono", 0.25); } /* ROM definition */ ROM_START( uknc ) + ROM_REGION16_LE(0400000, "maincpu", ROMREGION_ERASE00) ROM_REGION16_LE(0100000, "subcpu", ROMREGION_ERASE00) - ROM_LOAD("uknc.rom", 0x0000, 0x8000, CRC(a1536994) SHA1(b3c7c678c41ffa9b37f654fbf20fef7d19e6407b)) + ROM_LOAD("uknc.rom", 0, 0100000, CRC(a1536994) SHA1(b3c7c678c41ffa9b37f654fbf20fef7d19e6407b)) ROM_END } // anonymous namespace