// license:BSD-3-Clause // copyright-holders:AJR /******************************************************************************* Skeleton driver for Wyse WY-100 video terminal. The WY-100 was Wyse Technology's first product. Of the two 8276 CRTCs, one is used solely to keep track of which characters are protected, which is the only transparent attribute supported. Known emulation bugs: - Frequent screen glitches when writing to the display - No dimming of protected characters *******************************************************************************/ #include "emu.h" #include "bus/rs232/rs232.h" #include "cpu/mcs48/mcs48.h" #include "machine/bankdev.h" #include "machine/input_merger.h" #include "machine/scn_pci.h" #include "machine/wy50kb.h" #include "sound/spkrdev.h" #include "video/i8275.h" #include "screen.h" #include "speaker.h" class wy100_state : public driver_device { public: wy100_state(const machine_config &mconfig, device_type type, const char *tag) : driver_device(mconfig, type, tag) , m_maincpu(*this, "maincpu") , m_rambank(*this, "rambank") , m_crtc(*this, "crtc%u", 1U) , m_pci(*this, "pci") , m_modem(*this, "modem") , m_printer(*this, "aux") , m_chargen(*this, "chargen") { } void wy100(machine_config &config); protected: virtual void machine_start() override; private: I8275_DRAW_CHARACTER_MEMBER(draw_character); DECLARE_WRITE_LINE_MEMBER(brdy_w); DECLARE_WRITE_LINE_MEMBER(txd_w); void p2_w(u8 data); u8 memory_r(offs_t offset); void memory_w(offs_t offset, u8 data); void prg_map(address_map &map); void io_map(address_map &map); void bank_map(address_map &map); required_device m_maincpu; required_device m_rambank; required_device_array m_crtc; required_device m_pci; required_device m_modem; required_device m_printer; required_region_ptr m_chargen; bool m_brdy = false; bool m_bs_enable = false; bool m_txd = true; bool m_printer_select = false; }; void wy100_state::machine_start() { m_brdy = false; m_bs_enable = false; m_txd = true; m_printer_select = false; save_item(NAME(m_brdy)); save_item(NAME(m_bs_enable)); save_item(NAME(m_txd)); save_item(NAME(m_printer_select)); } WRITE_LINE_MEMBER(wy100_state::brdy_w) { m_brdy = state; } I8275_DRAW_CHARACTER_MEMBER(wy100_state::draw_character) { // LTEN attribute output is not used (GPA1 generates underline instead) u8 dots = 0; if (!vsp) { if (BIT(gpa, 1) && (linecount & 0xb) == 0xa) dots = 0xff; else if (!BIT(gpa, 0)) dots = m_chargen[(charcode << 4) | linecount]; } if (rvv) dots ^= 0xff; // TODO: dim protected characters const rgb_t fg = rgb_t::white(); const rgb_t bg = rgb_t::black(); for (int i = 0; i < 10; i++) bitmap.pix(y, x + i) = BIT(dots, i < 1 || i > 8 ? 7 : 8 - i) ? fg : bg; } WRITE_LINE_MEMBER(wy100_state::txd_w) { m_txd = state; if (m_printer_select) m_printer->write_txd(state); else m_modem->write_txd(state); } void wy100_state::p2_w(u8 data) { m_rambank->set_bank(data & 0x1f); if (!BIT(data, 6)) m_bs_enable = false; if (BIT(data, 7) && !m_printer_select) { m_printer_select = true; m_printer->write_txd(m_txd); m_modem->write_txd(1); } else if (!BIT(data, 7) && m_printer_select) { m_printer_select = false; m_modem->write_txd(m_txd); m_printer->write_txd(1); } } u8 wy100_state::memory_r(offs_t offset) { u8 p2 = m_maincpu->p2_r(); u8 data = BIT(p2, 5) ? m_pci->read(p2 & 3) : m_rambank->read8(offset); if (m_bs_enable && !machine().side_effects_disabled()) { u8 chardata = (data & 0xe0) == 0x80 ? data : data & 0x7f; m_crtc[0]->dack_w(chardata); m_crtc[1]->dack_w((chardata & 0xfe) | (BIT(data, 7) ? 0x00 : 0x01)); } return data; } void wy100_state::memory_w(offs_t offset, u8 data) { u8 p2 = m_maincpu->p2_r(); // CRTC access is write-only if (!BIT(p2, 6)) { m_crtc[0]->write(p2 & 1, data); m_crtc[1]->write(p2 & 1, data); } else if (m_brdy) m_bs_enable = true; if (BIT(p2, 5)) m_pci->write(p2 & 3, data); m_rambank->write8(offset, data); } void wy100_state::prg_map(address_map &map) { map(0x000, 0xfff).rom().region("maincpu", 0); } void wy100_state::io_map(address_map &map) { map(0x00, 0xff).rw(FUNC(wy100_state::memory_r), FUNC(wy100_state::memory_w)); } void wy100_state::bank_map(address_map &map) { map(0x0000, 0x0bff).nopw(); map(0x0c00, 0x0fff).ram(); // buffer RAM (P2114A-6 at 4-5A) map(0x1000, 0x1fff).ram(); // display RAM (P2114A-6 at 6-9A, optionally also at 10-13A) } static INPUT_PORTS_START(wy100) INPUT_PORTS_END void wy100_state::wy100(machine_config &config) { I8039(config, m_maincpu, 10.1376_MHz_XTAL); // INS8039N-11 m_maincpu->set_addrmap(AS_PROGRAM, &wy100_state::prg_map); m_maincpu->set_addrmap(AS_IO, &wy100_state::io_map); m_maincpu->p1_out_cb().set("keyboard", FUNC(wy100_keyboard_device::scan_w)).mask(0x7f).invert(); m_maincpu->p1_out_cb().append("spkrgate", FUNC(input_merger_device::in_w<0>)).bit(7); m_maincpu->p2_out_cb().set(FUNC(wy100_state::p2_w)); m_maincpu->t0_in_cb().set("keyboard", FUNC(wy100_keyboard_device::sense_r)).invert(); m_maincpu->t1_in_cb().set(m_pci, FUNC(scn2651_device::rxrdy_r)); WY100_KEYBOARD(config, "keyboard"); ADDRESS_MAP_BANK(config, m_rambank); m_rambank->set_addrmap(0, &wy100_state::bank_map); m_rambank->set_data_width(8); m_rambank->set_addr_width(13); m_rambank->set_stride(0x100); SCN2651(config, m_pci, 10.1376_MHz_XTAL / 2); // INS2651N m_pci->rts_handler().set(m_modem, FUNC(rs232_port_device::write_rts)); m_pci->dtr_handler().set(m_modem, FUNC(rs232_port_device::write_dtr)); m_pci->txd_handler().set(FUNC(wy100_state::txd_w)); screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER)); screen.set_raw(18.48_MHz_XTAL, 1000, 0, 800, 308, 0, 286); //screen.set_raw(18.48_MHz_XTAL, 1100, 0, 800, 336, 0, 312); screen.set_color(rgb_t::green()); screen.set_screen_update("crtc1", FUNC(i8276_device::screen_update)); for (auto &crtc : m_crtc) { I8276(config, crtc, 18.48_MHz_XTAL / 10); crtc->set_screen("screen"); crtc->set_character_width(10); } m_crtc[0]->set_display_callback(FUNC(wy100_state::draw_character)); m_crtc[0]->drq_wr_callback().set_inputline(m_maincpu, MCS48_INPUT_IRQ); m_crtc[0]->drq_wr_callback().append(FUNC(wy100_state::brdy_w)); m_crtc[0]->lc_wr_callback().set("spkrgate", FUNC(input_merger_device::in_w<1>)).bit(3); SPEAKER(config, "mono").front_center(); SPEAKER_SOUND(config, "speaker").add_route(ALL_OUTPUTS, "mono", 0.5); input_merger_device &spkrgate(INPUT_MERGER_ALL_HIGH(config, "spkrgate")); spkrgate.output_handler().set("speaker", FUNC(speaker_sound_device::level_w)); RS232_PORT(config, m_modem, default_rs232_devices, "loopback"); m_modem->dcd_handler().set(m_pci, FUNC(scn2651_device::dcd_w)); m_modem->cts_handler().set(m_pci, FUNC(scn2651_device::cts_w)); m_modem->rxd_handler().set(m_pci, FUNC(scn2651_device::rxd_w)); RS232_PORT(config, m_printer, default_rs232_devices, nullptr); m_printer->dsr_handler().set(m_pci, FUNC(scn2651_device::dsr_w)); } ROM_START(wy100) ROM_REGION(0x1000, "maincpu", 0) ROM_LOAD("wy100_00401f.bin", 0x0000, 0x1000, CRC(1f71de8f) SHA1(2bd9f712aba8b44823ce0b3e111da7b472a1ab38)) ROM_REGION(0x0800, "chargen", 0) ROM_LOAD("wy100_23-002-01c.bin", 0x0000, 0x0800, CRC(93c31537) SHA1(085e5ad110a76bee83e819a718a7d4cbfb8e07e7)) ROM_END COMP(1981, wy100, 0, 0, wy100, wy100, wy100_state, empty_init, "Wyse Technology", "WY-100", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_GRAPHICS)