diff --git a/scripts/src/bus.lua b/scripts/src/bus.lua index 2c708f35b4d..14e6b6187f6 100644 --- a/scripts/src/bus.lua +++ b/scripts/src/bus.lua @@ -2198,6 +2198,23 @@ if (BUSES["WANGPC"]~=null) then end +--------------------------------------------------- +-- +--@src/devices/bus/z29_kbd/keyboard.h,BUSES["Z29_KBD"] = true +--------------------------------------------------- + +if (BUSES["Z29_KBD"]~=null) then + files { + MAME_DIR .. "src/devices/bus/z29_kbd/keyboard.cpp", + MAME_DIR .. "src/devices/bus/z29_kbd/keyboard.h", + MAME_DIR .. "src/devices/bus/z29_kbd/he191_3425.cpp", + MAME_DIR .. "src/devices/bus/z29_kbd/he191_3425.h", + MAME_DIR .. "src/devices/bus/z29_kbd/md_kbd.cpp", + MAME_DIR .. "src/devices/bus/z29_kbd/md_kbd.h", + } +end + + --------------------------------------------------- -- --@src/devices/bus/z88/z88.h,BUSES["Z88"] = true diff --git a/scripts/target/mame/mess.lua b/scripts/target/mame/mess.lua index 396ed5572b6..db3a00a065b 100644 --- a/scripts/target/mame/mess.lua +++ b/scripts/target/mame/mess.lua @@ -918,6 +918,7 @@ BUSES["VTECH_MEMEXP"] = true BUSES["WANGPC"] = true BUSES["WSWAN"] = true BUSES["X68K"] = true +BUSES["Z29_KBD"] = true BUSES["Z88"] = true BUSES["ZORRO"] = true @@ -4179,6 +4180,7 @@ createMESSProjects(_target, _subtarget, "zenith") files { MAME_DIR .. "src/mame/drivers/mdt60.cpp", MAME_DIR .. "src/mame/drivers/z100.cpp", + MAME_DIR .. "src/mame/drivers/z22.cpp", MAME_DIR .. "src/mame/drivers/z29.cpp", } diff --git a/src/devices/bus/z29_kbd/he191_3425.cpp b/src/devices/bus/z29_kbd/he191_3425.cpp new file mode 100644 index 00000000000..69ea07f76d1 --- /dev/null +++ b/src/devices/bus/z29_kbd/he191_3425.cpp @@ -0,0 +1,240 @@ +// license:BSD-3-Clause +// copyright-holders:AJR +/*************************************************************************** + + Heath HE 191-3425 keyboard + + This 91-key detached keyboard is standard issue for the H-29 (Z-29) + terminal. It is also specified for the MDT 60 in its schematics. + + Since the 8021 MCU is not dumped, emulation is more or less a stub. + +***************************************************************************/ + +#include "emu.h" +#include "he191_3425.h" + +#include "cpu/mcs48/mcs48.h" +#include "machine/rescap.h" +#include "speaker.h" + + +DEFINE_DEVICE_TYPE(HE191_3425, he191_3425_device, "he191_3425", "Heath HE 191-3425 Keyboard") + +he191_3425_device::he191_3425_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : device_t(mconfig, HE191_3425, tag, owner, clock) + , device_z29_keyboard_interface(mconfig, *this) + , m_mcu(*this, "mcu") + , m_buzzer(*this, "buzzer") + , m_matrix(*this, {"B1", "B2", "B3", "B4", "B5", "B6", "B7", "B8", "B9", "B11", "B13", "B14"}) + , m_modifiers(*this, "MODIFIERS") + , m_leds(*this, "led%u", 1U) + , m_select(0) + , m_recv_data(true) +{ +} + +void he191_3425_device::device_resolve_objects() +{ + m_leds.resolve(); +} + +void he191_3425_device::device_start() +{ + m_leds[0] = 1; // L1: Power + + save_item(NAME(m_select)); + save_item(NAME(m_recv_data)); +} + +void he191_3425_device::receive_data(bool state) +{ + machine().scheduler().synchronize(timer_expired_delegate(FUNC(he191_3425_device::receive_data_synced), this), state); +} + +TIMER_CALLBACK_MEMBER(he191_3425_device::receive_data_synced) +{ + m_recv_data = param; +} + +u8 he191_3425_device::mcu_pa_r() +{ + return m_select < 12 ? m_matrix[m_select]->read() : 0xff; +} + +void he191_3425_device::mcu_pb_w(u8 data) +{ + transmit_data(!BIT(data, 3)); + m_leds[1] = !BIT(data, 4); // L2: Keyboard Lock + m_leds[2] = !BIT(data, 5); // L3: Off/Line + m_leds[3] = !BIT(data, 6); // L4: Caps Lock + m_buzzer->set_state(BIT(data, 7)); +} + +void he191_3425_device::mcu_pc_w(u8 data) +{ + m_select = data & 0xf; +} + +READ_LINE_MEMBER(he191_3425_device::mcu_t1_r) +{ + return m_recv_data; +} + +WRITE_LINE_MEMBER(he191_3425_device::shift_reset) +{ + m_mcu->set_input_line(INPUT_LINE_RESET, (m_modifiers->read() & 0x06) != 0x00 ? CLEAR_LINE : ASSERT_LINE); + reset_from_keyboard((m_modifiers->read() & 0x06) != 0x00); +} + + +static INPUT_PORTS_START(he191_3425) + PORT_START("B1") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(ENTER_PAD)) PORT_CODE(KEYCODE_ENTER_PAD) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(DEL_PAD)) PORT_CODE(KEYCODE_DEL_PAD) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(0_PAD)) PORT_CODE(KEYCODE_0_PAD) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('`') PORT_CHAR('~') PORT_CODE(KEYCODE_BACKSLASH) + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('0') PORT_CHAR(')') PORT_CODE(KEYCODE_0) + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('o') PORT_CHAR('O') PORT_CODE(KEYCODE_O) + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(';') PORT_CHAR(':') PORT_CODE(KEYCODE_COLON) + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('/') PORT_CHAR('?') PORT_CODE(KEYCODE_SLASH) + + PORT_START("B2") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Keypad 3 DL") PORT_CHAR(UCHAR_MAMEKEY(3_PAD)) PORT_CODE(KEYCODE_3_PAD) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(2_PAD)) PORT_CODE(KEYCODE_2_PAD) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Keypad 1 IL") PORT_CHAR(UCHAR_MAMEKEY(1_PAD)) PORT_CODE(KEYCODE_1_PAD) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(F9)) PORT_CODE(KEYCODE_F9) + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('9') PORT_CHAR('(') PORT_CODE(KEYCODE_9) + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('i') PORT_CHAR('I') PORT_CODE(KEYCODE_I) + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('l') PORT_CHAR('L') PORT_CODE(KEYCODE_L) + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('.') PORT_CHAR('>') PORT_CODE(KEYCODE_STOP) + + PORT_START("B3") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(6_PAD)) PORT_CODE(KEYCODE_6_PAD) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(5_PAD)) PORT_CODE(KEYCODE_5_PAD) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(4_PAD)) PORT_CODE(KEYCODE_4_PAD) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(F8)) PORT_CODE(KEYCODE_F8) + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('8') PORT_CHAR('*') PORT_CODE(KEYCODE_8) + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('u') PORT_CHAR('U') PORT_CODE(KEYCODE_U) + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('k') PORT_CHAR('K') PORT_CODE(KEYCODE_K) + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(',') PORT_CHAR('<') PORT_CODE(KEYCODE_COMMA) + + PORT_START("B4") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Keypad 9 DC") PORT_CHAR(UCHAR_MAMEKEY(9_PAD)) PORT_CODE(KEYCODE_9_PAD) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(8_PAD)) PORT_CODE(KEYCODE_8_PAD) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Keypad 7 IC") PORT_CHAR(UCHAR_MAMEKEY(7_PAD)) PORT_CODE(KEYCODE_7_PAD) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(F7)) PORT_CODE(KEYCODE_F7) + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('7') PORT_CHAR('&') PORT_CODE(KEYCODE_7) + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('y') PORT_CHAR('Y') PORT_CODE(KEYCODE_Y) + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('j') PORT_CHAR('J') PORT_CODE(KEYCODE_J) + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('m') PORT_CHAR('M') PORT_CODE(KEYCODE_M) + + PORT_START("B5") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Help") PORT_CODE(KEYCODE_F10) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Line Feed") PORT_CHAR(0x0a) PORT_CODE(KEYCODE_RALT) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Space Bar") PORT_CHAR(' ') PORT_CODE(KEYCODE_SPACE) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(F6)) PORT_CODE(KEYCODE_F6) + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('6') PORT_CHAR('^') PORT_CODE(KEYCODE_6) + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('t') PORT_CHAR('T') PORT_CODE(KEYCODE_T) + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('h') PORT_CHAR('H') PORT_CODE(KEYCODE_H) + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('n') PORT_CHAR('N') PORT_CODE(KEYCODE_N) + + PORT_START("B6") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('\\') PORT_CHAR('|') PORT_CODE(KEYCODE_RCONTROL) // to right of Return key + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Return") PORT_CHAR(0x0d) PORT_CODE(KEYCODE_ENTER) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('\'') PORT_CHAR('"') PORT_CODE(KEYCODE_QUOTE) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(F5)) PORT_CODE(KEYCODE_F5) + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('5') PORT_CHAR('%') PORT_CODE(KEYCODE_5) + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('r') PORT_CHAR('R') PORT_CODE(KEYCODE_R) + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('g') PORT_CHAR('G') PORT_CODE(KEYCODE_G) + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('b') PORT_CHAR('B') PORT_CODE(KEYCODE_B) + + PORT_START("B7") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(']') PORT_CHAR('}') PORT_CODE(KEYCODE_CLOSEBRACE) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('[') PORT_CHAR('{') PORT_CODE(KEYCODE_OPENBRACE) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('p') PORT_CHAR('P') PORT_CODE(KEYCODE_P) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(F4)) PORT_CODE(KEYCODE_F4) + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('4') PORT_CHAR('$') PORT_CODE(KEYCODE_4) + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('e') PORT_CHAR('E') PORT_CODE(KEYCODE_E) + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('f') PORT_CHAR('F') PORT_CODE(KEYCODE_F) + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('v') PORT_CHAR('V') PORT_CODE(KEYCODE_V) + + PORT_START("B8") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Delete") PORT_CHAR(UCHAR_MAMEKEY(DEL)) PORT_CODE(KEYCODE_DEL) // to right of `/~ key + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(HOME)) PORT_CODE(KEYCODE_F11) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(DOWN)) PORT_CODE(KEYCODE_DOWN) // between +/= and Back Space keys + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(F3)) PORT_CODE(KEYCODE_F3) + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('3') PORT_CHAR('#') PORT_CODE(KEYCODE_3) + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('w') PORT_CHAR('W') PORT_CODE(KEYCODE_W) + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('d') PORT_CHAR('D') PORT_CODE(KEYCODE_D) + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('c') PORT_CHAR('C') PORT_CODE(KEYCODE_C) + + PORT_START("B9") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Back Space") PORT_CHAR(0x08) PORT_CODE(KEYCODE_BACKSPACE) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('=') PORT_CHAR('+') PORT_CODE(KEYCODE_EQUALS) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('-') PORT_CHAR('_') PORT_CODE(KEYCODE_MINUS) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(F2)) PORT_CODE(KEYCODE_F2) + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('2') PORT_CHAR('@') PORT_CODE(KEYCODE_2) + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('q') PORT_CHAR('Q') PORT_CODE(KEYCODE_Q) + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('s') PORT_CHAR('S') PORT_CODE(KEYCODE_S) + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('x') PORT_CHAR('X') PORT_CODE(KEYCODE_X) + + PORT_START("B11") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(RIGHT)) PORT_CODE(KEYCODE_RIGHT) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(UP)) PORT_CODE(KEYCODE_UP) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(LEFT)) PORT_CODE(KEYCODE_LEFT) // to right of Home key + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(F1)) PORT_CODE(KEYCODE_F1) + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('1') PORT_CHAR('!') PORT_CODE(KEYCODE_1) + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Tab") PORT_CHAR('\t') PORT_CODE(KEYCODE_TAB) + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('a') PORT_CHAR('A') PORT_CODE(KEYCODE_A) + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('z') PORT_CHAR('Z') PORT_CODE(KEYCODE_Z) + + PORT_START("B13") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(COMMA_PAD)) PORT_CODE(KEYCODE_PLUS_PAD) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(MINUS_PAD)) PORT_CODE(KEYCODE_MINUS_PAD) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("No Scroll") PORT_CODE(KEYCODE_LALT) + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Set Up") PORT_CODE(KEYCODE_ESC) + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Esc") PORT_CHAR(0x1b) PORT_CODE(KEYCODE_TILDE) + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Erase") PORT_CODE(KEYCODE_F12) + + PORT_START("B14") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(CAPSLOCK)) PORT_CODE(KEYCODE_CAPSLOCK) + PORT_BIT(0xfe, IP_ACTIVE_LOW, IPT_UNUSED) + + PORT_START("MODIFIERS") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Ctrl") PORT_CHAR(UCHAR_SHIFT_2) PORT_CODE(KEYCODE_LCONTROL) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Shift") PORT_CHAR(UCHAR_SHIFT_1) PORT_CODE(KEYCODE_LSHIFT) PORT_CODE(KEYCODE_RSHIFT) PORT_WRITE_LINE_MEMBER(he191_3425_device, shift_reset) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Break Reset") PORT_CODE(KEYCODE_PAUSE) PORT_WRITE_LINE_MEMBER(he191_3425_device, shift_reset) // to right of Back Space key + PORT_BIT(0xf8, IP_ACTIVE_LOW, IPT_UNUSED) +INPUT_PORTS_END + +ioport_constructor he191_3425_device::device_input_ports() const +{ + return INPUT_PORTS_NAME(he191_3425); +} + +void he191_3425_device::device_add_mconfig(machine_config &config) +{ + i8021_device &mcu(I8021(config, m_mcu, 3.579545_MHz_XTAL)); + mcu.bus_in_cb().set(FUNC(he191_3425_device::mcu_pa_r)); + mcu.p1_in_cb().set_ioport("MODIFIERS"); + mcu.p1_out_cb().set(FUNC(he191_3425_device::mcu_pb_w)); + mcu.p2_out_cb().set(FUNC(he191_3425_device::mcu_pc_w)); + mcu.t1_in_cb().set(FUNC(he191_3425_device::mcu_t1_r)); + + SPEAKER(config, "speaker").front_center(); + BEEP(config, m_buzzer, 1'000'000'000 / PERIOD_OF_555_ASTABLE_NSEC(RES_R(510), RES_R(510), CAP_U(1))); + m_buzzer->add_route(ALL_OUTPUTS, "speaker", 1.0); +} + +ROM_START(he191_3425) + ROM_REGION(0x400, "mcu", ROMREGION_ERASE00) + ROM_LOAD("p8021h-2155_444-100.z1", 0x000, 0x400, NO_DUMP) +ROM_END + +const tiny_rom_entry *he191_3425_device::device_rom_region() const +{ + return ROM_NAME(he191_3425); +} diff --git a/src/devices/bus/z29_kbd/he191_3425.h b/src/devices/bus/z29_kbd/he191_3425.h new file mode 100644 index 00000000000..cf0129936fb --- /dev/null +++ b/src/devices/bus/z29_kbd/he191_3425.h @@ -0,0 +1,58 @@ +// license:BSD-3-Clause +// copyright-holders:AJR + +#ifndef MAME_BUS_Z29_KBD_HE191_3425_H +#define MAME_BUS_Z29_KBD_HE191_3425_H + +#pragma once + +#include "bus/z29_kbd/keyboard.h" +#include "sound/beep.h" + + +class he191_3425_device : public device_t, public device_z29_keyboard_interface +{ +public: + // device type constructor + he191_3425_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); + + // miscellanous handlers + DECLARE_WRITE_LINE_MEMBER(shift_reset); + +protected: + // device-level overrides + virtual void device_resolve_objects() override; + virtual void device_start() override; + virtual ioport_constructor device_input_ports() const override; + virtual void device_add_mconfig(machine_config &config) override; + virtual const tiny_rom_entry *device_rom_region() const override; + + // device_z29_keyboard_interface overrides + virtual void receive_data(bool state) override; + +private: + // MCU port handlers + u8 mcu_pa_r(); + void mcu_pb_w(u8 data); + void mcu_pc_w(u8 data); + DECLARE_READ_LINE_MEMBER(mcu_t1_r); + + // misc. helpers + TIMER_CALLBACK_MEMBER(receive_data_synced); + + // object finders + required_device m_mcu; + required_device m_buzzer; + required_ioport_array<12> m_matrix; + required_ioport m_modifiers; + output_finder<4> m_leds; + + // internal state + u8 m_select; + bool m_recv_data; +}; + +// device type declaration +DECLARE_DEVICE_TYPE(HE191_3425, he191_3425_device) + +#endif // MAME_BUS_Z29_KBD_HE191_3425_H diff --git a/src/devices/bus/z29_kbd/keyboard.cpp b/src/devices/bus/z29_kbd/keyboard.cpp new file mode 100644 index 00000000000..637bc8d4389 --- /dev/null +++ b/src/devices/bus/z29_kbd/keyboard.cpp @@ -0,0 +1,117 @@ +// license:BSD-3-Clause +// copyright-holders:AJR +/*************************************************************************** + + Zenith Z-29 keyboard port + + This supports the custom serial interface for the H-29/Z-29 and other + early Heath/Zenith terminals with detachable keyboards. (Keyboards for + later Zenith terminals such as the Z-49 use a standard asynchronous + serial protocol.) + + All printable characters outside of the numeric keypad use standard + ASCII codes, as do Back Space, Line Feed, Return, Esc and Del. The + following codes are assigned to other keys: + + 80 Up + 81 Down + 82 Left + 83 Right + 84 Home + 85 Erase + 86 Help + 87 No Scroll + 88 Set Up + 89 Break + 8A Caps Lock + 8B Tab + 8C Space Bar + 8F (Power On) + 90 0 (Keypad) + 91 1 (Keypad) + 92 2 (Keypad) + 93 3 (Keypad) + 94 4 (Keypad) + 95 5 (Keypad) + 96 6 (Keypad) + 97 7 (Keypad) + 98 8 (Keypad) + 99 9 (Keypad) + 9A . (Keypad) + 9B Enter (Keypad) + 9C - (Keypad) + 9D , (Keypad) + 9F 80 F1 + 9F 81 F2 + 9F 82 F3 + 9F 83 F4 + 9F 84 F5 + 9F 85 F6 + 9F 86 F7 + 9F 87 F8 + 9F 88 F9 + + Bit 6 is set in these codes when pressed with Shift, and bit 5 when + pressed with Ctrl. + +***************************************************************************/ + +#include "emu.h" +#include "keyboard.h" + +#include "he191_3425.h" +#include "md_kbd.h" + +//************************************************************************** +// Z-29 KEYBOARD PORT DEVICE +//************************************************************************** + +DEFINE_DEVICE_TYPE(Z29_KEYBOARD, z29_keyboard_port_device, "z29_kbd", "Z-29 Keyboard Port") + +z29_keyboard_port_device::z29_keyboard_port_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : device_t(mconfig, Z29_KEYBOARD, tag, owner, clock) + , device_single_card_slot_interface(mconfig, *this) + , m_keyin_callback(*this) + , m_reset_callback(*this) + , m_kbd(nullptr) +{ +} + +void z29_keyboard_port_device::device_config_complete() +{ + m_kbd = get_card_device(); +} + +void z29_keyboard_port_device::device_resolve_objects() +{ + m_keyin_callback.resolve_safe(); + m_reset_callback.resolve_safe(); +} + +void z29_keyboard_port_device::device_start() +{ +} + +//************************************************************************** +// Z-29 KEYBOARD INTERFACE +//************************************************************************** + +device_z29_keyboard_interface::device_z29_keyboard_interface(const machine_config &mconfig, device_t &device) + : device_interface(device, "z29kbd") + , m_port(device, DEVICE_SELF_OWNER) +{ +} + +device_z29_keyboard_interface::~device_z29_keyboard_interface() +{ +} + +//************************************************************************** +// KEYBOARD OPTIONS +//************************************************************************** + +void z29_keyboards(device_slot_interface &slot) +{ + slot.option_add("heath", HE191_3425); + slot.option_add("md", MD_KEYBOARD); +} diff --git a/src/devices/bus/z29_kbd/keyboard.h b/src/devices/bus/z29_kbd/keyboard.h new file mode 100644 index 00000000000..501d8bbe569 --- /dev/null +++ b/src/devices/bus/z29_kbd/keyboard.h @@ -0,0 +1,104 @@ +// license:BSD-3-Clause +// copyright-holders:AJR +/*************************************************************************** + + Zenith Z-29 keyboard port + +***************************************************************************/ + +#ifndef MAME_BUS_Z29_KBD_KEYBOARD_H +#define MAME_BUS_Z29_KBD_KEYBOARD_H + +#pragma once + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// forward declaration +class device_z29_keyboard_interface; + +// ======================> z29_keyboard_port_device + +class z29_keyboard_port_device : public device_t, public device_single_card_slot_interface +{ + friend class device_z29_keyboard_interface; + +public: + // construction/destruction + z29_keyboard_port_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); + template + z29_keyboard_port_device(const machine_config &mconfig, const char *tag, device_t *owner, T &&opts, const char *dflt) + : z29_keyboard_port_device(mconfig, tag, owner, 0U) + { + option_reset(); + opts(*this); + set_default_option(dflt); + set_fixed(false); + } + + // callback configuration + auto keyin_callback() { return m_keyin_callback.bind(); } + auto reset_callback() { return m_reset_callback.bind(); } + + // line handler + inline DECLARE_WRITE_LINE_MEMBER(keyout_w); + +protected: + // device-level overrides + virtual void device_config_complete() override; + virtual void device_resolve_objects() override; + virtual void device_start() override; + + // called from keyboard + void transmit_data(bool state) { m_keyin_callback(state); } + void reset_from_keyboard(bool state) { m_reset_callback(state); } + +private: + // line callbacks + devcb_write_line m_keyin_callback; + devcb_write_line m_reset_callback; + + // selected keyboard + device_z29_keyboard_interface *m_kbd; +}; + +// ======================> device_z29_keyboard_interface + +class device_z29_keyboard_interface : public device_interface +{ + friend class z29_keyboard_port_device; + +protected: + // construction/destruction + device_z29_keyboard_interface(const machine_config &mconfig, device_t &device); + virtual ~device_z29_keyboard_interface(); + + void transmit_data(bool state) { m_port->transmit_data(state); } + void reset_from_keyboard(bool state) { m_port->reset_from_keyboard(state); } + + virtual void receive_data(bool state) = 0; + +private: + // parent port + required_device m_port; +}; + +// device type definition +DECLARE_DEVICE_TYPE(Z29_KEYBOARD, z29_keyboard_port_device) + +// standard options +extern void z29_keyboards(device_slot_interface &slot); + +//************************************************************************** +// INLINE FUNCTIONS +//************************************************************************** + +WRITE_LINE_MEMBER(z29_keyboard_port_device::keyout_w) +{ + if (m_kbd != nullptr) + m_kbd->receive_data(state); +} + +#endif // MAME_BUS_Z29_KBD_KEYBOARD_H diff --git a/src/devices/bus/z29_kbd/md_kbd.cpp b/src/devices/bus/z29_kbd/md_kbd.cpp new file mode 100644 index 00000000000..1a313af10ce --- /dev/null +++ b/src/devices/bus/z29_kbd/md_kbd.cpp @@ -0,0 +1,277 @@ +// license:BSD-3-Clause +// copyright-holders:AJR +/*************************************************************************** + + Micro-Decision keyboard + + This 93-key keyboard was obtained with a Morrow MD3-P. The unit part + number is unknown, but "DEKU-0224-PHM-B" and "I/F PCB FOR 14515B" are + silkscreened on the component board. + + Like the original Z-29 keyboard, it may also have been designed by + Heath/Zenith. It is missing the Erase, Set Up and Break keys (though + the first two are still recognized by the program), but has five + additional function keys instead. + + Some clumsy coding suggests that the program was originally designed + for an 8048 operating in single-chip mode, with the 14515B and LS175 + having being added to latch outputs also sent to the upper half of + Port 2. + +***************************************************************************/ + +#include "emu.h" +#include "md_kbd.h" + +#include "machine/rescap.h" +#include "speaker.h" + + +DEFINE_DEVICE_TYPE(MD_KEYBOARD, md_keyboard_device, "md_kbd", "Micro-Decision Keyboard") + +md_keyboard_device::md_keyboard_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : device_t(mconfig, MD_KEYBOARD, tag, owner, clock) + , device_z29_keyboard_interface(mconfig, *this) + , m_mcu(*this, "mcu") + , m_buzzer(*this, "buzzer") + , m_matrix(*this, "S%u", 0U) + , m_leds(*this, "led%u", 1U) + , m_14515b_select(0) + , m_ls175_clock(true) + , m_recv_data(true) +{ +} + +void md_keyboard_device::device_resolve_objects() +{ + m_leds.resolve(); +} + +void md_keyboard_device::device_start() +{ + save_item(NAME(m_14515b_select)); + save_item(NAME(m_ls175_clock)); + save_item(NAME(m_recv_data)); +} + +void md_keyboard_device::device_reset() +{ + ls175_w(0); +} + +void md_keyboard_device::receive_data(bool state) +{ + machine().scheduler().synchronize(timer_expired_delegate(FUNC(md_keyboard_device::receive_data_synced), this), state); +} + +TIMER_CALLBACK_MEMBER(md_keyboard_device::receive_data_synced) +{ + m_recv_data = param; +} + +void md_keyboard_device::ls175_w(u8 data) +{ + m_leds[0] = !BIT(data, 7); // Caps Lock + m_leds[1] = !BIT(data, 5); // Keyboard lock? + m_buzzer->set_state(BIT(data, 6)); +} + +u8 md_keyboard_device::mcu_p1_r() +{ + return 0xc0 | m_matrix[m_14515b_select]->read(); +} + +void md_keyboard_device::mcu_p1_w(u8 data) +{ + transmit_data(!BIT(data, 7)); + if (!m_ls175_clock && BIT(data, 6)) + ls175_w(m_mcu->p2_r()); + m_ls175_clock = BIT(data, 6); +} + +READ_LINE_MEMBER(md_keyboard_device::mcu_t1_r) +{ + return m_recv_data; +} + +void md_keyboard_device::mcu_movx_w(u8 data) +{ + m_14515b_select = (data >> 4) & 0x0f; +} + +void md_keyboard_device::prog_map(address_map &map) +{ + map(0x000, 0xfff).rom().region("program", 0); +} + +void md_keyboard_device::ext_map(address_map &map) +{ + map(0x00, 0x00).mirror(0xff).w(FUNC(md_keyboard_device::mcu_movx_w)); +} + + +static INPUT_PORTS_START(md_kbd) + + PORT_START("S0") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('q') PORT_CHAR('Q') PORT_CODE(KEYCODE_Q) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('g') PORT_CHAR('G') PORT_CODE(KEYCODE_G) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(';') PORT_CHAR(':') PORT_CODE(KEYCODE_COLON) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(0_PAD)) PORT_CODE(KEYCODE_0_PAD) + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('0') PORT_CHAR(')') PORT_CODE(KEYCODE_0) + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Erase") // not actually on keyboard? + + PORT_START("S1") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('w') PORT_CHAR('W') PORT_CODE(KEYCODE_W) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('b') PORT_CHAR('B') PORT_CODE(KEYCODE_B) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(']') PORT_CHAR('}') PORT_CODE(KEYCODE_CLOSEBRACE) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(9_PAD)) PORT_CODE(KEYCODE_9_PAD) + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('9') PORT_CHAR('(') PORT_CODE(KEYCODE_9) + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Help") PORT_CODE(KEYCODE_F12) + + PORT_START("S2") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('e') PORT_CHAR('E') PORT_CODE(KEYCODE_E) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('n') PORT_CHAR('N') PORT_CODE(KEYCODE_N) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('[') PORT_CHAR('{') PORT_CODE(KEYCODE_OPENBRACE) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(8_PAD)) PORT_CODE(KEYCODE_8_PAD) + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('8') PORT_CHAR('*') PORT_CODE(KEYCODE_8) + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Home Clear") PORT_CHAR(UCHAR_MAMEKEY(HOME)) PORT_CODE(KEYCODE_F11) + + PORT_START("S3") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('r') PORT_CHAR('R') PORT_CODE(KEYCODE_R) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('m') PORT_CHAR('M') PORT_CODE(KEYCODE_M) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('-') PORT_CHAR('_') PORT_CODE(KEYCODE_MINUS) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(7_PAD)) PORT_CODE(KEYCODE_7_PAD) + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('7') PORT_CHAR('&') PORT_CODE(KEYCODE_7) + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_UNUSED) + + PORT_START("S4") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('f') PORT_CHAR('F') PORT_CODE(KEYCODE_F) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('l') PORT_CHAR('L') PORT_CODE(KEYCODE_L) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('=') PORT_CHAR('+') PORT_CODE(KEYCODE_EQUALS) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(6_PAD)) PORT_CODE(KEYCODE_6_PAD) + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('6') PORT_CHAR('^') PORT_CODE(KEYCODE_6) + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("No Scroll") PORT_CODE(KEYCODE_ESC) + + PORT_START("S5") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('d') PORT_CHAR('D') PORT_CODE(KEYCODE_D) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('k') PORT_CHAR('K') PORT_CODE(KEYCODE_K) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('`') PORT_CHAR('~') PORT_CODE(KEYCODE_BACKSLASH) // to right of +/= + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(5_PAD)) PORT_CODE(KEYCODE_5_PAD) + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('5') PORT_CHAR('%') PORT_CODE(KEYCODE_5) + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Caps Lock") PORT_CHAR(UCHAR_MAMEKEY(CAPSLOCK)) PORT_CODE(KEYCODE_CAPSLOCK) + + PORT_START("S6") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('s') PORT_CHAR('S') PORT_CODE(KEYCODE_S) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('j') PORT_CHAR('J') PORT_CODE(KEYCODE_J) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('\'') PORT_CHAR('"') PORT_CODE(KEYCODE_QUOTE) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(4_PAD)) PORT_CODE(KEYCODE_4_PAD) + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('4') PORT_CHAR('$') PORT_CODE(KEYCODE_4) + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Del") PORT_CHAR(UCHAR_MAMEKEY(DEL)) PORT_CODE(KEYCODE_DEL) + + PORT_START("S7") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('a') PORT_CHAR('A') PORT_CODE(KEYCODE_A) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('h') PORT_CHAR('H') PORT_CODE(KEYCODE_H) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('p') PORT_CHAR('P') PORT_CODE(KEYCODE_P) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(3_PAD)) PORT_CODE(KEYCODE_3_PAD) + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('3') PORT_CHAR('#') PORT_CODE(KEYCODE_3) + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(UP)) PORT_CODE(KEYCODE_UP) + + PORT_START("S8") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('z') PORT_CHAR('Z') PORT_CODE(KEYCODE_Z) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('t') PORT_CHAR('T') PORT_CODE(KEYCODE_T) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('o') PORT_CHAR('O') PORT_CODE(KEYCODE_O) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(2_PAD)) PORT_CODE(KEYCODE_2_PAD) + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('2') PORT_CHAR('@') PORT_CODE(KEYCODE_2) + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(DOWN)) PORT_CODE(KEYCODE_DOWN) + + PORT_START("S9") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('x') PORT_CHAR('X') PORT_CODE(KEYCODE_X) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('y') PORT_CHAR('Y') PORT_CODE(KEYCODE_Y) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('\\') PORT_CHAR('|') PORT_CODE(KEYCODE_RCONTROL) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(1_PAD)) PORT_CODE(KEYCODE_1_PAD) + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('1') PORT_CHAR('!') PORT_CODE(KEYCODE_1) + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(RIGHT)) PORT_CODE(KEYCODE_RIGHT) + + PORT_START("S10") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('c') PORT_CHAR('C') PORT_CODE(KEYCODE_C) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('u') PORT_CHAR('U') PORT_CODE(KEYCODE_U) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(',') PORT_CHAR('<') PORT_CODE(KEYCODE_COMMA) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(COMMA_PAD)) PORT_CODE(KEYCODE_PLUS_PAD) + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Esc") PORT_CHAR(0x1b) PORT_CODE(KEYCODE_TILDE) + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(LEFT)) PORT_CODE(KEYCODE_LEFT) + + PORT_START("S11") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('v') PORT_CHAR('V') PORT_CODE(KEYCODE_V) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('i') PORT_CHAR('I') PORT_CODE(KEYCODE_I) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('.') PORT_CHAR('>') PORT_CODE(KEYCODE_STOP) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(DEL_PAD)) PORT_CODE(KEYCODE_DEL_PAD) + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Tab") PORT_CHAR('\t') PORT_CODE(KEYCODE_TAB) + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('/') PORT_CHAR('?') PORT_CODE(KEYCODE_SLASH) + + PORT_START("S12") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(' ') PORT_CODE(KEYCODE_SPACE) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Return") PORT_CHAR(0x0d) PORT_CODE(KEYCODE_ENTER) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Keypad Enter +") PORT_CHAR(UCHAR_MAMEKEY(ENTER_PAD)) PORT_CODE(KEYCODE_ENTER_PAD) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(MINUS_PAD)) PORT_CODE(KEYCODE_MINUS_PAD) + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Line Feed") PORT_CHAR(0x0a) PORT_CODE(KEYCODE_RALT) + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Back Space") PORT_CHAR(0x08) PORT_CODE(KEYCODE_BACKSPACE) + + PORT_START("S13") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(F1)) PORT_CODE(KEYCODE_F1) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(F2)) PORT_CODE(KEYCODE_F2) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(F3)) PORT_CODE(KEYCODE_F3) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(F4)) PORT_CODE(KEYCODE_F4) + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(F5)) PORT_CODE(KEYCODE_F5) + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(F6)) PORT_CODE(KEYCODE_F6) + + PORT_START("S14") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(F7)) PORT_CODE(KEYCODE_F7) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(F8)) PORT_CODE(KEYCODE_F8) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(F9)) PORT_CODE(KEYCODE_F9) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(F10)) PORT_CODE(KEYCODE_F10) + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("FA") PORT_CHAR(UCHAR_MAMEKEY(F11)) + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("FB") PORT_CHAR(UCHAR_MAMEKEY(F12)) + + PORT_START("S15") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Setup") // not actually on keyboard? + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("FD") PORT_CHAR(UCHAR_MAMEKEY(F14)) + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("FC") PORT_CHAR(UCHAR_MAMEKEY(F13)) + + PORT_START("MODIFIERS") + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Ctrl") PORT_CHAR(UCHAR_SHIFT_2) PORT_CODE(KEYCODE_LCONTROL) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Shift") PORT_CHAR(UCHAR_SHIFT_1) PORT_CODE(KEYCODE_LSHIFT) PORT_CODE(KEYCODE_RSHIFT) +INPUT_PORTS_END + +ioport_constructor md_keyboard_device::device_input_ports() const +{ + return INPUT_PORTS_NAME(md_kbd); +} + +void md_keyboard_device::device_add_mconfig(machine_config &config) +{ + // U4 is M5L8048-052P (internal ROM likely unused), but location is silkscreened "8035" + I8035(config, m_mcu, 3.579545_MHz_XTAL); // "CSA 3 58MT" resonator + m_mcu->set_addrmap(AS_PROGRAM, &md_keyboard_device::prog_map); + m_mcu->set_addrmap(AS_IO, &md_keyboard_device::ext_map); + m_mcu->p1_in_cb().set(FUNC(md_keyboard_device::mcu_p1_r)); + m_mcu->p1_out_cb().set(FUNC(md_keyboard_device::mcu_p1_w)); + m_mcu->p2_in_cb().set_ioport("MODIFIERS"); + m_mcu->t1_in_cb().set(FUNC(md_keyboard_device::mcu_t1_r)); + + SPEAKER(config, "speaker").front_center(); + BEEP(config, m_buzzer, 1'000'000'000 / PERIOD_OF_555_ASTABLE_NSEC(RES_R(510), RES_R(510), CAP_U(1))); + m_buzzer->add_route(ALL_OUTPUTS, "speaker", 1.0); +} + +ROM_START(md_kbd) + ROM_REGION(0x1000, "program", 0) + ROM_LOAD("kb-rom_rev_3.4_27d4.u5", 0x0000, 0x1000, CRC(c34b606b) SHA1(20cf62fc31257b6c3e767152086f2604fead97bd)) // location marked "2716/2732" +ROM_END + +const tiny_rom_entry *md_keyboard_device::device_rom_region() const +{ + return ROM_NAME(md_kbd); +} diff --git a/src/devices/bus/z29_kbd/md_kbd.h b/src/devices/bus/z29_kbd/md_kbd.h new file mode 100644 index 00000000000..8a81b9a461d --- /dev/null +++ b/src/devices/bus/z29_kbd/md_kbd.h @@ -0,0 +1,61 @@ +// license:BSD-3-Clause +// copyright-holders:AJR + +#ifndef MAME_BUS_Z29_KBD_MD_KBD_H +#define MAME_BUS_Z29_KBD_MD_KBD_H + +#pragma once + +#include "keyboard.h" +#include "cpu/mcs48/mcs48.h" +#include "sound/beep.h" + +class md_keyboard_device : public device_t, public device_z29_keyboard_interface +{ +public: + // device type constructor + md_keyboard_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); + +protected: + // device-level overrides + virtual void device_resolve_objects() override; + virtual void device_start() override; + virtual void device_reset() override; + virtual ioport_constructor device_input_ports() const override; + virtual void device_add_mconfig(machine_config &config) override; + virtual const tiny_rom_entry *device_rom_region() const override; + + // device_z29_keyboard_interface overrides + virtual void receive_data(bool state) override; + +private: + // MCU handlers + u8 mcu_p1_r(); + void mcu_p1_w(u8 data); + DECLARE_READ_LINE_MEMBER(mcu_t1_r); + void mcu_movx_w(u8 data); + + // misc. helpers + TIMER_CALLBACK_MEMBER(receive_data_synced); + void ls175_w(u8 data); + + // address maps + void prog_map(address_map &map); + void ext_map(address_map &map); + + // object finders + required_device m_mcu; + required_device m_buzzer; + required_ioport_array<16> m_matrix; + output_finder<2> m_leds; + + // internal state + u8 m_14515b_select; + bool m_ls175_clock; + bool m_recv_data; +}; + +// device type declaration +DECLARE_DEVICE_TYPE(MD_KEYBOARD, md_keyboard_device) + +#endif // MAME_BUS_Z29_KBD_MD_KBD_H diff --git a/src/mame/drivers/mdt60.cpp b/src/mame/drivers/mdt60.cpp index 493ee5daf07..90ef746f92a 100644 --- a/src/mame/drivers/mdt60.cpp +++ b/src/mame/drivers/mdt60.cpp @@ -2,58 +2,41 @@ // copyright-holders:AJR /************************************************************************** - Skeleton driver for MDT 60 and related Zenith terminals. - MDT 60 was designed by Zenith for use with Morrow's Micro-Decision computers as a low-cost terminal with limited features. It appears to be a stripped-down version of some previously designed terminal, with the auxiliary port omitted from the Morrow version even though - the schematics published by Morrow include it. Morrow's schematics - also include the same keyboard used by the Z-29, though the actual - keyboard found with one unit was different. + the schematics published in its service manual include it. These + schematics also include the same keyboard used by the Z-29, though + the actual keyboard found with one unit was different. **************************************************************************/ #include "emu.h" #include "bus/rs232/rs232.h" +#include "bus/z29_kbd/keyboard.h" #include "cpu/m6502/m6502.h" -#include "machine/eepromser.h" #include "machine/i8251.h" -#include "machine/pit8253.h" #include "video/mc6845.h" #include "screen.h" -class mdt60_base_state : public driver_device -{ -public: - mdt60_base_state(const machine_config &mconfig, device_type type, const char *tag) - : driver_device(mconfig, type, tag) - , m_maincpu(*this, "maincpu") - , m_crtc(*this, "crtc") - , m_uart(*this, "uart%u", 0U) - , m_charram(*this, "charram") - { - } - -protected: - MC6845_ON_UPDATE_ADDR_CHANGED(update_cb); - - required_device m_maincpu; - required_device m_crtc; - optional_device_array m_uart; - required_shared_ptr m_charram; -}; - -class mdt60_state : public mdt60_base_state +class mdt60_state : public driver_device { public: mdt60_state(const machine_config &mconfig, device_type type, const char *tag) - : mdt60_base_state(mconfig, type, tag) + : driver_device(mconfig, type, tag) + , m_maincpu(*this, "maincpu") + , m_keyboard(*this, "keyboard") + , m_crtc(*this, "crtc") + , m_uart(*this, "uart%u", 0U) + , m_charram(*this, "charram") , m_charrom(*this, "charrom") , m_attrram(*this, "attrram") , m_dip0(*this, "DIP0") + , m_baud_timer(nullptr) , m_keyin(false) - , m_reverse(false) + , m_output_reg(0x3f) + , m_timer_output(false) { } @@ -65,6 +48,8 @@ protected: private: MC6845_UPDATE_ROW(update_row); + MC6845_ON_UPDATE_ADDR_CHANGED(update_cb); + TIMER_CALLBACK_MEMBER(baud_timer); DECLARE_WRITE_LINE_MEMBER(keyin_w); u8 dip0_r(offs_t offset); @@ -72,54 +57,30 @@ private: void mem_map(address_map &map); + required_device m_maincpu; + required_device m_keyboard; + required_device m_crtc; + optional_device_array m_uart; + required_shared_ptr m_charram; required_region_ptr m_charrom; required_shared_ptr m_attrram; required_ioport m_dip0; + emu_timer *m_baud_timer; + bool m_keyin; - bool m_reverse; -}; - -class z22_state : public mdt60_base_state -{ -public: - z22_state(const machine_config &mconfig, device_type type, const char *tag) - : mdt60_base_state(mconfig, type, tag) - , m_eeprom(*this, "eeprom") - , m_fontram(*this, "fontram") - , m_eeprom_clk(false) - { - } - - void z22(machine_config &config); - -protected: - virtual void machine_start() override; - -private: - MC6845_UPDATE_ROW(update_row); - - u8 status_r(); - void control_w(u8 data); - DECLARE_WRITE_LINE_MEMBER(eeprom_clock_w); - - void mem_map(address_map &map); - - required_device m_eeprom; - required_shared_ptr m_fontram; - - bool m_eeprom_clk; + u8 m_output_reg; + bool m_timer_output; }; void mdt60_state::machine_start() { - save_item(NAME(m_keyin)); - save_item(NAME(m_reverse)); -} + m_baud_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(mdt60_state::baud_timer), this)); + m_baud_timer->adjust(attotime::zero); -void z22_state::machine_start() -{ - save_item(NAME(m_eeprom_clk)); + save_item(NAME(m_keyin)); + save_item(NAME(m_output_reg)); + save_item(NAME(m_timer_output)); } void mdt60_state::machine_reset() @@ -128,6 +89,23 @@ void mdt60_state::machine_reset() } +TIMER_CALLBACK_MEMBER(mdt60_state::baud_timer) +{ + m_timer_output = !m_timer_output; + + // LS352 multiplexer has inverting outputs + m_uart[0]->write_rxc(!m_timer_output); + m_uart[0]->write_txc(!m_timer_output); + + constexpr auto time_base = 16.5888_MHz_XTAL / 9; + if ((m_output_reg & 0x06) == 0x00) + m_baud_timer->adjust(attotime::from_ticks(m_timer_output ? 2 : 4, time_base)); + else if ((m_output_reg & 0x06) == 0x06) + m_baud_timer->adjust(attotime::from_ticks(48, time_base)); + else + m_baud_timer->adjust(attotime::from_ticks(3 * (m_output_reg & 0x06), time_base)); +} + MC6845_UPDATE_ROW(mdt60_state::update_row) { u32 *pix = &bitmap.pix32(y); @@ -147,7 +125,7 @@ MC6845_UPDATE_ROW(mdt60_state::update_row) rgb_t fg = BIT(adata, 1) ? rgb_t::white() : rgb_t(0xc0, 0xc0, 0xc0); rgb_t bg = rgb_t::black(); - if (m_reverse) + if (BIT(m_output_reg, 5)) std::swap(fg, bg); for (int n = 8; n >= 0; n--) @@ -155,27 +133,7 @@ MC6845_UPDATE_ROW(mdt60_state::update_row) } } -MC6845_UPDATE_ROW(z22_state::update_row) -{ - u32 *pix = &bitmap.pix32(y); - - for (unsigned x = 0; x < x_count; x++) - { - u8 cdata = m_charram[(ma + x) & 0x7ff]; - u16 dots = m_fontram[(cdata & 0x7f) << 4 | ra] << 1; - - if (x == cursor_x) - dots = ~dots; - - rgb_t fg = rgb_t::white(); - rgb_t bg = rgb_t::black(); - - for (int n = 8; n >= 0; n--) - *pix++ = BIT(dots, n) ? fg : bg; - } -} - -MC6845_ON_UPDATE_ADDR_CHANGED(mdt60_base_state::update_cb) +MC6845_ON_UPDATE_ADDR_CHANGED(mdt60_state::update_cb) { } @@ -190,9 +148,9 @@ u8 mdt60_state::dip0_r(offs_t offset) { u8 buffer = 0xff; if (!BIT(offset, 0)) - buffer &= m_dip0->read() | 0x80; + buffer &= m_dip0->read() >> 1 | 0x80; if (!BIT(offset, 1)) - buffer &= m_dip0->read() >> 7 | 0xfe; + buffer &= m_dip0->read() | 0xfe; if (!m_keyin) buffer &= 0x7f; return buffer; @@ -200,29 +158,11 @@ u8 mdt60_state::dip0_r(offs_t offset) void mdt60_state::reg_w(u8 data) { - //m_keyboard->keyout_w(BIT(data, 0)); - m_reverse = BIT(data, 5); -} + if (BIT(data, 0) != BIT(m_output_reg, 0)) + m_keyboard->keyout_w(BIT(data, 0)); -u8 z22_state::status_r() -{ - u8 result = 0; - if (m_eeprom_clk) - result |= 0x02; - if (!m_eeprom->do_read()) - result |= 0x01; - return result; -} - -void z22_state::control_w(u8 data) -{ - m_eeprom->di_write(!BIT(data, 7)); - m_eeprom->cs_write(BIT(data, 6)); -} - -WRITE_LINE_MEMBER(z22_state::eeprom_clock_w) -{ - m_eeprom_clk = state; + // Bits 1–2 & 3–4 select 1 of 4 baud rates for each UART; bit 5 selects inverse video + m_output_reg = data & 0x3f; } void mdt60_state::mem_map(address_map &map) @@ -240,23 +180,9 @@ void mdt60_state::mem_map(address_map &map) map(0xe000, 0xefff).mirror(0x1000).rom().region("coderom", 0); } -void z22_state::mem_map(address_map &map) -{ - map(0x0000, 0x07ff).ram(); - map(0x2000, 0x27ff).ram().share("charram"); - map(0x4000, 0x4001).rw(m_uart[1], FUNC(i8251_device::read), FUNC(i8251_device::write)); - map(0x6000, 0x67ff).ram().share("fontram"); - map(0x8000, 0x8001).rw(m_uart[0], FUNC(i8251_device::read), FUNC(i8251_device::write)); - map(0x8800, 0x8800).rw(m_crtc, FUNC(r6545_1_device::status_r), FUNC(r6545_1_device::address_w)); - map(0x8801, 0x8801).rw(m_crtc, FUNC(r6545_1_device::register_r), FUNC(r6545_1_device::register_w)); - map(0x9000, 0x9003).w("pit", FUNC(pit8254_device::write)); - map(0xa000, 0xa000).rw(FUNC(z22_state::status_r), FUNC(z22_state::control_w)); - map(0xc000, 0xffff).rom().region("program", 0); -} - static INPUT_PORTS_START(mdt60) - PORT_START("DIP0") // TODO: verify bit assignments + PORT_START("DIP0") PORT_DIPNAME(0x03, 0x01, "Baud Rate") PORT_DIPLOCATION("SW1:1,2") PORT_DIPSETTING(0x03, "300") PORT_DIPSETTING(0x02, "1200") @@ -284,9 +210,6 @@ static INPUT_PORTS_START(mdt60) PORT_BIT(0xff, 0xff, IPT_UNUSED) // SW2 is unpopulated INPUT_PORTS_END -static INPUT_PORTS_START(z22) -INPUT_PORTS_END - // XTAL frequency is specified as 16.589 MHz on actual parts as well as in MDT 60 schematics. // This has been assumed to be a lower-precision specification of the common 16.5888 MHz value. @@ -297,12 +220,15 @@ void mdt60_state::mdt60(machine_config &config) I8251(config, m_uart[0], 16.5888_MHz_XTAL / 9); // TMP8251AP (U19) m_uart[0]->rxrdy_handler().set_inputline(m_maincpu, m6512_device::NMI_LINE); - m_uart[0]->txd_handler().set("computer", FUNC(rs232_port_device::write_txd)); - m_uart[0]->dtr_handler().set("computer", FUNC(rs232_port_device::write_dtr)); - m_uart[0]->rts_handler().set("computer", FUNC(rs232_port_device::write_rts)); + m_uart[0]->txd_handler().set("comm", FUNC(rs232_port_device::write_txd)); + m_uart[0]->dtr_handler().set("comm", FUNC(rs232_port_device::write_dtr)); + m_uart[0]->rts_handler().set("comm", FUNC(rs232_port_device::write_rts)); // UART 1 (at U28) is unpopulated and not used by code + Z29_KEYBOARD(config, m_keyboard, z29_keyboards, "md"); + m_keyboard->keyin_callback().set(FUNC(mdt60_state::keyin_w)).invert(); + screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER)); screen.set_color(rgb_t::amber()); screen.set_raw(16.5888_MHz_XTAL, 918, 0, 720, 301, 0, 288); @@ -314,54 +240,10 @@ void mdt60_state::mdt60(machine_config &config) m_crtc->set_char_width(9); m_crtc->set_update_row_callback(FUNC(mdt60_state::update_row)); m_crtc->set_on_update_addr_change_callback(FUNC(mdt60_state::update_cb)); + // LPEN is tied to GND (code uses this to determine CRTC type) - rs232_port_device &computer(RS232_PORT(config, "computer", default_rs232_devices, nullptr)); - computer.rxd_handler().set(m_uart[0], FUNC(i8251_device::write_rxd)); - computer.dsr_handler().set(m_uart[0], FUNC(i8251_device::write_dsr)); - computer.cts_handler().set(m_uart[0], FUNC(i8251_device::write_cts)); -} - -void z22_state::z22(machine_config &config) -{ - M6512(config, m_maincpu, 16.5888_MHz_XTAL / 9); // R6512AP - m_maincpu->set_addrmap(AS_PROGRAM, &z22_state::mem_map); - - I8251(config, m_uart[0], 16.5888_MHz_XTAL / 9); // NEC D8251AC (U33) + Intel P8251A (U35) - m_uart[0]->rxrdy_handler().set_inputline(m_maincpu, m6512_device::NMI_LINE); - m_uart[0]->txd_handler().set("comm", FUNC(rs232_port_device::write_txd)); - m_uart[0]->dtr_handler().set("comm", FUNC(rs232_port_device::write_dtr)); - m_uart[0]->rts_handler().set("comm", FUNC(rs232_port_device::write_rts)); - - I8251(config, m_uart[1], 16.5888_MHz_XTAL / 9); - - EEPROM_93C06_16BIT(config, m_eeprom); // NMC9306 (U27) - - pit8254_device &pit(PIT8254(config, "pit")); // Intel P8254 - pit.set_clk<0>(16.5888_MHz_XTAL / 9); - pit.set_clk<1>(16.5888_MHz_XTAL / 9); - pit.set_clk<2>(16.5888_MHz_XTAL / 9); - pit.out_handler<0>().set(m_uart[1], FUNC(i8251_device::write_rxc)); - pit.out_handler<0>().append(m_uart[1], FUNC(i8251_device::write_txc)); - pit.out_handler<0>().append(m_eeprom, FUNC(eeprom_serial_93cxx_device::clk_write)); // weird synchronous clocking - pit.out_handler<0>().append(FUNC(z22_state::eeprom_clock_w)); - pit.out_handler<1>().set(m_uart[0], FUNC(i8251_device::write_rxc)); - pit.out_handler<2>().set(m_uart[0], FUNC(i8251_device::write_txc)); // or the other way around? - - screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER)); - screen.set_color(rgb_t::amber()); - screen.set_raw(16.5888_MHz_XTAL, 873, 0, 720, 317, 0, 300); - screen.set_screen_update(m_crtc, FUNC(r6545_1_device::screen_update)); - - R6545_1(config, m_crtc, 16.5888_MHz_XTAL / 9); // R6545-1AP - m_crtc->set_screen("screen"); - m_crtc->set_show_border_area(false); - m_crtc->set_char_width(9); - m_crtc->set_update_row_callback(FUNC(z22_state::update_row)); - m_crtc->set_on_update_addr_change_callback(FUNC(z22_state::update_cb)); - - // TODO: onboard buzzer - - rs232_port_device &comm(RS232_PORT(config, "comm", default_rs232_devices, nullptr)); + rs232_port_device &comm(RS232_PORT(config, "comm", default_rs232_devices, "loopback")); + // Service Manual suggests shorting pins with a bent paper clip if no DB-25 loopback connector is available ;-) comm.rxd_handler().set(m_uart[0], FUNC(i8251_device::write_rxd)); comm.dsr_handler().set(m_uart[0], FUNC(i8251_device::write_dsr)); comm.cts_handler().set(m_uart[0], FUNC(i8251_device::write_cts)); @@ -370,17 +252,11 @@ void z22_state::z22(machine_config &config) ROM_START(mdt60) ROM_REGION(0x1000, "coderom", 0) + // "ROM REV. 1.7 -- Copyright (C) 1983 by Morrow Designs, Inc." ROM_LOAD("vb-rom_1.7_bcfd.u9", 0x0000, 0x1000, CRC(3902f7b3) SHA1(ee0ce7f68efe20efe1ab8a44888e276f08fe2d07)) ROM_REGION(0x1000, "charrom", 0) ROM_LOAD("char_gen_b207.u6", 0x0000, 0x1000, CRC(b19432da) SHA1(fa73641c08b778f19a17676a7f4074f69b7b55dd)) ROM_END -ROM_START(z22) - ROM_REGION(0x4000, "program", 0) - ROM_LOAD("u39.bin", 0x0000, 0x2000, CRC(2f62c1f8) SHA1(448581d987fee6b4303e481e78f46d3255baccbb)) // D2764A-3 - ROM_LOAD("u38.bin", 0x2000, 0x2000, CRC(f0bfe9b5) SHA1(8807841b28549d0ddf30275fc6035a66093f8768)) // D2764A-3 -ROM_END - -SYST(1983, mdt60, 0, 0, mdt60, mdt60, mdt60_state, empty_init, "Morrow", "MDT 60 Video Display Terminal", MACHINE_NOT_WORKING | MACHINE_NO_SOUND) -SYST(1984, z22, 0, 0, z22, z22, z22_state, empty_init, "Zenith Data Systems", "Z-22 Terminal", MACHINE_NOT_WORKING | MACHINE_NO_SOUND) +SYST(1983, mdt60, 0, 0, mdt60, mdt60, mdt60_state, empty_init, "Morrow Designs", "MDT 60 Video Display Terminal", MACHINE_SUPPORTS_SAVE) diff --git a/src/mame/drivers/z22.cpp b/src/mame/drivers/z22.cpp new file mode 100644 index 00000000000..7421bf9ad16 --- /dev/null +++ b/src/mame/drivers/z22.cpp @@ -0,0 +1,215 @@ +// license:BSD-3-Clause +// copyright-holders:AJR +/************************************************************************** + + Skeleton driver for Zenith Z-22 terminal. + + Despite featuring much of the same hardware as the MDT 60, with the + CPU, CRTC and UART types and even dot clock frequency being identical, + much else is different: a serial EEPROM replaces DIP switches, an 8254 + generates baud rates, fonts are uploaded to RAM, and the serial + keyboard protocol is incompatible. + +**************************************************************************/ + +#include "emu.h" +#include "bus/rs232/rs232.h" +#include "cpu/m6502/m6502.h" +#include "machine/eepromser.h" +#include "machine/i8251.h" +#include "machine/pit8253.h" +#include "video/mc6845.h" +#include "screen.h" + +class z22_state : public driver_device +{ +public: + z22_state(const machine_config &mconfig, device_type type, const char *tag) + : driver_device(mconfig, type, tag) + , m_maincpu(*this, "maincpu") + , m_crtc(*this, "crtc") + , m_uart(*this, "uart%u", 0U) + , m_eeprom(*this, "eeprom") + , m_dispram(*this, "dispram") + , m_fontram(*this, "fontram") + , m_eeprom_clk(false) + { + } + + void z22(machine_config &config); + +protected: + virtual void machine_start() override; + virtual void machine_reset() override; + +private: + MC6845_UPDATE_ROW(update_row); + MC6845_ON_UPDATE_ADDR_CHANGED(update_cb); + + u8 irq_ack_r(); + u8 status_r(); + void control_w(u8 data); + + DECLARE_WRITE_LINE_MEMBER(eeprom_clock_w); + + void mem_map(address_map &map); + + required_device m_maincpu; + required_device m_crtc; + optional_device_array m_uart; + required_device m_eeprom; + required_shared_ptr m_dispram; + required_shared_ptr m_fontram; + + bool m_eeprom_clk; +}; + +void z22_state::machine_start() +{ + save_item(NAME(m_eeprom_clk)); +} + +void z22_state::machine_reset() +{ + control_w(0); +} + + +MC6845_UPDATE_ROW(z22_state::update_row) +{ + u32 *pix = &bitmap.pix32(y); + + for (unsigned x = 0; x < x_count; x++) + { + u8 cdata = m_dispram[(ma + x) & 0x7ff]; + u16 dots = m_fontram[(cdata & 0x7f) << 4 | ra] << 1; + + if (x == cursor_x) + dots = ~dots; + + rgb_t fg = rgb_t::white(); + rgb_t bg = rgb_t::black(); + + for (int n = 8; n >= 0; n--) + *pix++ = BIT(dots, n) ? fg : bg; + } +} + +MC6845_ON_UPDATE_ADDR_CHANGED(z22_state::update_cb) +{ +} + + +u8 z22_state::irq_ack_r() +{ + if (!machine().side_effects_disabled()) + m_maincpu->set_input_line(m6512_device::IRQ_LINE, CLEAR_LINE); + return 0xff; +} + +u8 z22_state::status_r() +{ + u8 result = 0; + if (!m_eeprom->do_read()) + result |= 0x01; + if (m_eeprom_clk) + result |= 0x02; + // TODO: bit 7 = received keyboard data + return result; +} + +void z22_state::control_w(u8 data) +{ + m_eeprom->di_write(!BIT(data, 7)); + m_eeprom->cs_write(BIT(data, 6)); + //m_keyboard->keyout_w(BIT(data, 0)); +} + +WRITE_LINE_MEMBER(z22_state::eeprom_clock_w) +{ + m_eeprom_clk = state; + if (state) + m_maincpu->set_input_line(m6512_device::IRQ_LINE, ASSERT_LINE); +} + +void z22_state::mem_map(address_map &map) +{ + map(0x0000, 0x07ff).ram(); + map(0x2000, 0x27ff).ram().share("dispram"); + map(0x4000, 0x4001).rw(m_uart[1], FUNC(i8251_device::read), FUNC(i8251_device::write)); + map(0x6000, 0x67ff).ram().share("fontram"); + map(0x8000, 0x8001).rw(m_uart[0], FUNC(i8251_device::read), FUNC(i8251_device::write)); + map(0x8800, 0x8800).rw(m_crtc, FUNC(r6545_1_device::status_r), FUNC(r6545_1_device::address_w)); + map(0x8801, 0x8801).rw(m_crtc, FUNC(r6545_1_device::register_r), FUNC(r6545_1_device::register_w)); + map(0x9000, 0x9003).w("pit", FUNC(pit8254_device::write)); + map(0x9800, 0x9800).r(FUNC(z22_state::irq_ack_r)); + map(0xa000, 0xa000).rw(FUNC(z22_state::status_r), FUNC(z22_state::control_w)); + map(0xc000, 0xffff).rom().region("program", 0); +} + + +static INPUT_PORTS_START(z22) +INPUT_PORTS_END + +// XTAL frequency is specified as 16.589 MHz on actual parts. As with the MDT 60, this +// has been assumed to be a lower-precision specification of the common 16.5888 MHz value. + +void z22_state::z22(machine_config &config) +{ + M6512(config, m_maincpu, 16.5888_MHz_XTAL / 9); // R6512AP + m_maincpu->set_addrmap(AS_PROGRAM, &z22_state::mem_map); + + I8251(config, m_uart[0], 16.5888_MHz_XTAL / 9); // NEC D8251AC (U33) + Intel P8251A (U35) + m_uart[0]->rxrdy_handler().set_inputline(m_maincpu, m6512_device::NMI_LINE); + m_uart[0]->txd_handler().set("comm", FUNC(rs232_port_device::write_txd)); + m_uart[0]->dtr_handler().set("comm", FUNC(rs232_port_device::write_dtr)); + m_uart[0]->rts_handler().set("comm", FUNC(rs232_port_device::write_rts)); + + I8251(config, m_uart[1], 16.5888_MHz_XTAL / 9); + m_uart[1]->txd_handler().set("printer", FUNC(rs232_port_device::write_txd)); + + EEPROM_93C06_16BIT(config, m_eeprom); // NMC9306 (U27) + + pit8254_device &pit(PIT8254(config, "pit")); // Intel P8254 + pit.set_clk<0>(16.5888_MHz_XTAL / 9); + pit.set_clk<1>(16.5888_MHz_XTAL / 9); + pit.set_clk<2>(16.5888_MHz_XTAL / 9); + pit.out_handler<0>().set(m_eeprom, FUNC(eeprom_serial_93cxx_device::clk_write)); // weird synchronous clocking + pit.out_handler<0>().append(FUNC(z22_state::eeprom_clock_w)); + pit.out_handler<1>().set(m_uart[0], FUNC(i8251_device::write_rxc)); + pit.out_handler<2>().set(m_uart[0], FUNC(i8251_device::write_txc)); // or the other way around? + pit.out_handler<2>().append(m_uart[1], FUNC(i8251_device::write_txc)); + + // TODO: Keyboard (asynchronous serial, like Z-49?) + + screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER)); + screen.set_color(rgb_t::amber()); + screen.set_raw(16.5888_MHz_XTAL, 873, 0, 720, 317, 0, 300); + screen.set_screen_update(m_crtc, FUNC(r6545_1_device::screen_update)); + + R6545_1(config, m_crtc, 16.5888_MHz_XTAL / 9); // R6545-1AP + m_crtc->set_screen("screen"); + m_crtc->set_show_border_area(false); + m_crtc->set_char_width(9); + m_crtc->set_update_row_callback(FUNC(z22_state::update_row)); + m_crtc->set_on_update_addr_change_callback(FUNC(z22_state::update_cb)); + + // TODO: onboard buzzer + + rs232_port_device &comm(RS232_PORT(config, "comm", default_rs232_devices, nullptr)); + comm.rxd_handler().set(m_uart[0], FUNC(i8251_device::write_rxd)); + comm.dsr_handler().set(m_uart[0], FUNC(i8251_device::write_dsr)); + comm.cts_handler().set(m_uart[0], FUNC(i8251_device::write_cts)); + + rs232_port_device &printer(RS232_PORT(config, "printer", default_rs232_devices, nullptr)); + printer.dsr_handler().set(m_uart[1], FUNC(i8251_device::write_dsr)); +} + + +ROM_START(z22) + ROM_REGION(0x4000, "program", 0) + ROM_LOAD("u39.bin", 0x0000, 0x2000, CRC(2f62c1f8) SHA1(448581d987fee6b4303e481e78f46d3255baccbb)) // D2764A-3 + ROM_LOAD("u38.bin", 0x2000, 0x2000, CRC(f0bfe9b5) SHA1(8807841b28549d0ddf30275fc6035a66093f8768)) // D2764A-3 +ROM_END + +SYST(1984, z22, 0, 0, z22, z22, z22_state, empty_init, "Zenith Data Systems", "Z-22 Terminal", MACHINE_NOT_WORKING | MACHINE_NO_SOUND) diff --git a/src/mame/drivers/z29.cpp b/src/mame/drivers/z29.cpp index b491c3abe06..37098f75af6 100644 --- a/src/mame/drivers/z29.cpp +++ b/src/mame/drivers/z29.cpp @@ -8,8 +8,8 @@ #include "emu.h" //#include "bus/rs232/rs232.h" +#include "bus/z29_kbd/keyboard.h" #include "cpu/mcs51/mcs51.h" -#include "cpu/mcs48/mcs48.h" #include "machine/x2212.h" #include "video/i8275.h" #include "screen.h" @@ -20,11 +20,14 @@ public: z29_state(const machine_config &mconfig, device_type type, const char *tag) : driver_device(mconfig, type, tag) , m_maincpu(*this, "maincpu") + , m_keyboard(*this, "keyboard") , m_crtc(*this, "crtc%u", 1U) , m_nvram(*this, "nvram") , m_charmem(*this, "charmem") , m_attrmem(*this, "attrmem") , m_chargen(*this, "chargen") + , m_dmatype(true) + , m_keyin(true) { } @@ -34,8 +37,10 @@ protected: virtual void machine_start() override; private: + DECLARE_WRITE_LINE_MEMBER(keyin_w); + u8 p1_r(); void p3_w(u8 data); - DECLARE_READ8_MEMBER(bs_24k_r); + u8 bs_24k_r(offs_t offset); void crtc_w(offs_t offset, u8 data); void latch_12k_w(u8 data); @@ -43,6 +48,7 @@ private: void ext_map(address_map &map); required_device m_maincpu; + required_device m_keyboard; required_device_array m_crtc; required_device m_nvram; @@ -51,11 +57,23 @@ private: required_region_ptr m_chargen; bool m_dmatype; + bool m_keyin; }; void z29_state::machine_start() { save_item(NAME(m_dmatype)); + save_item(NAME(m_keyin)); +} + +WRITE_LINE_MEMBER(z29_state::keyin_w) +{ + m_keyin = state; +} + +u8 z29_state::p1_r() +{ + return m_keyin ? 0xfd : 0xff; } void z29_state::p3_w(u8 data) @@ -63,7 +81,7 @@ void z29_state::p3_w(u8 data) m_dmatype = BIT(data, 4); } -READ8_MEMBER(z29_state::bs_24k_r) +u8 z29_state::bs_24k_r(offs_t offset) { if (!machine().side_effects_disabled()) { @@ -122,11 +140,16 @@ void z29_state::z29(machine_config &config) I8031(config, m_maincpu, 14.784_MHz_XTAL / 2); // Intel P8031AH m_maincpu->set_addrmap(AS_PROGRAM, &z29_state::prg_map); m_maincpu->set_addrmap(AS_IO, &z29_state::ext_map); - m_maincpu->port_in_cb<1>().set_constant(0xfd); // hack around keyboard not working + m_maincpu->port_in_cb<1>().set(FUNC(z29_state::p1_r)); + m_maincpu->port_out_cb<1>().set(m_keyboard, FUNC(z29_keyboard_port_device::keyout_w)).bit(0).invert(); m_maincpu->port_out_cb<3>().set(FUNC(z29_state::p3_w)); X2210(config, m_nvram); + Z29_KEYBOARD(config, m_keyboard, z29_keyboards, /*"heath"*/ "md"); + m_keyboard->keyin_callback().set(FUNC(z29_state::keyin_w)); + m_keyboard->reset_callback().set_inputline(m_maincpu, INPUT_LINE_RESET).invert(); + screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER)); screen.set_raw(14.784_MHz_XTAL, 880, 0, 640, 280, 0, 250); screen.set_screen_update("crtc1", FUNC(i8276_device::screen_update)); @@ -136,8 +159,6 @@ void z29_state::z29(machine_config &config) m_crtc[0]->irq_wr_callback().set_inputline(m_maincpu, MCS51_INT1_LINE); I8276(config, m_crtc[1], 14.784_MHz_XTAL / 8).set_character_width(8); - - I8021(config, "kbdmcu", 3.579545_MHz_XTAL).set_disable(); } @@ -148,9 +169,6 @@ ROM_START(z29) // All EPROMs on 85-2835-1 terminal board are HN482732AG-30 ROM_REGION(0x1000, "chargen", 0) ROM_LOAD("u429.bin", 0x0000, 0x1000, CRC(5e3bc5bf) SHA1(18d73e3d74a9768bee8b063ea45891f955558ae7)) - - ROM_REGION(0x400, "kbdmcu", 0) - ROM_LOAD("444-100.bin", 0x000, 0x400, NO_DUMP) ROM_END diff --git a/src/mame/mame.lst b/src/mame/mame.lst index 89dc8475b88..76cb5890925 100644 --- a/src/mame/mame.lst +++ b/src/mame/mame.lst @@ -21873,7 +21873,6 @@ fl100 // (c) 198? Grundig @source:mdt60.cpp mdt60 // -z22 // @source:meadows.cpp bowl3d // [1978?] @@ -41792,6 +41791,9 @@ z1013k69 // z1013k76 // z1013s60 // +@source:z22.cpp +z22 // + @source:z29.cpp z29 // diff --git a/src/mame/mess.flt b/src/mame/mess.flt index 147370eecfa..299c05b17c8 100644 --- a/src/mame/mess.flt +++ b/src/mame/mess.flt @@ -1075,6 +1075,7 @@ ymtx81z.cpp ymvl70.cpp z100.cpp z1013.cpp +z22.cpp z29.cpp z80dev.cpp z80ne.cpp