1 // license:BSD-3-Clause
2 // copyright-holders:AJR
3 /*******************************************************************************
4
5 Skeleton driver for Wyse WY-100 video terminal.
6
7 The WY-100 was Wyse Technology's first product.
8
9 Of the two 8276 CRTCs, one is used solely to keep track of which characters
10 are protected, which is the only transparent attribute supported.
11
12 Known emulation bugs:
13 - Frequent screen glitches when writing to the display
14 - No dimming of protected characters
15
16 *******************************************************************************/
17
18 #include "emu.h"
19 #include "bus/rs232/rs232.h"
20 #include "cpu/mcs48/mcs48.h"
21 #include "machine/bankdev.h"
22 #include "machine/input_merger.h"
23 #include "machine/scn_pci.h"
24 #include "machine/wy50kb.h"
25 #include "sound/spkrdev.h"
26 #include "video/i8275.h"
27 #include "screen.h"
28 #include "speaker.h"
29
30 class wy100_state : public driver_device
31 {
32 public:
wy100_state(const machine_config & mconfig,device_type type,const char * tag)33 wy100_state(const machine_config &mconfig, device_type type, const char *tag)
34 : driver_device(mconfig, type, tag)
35 , m_maincpu(*this, "maincpu")
36 , m_rambank(*this, "rambank")
37 , m_crtc(*this, "crtc%u", 1U)
38 , m_pci(*this, "pci")
39 , m_modem(*this, "modem")
40 , m_printer(*this, "aux")
41 , m_chargen(*this, "chargen")
42 {
43 }
44
45 void wy100(machine_config &config);
46
47 protected:
48 virtual void machine_start() override;
49
50 private:
51 I8275_DRAW_CHARACTER_MEMBER(draw_character);
52
53 DECLARE_WRITE_LINE_MEMBER(brdy_w);
54 DECLARE_WRITE_LINE_MEMBER(txd_w);
55 void p2_w(u8 data);
56 u8 memory_r(offs_t offset);
57 void memory_w(offs_t offset, u8 data);
58
59 void prg_map(address_map &map);
60 void io_map(address_map &map);
61 void bank_map(address_map &map);
62
63 required_device<mcs48_cpu_device> m_maincpu;
64 required_device<address_map_bank_device> m_rambank;
65 required_device_array<i8276_device, 2> m_crtc;
66 required_device<scn2651_device> m_pci;
67 required_device<rs232_port_device> m_modem;
68 required_device<rs232_port_device> m_printer;
69
70 required_region_ptr<u8> m_chargen;
71
72 bool m_brdy;
73 bool m_bs_enable;
74 bool m_txd;
75 bool m_printer_select;
76 };
77
machine_start()78 void wy100_state::machine_start()
79 {
80 m_brdy = false;
81 m_bs_enable = false;
82 m_txd = true;
83 m_printer_select = false;
84
85 save_item(NAME(m_brdy));
86 save_item(NAME(m_bs_enable));
87 save_item(NAME(m_txd));
88 save_item(NAME(m_printer_select));
89 }
90
WRITE_LINE_MEMBER(wy100_state::brdy_w)91 WRITE_LINE_MEMBER(wy100_state::brdy_w)
92 {
93 m_brdy = state;
94 }
95
I8275_DRAW_CHARACTER_MEMBER(wy100_state::draw_character)96 I8275_DRAW_CHARACTER_MEMBER(wy100_state::draw_character)
97 {
98 // LTEN attribute output is not used (GPA1 generates underline instead)
99 u8 dots = 0;
100 if (!vsp)
101 {
102 if (BIT(gpa, 1) && (linecount & 0xb) == 0xa)
103 dots = 0xff;
104 else if (!BIT(gpa, 0))
105 dots = m_chargen[(charcode << 4) | linecount];
106 }
107 if (rvv)
108 dots ^= 0xff;
109
110 // TODO: dim protected characters
111 const rgb_t fg = rgb_t::white();
112 const rgb_t bg = rgb_t::black();
113 for (int i = 0; i < 10; i++)
114 bitmap.pix(y, x + i) = BIT(dots, i < 1 || i > 8 ? 7 : 8 - i) ? fg : bg;
115 }
116
WRITE_LINE_MEMBER(wy100_state::txd_w)117 WRITE_LINE_MEMBER(wy100_state::txd_w)
118 {
119 m_txd = state;
120 if (m_printer_select)
121 m_printer->write_txd(state);
122 else
123 m_modem->write_txd(state);
124 }
125
p2_w(u8 data)126 void wy100_state::p2_w(u8 data)
127 {
128 m_rambank->set_bank(data & 0x1f);
129 if (!BIT(data, 6))
130 m_bs_enable = false;
131 if (BIT(data, 7) && !m_printer_select)
132 {
133 m_printer_select = true;
134 m_printer->write_txd(m_txd);
135 m_modem->write_txd(1);
136 }
137 else if (!BIT(data, 7) && m_printer_select)
138 {
139 m_printer_select = false;
140 m_modem->write_txd(m_txd);
141 m_printer->write_txd(1);
142 }
143 }
144
memory_r(offs_t offset)145 u8 wy100_state::memory_r(offs_t offset)
146 {
147 u8 p2 = m_maincpu->p2_r();
148 u8 data = BIT(p2, 5) ? m_pci->read(p2 & 3) : m_rambank->read8(offset);
149 if (m_bs_enable && !machine().side_effects_disabled())
150 {
151 u8 chardata = (data & 0xe0) == 0x80 ? data : data & 0x7f;
152 m_crtc[0]->dack_w(chardata);
153 m_crtc[1]->dack_w((chardata & 0xfe) | (BIT(data, 7) ? 0x00 : 0x01));
154 }
155 return data;
156 }
157
memory_w(offs_t offset,u8 data)158 void wy100_state::memory_w(offs_t offset, u8 data)
159 {
160 u8 p2 = m_maincpu->p2_r();
161
162 // CRTC access is write-only
163 if (!BIT(p2, 6))
164 {
165 m_crtc[0]->write(p2 & 1, data);
166 m_crtc[1]->write(p2 & 1, data);
167 }
168 else if (m_brdy)
169 m_bs_enable = true;
170
171 if (BIT(p2, 5))
172 m_pci->write(p2 & 3, data);
173
174 m_rambank->write8(offset, data);
175 }
176
prg_map(address_map & map)177 void wy100_state::prg_map(address_map &map)
178 {
179 map(0x000, 0xfff).rom().region("maincpu", 0);
180 }
181
io_map(address_map & map)182 void wy100_state::io_map(address_map &map)
183 {
184 map(0x00, 0xff).rw(FUNC(wy100_state::memory_r), FUNC(wy100_state::memory_w));
185 }
186
bank_map(address_map & map)187 void wy100_state::bank_map(address_map &map)
188 {
189 map(0x0000, 0x0bff).nopw();
190 map(0x0c00, 0x0fff).ram(); // buffer RAM (P2114A-6 at 4-5A)
191 map(0x1000, 0x1fff).ram(); // display RAM (P2114A-6 at 6-9A, optionally also at 10-13A)
192 }
193
194
INPUT_PORTS_START(wy100)195 static INPUT_PORTS_START(wy100)
196 INPUT_PORTS_END
197
198
199 void wy100_state::wy100(machine_config &config)
200 {
201 I8039(config, m_maincpu, 10.1376_MHz_XTAL); // INS8039N-11
202 m_maincpu->set_addrmap(AS_PROGRAM, &wy100_state::prg_map);
203 m_maincpu->set_addrmap(AS_IO, &wy100_state::io_map);
204 m_maincpu->p1_out_cb().set("keyboard", FUNC(wy100_keyboard_device::scan_w)).mask(0x7f).invert();
205 m_maincpu->p1_out_cb().append("spkrgate", FUNC(input_merger_device::in_w<0>)).bit(7);
206 m_maincpu->p2_out_cb().set(FUNC(wy100_state::p2_w));
207 m_maincpu->t0_in_cb().set("keyboard", FUNC(wy100_keyboard_device::sense_r)).invert();
208 m_maincpu->t1_in_cb().set(m_pci, FUNC(scn2651_device::rxrdy_r));
209
210 WY100_KEYBOARD(config, "keyboard");
211
212 ADDRESS_MAP_BANK(config, m_rambank);
213 m_rambank->set_addrmap(0, &wy100_state::bank_map);
214 m_rambank->set_data_width(8);
215 m_rambank->set_addr_width(13);
216 m_rambank->set_stride(0x100);
217
218 SCN2651(config, m_pci, 10.1376_MHz_XTAL / 2); // INS2651N
219 m_pci->rts_handler().set(m_modem, FUNC(rs232_port_device::write_rts));
220 m_pci->dtr_handler().set(m_modem, FUNC(rs232_port_device::write_dtr));
221 m_pci->txd_handler().set(FUNC(wy100_state::txd_w));
222
223 screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER));
224 screen.set_raw(18.48_MHz_XTAL, 1000, 0, 800, 308, 0, 286);
225 //screen.set_raw(18.48_MHz_XTAL, 1100, 0, 800, 336, 0, 312);
226 screen.set_color(rgb_t::green());
227 screen.set_screen_update("crtc1", FUNC(i8276_device::screen_update));
228
229 for (auto &crtc : m_crtc)
230 {
231 I8276(config, crtc, 18.48_MHz_XTAL / 10);
232 crtc->set_screen("screen");
233 crtc->set_character_width(10);
234 }
235 m_crtc[0]->set_display_callback(FUNC(wy100_state::draw_character));
236 m_crtc[0]->drq_wr_callback().set_inputline(m_maincpu, MCS48_INPUT_IRQ);
237 m_crtc[0]->drq_wr_callback().append(FUNC(wy100_state::brdy_w));
238 m_crtc[0]->lc_wr_callback().set("spkrgate", FUNC(input_merger_device::in_w<1>)).bit(3);
239
240 SPEAKER(config, "mono").front_center();
241 SPEAKER_SOUND(config, "speaker").add_route(ALL_OUTPUTS, "mono", 0.5);
242 input_merger_device &spkrgate(INPUT_MERGER_ALL_HIGH(config, "spkrgate"));
243 spkrgate.output_handler().set("speaker", FUNC(speaker_sound_device::level_w));
244
245 RS232_PORT(config, m_modem, default_rs232_devices, "loopback");
246 m_modem->dcd_handler().set(m_pci, FUNC(scn2651_device::dcd_w));
247 m_modem->cts_handler().set(m_pci, FUNC(scn2651_device::cts_w));
248 m_modem->rxd_handler().set(m_pci, FUNC(scn2651_device::rxd_w));
249
250 RS232_PORT(config, m_printer, default_rs232_devices, nullptr);
251 m_printer->dsr_handler().set(m_pci, FUNC(scn2651_device::dsr_w));
252 }
253
254
255 ROM_START(wy100)
256 ROM_REGION(0x1000, "maincpu", 0)
257 ROM_LOAD("wy100_00401f.bin", 0x0000, 0x1000, CRC(1f71de8f) SHA1(2bd9f712aba8b44823ce0b3e111da7b472a1ab38))
258
259 ROM_REGION(0x0800, "chargen", 0)
260 ROM_LOAD("wy100_23-002-01c.bin", 0x0000, 0x0800, CRC(93c31537) SHA1(085e5ad110a76bee83e819a718a7d4cbfb8e07e7))
261 ROM_END
262
263
264 COMP(1981, wy100, 0, 0, wy100, wy100, wy100_state, empty_init, "Wyse Technology", "WY-100", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_GRAPHICS)
265