// 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.pix(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)