From 8c17acdc71d9f59b57c0d5f3bae2a855172cb915 Mon Sep 17 00:00:00 2001 From: 68bit <53298758+68bit@users.noreply.github.com> Date: Tue, 17 Sep 2019 13:01:16 +1000 Subject: [PATCH] MEKD4 and D5: new machines (#5632) * MEK6809D4: new machine Motorola MC6809 evaluation board. This emulation implements the keypad and LED 7 segment display, the RS-232 terminal interface, and the MEK68R2 MC6845 CRT and parallel keyboard interface. The RAM and ROM banking is not yet implemented but most of the D4BUG monitor commands are supported. * MEK6802D5: new machine Motorola MC6802 trainer board. This emulation implements the keypad and LED 7 segment display, and the RS-232 terminal interface even though there is no monitor support for it. All the D5BUG monitor commands appear to be working. --- scripts/target/mame/mess.lua | 2 + src/mame/drivers/mekd4.cpp | 1035 ++++++++++++++++++++++++++++++++++ src/mame/drivers/mekd5.cpp | 527 +++++++++++++++++ src/mame/layout/mekd4.lay | 305 ++++++++++ src/mame/layout/mekd5.lay | 296 ++++++++++ src/mame/mame.lst | 6 + src/mame/mess.flt | 2 + 7 files changed, 2173 insertions(+) create mode 100644 src/mame/drivers/mekd4.cpp create mode 100644 src/mame/drivers/mekd5.cpp create mode 100644 src/mame/layout/mekd4.lay create mode 100644 src/mame/layout/mekd5.lay diff --git a/scripts/target/mame/mess.lua b/scripts/target/mame/mess.lua index 0eb53373609..76ba4a6e1cc 100644 --- a/scripts/target/mame/mess.lua +++ b/scripts/target/mame/mess.lua @@ -2701,6 +2701,8 @@ files { MAME_DIR .. "src/mame/drivers/m6805evs.cpp", MAME_DIR .. "src/mame/drivers/m68705prg.cpp", MAME_DIR .. "src/mame/drivers/mekd2.cpp", + MAME_DIR .. "src/mame/drivers/mekd4.cpp", + MAME_DIR .. "src/mame/drivers/mekd5.cpp", MAME_DIR .. "src/mame/drivers/mvme147.cpp", MAME_DIR .. "src/mame/drivers/mvme162.cpp", } diff --git a/src/mame/drivers/mekd4.cpp b/src/mame/drivers/mekd4.cpp new file mode 100644 index 00000000000..6bea2ef88b8 --- /dev/null +++ b/src/mame/drivers/mekd4.cpp @@ -0,0 +1,1035 @@ +// license:BSD-3-Clause +// copyright-holders: 68bit +/****************************************************************************** + +Motorola Evaluation Kit 6809 D4 - MEK6809D4 + +Memory map + +Range Short Description + +0000-0fff RAM User RAM, 4K, default location. It can be remapped to any 1K + address boundary and on any RAM page, or disabled. + +0000-7fff RAM Off board RAM typically maps in this range, on any RAM page. + +9000-9fff RAM MEK68R2 Screen RAM + +e000-e07f I/O I/O1 Select Area +e080-e0ff I/O I/O2 Select Area, includes system I/O below. + +e0f1-e0ff SYSIO Onboard system I/O is always mapped to these addresses + irrespective of the RAM or ROM pages. +e0f1-e0f1 Cfg Read: 4-bit Config jumper; Write: RAM/ROM page latch +e0f2-e0f3 ACIA Console RS-232 +e0f4-e0f7 PIA Stop on address comparator PIA. A0 and A1 are reversed. +e0f8-e0fb PIA Keypad and LED display +e0fc-e0ff PIA User PIA on Keypad-display board + +e400-e7ff RAM Onboad 1K stack RAM. Always mapped to these addresses + irrespective of the RAM or ROM page. + +e800-efff ROM ROMG U61, normal location. +f000-ffff ROM ROMH U62, normal location. + + +The onboard 4K user RAM can be placed at any 1K address boundary on any RAM +page and on multiple RAM pages. The default is 0x0000 to 0x0fff on all RAM +pages, but jumpers may be added at connector J2 to modify this selection. If a +jumper is present across pins 1-2, or 3-4, or 5-6, or 7-8, then address lines +A15 to A12 respectively must be high (rather than low) for the user RAM to be +selected. By default, with no jumpers installed, the RAM page address lines +RAP0 to RAP2 are 'do not care', but J2 pin pairs can be jumpered to select the +user RAM only when these are high or low - pins 9-10 select RAP0 being high, +pins 11-12 select RAP0 being low, pins 13-14 select RAP1 being high, etc. The +user RAM can also be disabled by jumpering any of pins 10, 12, 14, 16, 18, 20 +low which can be done by jumpering any of these to any of pins 2, 4, 6, or 8. +The user RAM data bus is buffered and so long as it is decoded then the data +lines are driven so removing this RAM does not free the decoded address range, +and the onboard user RAM takes precedence over off board addressing. It would +cause a data bus conflict if the user RAM were decoded in the same address +range as the onboard stack RAM, ROM, or the system I/O. This user RAM can also +be write protected by removing the jumper between pins 11-12 at J1. + +TODO implement the 4K user RAM mapping. + +There are eight onboard ROM sockets, labeled ROM/A to ROM/H. ROM/A to ROM/D +have addressing for A0 to A12 so support 8K devices, however collectively +their A11 and/or A12 lines can be jumpered low or high to support smaller +devices. The ROM/E and ROM/F have addressing for A0 to A11 so support 4K +devices, but can be collectively jumpered for 1K, 2K or 4K operation. ROM/G +and ROM/H are used for the monitor ROMS and support 2K or 4K devices +individually, and the standard ROM sizes are 2K and 4K respectively. The +onboard ROM data bus is buffered and so long as it is decoded then the data +lines are driven so removing a ROM does not free the decoded address range, +and the onboard ROM takes precedence over off board addressing. It would cause +a data bus conflict if this ROM were decoded in the same address range as +the onboard stack RAM, the user RAM, or the system I/O. The data bus buffer +for the ROMs is not bi-directional, it would appear to not be possible to +place RAM or I/O in these sockets, and it appears that it would cause a bus +conflict if there were a valid write to these ROMs, and the W/R line is wired +to the ROM decoder to support that - not sure what was intended here? + +The onboard ROM selection is handled by a 1K mapping ROM in U31. The outputs +D0 to D7 selecting ROM/A to ROM/H respectively when low. It was up to the +programming of this ROM to avoid address conflicts, to select only one ROM at +a time. The ROM address inputs A9 to A0 are respectively: A15, A14, A13, A12, +A11, A10, ROP2, ROP1, ROP0, R/W. This allows mapping ROMS on 1K address map +boundaries. The default mapping ROM was label "D4MAP 00", a MCM68A316, and did +not select any ROM 0x4000. + +The mapping ROM pins 18 and 20 and wired to 0V, pin 21 is wired to +5V, pin +19 can be jumpered to 0V or 5V, defaulting to 0V. So could a single supply +EPROM could be substituted. Pin 19 is A10 on a 2716 EPROM the lower half of a +2K EPROM could be used too. + +TODO implement the onboard ROMs and their mapping. + +There was a resident editor assembler product available for this system, the +"MEK6809EAC Editor/Assembler V1.0 2/80". It was supplied on a tape and side +one had a version to load into RAM at 0100 to 2fff, and side two had a version +that was ROMable at a000 to cfff. It supported the MEK68R2 CRT display or a +terminal and object code could be placed in memory or saved on tape. + +TODO This editor/assembler ROM might be a nice addition if it can be found. + +The CPU clock is either generated from the onboard 3.579545 MHz XTAL or +externally as set via J3. + +TODO could support 1MHz and 2MHz CPU operation. + +The board includes a hardware 'stop' address comparator which compares the +A0-A15 address lines to the output of the PIA at e0f4-e0f7, 'stop_pia' here, +and asserts that PIA's CA1 input when they match. The monitor software uses +this to trigger an interrupt to implement code tracing. The PIA port B outputs +B0 to B7 are compared to the address lines A0 to A7 respectively, and the port +A outputs A0 to A7 are compared to the address lines A8 to A15 +respectively. Notably the comparitor does not compare the RAM or ROM bank +lines, so this might be frustrating when used with code making use of +banking. It appears that the address comparator does not distinguish between +code versus data, so it would appear to be able to trigger on a data access +too, and although the monitor documenation does not mention such a use this +use is possible with the monitor. The trigger is also available at TP1 and +this could be informative in some hardware development, with the address set +and the interrupt disabled. The CA2 input can also be toggled low to generate +an interrupt as a manually 'abort'. + + +J1 +1-2 RS-232 console +3-4 R2 board present +7-8 Keypad present +5-6 300/1200 cassette baud rate +11-12 Write protect 4K user ram. + + +ASCII terminal commands: + - Memory change + - enter data, write to memory. + - increase address, same line + - increase address, new line + '-' or '^' - decrease address, new line + ';' - calculate branch offset to addr, 8 bit or 16 bit offset. + - return from memory change +'R' - Register editor + 'P' - Program counter + 'A' - A-Accumulator + 'B' - B-Accumulator + 'X' - X-Index + 'Y' - Y-Index + 'C' - Condition Codes + 'H' - RAM/ROM pages select latch, high nibble is ROM page, low RAM page. + 'D' - Direct Page + 'U' - U-Stack + 'S' - S-Stack + '1','2','3','4' - Definable 16-bit registers (memory locations) + - exit register editor + - display update + - next register + 'T' - trace one instruction + 'L' - trace one line (subroutine), using single stepping + 'R' - trace one line (subroutine), using hardware (real time) approach. +'Q' - Enter breakpoint editor + 'I' - insert breakpoint at , to stop after one times. + 'I'; - insert breakpoint at , to stop after times. + 'R' - remove breakpoing at + 'S' - set stop address, to stop after one times. + 'S'; - set stop address, to stop after times. + 'K' - clear all breakpoints and deactivate the stop address. + - exit breakpoint editor. +'G' - Continue at the pseudo program counter. +'G' - Go to user program at +'M' - Memory dump +'P' - Punch. Store information from memory to cassette. +'P' - Punch with offset, as if starting from . +'L' - Load. Read information to memory from cassette. +'L' - Load with offset. +'V' - Verify cassette data against memory. +'V' - Verify with offset. += - Convert hex to decimal. +#$ - Convert decimal to hex. +'U' - Switch R2 to User screen page. +'S' - Switch R2 to System screen page. +'X' - Enter special functions. + 'M' - Move memory. + 'F' - Fill memory. + 'S' - Search memory. Escape to pause. + 'A' - ASCII Entry. + '@' - End of message. + - Exit ASCII entry. + - Delete last character. + - When using R2D, back up. + + +MEK68KPD commands: + +RS (Reset) Reset, wired to the CPU reset line +EX (Escape) Typically aborts user program. Switch from CRT to KPD. +M (Memory display/change) + Digits 5 and 6 show the entered data, and are blank unless it differs. + Digits 7 and 8 show the actual data at the address. + G - increase the address. + M - decreases the address. + FS - Offset calculation. Enter address, then press 'GO'. + Last digit is S for a short offset and L for a long 16 bit offset. + FS - stores the offset and returns to memory display and increased the address. + FC - return to memory display at the same address. + EX - exits memory display. +RD (Register display/alter) + The 'HP' register is the hardware page register, upper nibble the ROM page, + lower the RAM page, 8 pages each. + The 'SA' register is the hardware stop address. + FS - at register 'SA', to change the 'number of times'. + FC - at register 'SA', to change the stop address. + G - advance to next register. + M - previous register. + T/B - trace a single instruction + P/L - trace user line, an entire subroutine if next, slow software version. + RD - trace user line, using the stop address hardware. + EX - exits register display. +GO to user program. + If no address if entered then it uses the pseudo PC, it continues. + Enter the address and press 'Go' to use that entered address. + It firstly checks that there is RAM at the stack pointer. +FS GO - enter the address, then FS, then GO and it runs as a sub of the LED + display code allowing use of the LED display. The sub should be quick + relative to the 1ms display update period. +FS T/B - Breakpoint editor + GO - advance to next breakpoing, up to 8, then loops. + FC - deactivate breakpoint + FS - edit the 'number of times before stopping' for the current entry. + FS - enter an address then press FS to enter that as a breakpoint address + and then edit the 'number of times before stopping'. + EX - exits breakpoing editor. +P/L (Punch tape) + Enter an address before P/L to set the apparent beginning address. + At the 'b' prompt enter the beginning address of the data, then 'GO'. + At the 'E' prompt enter the last address of the data. + Start the tape and press GO. There is a 30 second leader of $ff. +FS P/L (Load from tape) + Enter an address before FS for an offset load or verify?? +FS 0 to F + One of 16 user defined functions. Press FS then one number key 0 to F. + Numeric data may be entered before pressing FS. + A pointer to a table of 16 function address should be set at 0xe72e. + There is a reservation at 0xe730-0xe74f for this table. + The function address is stored in 0xe700 and called by the LED display + update function PUT every 1msec. + +******************************************************************************/ + +#include "emu.h" +#include "cpu/m6809/m6809.h" +#include "machine/input_merger.h" +#include "machine/bankdev.h" +#include "machine/6821pia.h" +#include "machine/6850acia.h" +#include "machine/mc14411.h" +#include "machine/clock.h" +#include "machine/timer.h" +#include "sound/wave.h" +#include "speaker.h" +#include "bus/rs232/rs232.h" +#include "mekd4.lh" +#include "imagedev/cassette.h" +#include "imagedev/snapquik.h" +#include "video/pwm.h" + +// MEK68R2 +#include "machine/terminal.h" +#include "video/mc6845.h" +#include "emupal.h" +#include "screen.h" +#include "render.h" + +class mekd4_state : public driver_device +{ +public: + mekd4_state(const machine_config &mconfig, device_type type, const char *tag) + : driver_device(mconfig, type, tag) + , m_maincpu(*this, "maincpu") + , m_bankdev(*this, "bankdev") + , m_stop_pia(*this, "stop_pia") + , m_kpd_pia(*this, "kpd_pia") + , m_display(*this, "display") + , m_user_pia(*this, "user_pia") + , m_brg(*this, "brg") + , m_tx_rate(*this, "tx_baud") + , m_rx_rate(*this, "rx_baud") + , m_acia(*this, "acia") + , m_cass(*this, "cassette") + , m_jumper1(*this, "jumper1") + , m_keypad_columns(*this, "COL%u", 0) + // MEK68R2 + , m_mc6845(*this, "mc6845") + , m_palette(*this, "palette") + , m_screen(*this, "screen") + , m_p_chargen(*this, "chargen") + , m_video_ram(*this, "videoram") + , m_r2_pia(*this, "r2_pia") + , m_r2_mode(*this, "r2_mode") + , m_r2_display_nationality(*this, "r2_display_nationality") + , m_r2_display_format(*this, "r2_display_format") + { } + + void mekd4(machine_config &config); + void init_mekd4(); + + DECLARE_WRITE_LINE_MEMBER(reset_key_w); + DECLARE_INPUT_CHANGED_MEMBER(keypad_changed); + +private: + DECLARE_READ8_MEMBER(main_r); + DECLARE_WRITE8_MEMBER(main_w); + DECLARE_READ8_MEMBER(config_r); + DECLARE_WRITE8_MEMBER(page_w); + DECLARE_READ8_MEMBER(stop_pia_r); + DECLARE_WRITE8_MEMBER(stop_pia_w); + DECLARE_WRITE8_MEMBER(stop_pia_pa_w); + DECLARE_WRITE8_MEMBER(stop_pia_pb_w); + DECLARE_READ_LINE_MEMBER(stop_pia_ca2_r); + uint16_t m_stop_address; + + // Clocks + DECLARE_WRITE_LINE_MEMBER(write_f1_clock); + DECLARE_WRITE_LINE_MEMBER(write_f3_clock); + DECLARE_WRITE_LINE_MEMBER(write_f7_clock); + DECLARE_WRITE_LINE_MEMBER(write_f8_clock); + DECLARE_WRITE_LINE_MEMBER(write_f9_clock); + DECLARE_WRITE_LINE_MEMBER(write_f13_clock); + + DECLARE_READ_LINE_MEMBER(keypad_cb1_r); + DECLARE_READ8_MEMBER(keypad_key_r); + DECLARE_WRITE8_MEMBER(led_digit_w); + DECLARE_WRITE8_MEMBER(led_segment_w); + + DECLARE_READ_LINE_MEMBER(stop_pia_cb1_r); + DECLARE_WRITE_LINE_MEMBER(stop_pia_cb2_w); + + void mekd4_stop_mem(address_map &map); + void mekd4_mem(address_map &map); + + address_space *m_banked_space; + + bool keypad_key_pressed(); + + uint32_t screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); + + uint8_t m_rom_page; // aka ROP0, ROP1, ROP2 + uint8_t m_ram_page; // aka RAP0, RAP1, RAP2 + uint8_t m_cass_data[4]; + uint8_t m_segment; + uint8_t m_digit; + bool m_cassbit; + bool m_cassold; + virtual void machine_start() override; + virtual void machine_reset() override; + required_device m_maincpu; + required_device m_bankdev; + required_device m_stop_pia; + required_device m_kpd_pia; + required_device m_display; + required_device m_user_pia; + required_device m_brg; + required_ioport m_tx_rate; + required_ioport m_rx_rate; + required_device m_acia; + required_device m_cass; + required_ioport m_jumper1; + required_ioport_array<4> m_keypad_columns; + + // MEK68R2 + MC6845_UPDATE_ROW(update_row); + DECLARE_READ8_MEMBER(r2_pia_pa_r); + DECLARE_READ8_MEMBER(r2_pia_pb_r); + DECLARE_WRITE_LINE_MEMBER(r2_hsync_changed); + DECLARE_WRITE_LINE_MEMBER(r2_vsync_changed); + DECLARE_READ_LINE_MEMBER(r2_pia_cb1_r); + optional_device m_mc6845; + optional_device m_palette; + optional_device m_screen; + optional_region_ptr m_p_chargen; + optional_shared_ptr m_video_ram; + optional_device m_r2_pia; + optional_ioport m_r2_mode; + optional_ioport m_r2_display_nationality; + optional_ioport m_r2_display_format; + void kbd_put(uint8_t data); + uint8_t m_term_data; + bool m_r2_vsync; +}; + + + +/*********************************************************** + + Address Map + +************************************************************/ + +void mekd4_state::mekd4_stop_mem(address_map &map) +{ + map(0x0000, 0xffff).rw(FUNC(mekd4_state::main_r), FUNC(mekd4_state::main_w)); +} + +void mekd4_state::mekd4_mem(address_map &map) +{ + map(0x0000, 0x7fff).ram(); + + /* MEK68R2 Video RAM 9000-9fff */ + map(0x9000, 0x9fff).ram().share(m_video_ram); + + /* MEK68VG VDG Scroll register f040-f041 */ + + /* MEK68R2 CRT register f042-f043 */ + map(0xe042, 0xe042).w(m_mc6845, FUNC(mc6845_device::address_w)); + map(0xe043, 0xe043).rw(m_mc6845, FUNC(mc6845_device::register_r), FUNC(mc6845_device::register_w)); + + /* MEK68R2 PIA (Keyboard) */ + map(0xe044, 0xe047).rw(m_r2_pia, FUNC(pia6821_device::read), FUNC(pia6821_device::write)); + + map(0xe0f1, 0xe0f1).rw(FUNC(mekd4_state::config_r), FUNC(mekd4_state::page_w)); + map(0xe0f2, 0xe0f3).rw(m_acia, FUNC(acia6850_device::read), FUNC(acia6850_device::write)); + map(0xe0f4, 0xe0f7).rw(FUNC(mekd4_state::stop_pia_r), FUNC(mekd4_state::stop_pia_w)); + map(0xe0f8, 0xe0fb).rw(m_kpd_pia, FUNC(pia6821_device::read), FUNC(pia6821_device::write)); + map(0xe0fc, 0xe0ff).rw(m_user_pia, FUNC(pia6821_device::read), FUNC(pia6821_device::write)); + + map(0xe400, 0xe7ff).ram(); + + map(0xe800, 0xefff).rom(); + map(0xf000, 0xffff).rom(); +} + +/*********************************************************** + + Keys + +************************************************************/ + +static INPUT_PORTS_START(mekd4) + + PORT_START("jumper1") + PORT_DIPNAME(0x01, 0x00, "RS-232 console (D4B)") + PORT_DIPSETTING(0x00, DEF_STR(On)) + PORT_DIPSETTING(0x01, DEF_STR(Off)) + PORT_DIPNAME(0x02, 0x00, "MEK68R2 present (D4C)") + PORT_DIPSETTING(0x00, DEF_STR(On)) + PORT_DIPSETTING(0x02, DEF_STR(Off)) + PORT_DIPNAME(0x04, 0x00, "Cassette baud rate") + PORT_DIPSETTING(0x00, "1200") + PORT_DIPSETTING(0x04, "300") + PORT_DIPNAME(0x08, 0x00, "Keypad and display present (D4A)") + PORT_DIPSETTING(0x00, DEF_STR(On)) + PORT_DIPSETTING(0x08, DEF_STR(Off)) + + PORT_START("tx_baud") + PORT_CONFNAME(0x3f, 1, "RS232 TX Baud Rate") + PORT_CONFSETTING(0x01, "9600") + PORT_CONFSETTING(0x02, "4800") + PORT_CONFSETTING(0x04, "1200") + PORT_CONFSETTING(0x08, "600") + PORT_CONFSETTING(0x10, "300") + PORT_CONFSETTING(0x20, "110") + + PORT_START("rx_baud") + PORT_CONFNAME(0x3f, 1, "RS232 RX Baud Rate") + PORT_CONFSETTING(0x01, "9600") + PORT_CONFSETTING(0x02, "4800") + PORT_CONFSETTING(0x04, "1200") + PORT_CONFSETTING(0x08, "600") + PORT_CONFSETTING(0x10, "300") + PORT_CONFSETTING(0x20, "110") + + // RESET is not wired to the key matrix. + PORT_START("RESET") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYPAD) PORT_NAME("RS") PORT_WRITE_LINE_DEVICE_MEMBER(DEVICE_SELF, mekd4_state, reset_key_w) + + // PORT_CODEs are not assigned to the keypad to allow it on screen at + // the same time as the terminal or CRT console which also receive + // keyboard inputs. When a keyboard is available the keypad is of + // limited use, but still useful to interrupt code or reset the + // machine. If MAME someday allows the keyboard input focus to be + // switched then this might be redesigned. + PORT_START("COL0") + PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, mekd4_state, keypad_changed, 0) PORT_NAME("M") + PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, mekd4_state, keypad_changed, 0) PORT_NAME("FS") + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, mekd4_state, keypad_changed, 0) PORT_NAME("7") + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, mekd4_state, keypad_changed, 0) PORT_NAME("4") + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, mekd4_state, keypad_changed, 0) PORT_NAME("1") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, mekd4_state, keypad_changed, 0) PORT_NAME("0") + + PORT_START("COL1") + PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, mekd4_state, keypad_changed, 0) PORT_NAME("EX") + PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, mekd4_state, keypad_changed, 0) PORT_NAME("FC") + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, mekd4_state, keypad_changed, 0) PORT_NAME("8") + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, mekd4_state, keypad_changed, 0) PORT_NAME("5") + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, mekd4_state, keypad_changed, 0) PORT_NAME("2") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, mekd4_state, keypad_changed, 0) PORT_NAME("F") + + PORT_START("COL2") + PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, mekd4_state, keypad_changed, 0) PORT_NAME("RD") + PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, mekd4_state, keypad_changed, 0) PORT_NAME("P/L") + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, mekd4_state, keypad_changed, 0) PORT_NAME("9") + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, mekd4_state, keypad_changed, 0) PORT_NAME("6") + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, mekd4_state, keypad_changed, 0) PORT_NAME("3") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, mekd4_state, keypad_changed, 0) PORT_NAME("E") + + PORT_START("COL3") + PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, mekd4_state, keypad_changed, 0) PORT_NAME("GO") + PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, mekd4_state, keypad_changed, 0) PORT_NAME("T/B") + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, mekd4_state, keypad_changed, 0) PORT_NAME("A") + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, mekd4_state, keypad_changed, 0) PORT_NAME("B") + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, mekd4_state, keypad_changed, 0) PORT_NAME("C") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, mekd4_state, keypad_changed, 0) PORT_NAME("D") + + // MEK68R2 + + PORT_START("r2_mode") + PORT_DIPNAME(0x1, 0, "R2 Mode") + PORT_DIPSETTING(0, "Normal") + PORT_DIPSETTING(1, "Dumb terminal") + + PORT_START("r2_display_nationality") + PORT_DIPNAME(0x1, 1, "Display nationality") + PORT_DIPSETTING(0, "US") + PORT_DIPSETTING(1, "Europe") + + PORT_START("r2_display_format") + PORT_DIPNAME(0x0003, 2, "Display format") + PORT_DIPSETTING(0, "16 lines of 32 characters") + PORT_DIPSETTING(1, "16 lines of 64 characters") + PORT_DIPSETTING(2, "20 lines of 80 characters") + PORT_DIPSETTING(3, "User defined") + +INPUT_PORTS_END + + +/*********************************************************** + + Stop comparitor. + +************************************************************/ + +READ8_MEMBER(mekd4_state::main_r) +{ + if (offset == m_stop_address && !machine().side_effects_disabled()) + { + m_stop_pia->ca1_w(CLEAR_LINE); + m_stop_pia->ca1_w(ASSERT_LINE); + m_stop_pia->ca1_w(CLEAR_LINE); + } + return m_banked_space->read_byte(offset); +} + +WRITE8_MEMBER(mekd4_state::main_w) +{ + if (offset == m_stop_address && !machine().side_effects_disabled()) + { + m_stop_pia->ca1_w(CLEAR_LINE); + m_stop_pia->ca1_w(ASSERT_LINE); + m_stop_pia->ca1_w(CLEAR_LINE); + } + m_banked_space->write_byte(offset, data); +} + +READ8_MEMBER(mekd4_state::config_r) +{ + return 0xf0 | m_jumper1->read(); +} + +// The design reversed the A0 and A1 lines so that +// a 16 bit write could write both data addresses. +READ8_MEMBER(mekd4_state::stop_pia_r) +{ + // Reverse the A0 and A1 address lines; + int8_t reversed = BIT(offset, 0) << 1 | BIT(offset, 1); + return m_stop_pia->read(reversed); +} + +WRITE8_MEMBER(mekd4_state::stop_pia_w) +{ + // Reverse the A0 and A1 address lines; + int8_t reversed = BIT(offset, 0) << 1 | BIT(offset, 1); + m_stop_pia->write(reversed, data); +} + +WRITE8_MEMBER(mekd4_state::stop_pia_pa_w) +{ + m_stop_address = (m_stop_address & 0x00ff) | (data << 8); +} + +WRITE8_MEMBER(mekd4_state::stop_pia_pb_w) +{ + m_stop_address = (m_stop_address & 0xff00) | data; +} + +// Connected to 'abort' TP2. Can be toggled low to and abort user code. +READ_LINE_MEMBER(mekd4_state::stop_pia_ca2_r) +{ + return 1; +} + +/*********************************************************** + + RAM and ROM paging + +************************************************************/ + +WRITE8_MEMBER(mekd4_state::page_w) +{ + m_rom_page = data & 0x07; + m_ram_page = (data >> 4) & 0x07; +} + +/*********************************************************** + + Keypad + +************************************************************/ + +WRITE_LINE_MEMBER(mekd4_state::reset_key_w) +{ + m_maincpu->set_input_line(INPUT_LINE_RESET, state ? CLEAR_LINE : ASSERT_LINE); + + // TODO reset other devices. +} + +bool mekd4_state::keypad_key_pressed() +{ + return (m_keypad_columns[0]->read() & m_digit) || + (m_keypad_columns[1]->read() & m_digit) || + (m_keypad_columns[2]->read() & m_digit) || + (m_keypad_columns[3]->read() & m_digit); +} + +INPUT_CHANGED_MEMBER(mekd4_state::keypad_changed) +{ + m_kpd_pia->cb1_w(mekd4_state::keypad_key_pressed()); +} + +READ_LINE_MEMBER(mekd4_state::keypad_cb1_r) +{ + return mekd4_state::keypad_key_pressed(); +} + +READ8_MEMBER(mekd4_state::keypad_key_r) +{ + uint8_t mux = (m_digit & 0xc0) >> 6; + uint8_t i = (m_keypad_columns[mux]->read() & m_digit) ? 0 : 0x80; + + return i | m_segment; +} + +/*********************************************************** + + Seven segment LED display + +************************************************************/ + +// PA +WRITE8_MEMBER(mekd4_state::led_segment_w) +{ + m_segment = data & 0x7f; + m_display->matrix(m_digit, ~m_segment); +} + +// PB +WRITE8_MEMBER(mekd4_state::led_digit_w) +{ + m_digit = data; + m_display->matrix(m_digit, ~m_segment); + // Update the keypad pressed output which depends on m_digit. + m_kpd_pia->cb1_w(mekd4_state::keypad_key_pressed()); + +} + + +/*********************************************************** + + Cassette + +************************************************************/ + +READ_LINE_MEMBER(mekd4_state::stop_pia_cb1_r) +{ + uint8_t state = m_cass->input() > +0.0; + return state; +} + +WRITE_LINE_MEMBER(mekd4_state::stop_pia_cb2_w) +{ + m_cass->output(state ? -1.0 : +1.0); +} + +/*********************************************************** + + ACIA clocks + +************************************************************/ + +WRITE_LINE_MEMBER(mekd4_state::write_f1_clock) +{ + if (BIT(m_tx_rate->read(), 0)) + m_acia->write_txc(state); + if (BIT(m_rx_rate->read(), 0)) + m_acia->write_rxc(state); +} + +WRITE_LINE_MEMBER(mekd4_state::write_f3_clock) +{ + if (BIT(m_tx_rate->read(), 1)) + m_acia->write_txc(state); + if (BIT(m_rx_rate->read(), 1)) + m_acia->write_rxc(state); +} + +WRITE_LINE_MEMBER(mekd4_state::write_f7_clock) +{ + if (BIT(m_tx_rate->read(), 2)) + m_acia->write_txc(state); + if (BIT(m_rx_rate->read(), 2)) + m_acia->write_rxc(state); +} + +WRITE_LINE_MEMBER(mekd4_state::write_f8_clock) +{ + if (BIT(m_tx_rate->read(), 3)) + m_acia->write_txc(state); + if (BIT(m_rx_rate->read(), 3)) + m_acia->write_rxc(state); +} + +WRITE_LINE_MEMBER(mekd4_state::write_f9_clock) +{ + if (BIT(m_tx_rate->read(), 4)) + m_acia->write_txc(state); + if (BIT(m_rx_rate->read(), 4)) + m_acia->write_rxc(state); +} + +WRITE_LINE_MEMBER(mekd4_state::write_f13_clock) +{ + if (BIT(m_tx_rate->read(), 5)) + m_acia->write_txc(state); + if (BIT(m_rx_rate->read(), 5)) + m_acia->write_rxc(state); +} + +/*********************************************************** + + MEK68R2 + + This might in future be moved to a slot device, on a bus. + +************************************************************/ + +// Delivery of keyboard inputs to the MEK68R2 keyboard is disabled when on +// views with the RS232 terminal, assuming that this keyboard is not present. +// Also disable delivery when the 'MEK68R2 present' jumper indicates it is +// disabled, assuming that this keyboard is not present. +void mekd4_state::kbd_put(uint8_t data) +{ + uint8_t view = machine().render().first_target()->view(); + if (view == 0) + return; + + if (BIT(m_jumper1->read(), 1)) + return; + + m_term_data = data; + // Triggers on the falling edge. + m_r2_pia->ca1_w(ASSERT_LINE); + m_r2_pia->ca1_w(CLEAR_LINE); + m_r2_pia->ca1_w(ASSERT_LINE); +} + +// PA0 to PA6 - Keyboard data. +// PA7 - Display nationality, 0 USA, 1 Europe. +READ8_MEMBER(mekd4_state::r2_pia_pa_r) +{ + uint8_t ret = m_term_data; + int8_t display_nationality = m_r2_display_nationality->read(); + m_term_data = 0; + return ret | (display_nationality << 7); +} + +// PB0 - Mode: 0 normal, 1 dumb terminal. +// PB1,2,3 - N/C +// PB4 - User defined +// PB5 - Light pen control. +// PB7, PB6 - Display format. +// 00 - 16 lines of 32 characters. +// 01 - 16 lines of 64 characters. +// 10 - 20 lines of 80 characters. +// 11 - User defined. +READ8_MEMBER(mekd4_state::r2_pia_pb_r) +{ + int8_t display_format = m_r2_display_format->read(); + int8_t mode = m_r2_mode->read(); + return (display_format << 6) | mode; +} + +WRITE_LINE_MEMBER(mekd4_state::r2_hsync_changed) +{ + m_r2_pia->cb2_w(state); +} + +WRITE_LINE_MEMBER(mekd4_state::r2_vsync_changed) +{ + m_r2_vsync = state; + m_r2_pia->cb1_w(state); +} + +READ_LINE_MEMBER(mekd4_state::r2_pia_cb1_r) +{ + return m_r2_vsync; +} + +MC6845_UPDATE_ROW(mekd4_state::update_row) +{ + const pen_t *pen = m_palette->pens(); + + int x = 0; + + for (int column = 0; column < x_count; column++) + { + uint8_t code = m_video_ram[(ma + column) & 0xfff]; + int dcursor = (column == cursor_x); + + if (BIT(code, 7)) { + /* Lores 6 pixel character. + ----------- + | D1 | D0 | + | D3 | D2 | + | D5 | D4 | + ----------- + D6 - 1 Grey tone, 0 brightness. + */ + int pixel = ((ra & 0x0c) >> 1) + 1; + int dout = BIT(code, pixel); + int grey = BIT(code, 6); + int color = ((dcursor ^ dout) && de) << !grey; + bitmap.pix32(y, x++) = pen[color]; + bitmap.pix32(y, x++) = pen[color]; + bitmap.pix32(y, x++) = pen[color]; + bitmap.pix32(y, x++) = pen[color]; + pixel--; + dout = BIT(code, pixel); + color = ((dcursor ^ dout) && de) << !grey; + bitmap.pix32(y, x++) = pen[color]; + bitmap.pix32(y, x++) = pen[color]; + bitmap.pix32(y, x++) = pen[color]; + bitmap.pix32(y, x++) = pen[color]; + } else { + offs_t address = ra < 8 ? ((code & 0x7f) << 3) | (ra & 0x07) : 0; + uint8_t data = m_p_chargen[address]; + + for (int bit = 0; bit < 8; bit++) + { + int dout = BIT(data, 7); + int color = ((dcursor ^ dout) && de) << 1; + + bitmap.pix32(y, x++) = pen[color]; + + data <<= 1; + } + } + } +} + + +/*********************************************************** + +************************************************************/ + +void mekd4_state::init_mekd4() +{ +} + +void mekd4_state::machine_start() +{ + m_banked_space = &subdevice("bankdev")->space(AS_PROGRAM); +} + +void mekd4_state::machine_reset() +{ + m_rom_page = 0; + m_ram_page = 0; + m_stop_address = 0x0000; + + // Avoid triggering an early interrupt when CB1 lowered. The mc6821 + // driver resets CB1 high and to trigger on a high to low + // transition. The mekd4 programs CB1 to trigger on a low to high + // transition and configuring this earlier here is adequate. + m_kpd_pia->write(1, 2); + m_kpd_pia->cb2_w(ASSERT_LINE); // Pulled high. + + m_brg->rsa_w(CLEAR_LINE); + m_brg->rsb_w(ASSERT_LINE); + + // MEK68R2 + m_r2_pia->ca1_w(ASSERT_LINE); + m_r2_pia->ca2_w(ASSERT_LINE); + m_r2_vsync = 0; + m_r2_pia->cb1_w(m_r2_vsync); + m_r2_pia->cb2_w(0); +} + +/*********************************************************** + + Machine + +************************************************************/ + +static DEVICE_INPUT_DEFAULTS_START(terminal) + DEVICE_INPUT_DEFAULTS("RS232_RXBAUD", 0xff, RS232_BAUD_9600) + DEVICE_INPUT_DEFAULTS("RS232_TXBAUD", 0xff, RS232_BAUD_9600) + DEVICE_INPUT_DEFAULTS("RS232_STARTBITS", 0xff, RS232_STARTBITS_1) + DEVICE_INPUT_DEFAULTS("RS232_DATABITS", 0xff, RS232_DATABITS_8) + DEVICE_INPUT_DEFAULTS("RS232_PARITY", 0xff, RS232_PARITY_NONE) + DEVICE_INPUT_DEFAULTS("RS232_STOPBITS", 0xff, RS232_STOPBITS_1) +DEVICE_INPUT_DEFAULTS_END + +void mekd4_state::mekd4(machine_config &config) +{ + MC6809(config, m_maincpu, 3.579545_MHz_XTAL); + m_maincpu->set_addrmap(AS_PROGRAM, &mekd4_state::mekd4_stop_mem); + + ADDRESS_MAP_BANK(config, m_bankdev, 0); + m_bankdev->set_endianness(ENDIANNESS_BIG); + m_bankdev->set_data_width(8); + m_bankdev->set_addr_width(20); + m_bankdev->set_addrmap(AS_PROGRAM, &mekd4_state::mekd4_mem); + + INPUT_MERGER_ANY_HIGH(config, "mainirq").output_handler().set_inputline(m_maincpu, M6809_IRQ_LINE); + INPUT_MERGER_ANY_HIGH(config, "mainnmi").output_handler().set_inputline(m_maincpu, INPUT_LINE_NMI); + + /* LED display */ + PWM_DISPLAY(config, m_display).set_size(8, 7); + m_display->set_segmask(0xff, 0x7f); + + config.set_default_layout(layout_mekd4); + + SPEAKER(config, "mono").front_center(); + + CASSETTE(config, m_cass); + m_cass->set_default_state(CASSETTE_STOPPED | CASSETTE_MOTOR_ENABLED | CASSETTE_SPEAKER_ENABLED); + m_cass->add_route(ALL_OUTPUTS, "mono", 0.05); + + // IRQ is not connected. RTS, CTS, and DCD are available. + ACIA6850(config, m_acia, 0); + m_acia->txd_handler().set("rs232", FUNC(rs232_port_device::write_txd)); + + MC14411(config, m_brg, XTAL(1'843'200)); + m_brg->out_f<1>().set(FUNC(mekd4_state::write_f1_clock)); + m_brg->out_f<3>().set(FUNC(mekd4_state::write_f3_clock)); + m_brg->out_f<7>().set(FUNC(mekd4_state::write_f7_clock)); + m_brg->out_f<8>().set(FUNC(mekd4_state::write_f8_clock)); + m_brg->out_f<9>().set(FUNC(mekd4_state::write_f9_clock)); + m_brg->out_f<13>().set(FUNC(mekd4_state::write_f13_clock)); + + rs232_port_device &rs232(RS232_PORT(config, "rs232", default_rs232_devices, "terminal")); + rs232.rxd_handler().set(m_acia, FUNC(acia6850_device::write_rxd)); + rs232.set_option_device_input_defaults("terminal", DEVICE_INPUT_DEFAULTS_NAME(terminal)); + + // Stop PIA. IRQB is NC. + PIA6821(config, m_stop_pia, 0); + m_stop_pia->writepa_handler().set(FUNC(mekd4_state::stop_pia_pa_w)); + m_stop_pia->writepb_handler().set(FUNC(mekd4_state::stop_pia_pb_w)); + m_stop_pia->readca2_handler().set(FUNC(mekd4_state::stop_pia_ca2_r)); + m_stop_pia->readcb1_handler().set(FUNC(mekd4_state::stop_pia_cb1_r)); + m_stop_pia->cb2_handler().set(FUNC(mekd4_state::stop_pia_cb2_w)); + m_stop_pia->irqa_handler().set("mainnmi", FUNC(input_merger_device::in_w<0>)); + + // Keypad and display PIA. CA1, CA2, IRQA are NC. CB2 is pulled high. + PIA6821(config, m_kpd_pia, 0); + m_kpd_pia->readpa_handler().set(FUNC(mekd4_state::keypad_key_r)); + m_kpd_pia->readcb1_handler().set(FUNC(mekd4_state::keypad_cb1_r)); + m_kpd_pia->writepa_handler().set(FUNC(mekd4_state::led_segment_w)); + m_kpd_pia->writepb_handler().set(FUNC(mekd4_state::led_digit_w)); + m_kpd_pia->irqb_handler().set("mainnmi", FUNC(input_merger_device::in_w<1>)); + + // Keypad and display board User PIA. + PIA6821(config, m_user_pia, 0); + m_user_pia->irqa_handler().set("mainirq", FUNC(input_merger_device::in_w<0>)); + m_user_pia->irqb_handler().set("mainirq", FUNC(input_merger_device::in_w<1>)); + + // MEK68R2 + + SCREEN(config, m_screen, SCREEN_TYPE_RASTER); + + m_screen->set_refresh_hz(50); + m_screen->set_size(80 * 8 + 80 * 10, 20 * 12 + 100); + m_screen->set_visarea(0, 80 * 8 + 80 * 10 - 1, 0, 20 * 12 + 100 - 1); + m_screen->set_screen_update("mc6845", FUNC(mc6845_device::screen_update)); + + PALETTE(config, m_palette, palette_device::MONOCHROME_HIGHLIGHT); + + MC6845(config, m_mc6845, XTAL(14'318'181)/8); + m_mc6845->set_screen("screen"); + m_mc6845->set_show_border_area(false); + m_mc6845->set_char_width(8); + m_mc6845->set_update_row_callback(FUNC(mekd4_state::update_row), this); + m_mc6845->out_hsync_callback().set(FUNC(mekd4_state::r2_hsync_changed)); + m_mc6845->out_vsync_callback().set(FUNC(mekd4_state::r2_vsync_changed)); + + // PA is the keyboard data and a mode flag. + // CA1 is keyboard strobe. + // CA2 light pen input. + // PB0 is mode flags and light pen control. + // CB1 is VSYNC, and CB2 is HSYNC. + PIA6821(config, m_r2_pia, 0); + m_r2_pia->readpa_handler().set(FUNC(mekd4_state::r2_pia_pa_r)); + m_r2_pia->readpb_handler().set(FUNC(mekd4_state::r2_pia_pb_r)); + m_r2_pia->readcb1_handler().set(FUNC(mekd4_state::r2_pia_cb1_r)); + m_r2_pia->irqa_handler().set("mainirq", FUNC(input_merger_device::in_w<2>)); + m_r2_pia->irqb_handler().set("mainirq", FUNC(input_merger_device::in_w<3>)); + + generic_keyboard_device &keyboard(GENERIC_KEYBOARD(config, "keyboard", 0)); + keyboard.set_keyboard_callback(FUNC(mekd4_state::kbd_put)); +} + +/*********************************************************** + + ROMS + +************************************************************/ + +ROM_START(mekd4) + ROM_REGION(0x10000,"bankdev",0) + ROM_LOAD("d4bugr2.rom", 0xe800, 0x0800, CRC(0b80a67d) SHA1(20d980767a7a667fe0f8e377bb2c29e297e6c635)) + ROM_LOAD("d4bugkpd.rom", 0xf000, 0x1000, CRC(1fdf414a) SHA1(3c8883a6ee0ae89398d9be5a5843db4c3b20f7fd)) + ROM_REGION(0x0400, "chargen",0) + ROM_LOAD("mcm6674p.chr", 0x0000, 0x0400, CRC(1c22088a) SHA1(b5f0bd0cfdec0cd5c1cb764506bef3c17d6af0eb)) + ROM_REGION(0x0400, "rommap",0) + ROM_LOAD("d4map00.rom", 0x0000, 0x0400, CRC(7e676444) SHA1(4f8a7443da509561be958786f9bd72eac3969a89)) +ROM_END + +/*************************************************************************** + + Game driver(s) + +***************************************************************************/ + +// YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS +COMP(1980, mekd4, 0, 0, mekd4, mekd4, mekd4_state, init_mekd4, "Motorola", "MEK6802D4" , MACHINE_NO_SOUND) diff --git a/src/mame/drivers/mekd5.cpp b/src/mame/drivers/mekd5.cpp new file mode 100644 index 00000000000..56b00f13b7e --- /dev/null +++ b/src/mame/drivers/mekd5.cpp @@ -0,0 +1,527 @@ +// license:BSD-3-Clause +// copyright-holders: 68bit +/****************************************************************************** + +Motorola Evaluation Kit 6802 D5 - MEK6802D5 + +Memory map + +Range Short Description + +0000-dfff RAM Either 128 bytes on board, or external + +e000-e3ff RAM Static RAM, 1K. +e400-e47f RAM System RAM +e480-e483 PIA User PIA +e484-e487 PIA System PIA + +e700-e701 ACIA System ACIA. + +e800-efff ROM Optional user ROM +f000-f7ff ROM D5BUG monitor ROM +f800-ffff ROM D5BUG (mirror), or optional user ROM. + + +A 1K or 2K optional user ROM or EPROM can be installed and mapped to either +0xe800-0xefff, or to 0xf800-0xffff, set via jumper 3. +TODO implement this user ROM. + +The board has provision for an ACIA, and the documentation mentions that it is +not used when there is a keypad, and the keypad is removable. However the +D5BUG monitor has no support for this ACIA. Was there an alternative official +monitor that used this ACIA? + + +Keypad commands: + +RS (Reset) Reset, wired to the CPU reset line +EX (Escape) Typically aborts user program. +M (Memory display/change) + Digits 5 and 6 show the actual data at the address. + G - increase the address. + M - decreases the address. + FS - Offset calculation. Enter address, then press 'GO'. + GO - stores the offset and returns to memory display and increased the address. + FC - return to memory display, without storing the offset. + M - return to memory display, after a BAD offset. + EX - exits memory display. +RD (Register display/alter) + G - advance to next register. + M - previous register. + T/B - trace a single instruction + EX - exits register display. +GO to user program. + If no address if entered then it uses the pseudo PC, it continues. + Enter the address and press 'Go' to use that entered address. + It firstly checks that there is RAM at the stack pointer. +FS T/B - Breakpoint editor + GO - advance to next breakpoing, up to 8, then loops. + FS - insert a breakpoint + FC - deactivate breakpoint + EX - exits breakpoing editor. +P/L (Punch tape) + At the 'bb' prompt enter the beginning address of the data, then 'GO'. + At the 'EE' prompt enter the last address of the data. + Start the tape and press GO. There is a 30 second leader of $ff. +FS P/L (Load from tape) +FS RD (Verify from tape) +FS 0 to F + One of 16 user defined functions. Press FS then one number key 0 to F. + A pointer to a table of 16 function addresses should be set at 0xe43f. + +******************************************************************************/ + +#include "emu.h" +#include "cpu/m6800/m6800.h" +#include "machine/input_merger.h" +#include "machine/6821pia.h" +#include "machine/6850acia.h" +#include "machine/mc14411.h" +#include "machine/clock.h" +#include "machine/timer.h" +#include "video/pwm.h" +#include "sound/wave.h" +#include "speaker.h" +#include "bus/rs232/rs232.h" +#include "machine/terminal.h" +#include "imagedev/cassette.h" +#include "imagedev/snapquik.h" +#include "render.h" +#include "mekd5.lh" + +#define XTAL_MEKD5 3.579545_MHz_XTAL + +class mekd5_state : public driver_device +{ +public: + enum + { + TIMER_TRACE + }; + + mekd5_state(const machine_config &mconfig, device_type type, const char *tag) + : driver_device(mconfig, type, tag) + , m_maincpu(*this, "maincpu") + , m_kpd_pia(*this, "kpd_pia") + , m_user_pia(*this, "user_pia") + , m_display(*this, "display") + , m_brg(*this, "brg") + , m_baud_rate(*this, "baud_rate") + , m_acia(*this, "acia") + , m_cass(*this, "cassette") + , m_keypad_columns(*this, "COL%u", 0) + { } + + void mekd5(machine_config &config); + void init_mekd5(); + + DECLARE_WRITE_LINE_MEMBER(reset_key_w); + DECLARE_INPUT_CHANGED_MEMBER(keypad_changed); + +private: + DECLARE_WRITE_LINE_MEMBER(trace_timer_clear_w); + + DECLARE_READ_LINE_MEMBER(keypad_cb1_r); + DECLARE_READ8_MEMBER(keypad_key_r); + DECLARE_WRITE8_MEMBER(led_digit_w); + DECLARE_WRITE8_MEMBER(led_segment_w); + DECLARE_READ_LINE_MEMBER(kansas_r); + + // Clocks + DECLARE_WRITE_LINE_MEMBER(write_f1_clock); + DECLARE_WRITE_LINE_MEMBER(write_f3_clock); + DECLARE_WRITE_LINE_MEMBER(write_f5_clock); + DECLARE_WRITE_LINE_MEMBER(write_f7_clock); + DECLARE_WRITE_LINE_MEMBER(write_f9_clock); + DECLARE_WRITE_LINE_MEMBER(write_f13_clock); + + void mekd5_mem(address_map &map); + + bool keypad_key_pressed(); + + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override; + uint8_t m_segment; + uint8_t m_digit; + virtual void machine_start() override; + virtual void machine_reset() override; + required_device m_maincpu; + required_device m_kpd_pia; + required_device m_user_pia; + required_device m_display; + required_device m_brg; + required_ioport m_baud_rate; + required_device m_acia; + required_device m_cass; + required_ioport_array<4> m_keypad_columns; +}; + + + +/*********************************************************** + + Address Map + +************************************************************/ + +void mekd5_state::mekd5_mem(address_map &map) +{ + map(0x0000, 0xdfff).ram(); + map(0xe000, 0xe3ff).ram(); + map(0xe400, 0xe47f).ram(); + + map(0xe480, 0xe483).mirror(0x0378).rw(m_user_pia, FUNC(pia6821_device::read), FUNC(pia6821_device::write)); + map(0xe484, 0xe487).mirror(0x0378).rw(m_kpd_pia, FUNC(pia6821_device::read), FUNC(pia6821_device::write)); + + map(0xe700, 0xe701).mirror(0x003e).rw(m_acia, FUNC(acia6850_device::read), FUNC(acia6850_device::write)); + + /* D5BUG ROM */ + map(0xf000, 0xf7ff).rom().mirror(0x0800); +} + +/*********************************************************** + + Keys + +************************************************************/ + +static INPUT_PORTS_START(mekd5) + + // RESET is not wired to the key matrix. + PORT_START("RESET") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYPAD) PORT_NAME("RS") PORT_WRITE_LINE_DEVICE_MEMBER(DEVICE_SELF, mekd5_state, reset_key_w) + + PORT_START("COL0") + PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, mekd5_state, keypad_changed, 0) PORT_NAME("M") PORT_CODE(KEYCODE_M) + PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, mekd5_state, keypad_changed, 0) PORT_NAME("FS") PORT_CODE(KEYCODE_S) + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, mekd5_state, keypad_changed, 0) PORT_NAME("7") PORT_CODE(KEYCODE_7) + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, mekd5_state, keypad_changed, 0) PORT_NAME("4") PORT_CODE(KEYCODE_4) + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, mekd5_state, keypad_changed, 0) PORT_NAME("1") PORT_CODE(KEYCODE_1) + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, mekd5_state, keypad_changed, 0) PORT_NAME("0") PORT_CODE(KEYCODE_0) + + PORT_START("COL1") + PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, mekd5_state, keypad_changed, 0) PORT_NAME("EX") PORT_CODE(KEYCODE_X) + PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, mekd5_state, keypad_changed, 0) PORT_NAME("FC") PORT_CODE(KEYCODE_W) + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, mekd5_state, keypad_changed, 0) PORT_NAME("8") PORT_CODE(KEYCODE_8) + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, mekd5_state, keypad_changed, 0) PORT_NAME("5") PORT_CODE(KEYCODE_5) + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, mekd5_state, keypad_changed, 0) PORT_NAME("2") PORT_CODE(KEYCODE_2) + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, mekd5_state, keypad_changed, 0) PORT_NAME("F") PORT_CODE(KEYCODE_F) + + PORT_START("COL2") + PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, mekd5_state, keypad_changed, 0) PORT_NAME("RD") PORT_CODE(KEYCODE_R) + PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, mekd5_state, keypad_changed, 0) PORT_NAME("P/L") PORT_CODE(KEYCODE_P) + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, mekd5_state, keypad_changed, 0) PORT_NAME("9") PORT_CODE(KEYCODE_9) + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, mekd5_state, keypad_changed, 0) PORT_NAME("6") PORT_CODE(KEYCODE_6) + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, mekd5_state, keypad_changed, 0) PORT_NAME("3") PORT_CODE(KEYCODE_3) + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, mekd5_state, keypad_changed, 0) PORT_NAME("E") PORT_CODE(KEYCODE_E) + + PORT_START("COL3") + PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, mekd5_state, keypad_changed, 0) PORT_NAME("GO") PORT_CODE(KEYCODE_G) + PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, mekd5_state, keypad_changed, 0) PORT_NAME("T/B") PORT_CODE(KEYCODE_T) + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, mekd5_state, keypad_changed, 0) PORT_NAME("A") PORT_CODE(KEYCODE_A) + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, mekd5_state, keypad_changed, 0) PORT_NAME("B") PORT_CODE(KEYCODE_B) + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, mekd5_state, keypad_changed, 0) PORT_NAME("C") PORT_CODE(KEYCODE_C) + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, mekd5_state, keypad_changed, 0) PORT_NAME("D") PORT_CODE(KEYCODE_D) + + /* RS232 baud rates available via J5. */ + PORT_START("baud_rate") + PORT_CONFNAME(0x3f, 1, "RS232 Baud Rate") + PORT_CONFSETTING(0x01, "9600") + PORT_CONFSETTING(0x02, "4800") + PORT_CONFSETTING(0x04, "2400") + PORT_CONFSETTING(0x08, "1200") + PORT_CONFSETTING(0x10, "300") + PORT_CONFSETTING(0x20, "110") + +INPUT_PORTS_END + +/*********************************************************** + + Trace timer + +************************************************************/ + +void mekd5_state::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch (id) + { + case TIMER_TRACE: + // CB2 is programmed to trigger on the falling edge, so after + // a count of 16. CB2 input comes from a counter, so the duty + // cycle should be 50/50, but it makes no difference to rise + // and fall here. + m_kpd_pia->cb2_w(1); + m_kpd_pia->cb2_w(0); + break; + default: + assert_always(false, "Unknown id in mekd5_state::device_timer"); + } +} + + +// Expect a delay of 16 cycles. However the 6800 cycle model appears to +// account for the store that writes here as occuring at the start of that +// instruction adding 5 cycles to give an effective 21 cycles. TODO adjust +// this back to 16 cycles when the 6800 cycle timing becomes more accurate. +WRITE_LINE_MEMBER(mekd5_state::trace_timer_clear_w) +{ + if (state) + m_kpd_pia->cb2_w(0); + else + timer_set(attotime::from_ticks(21, XTAL_MEKD5 / 4), TIMER_TRACE); +} + +/*********************************************************** + + Keypad + +************************************************************/ + +// Keypad input is disable on views with the RS232 input. + +WRITE_LINE_MEMBER(mekd5_state::reset_key_w) +{ + uint8_t view = machine().render().first_target()->view(); + if (view > 1) return; + + m_maincpu->set_input_line(INPUT_LINE_RESET, state ? CLEAR_LINE : ASSERT_LINE); + + // TODO reset other devices. +} + + +bool mekd5_state::keypad_key_pressed() +{ + uint8_t view = machine().render().first_target()->view(); + if (view > 1) return 0; + + return (m_keypad_columns[0]->read() & m_digit) || + (m_keypad_columns[1]->read() & m_digit) || + (m_keypad_columns[2]->read() & m_digit) || + (m_keypad_columns[3]->read() & m_digit); +} + +INPUT_CHANGED_MEMBER(mekd5_state::keypad_changed) +{ + m_kpd_pia->cb1_w(mekd5_state::keypad_key_pressed()); +} + +READ_LINE_MEMBER(mekd5_state::keypad_cb1_r) +{ + return mekd5_state::keypad_key_pressed(); +} + +READ8_MEMBER(mekd5_state::keypad_key_r) +{ + uint8_t view = machine().render().first_target()->view(); + if (view > 1) return m_segment; + + uint8_t mux = (m_digit & 0xc0) >> 6; + uint8_t i = (m_keypad_columns[mux]->read() & m_digit) ? 0 : 0x80; + + return i | m_segment; +} + +/*********************************************************** + + Seven segment LED display, and cassette + +************************************************************/ + +// PA +WRITE8_MEMBER(mekd5_state::led_segment_w) +{ + m_segment = data & 0x7f; + m_display->matrix(m_digit & 0x3f, ~m_segment); +} + +// PB +WRITE8_MEMBER(mekd5_state::led_digit_w) +{ + m_digit = data; + m_display->matrix(m_digit & 0x3f, ~m_segment); + // PB7 also drives the cassette output. + m_cass->output(BIT(data, 7) ? -1.0 : +1.0); + // Update the keypad pressed output which depends on m_digit. + m_kpd_pia->cb1_w(mekd5_state::keypad_key_pressed()); +} + +READ_LINE_MEMBER(mekd5_state::kansas_r) +{ + uint8_t data = m_cass->input() > +0.0; + return data; +} + + +/*********************************************************** + + ACIA clocks + +************************************************************/ + +WRITE_LINE_MEMBER(mekd5_state::write_f1_clock) +{ + if (BIT(m_baud_rate->read(), 0)) + { + m_acia->write_txc(state); + m_acia->write_rxc(state); + } +} + +WRITE_LINE_MEMBER(mekd5_state::write_f3_clock) +{ + if (BIT(m_baud_rate->read(), 1)) + { + m_acia->write_txc(state); + m_acia->write_rxc(state); + } +} + +WRITE_LINE_MEMBER(mekd5_state::write_f5_clock) +{ + if (BIT(m_baud_rate->read(), 2)) + { + m_acia->write_txc(state); + m_acia->write_rxc(state); + } +} + +WRITE_LINE_MEMBER(mekd5_state::write_f7_clock) +{ + if (BIT(m_baud_rate->read(), 3)) + { + m_acia->write_txc(state); + m_acia->write_rxc(state); + } +} + +WRITE_LINE_MEMBER(mekd5_state::write_f9_clock) +{ + if (BIT(m_baud_rate->read(), 4)) + { + m_acia->write_txc(state); + m_acia->write_rxc(state); + } +} + +WRITE_LINE_MEMBER(mekd5_state::write_f13_clock) +{ + if (BIT(m_baud_rate->read(), 5)) + { + m_acia->write_txc(state); + m_acia->write_rxc(state); + } +} + + +/*********************************************************** + +************************************************************/ + +void mekd5_state::init_mekd5() +{ +} + +void mekd5_state::machine_start() +{ +} + +void mekd5_state::machine_reset() +{ + // Trace timer out low. + m_kpd_pia->cb2_w(0); + + m_brg->rsa_w(CLEAR_LINE); + m_brg->rsb_w(ASSERT_LINE); + + // /DCD and /CTS are wired low. + m_acia->write_dcd(CLEAR_LINE); + m_acia->write_cts(CLEAR_LINE); +} + +/*********************************************************** + + Machine + +************************************************************/ + +static DEVICE_INPUT_DEFAULTS_START(terminal) + DEVICE_INPUT_DEFAULTS("RS232_RXBAUD", 0xff, RS232_BAUD_9600) + DEVICE_INPUT_DEFAULTS("RS232_TXBAUD", 0xff, RS232_BAUD_9600) + DEVICE_INPUT_DEFAULTS("RS232_STARTBITS", 0xff, RS232_STARTBITS_1) + DEVICE_INPUT_DEFAULTS("RS232_DATABITS", 0xff, RS232_DATABITS_8) + DEVICE_INPUT_DEFAULTS("RS232_PARITY", 0xff, RS232_PARITY_NONE) + DEVICE_INPUT_DEFAULTS("RS232_STOPBITS", 0xff, RS232_STOPBITS_1) +DEVICE_INPUT_DEFAULTS_END + +void mekd5_state::mekd5(machine_config &config) +{ + M6802(config, m_maincpu, XTAL_MEKD5); /* 894.8 kHz clock */ + m_maincpu->set_addrmap(AS_PROGRAM, &mekd5_state::mekd5_mem); + + INPUT_MERGER_ANY_HIGH(config, "mainirq").output_handler().set_inputline(m_maincpu, M6802_IRQ_LINE); + INPUT_MERGER_ANY_HIGH(config, "mainnmi").output_handler().set_inputline(m_maincpu, INPUT_LINE_NMI); + + // LED display + PWM_DISPLAY(config, m_display).set_size(6, 7); + m_display->set_segmask(0x3f, 0x7f); + + config.set_default_layout(layout_mekd5); + + SPEAKER(config, "mono").front_center(); + + CASSETTE(config, m_cass); + m_cass->set_default_state(CASSETTE_STOPPED | CASSETTE_MOTOR_ENABLED | CASSETTE_SPEAKER_ENABLED); + m_cass->add_route(ALL_OUTPUTS, "mono", 0.05); + + // Keypad and display PIA (U23). IRQA is NC. CB2 is trace timer input. + PIA6821(config, m_kpd_pia, 0); + m_kpd_pia->readpa_handler().set(FUNC(mekd5_state::keypad_key_r)); + m_kpd_pia->writepa_handler().set(FUNC(mekd5_state::led_segment_w)); + m_kpd_pia->writepb_handler().set(FUNC(mekd5_state::led_digit_w)); + m_kpd_pia->readca1_handler().set(FUNC(mekd5_state::kansas_r)); + m_kpd_pia->ca2_handler().set(FUNC(mekd5_state::trace_timer_clear_w)); + m_kpd_pia->readcb1_handler().set(FUNC(mekd5_state::keypad_cb1_r)); + m_kpd_pia->irqb_handler().set("mainnmi", FUNC(input_merger_device::in_w<1>)); + + // User PIA (U9). + // IRQA and IRQB can be independently jumpered to IRQ or NMI via J1. + // All the I/O lines are available at the User I/O connector. + PIA6821(config, m_user_pia, 0); + + // IRQ is NC. RX and TX clk are wired together. RTS is available. + // /DCD and /CTS and wired low. + ACIA6850(config, m_acia, 0); + m_acia->txd_handler().set("rs232", FUNC(rs232_port_device::write_txd)); + + MC14411(config, m_brg, XTAL(1'843'200)); + m_brg->out_f<1>().set(FUNC(mekd5_state::write_f1_clock)); + m_brg->out_f<3>().set(FUNC(mekd5_state::write_f3_clock)); + m_brg->out_f<5>().set(FUNC(mekd5_state::write_f5_clock)); + m_brg->out_f<7>().set(FUNC(mekd5_state::write_f7_clock)); + m_brg->out_f<9>().set(FUNC(mekd5_state::write_f9_clock)); + m_brg->out_f<13>().set(FUNC(mekd5_state::write_f13_clock)); + + rs232_port_device &rs232(RS232_PORT(config, "rs232", default_rs232_devices, "terminal")); + rs232.rxd_handler().set(m_acia, FUNC(acia6850_device::write_rxd)); + rs232.set_option_device_input_defaults("terminal", DEVICE_INPUT_DEFAULTS_NAME(terminal)); +} + +/*********************************************************** + + ROMS + +************************************************************/ + +ROM_START(mekd5) + ROM_REGION(0x10000,"maincpu",0) + ROM_LOAD("d5bug.rom", 0xf000, 0x0800, CRC(67c00a2c) SHA1(ae321dbca0baf4b67d62bfec77266d9132b973bf)) +ROM_END + +/*************************************************************************** + + Game driver(s) + +***************************************************************************/ + +// YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS +COMP( 1980, mekd5, 0, 0, mekd5, mekd5, mekd5_state, init_mekd5, "Motorola", "MEK6802D5" , MACHINE_NO_SOUND ) diff --git a/src/mame/layout/mekd4.lay b/src/mame/layout/mekd4.lay new file mode 100644 index 00000000000..b1ebbc79ec8 --- /dev/null +++ b/src/mame/layout/mekd4.lay @@ -0,0 +1,305 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/mame/layout/mekd5.lay b/src/mame/layout/mekd5.lay new file mode 100644 index 00000000000..23ec8575a3a --- /dev/null +++ b/src/mame/layout/mekd5.lay @@ -0,0 +1,296 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/mame/mame.lst b/src/mame/mame.lst index b1d850496c6..762c0ee233e 100644 --- a/src/mame/mame.lst +++ b/src/mame/mame.lst @@ -21493,6 +21493,12 @@ meijinsn // (c) 1986 SNK @source:mekd2.cpp mekd2 // 1977 Motorola Evaluation Kit +@source:mekd4.cpp +mekd4 // 1980 Motorola Evaluation Kit + +@source:mekd5.cpp +mekd5 // 1980 Motorola Evaluation Kit + @source:menghong.cpp crzyddz2 // 2006 Sealy menghong // 2004? Sealy diff --git a/src/mame/mess.flt b/src/mame/mess.flt index 5eb920bd744..f992b3dd452 100644 --- a/src/mame/mess.flt +++ b/src/mame/mess.flt @@ -463,6 +463,8 @@ mdisk.cpp megadriv.cpp megadriv_rad.cpp mekd2.cpp +mekd4.cpp +mekd5.cpp mephisto_brikett.cpp mephisto_glasgow.cpp mephisto_mm1.cpp