diff options
Diffstat (limited to 'src/devices/machine/swtpc8212.cpp')
-rw-r--r-- | src/devices/machine/swtpc8212.cpp | 565 |
1 files changed, 565 insertions, 0 deletions
diff --git a/src/devices/machine/swtpc8212.cpp b/src/devices/machine/swtpc8212.cpp new file mode 100644 index 00000000000..fea60261b0f --- /dev/null +++ b/src/devices/machine/swtpc8212.cpp @@ -0,0 +1,565 @@ +// license:BSD-3-Clause +// copyright-holders:AJR,68bit +/**************************************************************************** + +Driver for Southwest Technical Products video terminal 8210. + +MC6802P, 2xMC6821P, INS8250N, MCM66750, MC6845P, bank of 8 dips, crystals +17.0748 (video), 1.8432 (cpu/uart). On the back is a 25-pin RS-232 port, and a +25-pin printer port. + +The 8212 terminal appears similar in design to the CT-82 terminal for which +there is some documentation and a user guide. In particular it appears closest +to the 'Version B1'. There was also a 8209 terminal with an 9 inch CRT versus +the 12 inch CRT in the 8212. This terminal has also been labeled at the +CT8200. http://www.swtpc.com/mholley/CT_82/CT82_Index.htm + +The 8212 has three CRT controller configurations: + 1. 82 x 20 characters, with a height of 14 scan lines. + 2. 82 x 24 characters, with a height of 12 scan lines. + 3. 92 x 22 characters, with a height of 12 scan lines. + +There are two character generators: +1. The MCM66750 with 7x9 sized characters with some descending by 3 lines +giving an effective 7x12 sized character set. +2. An EPROM defining 8x16 sized characters for which only 12 scan lines are +used, and this is used for the graphics mode. + +These appear to map onto the CT-82 screen formats options as follows: +Format I: 82 by 20, MCM66750 character set. Ctrl-\ crtl-Q +Format II: 82 by 24, MCM66750 character set. Ctrl-\ crtl-R +Format III: 82 by 20, EPROM character set. Ctrl-\ crtl-S +Format IV: 82 by 24, EPROM character set. Ctrl-\ crtl-T +Graphics: 92 by 22, EPROM character set. Ctrl-] crtl-V + +The semi-graphics character set is defined in an EPROM, and that EPROM defines +these characters but here is a brief description of the graphics codes. It +includes graphics characters that support a two by three pixel array per +character. The codes 0x20 to 0x5f remain ASCII characters. The codes 0x00 to +0x1f have the following graphics encoding: + + 000xxxxx + ---------- + | D0 | D3 | + ----------- + | D1 | D4 | + ----------- + | D2 | 0 | + ----------- + +The codes 0x60 to 0x7f have the following graphics encoding: + + 011xxxxx + ----------- + | D0 | D3 | + ----------- + | D1 | D4 | + ----------- + | D2 | 1 | + ----------- + +The terminal includes a parallel printer output and Ctrl-] Ctrl-K enables +printer pass-through and Ctrl-] Ctrl-G disables pass-through. + +The terminal appears to include light pen support, and the positions is read +via Ctrl-] Ctrl-B, TODO. + +The numeric keypad is separte to the keyboard, returning a separate 4 bit code +and strobe. The CT-82 documentation suggests that the order of the bits on the +keypad bus is reversed. Photos of the 8212 show a 16 key keypad. The ROM has a +table starting at 0xb8e4 that maps the keypad code read from PIA 0 Port A bits +4 to 7 into a character code. This table has two vectors of 16 bytes, and the +first 16 are used when in the 'cursor' mode and the later 16 are uses when in +the 'numeric' keypad mode. In the 'cursor' mode, four of the keys are +underfined. TODO the labels of all the keypad keys could not be read from the +photo found, so could use a better photo of the keypad and an update here. + +The keypad codes in the ROM appear consistent with the CT-82 +documentation. However the codes for the left and right cursor keys are not +consistent with a UniFlex termcap entry for the 'ct8200' which has the right +cursor code being 0x1d and the left cursor code being 0x1e. The standard CT-82 +codes of Ctrl-D and Ctrl-I for these keys are not good choices for a 'Unix' +like terminal and it appears likely that there is either a ROM revision making +this trivial change to better work with UniFlex or that people did patch the +keypad codes. The keypad codes are single character codes so there is very +limit room to add more, and some of keys were not even assigned a code, +history! A ROM patch assigning code friendlier to Unix is included in this +emulator. + +A glitch in the interaction of the keyboard and the keypad has been noted. When +typing fast on the keyboard a character may not be sent. Then if another key is +typed on the keyboard the unsent code is lost. But if another key is typed on +the keypad then the unsent keyboard code is then sent and the keypad code is +lost. The firmware has a one character send buffer. TODO This might be a +firmware issue, or might be a problem with the emulation of the PIA or UART or +the keyboard or keypad strobes etc. + +TODO A generic keyboard is used. Might need some work to get a better keyboard +emulation. The CT-82 documentation mentions a 'Break' key. + +TODO A generic 'beep' is used. Might want to compare this with the actual 8212 +to better emulate the sound. + +TODO the CB2 input of 'pia0' at address 0x0080 is polled by the firmware, and +it is the first input checked in the ISR. On a CB2 interrupt the ISR checks +for a 'break' condition on the UART and if not then it clears the UART OUT1 +output. There are other suggestions in the firmware that the OUT1 and OUT2 +UART lines are being driven. The operation here is unknown? + +TODO Confirm the CPU XTAL. The terminal emulation appears slugish compared +with the documented claims, the hardware flow control is needed even at 9600 +and it does not operate at 38400 as documented. The CT82 manual mentions an +optional 4MHz crystal and that would run the CPU at 1MHz which is the rated +speed for the CPU and perhaps the 8212 uses that 4MHz XTAL or at least +something faster the current 1.8432MHz XTAL? + +The terminfo database does not appear to have an entry for this terminal, and +the following is offered that attempts to use the features of the terminal that +map to ncurses and this helped testing and it appears to run the ncurses tests +and some utilities ok. The cursor keys are set for the patched ROM option. Keep +in mind that it is an ASCII terminal so try an ISO-8859-1 locale, and also that +it has no tabs so it needs tab to space translation. + +swtp|ct8212|southwest technical products ct8212, + cols#82, lines#24, + bel=^G, civis=^E, clear=^L, cnorm=^U, cr=\r, + cub=^\^D%p1%c, cub1=^D, cud=^\^B%p1%c, cud1=^B, + cuf1=^R, cup=^K%p2%{32}%+%c%p1%{32}%+%c, + cuu=^\^A%p1%c, cuu1=^A, dch1=^\^H, dl1=^Z, ed=^V, el=^F, + el1=^\^F, home=^P, hpa=^\^W%p1%{32}%+%c, ich1=^\^X, + il1=^\^Y, ind=^N, + is2=^_^A$<250>^\^R$<50>^^^D^^^T^_^J\040^^^G^^^O^^^Z^]^W^I^R, + kbs=^H, kcub1=^B, kcud1=^N, kcuf1=^F, kcuu1=^P, khome=^A, + ll=^C, mc4=^]^G, mc5=^]^K, nel=\r\n, ri=^O, rmir=, rmso=^^^F, + smir=, smso=^^^V, vpa=^\^G%p1%{32}%+%c, + +****************************************************************************/ + +#include "emu.h" +#include "swtpc8212.h" + +#include "machine/input_merger.h" + +#include "screen.h" +#include "speaker.h" + +swtpc8212_device::swtpc8212_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, type, tag, owner, clock) + , m_maincpu(*this, "maincpu") + , m_pia0(*this, "pia0") + , m_pia1(*this, "pia1") + , m_uart(*this, "uart") + , m_crtc(*this, "crtc") + , m_chargen1(*this, "chargen1") + , m_chargen2(*this, "chargen2") + , m_video_ram(*this, "videoram") + , m_config(*this, "CONFIG") + , m_keypad(*this, "KEYPAD") + , m_one_stop_bit(*this, "ONE_STOP_BIT") + , m_bell_timer(nullptr) + , m_beeper(*this, "beeper") + , m_printer(*this, "printer") + , m_rs232_conn_txd_handler(*this) + , m_rs232_conn_dtr_handler(*this) + , m_rs232_conn_rts_handler(*this) +{ +} + +swtpc8212_device::swtpc8212_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : swtpc8212_device(mconfig, SWTPC8212, tag, owner, clock) +{ +} + +void swtpc8212_device::latch_w(uint8_t data) +{ + // Bits 0 to 3 control outputs that are intended to control and tape + // 'read' and 'punch' operations. These are strobes, about 10usec, and + // intended to trigger on the falling edge. + // + // Bit 0 - Read on output + // Bit 1 - Read off output + // Bit 2 - Punch on output + // Bit 3 - Punch off output + + // Bit 4 - ?? usually high + // Bit 5 - ?? usually low + + // Bits 6 and 7 change with the screen format. + // + // Bit 6 is zero for formats I and II, and one for formats III and IV + // and for the graphics format. Assume this selects between the + // characters sets, so formats III and IV might use an alternative + // custom text character set. + // + // Bit 6 - character set: 0 - standard; 1 - alternate/graphics. + // + // Bit 7 is zero in formats I, II, III, and IV, and one for the + // graphics format. Assume this controls the horizontal + // inter-character gap, eliminating the gap for the graphics format. + // + // Bit 7 - character width: 0 - 9 dots; 1 - 8 dots. + // + if (BIT(data, 7) == 0) + m_crtc->set_char_width(9); + else + m_crtc->set_char_width(8); + + m_latch_data = data; +} + + +uint8_t swtpc8212_device::pia0_pa_r() +{ + // PA0 controls the 'duplex' mode, the echoing back of characters, and + // appears to connect to a switch on the outer casing. + // + // PA1 On the CT-82 this enabled or disabled use of an optional ROM, + // but that function is disabled in the 8212, and this is probably + // unused. + // + // PA2 is Jumper B, and PA3 is Jumper A. + uint8_t config = m_config->read(); + + return (m_keypad_data << 4) | config; +} + +uint8_t swtpc8212_device::pia0_pb_r() +{ + return m_keyboard_data; +} + +void swtpc8212_device::keyboard_put(uint8_t data) +{ + m_keyboard_data = data; + // Triggers on the falling edge. + m_pia0->cb1_w(ASSERT_LINE); + m_pia0->cb1_w(CLEAR_LINE); + m_pia0->cb1_w(ASSERT_LINE); +} + +INPUT_CHANGED_MEMBER(swtpc8212_device::keypad_changed) +{ + uint16_t keys = m_keypad->read(); + uint8_t n; + + for (n = 0; n < 16; n++) + { + if (BIT(keys, n)) + break; + } + + m_keypad_data = n; + + if (newval) + { + m_pia0->ca1_w(ASSERT_LINE); + m_pia0->ca1_w(CLEAR_LINE); + m_pia0->ca1_w(ASSERT_LINE); + } +} + +void swtpc8212_device::pia0_ca2_w(int state) +{ + if (state == 0) + { + m_beeper->set_state(1); + m_bell_timer->reset(attotime::from_msec(250)); + } +} + +void swtpc8212_device::pia1_pa_w(uint8_t data) +{ + // External parallel printer data output. + m_printer_data = data; +} + +void swtpc8212_device::pia1_ca2_w(int state) +{ + // External parallel printer data ready. + + // Trigger on the falling edge. + if (m_printer_data_ready == 1 && state == 0) + { + m_printer->output(m_printer_data); + // Toggle the printer busy line as the software waits for a + // falling edge. + m_pia1->ca1_w(CLEAR_LINE); + m_pia1->ca1_w(ASSERT_LINE); + m_pia1->ca1_w(CLEAR_LINE); + } + m_printer_data_ready = state; +} + +MC6845_UPDATE_ROW(swtpc8212_device::update_row) +{ + int x = 0; + uint8_t *chargen = BIT(m_latch_data, 6) == 0 ? m_chargen1 : m_chargen2; + + for (int column = 0; column < x_count; column++) + { + uint8_t code = m_video_ram[(ma + column) & 0x07ff]; + int dcursor = (column == cursor_x); + + offs_t address = ra < 16 ? (code & 0x7f) | (ra & 0x0f) << 7 : 0; + uint8_t data = chargen[address]; + uint8_t intensity = BIT(code, 7); + + for (int bit = 0; bit < 8; bit++) + { + int dout = BIT(data, 7); + uint32_t font_color = 0; + if ((dcursor ^ dout) && de) + { + if (intensity) + font_color = rgb_t(0x10, 0xff, 0x10); + else + font_color = rgb_t(0x00, 0xd0, 0x00); + } + bitmap.pix(y, x++) = font_color; + data <<= 1; + } + + // Gap between characters + if (BIT(m_latch_data, 7) == 0) + x++; + } +} + +TIMER_CALLBACK_MEMBER(swtpc8212_device::bell_off) +{ + m_beeper->set_state(0); +} + +void swtpc8212_device::rs232_conn_dcd_w(int state) +{ + m_uart->dcd_w(state); +} + +void swtpc8212_device::rs232_conn_dsr_w(int state) +{ + m_uart->dsr_w(state); +} + +void swtpc8212_device::rs232_conn_ri_w(int state) +{ + m_uart->ri_w(state); +} + +void swtpc8212_device::rs232_conn_cts_w(int state) +{ + m_uart->cts_w(state); +} + +void swtpc8212_device::rs232_conn_rxd_w(int state) +{ + m_uart->rx_w(state); +} + +void swtpc8212_device::write_txd(int state) +{ + m_rs232_conn_txd_handler(state); +} + +void swtpc8212_device::write_dtr(int state) +{ + m_rs232_conn_dtr_handler(state); +} + +void swtpc8212_device::write_rts(int state) +{ + m_rs232_conn_rts_handler(state); +} + +void swtpc8212_device::device_start() +{ + m_bell_timer = timer_alloc(FUNC(swtpc8212_device::bell_off), this); + + save_item(NAME(m_latch_data)); + save_item(NAME(m_keyboard_data)); + save_item(NAME(m_printer_data)); + save_item(NAME(m_printer_data_ready)); +} + +void swtpc8212_device::device_reset() +{ + m_keyboard_data = 0; + m_pia0->cb1_w(ASSERT_LINE); + m_keypad_data = 0; + m_pia0->ca1_w(ASSERT_LINE); + + m_latch_data = 0x1f; + + m_beeper->set_state(0); + + m_printer_data = 0; + m_printer_data_ready = 1; + m_pia1->ca1_w(CLEAR_LINE); + + if (m_one_stop_bit->read()) + { + // Patch the firmware to use one stop bit. + uint8_t* program = memregion("program")->base(); + program[0x01ad] = 0x02; + } +} + +void swtpc8212_device::mem_map(address_map &map) +{ + map(0x0080, 0x0083).rw("pia0", FUNC(pia6821_device::read), FUNC(pia6821_device::write)); + map(0x0088, 0x0088).w("crtc", FUNC(mc6845_device::address_w)); + map(0x0089, 0x0089).rw("crtc", FUNC(mc6845_device::register_r), FUNC(mc6845_device::register_w)); + map(0x008c, 0x008c).w(FUNC(swtpc8212_device::latch_w)); + map(0x0090, 0x0097).rw("uart", FUNC(ins8250_device::ins8250_r), FUNC(ins8250_device::ins8250_w)); + map(0x0098, 0x009b).rw("pia1", FUNC(pia6821_device::read), FUNC(pia6821_device::write)); + map(0x4000, 0x47ff).mirror(0x1800).ram().share(m_video_ram); + map(0xb800, 0xbfff).rom().region("program", 0); + map(0xc000, 0xc7ff).mirror(0x3800).rom().region("program", 0x800); +} + + + + +INPUT_PORTS_START(swtpc8212) + + PORT_START("KEYPAD") + PORT_BIT(0x0002U, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("7 / Form") PORT_CHANGED_MEMBER(DEVICE_SELF, FUNC(swtpc8212_device::keypad_changed), 0) + PORT_BIT(0x0004U, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("8 / Xmit") PORT_CHANGED_MEMBER(DEVICE_SELF, FUNC(swtpc8212_device::keypad_changed), 0) + PORT_BIT(0x0001U, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("9 / ??") PORT_CHANGED_MEMBER(DEVICE_SELF, FUNC(swtpc8212_device::keypad_changed), 0) + PORT_BIT(0x0008U, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME(u8"÷ / ??") PORT_CHANGED_MEMBER(DEVICE_SELF, FUNC(swtpc8212_device::keypad_changed), 0) + PORT_BIT(0x0200U, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("4 / Scroll Up") PORT_CODE(KEYCODE_PGDN) PORT_CHANGED_MEMBER(DEVICE_SELF, FUNC(swtpc8212_device::keypad_changed), 0) + PORT_BIT(0x0400U, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME(u8"5 / \u2191") PORT_CODE(KEYCODE_UP) PORT_CHANGED_MEMBER(DEVICE_SELF, FUNC(swtpc8212_device::keypad_changed), 0) // U+2191 = ↑ + PORT_BIT(0x0100U, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("6 / Insert") PORT_CODE(KEYCODE_0_PAD) PORT_CHANGED_MEMBER(DEVICE_SELF, FUNC(swtpc8212_device::keypad_changed), 0) + PORT_BIT(0x0800U, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME(u8"× / ??") PORT_CHANGED_MEMBER(DEVICE_SELF, FUNC(swtpc8212_device::keypad_changed), 0) + PORT_BIT(0x0020U, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME(u8"1 / \u2190") PORT_CODE(KEYCODE_LEFT) PORT_CHANGED_MEMBER(DEVICE_SELF, FUNC(swtpc8212_device::keypad_changed), 0) // U+2190 = ← + PORT_BIT(0x0040U, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("2 / Home") PORT_CODE(KEYCODE_HOME) PORT_CHANGED_MEMBER(DEVICE_SELF, FUNC(swtpc8212_device::keypad_changed), 0) + PORT_BIT(0x0010U, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME(u8"3 / \u2192") PORT_CODE(KEYCODE_RIGHT) PORT_CHANGED_MEMBER(DEVICE_SELF, FUNC(swtpc8212_device::keypad_changed), 0) // U+2192 = → + PORT_BIT(0x0080U, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("- / LF") PORT_CHANGED_MEMBER(DEVICE_SELF, FUNC(swtpc8212_device::keypad_changed), 0) + PORT_BIT(0x2000U, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("0 / Scroll Down") PORT_CODE(KEYCODE_PGUP) PORT_CHANGED_MEMBER(DEVICE_SELF, FUNC(swtpc8212_device::keypad_changed), 0) + PORT_BIT(0x4000U, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME(u8"0 / \u2193") PORT_CODE(KEYCODE_DOWN) PORT_CHANGED_MEMBER(DEVICE_SELF, FUNC(swtpc8212_device::keypad_changed), 0) // U+2193 = ↓ + PORT_BIT(0x1000U, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME(". / Delete") PORT_CODE(KEYCODE_DEL_PAD) PORT_CHANGED_MEMBER(DEVICE_SELF, FUNC(swtpc8212_device::keypad_changed), 0) + PORT_BIT(0x8000U, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("+ / CR") PORT_CHANGED_MEMBER(DEVICE_SELF, FUNC(swtpc8212_device::keypad_changed), 0) + + PORT_START("DIP_SWITCHES") + PORT_DIPNAME(0x1f, 0x19, "Baud Rate") PORT_DIPLOCATION("DIP:5,4,3,2,1") + PORT_DIPSETTING(0x04, "110") + PORT_DIPSETTING(0x0a, "300") + PORT_DIPSETTING(0x0d, "600") + PORT_DIPSETTING(0x0f, "1200") + PORT_DIPSETTING(0x12, "2400") + PORT_DIPSETTING(0x16, "4800") + PORT_DIPSETTING(0x18, "7200") + PORT_DIPSETTING(0x19, "9600") + PORT_DIPSETTING(0x1c, "19200") + PORT_DIPSETTING(0x1f, "38400") + PORT_DIPNAME(0x20, 0x00, "Mode switch") PORT_DIPLOCATION("DIP:6") + PORT_DIPSETTING(0x00, "Conversational") + PORT_DIPSETTING(0x20, "Page edit") + PORT_DIPNAME(0x40, 0x00, "No Parity") PORT_DIPLOCATION("DIP:7") + PORT_DIPSETTING(0x00, "No Parity") + PORT_DIPSETTING(0x40, "Parity") + PORT_DIPNAME(0x80, 0x00, "Parity Select") PORT_DIPLOCATION("DIP:8") + PORT_DIPSETTING(0x00, "Odd or Mark") + PORT_DIPSETTING(0x80, "Even or Space") + + PORT_START("CONFIG") + PORT_CONFNAME(0x01, 0x01, "Duplex") + PORT_CONFSETTING(0x00, "Full duplex") + PORT_CONFSETTING(0x01, "Half duplex") + PORT_CONFNAME(0x02, 0x00, "Option ROM (Not used)") + PORT_CONFSETTING(0x00, DEF_STR(On)) + PORT_CONFSETTING(0x02, DEF_STR(Off)) + PORT_CONFNAME(0x04, 0x04, "Parity Select (Jumper B)") + PORT_CONFSETTING(0x00, "Odd or Even (On)") + PORT_CONFSETTING(0x04, "Mark or Space (Off)") + PORT_CONFNAME(0x08, 0x08, "Data bits (Jumper A)") + PORT_CONFSETTING(0x00, "7 bit data (On)") + PORT_CONFSETTING(0x08, "8 bit data (Off)") + + PORT_START("ONE_STOP_BIT") + PORT_CONFNAME(1, 1, "One stop bit patch") + PORT_CONFSETTING(0, "No") + PORT_CONFSETTING(1, "Yes - apply patch") + +INPUT_PORTS_END + + +ROM_START( swtpc8212 ) + ROM_REGION( 0x1000, "program", 0 ) + ROM_LOAD( "8224g_ver.1.1_6oct80.ic1", 0x0000, 0x0800, CRC(7d7f3c21) SHA1(f7e6e20b36a1c724a4e348bc784d0b7b5fb462a3) ) + ROM_LOAD( "8224g_ver.1.1_6oct80.ic2", 0x0800, 0x0800, CRC(2b118c22) SHA1(5fa031c834c7c582d5715764941499fcef51f477) ) + + ROM_REGION( 0x0800, "chargen1", 0 ) + ROM_LOAD( "mcm66750.rom", 0x0000, 0x0800, CRC(aedc2830) SHA1(49ce17d5b5cefb24e89ed3fd59887a652501b919) ) + ROM_REGION( 0x0800, "chargen2", 0 ) + ROM_LOAD( "grafix_8x12_22aug80.bin", 0x0000, 0x0800, CRC(a525ed65) SHA1(813d2e85ddb258c5b032b959e695ad33200cbcc4) ) +ROM_END + +void swtpc8212_device::device_add_mconfig(machine_config &config) +{ + M6802(config, m_maincpu, 1.8432_MHz_XTAL); + m_maincpu->set_addrmap(AS_PROGRAM, &swtpc8212_device::mem_map); + + INPUT_MERGER_ANY_HIGH(config, "mainirq").output_handler().set_inputline(m_maincpu, M6802_IRQ_LINE); + + // PA - various jumpers and keypad inputs. + // PB - parallel keyboard data input. + // CA1 - parallel keypad input strobe. + // CA2 - output, bell. + // CB1 - parallel keyboard input strobe. + // CB2 ?? + PIA6821(config, m_pia0); + m_pia0->readpa_handler().set(FUNC(swtpc8212_device::pia0_pa_r)); + m_pia0->readpb_handler().set(FUNC(swtpc8212_device::pia0_pb_r)); + m_pia0->ca2_handler().set(FUNC(swtpc8212_device::pia0_ca2_w)); + m_pia0->irqa_handler().set("mainirq", FUNC(input_merger_device::in_w<0>)); + m_pia0->irqb_handler().set("mainirq", FUNC(input_merger_device::in_w<1>)); + + // PA - parallel printer data outputs. + // PB - various config inputs. + // CA1 - parallel printer, 'busy' input. + // CA2 - parallel printer, 'data ready' output. + // CB1 - Handshake input? + // CB2 - Handshake output? + PIA6821(config, m_pia1); + m_pia1->writepa_handler().set(FUNC(swtpc8212_device::pia1_pa_w)); + m_pia1->ca1_w(0); // External parallel printer busy input. + m_pia1->ca2_handler().set(FUNC(swtpc8212_device::pia1_ca2_w)); + m_pia1->readpb_handler().set_ioport("DIP_SWITCHES"); + + INS8250(config, m_uart, 1.8432_MHz_XTAL); + m_uart->out_tx_callback().set(FUNC(swtpc8212_device::write_txd)); + m_uart->out_dtr_callback().set(FUNC(swtpc8212_device::write_dtr)); + m_uart->out_rts_callback().set(FUNC(swtpc8212_device::write_rts)); + m_uart->out_int_callback().set("mainirq", FUNC(input_merger_device::in_w<2>)); + + screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER)); + screen.set_raw(17.0748_MHz_XTAL, 918, 0, 738, 310, 0, 280); + screen.set_screen_update("crtc", FUNC(mc6845_device::screen_update)); + + MC6845(config, m_crtc, 17.0748_MHz_XTAL / 9); + m_crtc->set_char_width(9); + m_crtc->set_screen("screen"); + m_crtc->set_show_border_area(false); + m_crtc->set_update_row_callback(FUNC(swtpc8212_device::update_row)); + + generic_keyboard_device &keyboard(GENERIC_KEYBOARD(config, "keyboard", 0)); + keyboard.set_keyboard_callback(FUNC(swtpc8212_device::keyboard_put)); + + SPEAKER(config, "bell").front_center(); + BEEP(config, m_beeper, 2000); + m_beeper->add_route(ALL_OUTPUTS, "bell", 0.25); + + PRINTER(config, m_printer, 0); +} + +ioport_constructor swtpc8212_device::device_input_ports() const +{ + return INPUT_PORTS_NAME(swtpc8212); +} + +const tiny_rom_entry *swtpc8212_device::device_rom_region() const +{ + return ROM_NAME(swtpc8212); +} + +DEFINE_DEVICE_TYPE(SWTPC8212, swtpc8212_device, "swtpc8212_device", "SWTPC8212") |