1 // license:BSD-3-Clause
2 // copyright-holders:Carl
3
4 #include "emu.h"
5 #include "pcd.h"
6
7 #include "cpu/mcs48/mcs48.h"
8 #include "cpu/mcs51/mcs51.h"
9 #include "screen.h"
10
11
12 DEFINE_DEVICE_TYPE(PCD_VIDEO, pcd_video_device, "pcd_video", "Siemens PC-D Video")
13 DEFINE_DEVICE_TYPE(PCX_VIDEO, pcx_video_device, "pcx_video", "Siemens PC-X Video")
14
pcdx_video_device(const machine_config & mconfig,device_type type,const char * tag,device_t * owner,uint32_t clock)15 pcdx_video_device::pcdx_video_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) :
16 device_t(mconfig, type, tag, owner, clock),
17 device_gfx_interface(mconfig, *this, nullptr, "palette"),
18 m_maincpu(*this, ":maincpu"),
19 m_mcu(*this, "graphics"),
20 m_pic2(*this, ":pic2")
21 {
22 }
23
pcd_video_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)24 pcd_video_device::pcd_video_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
25 pcdx_video_device(mconfig, PCD_VIDEO, tag, owner, clock),
26 m_crtc(*this, "crtc"),
27 m_mouse_btn(*this, "MOUSE"),
28 m_mouse_x(*this, "MOUSEX"),
29 m_mouse_y(*this, "MOUSEY"),
30 m_vram(32*1024),
31 m_charram(8*1024)
32 {
33 }
34
pcx_video_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)35 pcx_video_device::pcx_video_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
36 pcdx_video_device(mconfig, PCX_VIDEO, tag, owner, clock),
37 device_serial_interface(mconfig, *this),
38 m_crtc(*this, "crtc"),
39 m_charrom(*this, "char"),
40 m_txd_handler(*this)
41 {
42 }
43
44 ROM_START( pcd_video )
45 ROM_REGION(0x400, "graphics", 0)
46 ROM_LOAD("s36361-d321-v1.bin", 0x000, 0x400, CRC(69baeb2a) SHA1(98b9cd0f38c51b4988a3aed0efcf004bedd115ff))
47 ROM_END
48
device_rom_region() const49 const tiny_rom_entry *pcd_video_device::device_rom_region() const
50 {
51 return ROM_NAME( pcd_video );
52 }
53
54 ROM_START( pcx_video )
55 ROM_REGION(0x2000, "char", 0)
CRC(e4933c16)56 ROM_LOAD("d12-graka.bin", 0x0000, 0x2000, CRC(e4933c16) SHA1(932ae1f0cd2b029b7f5fc3d2d1679e70b25c0828))
57
58 ROM_REGION(0x6000, "graphics", 0)
59 ROM_LOAD("d40-graka.bin", 0x0000, 0x2000, CRC(dce48252) SHA1(0d9a575b2d001168a36864d7bd5db1c3aca5fb8d))
60 ROM_LOAD("d39-graka.bin", 0x4000, 0x2000, CRC(02920e25) SHA1(145a6648d75c1dc4788f9bc7790281ef7e8f8426))
61 ROM_END
62
63 const tiny_rom_entry *pcx_video_device::device_rom_region() const
64 {
65 return ROM_NAME( pcx_video );
66 }
67
68 static const gfx_layout pcd_charlayout =
69 {
70 8, 14, /* 8 x 14 characters */
71 512, /* 512 characters */
72 1, /* 1 bits per pixel */
73 { 0 }, /* no bitplanes */
74 /* x offsets */
75 { 0, 1, 2, 3, 4, 5, 6, 7 },
76 /* y offsets */
77 { 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8, 8*8, 9*8, 10*8, 11*8, 12*8, 13*8, 14*8 },
78 8*16
79 };
80
81 static GFXDECODE_START( gfx_pcx )
82 GFXDECODE_DEVICE( "char", 0x0000, pcd_charlayout, 0, 1 )
83 GFXDECODE_END
84
INPUT_PORTS_START(pcd_mouse)85 static INPUT_PORTS_START( pcd_mouse )
86 PORT_START("MOUSE")
87 PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_BUTTON1) PORT_NAME("Right Mouse Button") PORT_CODE(MOUSECODE_BUTTON1)
88 PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_BUTTON2) PORT_NAME("Left Mouse Button") PORT_CODE(MOUSECODE_BUTTON2)
89
90 PORT_START("MOUSEX")
91 PORT_BIT( 0xfff, 0x000, IPT_MOUSE_X ) PORT_SENSITIVITY(50) PORT_KEYDELTA(0)
92
93 PORT_START("MOUSEY")
94 PORT_BIT( 0xfff, 0x000, IPT_MOUSE_Y ) PORT_SENSITIVITY(50) PORT_KEYDELTA(0)
95 INPUT_PORTS_END
96
97 ioport_constructor pcd_video_device::device_input_ports() const
98 {
99 return INPUT_PORTS_NAME(pcd_mouse);
100 }
101
device_add_mconfig(machine_config & config)102 void pcd_video_device::device_add_mconfig(machine_config &config)
103 {
104 i8741a_device &mcu(I8741A(config, "graphics", 16_MHz_XTAL / 2)); // NEC D8741AD
105 mcu.p1_in_cb().set(FUNC(pcd_video_device::p1_r));
106 mcu.p2_out_cb().set(FUNC(pcd_video_device::p2_w));
107 mcu.t1_in_cb().set(FUNC(pcd_video_device::t1_r));
108
109 // video hardware
110 screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER));
111 screen.set_raw(16_MHz_XTAL, 832, 0, 640, 381, 0, 350);
112 screen.set_screen_update("crtc", FUNC(scn2674_device::screen_update));
113
114 PALETTE(config, "palette", FUNC(pcd_video_device::pcdx_palette), 3);
115
116 SCN2674(config, m_crtc, 16_MHz_XTAL / 16);
117 m_crtc->set_character_width(16);
118 m_crtc->set_display_callback(FUNC(pcd_video_device::display_pixels));
119 m_crtc->set_screen("screen");
120
121 TIMER(config, "mouse_timer").configure_periodic(FUNC(pcd_video_device::mouse_timer), attotime::from_hz(15000)); // guess
122 }
123
pcx_vid_map(address_map & map)124 void pcx_video_device::pcx_vid_map(address_map &map)
125 {
126 map(0x0000, 0x5fff).rom().region("graphics", 0);
127 }
128
pcx_vid_io(address_map & map)129 void pcx_video_device::pcx_vid_io(address_map &map)
130 {
131 map(0x8000, 0x8007).rw(m_crtc, FUNC(scn2672_device::read), FUNC(scn2672_device::write));
132 map(0x8008, 0x8008).r(FUNC(pcx_video_device::unk_r));
133 map(0xa000, 0xa000).rw(m_crtc, FUNC(scn2672_device::buffer_r), FUNC(scn2672_device::buffer_w));
134 map(0xa001, 0xa001).rw(m_crtc, FUNC(scn2672_device::attr_buffer_r), FUNC(scn2672_device::attr_buffer_w));
135 map(0xa002, 0xa003).rw(FUNC(pcx_video_device::term_mcu_r), FUNC(pcx_video_device::term_mcu_w));
136 map(0xc000, 0xc7ff).ram();
137 }
138
pcx_char_ram(address_map & map)139 void pcx_video_device::pcx_char_ram(address_map &map)
140 {
141 map(0x0000, 0x07ff).ram();
142 }
143
pcx_attr_ram(address_map & map)144 void pcx_video_device::pcx_attr_ram(address_map &map)
145 {
146 map(0x0000, 0x07ff).ram();
147 }
148
device_add_mconfig(machine_config & config)149 void pcx_video_device::device_add_mconfig(machine_config &config)
150 {
151 i8031_device &gfx(I8031(config, "graphics", 24_MHz_XTAL / 2));
152 gfx.set_addrmap(AS_PROGRAM, &pcx_video_device::pcx_vid_map);
153 gfx.set_addrmap(AS_IO, &pcx_video_device::pcx_vid_io);
154 gfx.port_out_cb<1>().set(FUNC(pcx_video_device::p1_w));
155 gfx.serial_tx_cb().set(FUNC(pcx_video_device::tx_callback));
156 gfx.serial_rx_cb().set(FUNC(pcx_video_device::rx_callback));
157
158 // video hardware
159 screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER));
160 screen.set_raw(24_MHz_XTAL, 1272, 0, 960, 381, 0, 350);
161 screen.set_screen_update("crtc", FUNC(scn2672_device::screen_update));
162
163 PALETTE(config, "palette", palette_device::MONOCHROME);
164
165 SCN2672(config, m_crtc, 24_MHz_XTAL / 12); // used with SCB2673B
166 m_crtc->intr_callback().set_inputline("graphics", MCS51_INT0_LINE);
167 m_crtc->set_character_width(8);
168 m_crtc->set_display_callback(FUNC(pcx_video_device::display_pixels));
169 m_crtc->set_screen("screen");
170 m_crtc->set_addrmap(0, &pcx_video_device::pcx_char_ram);
171 m_crtc->set_addrmap(1, &pcx_video_device::pcx_attr_ram);
172 }
173
174
SCN2674_DRAW_CHARACTER_MEMBER(pcd_video_device::display_pixels)175 SCN2674_DRAW_CHARACTER_MEMBER(pcd_video_device::display_pixels)
176 {
177 address <<= 1;
178 if(lg)
179 {
180 uint16_t data = m_vram[address + 1] | (m_vram[address] << 8);
181 if(m_p2 & 8)
182 data = ~data;
183 for(int i = 0; i < 16; i++)
184 {
185 bitmap.pix(y, x++) = palette().pen(BIT(data, 15) ? 1 : 0);
186 data <<= 1;
187 }
188 }
189 else
190 {
191 uint8_t data, attr;
192 int bgnd = 0, fgnd = 1;
193 data = m_charram[m_vram[address] * 16 + linecount];
194 attr = m_vram[address + 1];
195 if(cursor)
196 data = 0xff;
197 if(ul && (attr & 0x20))
198 data = 0xff;
199
200 if(attr & 0x10)
201 data = ~data;
202 if(m_p2 & 8)
203 {
204 fgnd = 0;
205 bgnd = (attr & 8) ? 2 : 1;
206 }
207 else if(attr & 8)
208 bgnd = 2;
209 for(int i = 0; i < 8; i++)
210 {
211 rgb_t pix = palette().pen(BIT(data, 7) ? fgnd : bgnd);
212 bitmap.pix(y, x++) = pix;
213 bitmap.pix(y, x++) = pix;
214 data <<= 1;
215 }
216 }
217 }
218
SCN2672_DRAW_CHARACTER_MEMBER(pcx_video_device::display_pixels)219 SCN2672_DRAW_CHARACTER_MEMBER(pcx_video_device::display_pixels)
220 {
221 uint16_t data = m_charrom[charcode * 16 + linecount + (attrcode & 0x20 ? 4096 : 0)];
222
223 if (cursor)
224 data = 0xff;
225
226 if (BIT(m_p1, 5))
227 data ^= 0xff;
228
229 for (int i = 0; i < 8; i++)
230 {
231 rgb_t pix = palette().pen(BIT(data, 7) ? 1 : 0);
232 bitmap.pix(y, x++) = pix;
233 data <<= 1;
234 }
235 }
236
pcdx_palette(palette_device & palette) const237 void pcdx_video_device::pcdx_palette(palette_device &palette) const
238 {
239 palette.set_pen_color(0, rgb_t::black());
240 palette.set_pen_color(1, rgb_t::white());
241 palette.set_pen_color(2, rgb_t(128, 128, 128));
242 }
243
TIMER_DEVICE_CALLBACK_MEMBER(pcd_video_device::mouse_timer)244 TIMER_DEVICE_CALLBACK_MEMBER(pcd_video_device::mouse_timer)
245 {
246 m_t1 = (m_t1 == CLEAR_LINE) ? ASSERT_LINE : CLEAR_LINE;
247 if(m_t1)
248 {
249 switch(m_mouse.phase)
250 {
251 case 0:
252 m_mouse.xa = m_mouse.x > m_mouse.prev_x ? CLEAR_LINE : ASSERT_LINE;
253 m_mouse.xb = m_mouse.x < m_mouse.prev_x ? CLEAR_LINE : ASSERT_LINE;
254 m_mouse.ya = m_mouse.y > m_mouse.prev_y ? CLEAR_LINE : ASSERT_LINE;
255 m_mouse.yb = m_mouse.y < m_mouse.prev_y ? CLEAR_LINE : ASSERT_LINE;
256 break;
257 case 1:
258 m_mouse.xa = m_mouse.xb = m_mouse.x != m_mouse.prev_x ? CLEAR_LINE : ASSERT_LINE;
259 m_mouse.ya = m_mouse.yb = m_mouse.y != m_mouse.prev_y ? CLEAR_LINE : ASSERT_LINE;
260 break;
261 case 2:
262 m_mouse.xa = m_mouse.x < m_mouse.prev_x ? CLEAR_LINE : ASSERT_LINE;
263 m_mouse.xb = m_mouse.x > m_mouse.prev_x ? CLEAR_LINE : ASSERT_LINE;
264 m_mouse.ya = m_mouse.y < m_mouse.prev_y ? CLEAR_LINE : ASSERT_LINE;
265 m_mouse.yb = m_mouse.y > m_mouse.prev_y ? CLEAR_LINE : ASSERT_LINE;
266 break;
267 case 3:
268 m_mouse.xa = m_mouse.xb = ASSERT_LINE;
269 m_mouse.ya = m_mouse.yb = ASSERT_LINE;
270 m_mouse.prev_x = m_mouse.x;
271 m_mouse.prev_y = m_mouse.y;
272 m_mouse.x = m_mouse_x->read();
273 m_mouse.y = m_mouse_y->read();
274 break;
275 }
276
277 m_mouse.phase = (m_mouse.phase + 1) & 3;
278 }
279 }
280
vram_w(offs_t offset,uint8_t data)281 void pcd_video_device::vram_w(offs_t offset, uint8_t data)
282 {
283 if(m_vram_sw)
284 m_vram[offset] = data;
285 else if(!(offset & 1))
286 {
287 offset >>= 1;
288 m_charram[offset & 0x1fff] = data;
289 gfx(0)->mark_dirty(offset/16);
290 }
291 }
292
vram_r(offs_t offset)293 uint8_t pcd_video_device::vram_r(offs_t offset)
294 {
295 return m_vram[offset];
296 }
297
vram_sw_w(uint8_t data)298 void pcd_video_device::vram_sw_w(uint8_t data)
299 {
300 m_vram_sw = data & 1;
301 }
302
t1_r()303 uint8_t pcd_video_device::t1_r()
304 {
305 return m_t1;
306 }
307
p1_r()308 uint8_t pcd_video_device::p1_r()
309 {
310 uint8_t data = (m_mouse_btn->read() & 0x30) | 0x80; // char ram/rom jumper?
311 data |= (m_mouse.xa != CLEAR_LINE ? 0 : 1);
312 data |= (m_mouse.xb != CLEAR_LINE ? 0 : 2);
313 data |= (m_mouse.ya != CLEAR_LINE ? 0 : 4);
314 data |= (m_mouse.yb != CLEAR_LINE ? 0 : 8);
315
316 return data;
317 }
318
p2_w(uint8_t data)319 void pcd_video_device::p2_w(uint8_t data)
320 {
321 m_p2 = data;
322 m_pic2->ir7_w((data & 0x80) ? CLEAR_LINE : ASSERT_LINE);
323 }
324
term_r(offs_t offset)325 uint8_t pcx_video_device::term_r(offs_t offset)
326 {
327 switch(offset)
328 {
329 case 0:
330 m_pic2->ir0_w(CLEAR_LINE);
331 m_term_stat &= ~2;
332 return m_term_key;
333 case 1:
334 m_pic2->ir0_w(CLEAR_LINE);
335 return m_term_stat >> 1;
336 }
337 return 0xff;
338 }
339
term_w(offs_t offset,uint8_t data)340 void pcx_video_device::term_w(offs_t offset, uint8_t data)
341 {
342 if(!offset)
343 {
344 m_mcu->set_input_line(MCS51_INT1_LINE, ASSERT_LINE);
345 m_term_char = data;
346 m_term_stat |= 4;
347 }
348 }
349
term_mcu_r(offs_t offset)350 uint8_t pcx_video_device::term_mcu_r(offs_t offset)
351 {
352 switch(offset)
353 {
354 case 0:
355 m_mcu->set_input_line(MCS51_INT1_LINE, CLEAR_LINE);
356 m_pic2->ir0_w(ASSERT_LINE);
357 m_term_stat &= ~4;
358 return m_term_char;
359 case 1:
360 return m_term_stat;
361 }
362 return 0;
363 }
364
term_mcu_w(offs_t offset,uint8_t data)365 void pcx_video_device::term_mcu_w(offs_t offset, uint8_t data)
366 {
367 if(!offset)
368 {
369 m_term_key = data;
370 m_pic2->ir0_w(ASSERT_LINE);
371 m_term_stat |= 2;
372 }
373 }
374
detect_r()375 uint8_t pcdx_video_device::detect_r()
376 {
377 return 0;
378 }
379
detect_w(uint8_t data)380 void pcdx_video_device::detect_w(uint8_t data)
381 {
382 }
383
unk_r()384 uint8_t pcx_video_device::unk_r()
385 {
386 return 0x80;
387 }
388
p1_w(uint8_t data)389 void pcx_video_device::p1_w(uint8_t data)
390 {
391 m_p1 = data;
392 }
393
device_start()394 void pcd_video_device::device_start()
395 {
396 m_maincpu->space(AS_IO).install_readwrite_handler(0xfb00, 0xfb01, read8smo_delegate(*this, FUNC(pcdx_video_device::detect_r)), write8smo_delegate(*this, FUNC(pcdx_video_device::detect_w)), 0xff00);
397 m_maincpu->space(AS_PROGRAM).install_readwrite_handler(0xf0000, 0xf7fff, read8sm_delegate(*this, FUNC(pcd_video_device::vram_r)), write8sm_delegate(*this, FUNC(pcd_video_device::vram_w)), 0xffff);
398 set_gfx(0, std::make_unique<gfx_element>(&palette(), pcd_charlayout, &m_charram[0], 0, 1, 0));
399 }
400
device_reset()401 void pcd_video_device::device_reset()
402 {
403 m_mouse.phase = 0;
404 m_mouse.xa = m_mouse.xb = ASSERT_LINE;
405 m_mouse.ya = m_mouse.yb = ASSERT_LINE;
406 m_mouse.x = m_mouse.y = 0;
407 m_mouse.prev_x = m_mouse.prev_y = 0;
408 m_vram_sw = 1;
409 m_t1 = CLEAR_LINE;
410 }
411
map(address_map & map)412 void pcd_video_device::map(address_map &map)
413 {
414 map(0x00, 0x0f).w(m_crtc, FUNC(scn2674_device::write)).umask16(0x00ff);
415 map(0x00, 0x0f).r(m_crtc, FUNC(scn2674_device::read)).umask16(0xff00);
416 map(0x20, 0x20).w(FUNC(pcd_video_device::vram_sw_w));
417 map(0x30, 0x33).rw("graphics", FUNC(i8741a_device::upi41_master_r), FUNC(i8741a_device::upi41_master_w)).umask16(0x00ff);
418 }
419
device_start()420 void pcx_video_device::device_start()
421 {
422 m_maincpu->space(AS_IO).install_readwrite_handler(0xfb00, 0xfb01, read8smo_delegate(*this, FUNC(pcdx_video_device::detect_r)), write8smo_delegate(*this, FUNC(pcdx_video_device::detect_w)), 0x00ff);
423 m_txd_handler.resolve_safe();
424
425 set_data_frame(1, 8, PARITY_NONE, STOP_BITS_1);
426 set_rate(600);
427
428 decode_gfx(gfx_pcx);
429 }
430
device_reset()431 void pcx_video_device::device_reset()
432 {
433 m_term_key = 0;
434 m_term_stat = 0;
435 transmit_register_reset();
436 receive_register_reset();
437
438 m_txd_handler(1);
439 }
440
map(address_map & map)441 void pcx_video_device::map(address_map &map)
442 {
443 map(0x0, 0xf).rw(FUNC(pcx_video_device::term_r), FUNC(pcx_video_device::term_w));
444 }
445
rx_callback()446 uint8_t pcx_video_device::rx_callback()
447 {
448 return get_received_char();
449 }
450
tx_callback(uint8_t data)451 void pcx_video_device::tx_callback(uint8_t data)
452 {
453 transmit_register_setup(data);
454 }
455
tra_callback()456 void pcx_video_device::tra_callback()
457 {
458 m_txd_handler(transmit_register_get_data_bit());
459 }
460
rcv_complete()461 void pcx_video_device::rcv_complete()
462 {
463 receive_register_extract();
464 m_mcu->set_input_line(MCS51_RX_LINE, ASSERT_LINE);
465 m_mcu->set_input_line(MCS51_RX_LINE, CLEAR_LINE);
466 }
467