1 // license:BSD-3-Clause
2 // copyright-holders:Curt Coder
3 /*****************************************************************************
4 *
5 * video/abc806.c
6 *
7 ****************************************************************************/
8
9 #include "emu.h"
10 #include "includes/abc80x.h"
11 #include "screen.h"
12
13 //#define VERBOSE 1
14 #include "logmacro.h"
15
16
17 #define HORIZONTAL_PORCH_HACK 109
18 #define VERTICAL_PORCH_HACK 27
19
20
21
22 //-------------------------------------------------
23 // hrs_w - high resolution memory banking
24 //-------------------------------------------------
25
hrs_w(uint8_t data)26 void abc806_state::hrs_w(uint8_t data)
27 {
28 /*
29
30 bit signal description
31
32 0 VM15 visible screen memory area bit 0
33 1 VM16 visible screen memory area bit 1
34 2 VM17 visible screen memory area bit 2
35 3 VM18 visible screen memory area bit 3
36 4 F15 cpu accessible screen memory area bit 0
37 5 F16 cpu accessible screen memory area bit 1
38 6 F17 cpu accessible screen memory area bit 2
39 7 F18 cpu accessible screen memory area bit 3
40
41 */
42
43 LOG("%s HRS %02x\n", machine().describe_context(), data);
44
45 m_hrs = data;
46 }
47
48
49 //-------------------------------------------------
50 // hrc_w - high resolution color write
51 //-------------------------------------------------
52
hrc_w(offs_t offset,uint8_t data)53 void abc806_state::hrc_w(offs_t offset, uint8_t data)
54 {
55 int reg = (offset >> 8) & 0x0f;
56
57 m_hrc[reg] = data;
58 }
59
60
61 //-------------------------------------------------
62 // charram_r - character RAM read
63 //-------------------------------------------------
64
charram_r(offs_t offset)65 uint8_t abc806_state::charram_r(offs_t offset)
66 {
67 if (!machine().side_effects_disabled())
68 m_attr_data = m_attr_ram[offset];
69
70 return m_char_ram[offset];
71 }
72
73
74 //-------------------------------------------------
75 // charram_w - character RAM write
76 //-------------------------------------------------
77
charram_w(offs_t offset,uint8_t data)78 void abc806_state::charram_w(offs_t offset, uint8_t data)
79 {
80 if (!machine().side_effects_disabled())
81 m_attr_ram[offset] = m_attr_data;
82
83 m_char_ram[offset] = data;
84 }
85
86
87 //-------------------------------------------------
88 // ami_r - attribute memory read
89 //-------------------------------------------------
90
ami_r()91 uint8_t abc806_state::ami_r()
92 {
93 return m_attr_data;
94 }
95
96
97 //-------------------------------------------------
98 // amo_w - attribute memory write
99 //-------------------------------------------------
100
amo_w(uint8_t data)101 void abc806_state::amo_w(uint8_t data)
102 {
103 m_attr_data = data;
104 }
105
106
107 //-------------------------------------------------
108 // cli_r - palette PROM read
109 //-------------------------------------------------
110
cli_r(offs_t offset)111 uint8_t abc806_state::cli_r(offs_t offset)
112 {
113 /*
114
115 bit description
116
117 0 HRU II data bit 0
118 1 HRU II data bit 1
119 2 HRU II data bit 2
120 3 HRU II data bit 3
121 4
122 5
123 6
124 7 RTC data output
125
126 */
127
128 uint16_t hru2_addr = (m_hru2_a8 << 8) | (offset >> 8);
129 uint8_t data = m_hru2_prom->base()[hru2_addr] & 0x0f;
130
131 LOG("HRU II %03x : %01x\n", hru2_addr, data);
132
133 data |= m_rtc->dio_r() << 7;
134
135 return data;
136 }
137
138
139 //-------------------------------------------------
140 // sti_r - protection device read
141 //-------------------------------------------------
142
sti_r()143 uint8_t abc806_state::sti_r()
144 {
145 /*
146
147 bit description
148
149 0
150 1
151 2
152 3
153 4
154 5
155 6
156 7 PROT DOUT
157
158 */
159
160 return 0x7f;
161 }
162
163
164 //-------------------------------------------------
165 // sto_w -
166 //-------------------------------------------------
167
sto_w(uint8_t data)168 void abc806_state::sto_w(uint8_t data)
169 {
170 int level = BIT(data, 7);
171
172 switch (data & 0x07)
173 {
174 case 0:
175 // external memory enable
176 LOG("%s EME %u\n", machine().describe_context(), level);
177 m_eme = level;
178 break;
179 case 1:
180 // 40/80 column display
181 m_40 = level;
182 break;
183 case 2:
184 // HRU II address line 8, PROT A0
185 m_hru2_a8 = level;
186 break;
187 case 3:
188 // PROT INI
189 break;
190 case 4:
191 // text display enable
192 m_txoff = level;
193 break;
194 case 5:
195 // RTC chip select
196 m_rtc->cs_w(!level);
197 break;
198 case 6:
199 // RTC clock
200 m_rtc->clk_w(level);
201 break;
202 case 7:
203 // RTC data in, PROT DIN
204 m_rtc->dio_w(level);
205 break;
206 }
207 }
208
209
210 //-------------------------------------------------
211 // sso_w - sync offset write
212 //-------------------------------------------------
213
sso_w(uint8_t data)214 void abc806_state::sso_w(uint8_t data)
215 {
216 m_sync = data & 0x3f;
217 }
218
219
220 //-------------------------------------------------
221 // MC6845_UPDATE_ROW( abc806_update_row )
222 //-------------------------------------------------
223
MC6845_UPDATE_ROW(abc806_state::abc806_update_row)224 MC6845_UPDATE_ROW( abc806_state::abc806_update_row )
225 {
226 const pen_t *pen = m_palette->pens();
227
228 int fg_color = 7;
229 int bg_color = 0;
230 int underline = 0;
231 int flash = 0;
232 int e5 = m_40;
233 int e6 = m_40;
234 int th = 0;
235
236 y += m_sync + vbp;
237
238 for (int column = 0; column < x_count; column++)
239 {
240 uint8_t data = m_char_ram[(ma + column) & 0x7ff];
241 uint8_t attr = m_attr_ram[(ma + column) & 0x7ff];
242 uint8_t rad_data;
243
244 if ((attr & 0x07) == ((attr >> 3) & 0x07))
245 {
246 // special case
247 switch (attr >> 6)
248 {
249 case 0:
250 // use previously selected attributes
251 break;
252
253 case 1:
254 // reserved for future use
255 break;
256
257 case 2:
258 // blank
259 fg_color = 0;
260 bg_color = 0;
261 underline = 0;
262 flash = 0;
263 break;
264
265 case 3:
266 // double width
267 e5 = BIT(attr, 0);
268 e6 = BIT(attr, 1);
269
270 // read attributes from next byte
271 attr = m_attr_ram[(ma + column + 1) & 0x7ff];
272
273 if (attr != 0x00)
274 {
275 fg_color = attr & 0x07;
276 bg_color = (attr >> 3) & 0x07;
277 underline = BIT(attr, 6);
278 flash = BIT(attr, 7);
279 }
280 break;
281 }
282 }
283 else
284 {
285 // normal case
286 fg_color = attr & 0x07;
287 bg_color = (attr >> 3) & 0x07;
288 underline = BIT(attr, 6);
289 flash = BIT(attr, 7);
290 e5 = m_40;
291 e6 = m_40;
292 }
293
294 if (column == cursor_x)
295 {
296 rad_data = 0x0f;
297 }
298 else
299 {
300 uint16_t rad_addr = (e6 << 8) | (e5 << 7) | (flash << 6) | (underline << 4) | (m_flshclk << 5) | (ra & 0x0f);
301 rad_data = m_rad_prom->base()[rad_addr] & 0x0f;
302 }
303
304 uint16_t chargen_addr = (th << 12) | (data << 4) | rad_data;
305 uint8_t chargen_data = m_char_rom->base()[chargen_addr & 0xfff] << 2;
306 int x = hbp + (column + 4) * ABC800_CHAR_WIDTH;
307
308 for (int bit = 0; bit < ABC800_CHAR_WIDTH; bit++)
309 {
310 int color = BIT(chargen_data, 7) ? fg_color : bg_color;
311 if (!de) color = 0;
312
313 bitmap.pix(y, x++) = pen[color];
314
315 if (e5 || e6)
316 {
317 bitmap.pix(y, x++) = pen[color];
318 }
319
320 chargen_data <<= 1;
321 }
322
323 if (e5 || e6)
324 {
325 column++;
326 }
327 }
328 }
329
330
331 //-------------------------------------------------
332 // hs_w - horizontal sync write
333 //-------------------------------------------------
334
WRITE_LINE_MEMBER(abc806_state::hs_w)335 WRITE_LINE_MEMBER( abc806_state::hs_w )
336 {
337 int vsync;
338
339 if (!state)
340 {
341 m_v50_addr++;
342
343 // clock current vsync value into the shift register
344 m_vsync_shift <<= 1;
345 m_vsync_shift |= m_vsync;
346
347 vsync = BIT(m_vsync_shift, m_sync);
348
349 if (!m_d_vsync && vsync)
350 {
351 // clear V50 address
352 m_v50_addr = 0;
353 }
354 else if (m_d_vsync && !vsync)
355 {
356 // flash clock
357 if (m_flshclk_ctr & 0x20)
358 {
359 m_flshclk = !m_flshclk;
360 m_flshclk_ctr = 0;
361 }
362 else
363 {
364 m_flshclk_ctr++;
365 }
366 }
367
368 if (m_d_vsync != vsync)
369 {
370 // signal _DEW to DART
371 m_dart->rib_w(!vsync);
372 }
373
374 m_d_vsync = vsync;
375 }
376 }
377
378
379 //-------------------------------------------------
380 // vs_w - vertical sync write
381 //-------------------------------------------------
382
WRITE_LINE_MEMBER(abc806_state::vs_w)383 WRITE_LINE_MEMBER( abc806_state::vs_w )
384 {
385 m_vsync = state;
386 }
387
388
389 //-------------------------------------------------
390 // hr_update - high resolution screen update
391 //-------------------------------------------------
392
hr_update(bitmap_rgb32 & bitmap,const rectangle & cliprect)393 void abc806_state::hr_update(bitmap_rgb32 &bitmap, const rectangle &cliprect)
394 {
395 const pen_t *pen = m_palette->pens();
396
397 uint32_t addr = (m_hrs & 0x0f) << 15;
398
399 for (int y = m_sync + VERTICAL_PORCH_HACK; y < std::min(cliprect.max_y + 1, m_sync + VERTICAL_PORCH_HACK + 240); y++)
400 {
401 for (int sx = 0; sx < 128; sx++)
402 {
403 uint8_t data = m_video_ram[addr++];
404 uint16_t dot = (m_hrc[data >> 4] << 8) | m_hrc[data & 0x0f];
405
406 for (int pixel = 0; pixel < 4; pixel++)
407 {
408 int x = HORIZONTAL_PORCH_HACK + (ABC800_CHAR_WIDTH * 4) - 16 + (sx * 4) + pixel;
409
410 if (BIT(dot, 15) || (bitmap.pix(y, x) == rgb_t::black()))
411 {
412 bitmap.pix(y, x) = pen[(dot >> 12) & 0x07];
413 }
414
415 dot <<= 4;
416 }
417 }
418 }
419 }
420
421
video_start()422 void abc806_state::video_start()
423 {
424 // allocate memory
425 m_char_ram.allocate(m_char_ram_size);
426 m_attr_ram.allocate(m_char_ram_size);
427
428 uint32_t videoram_size = m_ram->size() - 0x8000;
429 m_video_ram.allocate(videoram_size);
430
431 // register for state saving
432 save_item(NAME(m_txoff));
433 save_item(NAME(m_40));
434 save_item(NAME(m_flshclk_ctr));
435 save_item(NAME(m_flshclk));
436 save_item(NAME(m_attr_data));
437 save_item(NAME(m_hrs));
438 save_item(NAME(m_hrc));
439 save_item(NAME(m_sync));
440 save_item(NAME(m_v50_addr));
441 save_item(NAME(m_hru2_a8));
442 save_item(NAME(m_vsync_shift));
443 save_item(NAME(m_vsync));
444 save_item(NAME(m_d_vsync));
445
446 // initialize variables
447 for (auto & elem : m_hrc)
448 {
449 elem = 0;
450 }
451
452 m_sync = 10;
453 m_d_vsync = 1;
454 m_vsync = 1;
455 m_40 = 1;
456 }
457
458
459 //-------------------------------------------------
460 // SCREEN_UPDATE( abc806 )
461 //-------------------------------------------------
462
screen_update(screen_device & screen,bitmap_rgb32 & bitmap,const rectangle & cliprect)463 uint32_t abc806_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
464 {
465 // clear screen
466 bitmap.fill(rgb_t::black(), cliprect);
467
468 if (!m_txoff)
469 {
470 // draw text
471 m_crtc->screen_update(screen, bitmap, cliprect);
472 }
473
474 // draw HR graphics
475 hr_update(bitmap, cliprect);
476
477 return 0;
478 }
479
480
481 //-------------------------------------------------
482 // PALETTE_INIT( abc806 )
483 //-------------------------------------------------
484
abc806_palette(palette_device & palette) const485 void abc806_state::abc806_palette(palette_device &palette) const
486 {
487 palette.set_pen_color(0, rgb_t::black());
488 palette.set_pen_color(1, rgb_t(0xff, 0x00, 0x00)); // red
489 palette.set_pen_color(2, rgb_t::green());
490 palette.set_pen_color(3, rgb_t(0xff, 0xff, 0x00)); // yellow
491 palette.set_pen_color(4, rgb_t(0x00, 0x00, 0xff)); // blue
492 palette.set_pen_color(5, rgb_t(0xff, 0x00, 0xff)); // magenta
493 palette.set_pen_color(6, rgb_t(0x00, 0xff, 0xff)); // cyan
494 palette.set_pen_color(7, rgb_t::white());
495 }
496
497
498 //-------------------------------------------------
499 // machine_config( abc806_video )
500 //-------------------------------------------------
501
abc806_video(machine_config & config)502 void abc806_state::abc806_video(machine_config &config)
503 {
504 MC6845(config, m_crtc, ABC800_CCLK);
505 m_crtc->set_screen(SCREEN_TAG);
506 m_crtc->set_show_border_area(true);
507 m_crtc->set_char_width(ABC800_CHAR_WIDTH);
508 m_crtc->set_update_row_callback(FUNC(abc806_state::abc806_update_row));
509 m_crtc->out_hsync_callback().set(FUNC(abc806_state::hs_w));
510 m_crtc->out_vsync_callback().set(FUNC(abc806_state::vs_w));
511
512 screen_device &screen(SCREEN(config, SCREEN_TAG, SCREEN_TYPE_RASTER));
513 screen.set_screen_update(FUNC(abc806_state::screen_update));
514 screen.set_raw(XTAL(12'000'000), 0x300, 0, 0x1e0, 0x13a, 0, 0xfa);
515
516 PALETTE(config, m_palette, FUNC(abc806_state::abc806_palette), 8);
517 }
518