2 Skelton for retropc emulator
4 Author : Kyuma Ohta <whatisthis.sowhat _at_ gmail.com>
8 History: 2016.12.28 Initial from HD46505 .
11 #include "towns_crtc.h"
15 EVENT_CRTC_VSTART = 1,
18 EVENT_CRTC_HSTART = 4,
30 void TOWNS_CRTC::initialize()
32 memset(regs, 0, sizeof(regs));
33 memset(regs_written, 0, sizeof(regs_written));
35 line_count[0] = line_count[1] = 0;
36 for(int i = 0; i < TOWNS_CRTC_MAX_LINES; i++) {
37 line_changed[0][i] = true;
38 line_changed[1][i] = true;
48 for(int i = 0; i < 2; i++) {
49 // ToDo: Allocate at external buffer (when using compute shaders).
50 linebuffers[i] = malloc(sizeof(linebuffer_t ) * TOWNS_CRTC_MAX_LINES);
51 if(linebuffers[i] != NULL) {
52 for(int l = 0; l < TOWNS_CRTC_MAX_LINES; l++) {
53 memset(&(linebuffers[i][l]), 0x00, sizeof(linebuffer_t));
58 //register_frame_event(this);
59 //register_vline_event(this);
63 void TOWNS_CRTC::release()
65 for(int i = 0; i < 2; i++) {
66 // ToDo: Allocate at external buffer (when using compute shaders).
67 if(linebuffers[i] != NULL) free(linebuffers[i]);
71 void TOWNS_CRTC::reset()
75 vblank = vsync = hsync = true;
77 // memset(regs, 0, sizeof(regs));
80 // initial settings for 1st frame
82 hz_total = (CHARS_PER_LINE > 54) ? CHARS_PER_LINE : 54;
86 hz_disp = (hz_total > 80) ? 80 : 40;
87 hs_start = hz_disp + 4;
88 hs_end = hs_start + 4;
90 vt_total = LINES_PER_FRAME;
91 vt_disp = (SCREEN_HEIGHT > LINES_PER_FRAME) ? (SCREEN_HEIGHT >> 1) : SCREEN_HEIGHT;
92 vs_start = vt_disp + 16;
93 vs_end = vs_start + 16;
95 timing_changed = false;
98 #if defined(TOWNS_CRTC_CHAR_CLOCK)
100 next_char_clock = TOWNS_CRTC_CHAR_CLOCK;
101 #elif defined(TOWNS_CRTC_HORIZ_FREQ)
103 next_horiz_freq = TOWNS_CRTC_HORIZ_FREQ;
106 line_count[0] = line_count[1] = 0;
107 for(int i = 0; i < TOWNS_CRTC_MAX_LINES; i++) {
108 line_changed[0][i] = true;
109 line_rendered[0][i] = false;
110 line_changed[1][i] = true;
111 line_rendered[1][i] = false;
113 if(event_id_hsync >= 0) cancel_event(this, event_id_hsync);
114 if(event_id_hsw >= 0) cancel_event(this, event_id_hsw);
115 if(event_id_vsync >= 0) cancel_event(this, event_id_vsync);
116 if(event_id_vstart >= 0) cancel_event(this, event_id_vstart);
117 if(event_id_vst1 >= 0) cancel_event(this, event_id_vst1);
118 if(event_id_vst2 >= 0) cancel_event(this, event_id_vst2);
119 if(event_id_vblank >= 0) cancel_event(this, event_id_vblank);
123 event_id_vstart = -1;
126 event_id_vblank = -1;
129 register_event(this, EVENT_CRTC_VSTART, vstart_us, false, &event_id_vstart);
132 void TOWNS_CRTC::set_crtc_clock(uint16_t val)
134 scsel = (val & 0x0c) >> 2;
136 static const double clocks[] = {
137 28.6363e6, 24.5454e6, 25.175e6, 21.0525e6
139 if(crtc_clock[clksel] != crtc_clock) {
140 crtc_clock = crtc_clock[clksel];
141 force_recalc_crtc_param();
145 void TOWNS_CRTC::force_recalc_crtc_param(void)
147 horiz_width_posi_us = crtc_clock * ((double)(regs[0] & 0x00fe)); // HSW1
148 horiz_width_nega_us = crtc_clock * ((double)(regs[1] & 0x00fe)); // HSW2
149 horiz_us = crtc_clock * ((double)((regs[4] & 0x07fe) + 1)); // HST
150 vsync_pre_us = ((double)(regs[5] & 0x1f)) * horiz_us; // VST1
152 double horiz_ref = horiz_us / 2.0;
154 vst2_us = ((double)(regs[6] & 0x1f)) * horiz_ref; // VST2
155 eet_us = ((double)(regs[7] & 0x1f)) * horiz_ref; // EET
156 frame_us = ((double)(regs[8] & 0x07ff)) * horiz_ref; // VST
158 for(int layer = 0; layer < 2; layer++) {
159 vert_start_us[layer] = ((double)(regs[(layer << 1) + 13] & 0x07ff)) * horiz_ref; // VDSx
160 vert_end_us[layer] = ((double)(regs[(layer << 1) + 13 + 1] & 0x07ff)) * horiz_ref; // VDEx
161 horiz_start_us[layer] = ((double)(regs[(layer << 1) + 9] & 0x07ff)) * crtc_clock ; // HDSx
162 horiz_end_us[layer] = ((double)(regs[(layer << 1) + 9 + 1] & 0x07ff)) * crtc_clock ; // HDEx
168 void TONWS_CRTC::write_io8(uint32_t addr, uint32_t data)
172 } else if(addr == 0x0442) {
175 rdata.l = (uint8_t)data;
176 write_io16(addr, rdata.w);
177 } else if(addr == 0x0443) {
180 rdata.h = (uint8_t)data;
181 write_io16(addr, rdata.w);
185 void TOWNS_CRTC::write_io16(uint32_t addr, uint32_t data)
187 if((addr & 0xfffe) == 0x0442) {
189 if((ch < 0x09) && ((ch >= 0x04) || (ch <= 0x01))) { // HSW1..VST
190 if(regs[ch] != (uint16_t)data) {
191 force_recalc_crtc_param();
193 } else if(ch < 0x11) { // HDS0..VDE1
194 uint8_t localch = ((ch - 0x09) / 2) & 1;
195 if(regs[ch] != (uint16_t)data) {
196 timing_changed[localch] = true;
197 // ToDo: Change render parameter within displaying.
198 force_recalc_crtc_param();
200 }else if(ch < 0x19) { // FA0..LO1
201 uint8_t localch = (ch - 0x11) / 4;
202 uint8_t localreg = (ch - 0x11) & 3;
203 if(regs[ch] != (uint16_t)data) {
204 address_changed[localch] = true;
207 vstart_addr[localch] = (uint32_t)(data & 0xffff);
210 hstart_words[localch] = (uint32_t)(data & 0x07ff);
213 frame_offet[localch] = (uint32_t)(data & 0xffff);
216 line_offet[localch] = (uint32_t)(data & 0xffff);
221 if(regs[ch] != (uint16_t)data) {
225 // ToDo: External SYNC.
232 pd.w = (uint16_t)data;
233 zfv[0] = ((pd.l & 0xf0) >> 4) + 1;
234 zfh[0] = (pd.l & 0x0f) + 1;
235 zfv[1] = ((pd.h & 0xf0) >> 4) + 1;
236 zfh[1] = (pd.h & 0x0f) + 1;
237 if((zfv[0] != zoom_factor_vert[0]) || (zfh[0] != zoom_factor_horiz[0])) {
238 timing_changed[0] = true;
239 address_changed[0] = true;
240 if(zfv[0] != zoom_factor_vert[0]) zoom_count_vert[0] = zfv[0];
242 if((zfv[1] != zoom_factor_vert[1]) || (zfh[1] != zoom_factor_horiz[1])) {
243 timing_changed[0] = true;
244 address_changed[0] = true;
245 if(zfv[1] != zoom_factor_vert[1]) zoom_count_vert[1] = zfv[1];
247 zoom_factor_vert[0] = zfv[0];
248 zoom_factor_horiz[0] = zfh[0];
249 zoom_factor_vert[1] = zfv[1];
250 zoom_factor_horiz[1] = zfh[1];
254 if(regs[ch] != data) {
255 if((data & 0x8000) == 0) {
261 if((data & 0x4000) == 0) {
267 impose_mode[1] = ((data & 0x0080) == 0);
268 impose_mode[0] = ((data & 0x0040) == 0);
269 carry_enable[1] = ((data & 0x0020) != 0);
270 carry_enable[0] = ((data & 0x0010) != 0);
272 dmode[0] = data & 0x03;
273 dmode[1] = (data & 0x0c) >> 2;
274 for(int i = 0; i < 2; i++) {
275 if(dmode[0] != display_mode[0]) {
276 mode_changed[0] = true;
277 notify_mode_changed(i, dmode[i]);
279 display_mode[i] = dmode[i];
284 set_crtc_clock((uint16_t)data);
286 case 5: // Reserved(REG#30)
289 // ToDo: External trigger.
294 regs[ch] = (uint16_t)data;
296 } else if(addr == 0x0440) {
301 uint16_t TOWNS_CRTC::read_reg30()
303 uint16_t data = 0x00f0;
304 data |= ((frame_in[1]) ? 0x8000 : 0);
305 data |= ((frame_in[0]) ? 0x4000 : 0);
306 data |= ((hdisp[1]) ? 0x2000 : 0);
307 data |= ((hdisp[0]) ? 0x1000 : 0);
308 //data |= ((eet) ? 0x0800 : 0);
309 data |= ((vsync) ? 0x0400 : 0);
310 data |= (!(hsync) ? 0x0200 : 0);
311 //data |= ((video_in) ? 0x0100 : 0);
312 //data |= ((half_tone) ? 0x0008 : 0);
313 //data |= ((sync_enable) ? 0x0004 : 0);
314 //data |= ((vcard_enable) ? 0x0002 : 0);
315 //data |= ((sub_carry) ? 0x0001 : 0);
319 uint32_t TOWNS_CRTC::read_io16(uint32_t addr)
321 addr = addr & 0xfffe;
324 } else if(addr == 0x0442) {
326 return (uint32_t)read_reg30();
334 uint32_t TOWNS_CRTC::read_io8(uint32_t addr)
338 } else if(addr == 0x0442) {
345 return (uint32_t)(d.l);
346 } else if(addr == 0x0443) {
353 return (uint32_t)(d.h);
358 void TOWNS_CRTC::render_32768(scrntype_t* dst, scrntype_t *mask, uint8_t* src, int y, int width, int layer)
360 if(dst == NULL) return;
361 if(mask == NULL) return;
362 if(src == NULL) return;
364 int magx = linebuffers[trans][y].mag[layer];
365 int pwidth = linebuffers[trans][y].pixels[layer];
366 int num = linebuffers[trans][y].num[layer];
367 uint8_t *p = linebuffers[trans][y].pixels_layer[layer];
369 scrntype_t *r = mask;
371 if((pwidth * magx) > width) {
372 pwidth = width / magx;
373 if((width % magx) != 0) {
377 __DECL_ALIGNED(16) uint16_t pbuf[8];
378 __DECL_ALIGNED(16) uint16_t rbuf[8];
379 __DECL_ALIGNED(16) uint16_t gbuf[8];
380 __DECL_ALIGNED(16) uint16_t bbuf[8];
381 __DECL_ALIGNED(32) scrntype_t sbuf[8];
382 __DECL_ALIGNED(32) scrntype_t abuf[8];
383 __DECL_ALIGNED(32) uint8_t a2buf[8];
386 for(x = 0; x < (pwidth >> 3); x++) {
387 for(int i = 0; i < 8; i++) {
388 pbuf[i] = read_2bytes_le_from(p);
391 for(int i = 0; i < 8; i++) {
396 for(int i = 0; i < 8; i++) {
397 rbuf[i] = rbuf[i] >> 5;
398 gbuf[i] = gbuf[i] >> 10;
400 for(int i = 0; i < 8; i++) {
401 rbuf[i] = rbuf[i] & 0x1f;
402 gbuf[i] = gbuf[i] & 0x1f;
403 bbuf[i] = bbuf[i] & 0x1f;
405 for(int i = 0; i < 8; i++) {
410 for(int i = 0; i < 8; i++) {
411 abuf[i] = (pbuf[i] & 0x8000) ? 0 : (scrntype_t)(-1);
412 a2buf[i] = (pbuf[i] & 0x8000) ? 0 : 255;
414 for(int i = 0; i < 8; i++) {
415 sbuf[i] = RGBA_COLOR(rbuf[i], gbuf[i], bbuf[i], a2buf[i]);
418 for(int i = 0; i < 8; i++) {
421 for(int i = 0; i < rwidth; i++) {
425 if(k >= width) break;
427 for(int i = 0; i < 8; i++) {
428 if(j = 0; j < magx; j++) {
432 if(k >= width) break;
434 if(k >= width) break;
438 if(k >= width) return;
439 if((pwidth & 7) != 0) {
440 int rwidth = pwidth & 7;
441 for(int i = 0; i < rwidth; i++) {
442 pbuf[i] = read_2bytes_le_from(p);
445 for(int i = 0; i < rwidth; i++) {
450 for(int i = 0; i < rwidth; i++) {
451 rbuf[i] = (rbuf[i] >> 5) & 0x1f;
452 gbuf[i] = (gbuf[i] >> 10) & 0x1f;
453 bbuf[i] = bbuf[i] & 0x1f;
455 for(int i = 0; i < rwidth; i++) {
460 for(int i = 0; i < rwidth; i++) {
461 abuf[i] = (pbuf[i] & 0x8000) ? 0 : (scrntype_t)(-1);
462 a2buf[i] = (pbuf[i] & 0x8000) ? 0 : 255;
464 for(int i = 0; i < rwidth; i++) {
465 sbuf[i] = RGBA_COLOR(rbuf[i], gbuf[i], bbuf[i], a2buf[i]);
468 for(int i = 0; i < rwidth; i++) {
471 for(int i = 0; i < rwidth; i++) {
475 if(k >= width) break;
477 for(int i = 0; i < rwidth; i++) {
478 if(j = 0; j < magx; j++) {
482 if(k >= width) break;
484 if(k >= width) break;
490 void TOWNS_CRTC::render_16(scrntype_t* dst, scrntype_t *mask, uint8_t* src, scrntype_t* pal, int y, int width, int layer)
492 if(dst == NULL) return;
493 if(mask == NULL) return;
494 if(src == NULL) return;
495 if(pal == NULL) return;
497 int magx = linebuffers[trans][y].mag[layer];
498 int pwidth = linebuffers[trans][y].pixels[layer];
499 int num = linebuffers[trans][y].num[layer];
500 uint8_t *p = linebuffers[trans][y].pixels_layer[layer];
502 scrntype_t *r = mask;
504 if((pwidth * magx) > width) {
505 pwidth = width / magx;
506 if((width % magx) != 0) {
510 __DECL_ALIGNED(16) uint8_t pbuf[8];
511 __DECL_ALIGNED(16) uint8_t hlbuf[16];
512 __DECL_ALIGNED(32) scrntype_t sbuf[16];
513 __DECL_ALIGNED(32) scrntype_t abuf[16];
516 for(x = 0; x < (pwidth >> 3); x++) {
517 for(int i = 0; i < 8; i++) {
520 for(int i = 0; i < 16; i += 2) {
521 hlbuf[i] = pbuf[i >> 1];
522 hlbuf[i + 1] = pbuf[i >> 1];
524 for(int i = 0; i < 16; i += 2) {
526 hlbuf[i + 1] = hlbuf[i + 1] & 15;
528 for(int i = 0; i < 16; i++) {
529 abuf[i] = (hlbuf[ii] == 0) ? 0 : (scrntype_t)(-1);
531 for(int i = 0; i < 16; i++) {
532 sbuf[i] = (hlbuf[i] == 0) ? RGBA_COLOR(0, 0, 0, 0) : pal[hlbuf[i]];
535 for(int i = 0; i < 16; i++) {
538 for(int i = 0; i < 16; i++) {
542 if(k >= width) break;
544 for(int i = 0; i < 16; i++) {
545 if(j = 0; j < magx; j++) {
549 if(k >= width) break;
551 if(k >= width) break;
555 if(k >= width) return;
556 int rwidth = pwidth & 7;
561 for(x = 0; x < rwidth; x++) {
565 ah = (tmph == 0) ? 0 : (scrntype_t)(-1);
566 al = (tmpl == 0) ? 0 : (scrntype_t)(-1);
567 sbuf[0] = (tmph == 0) ? RGBA_COLOR(0, 0, 0, 0) : pal[tmph];
568 sbuf[1] = (tmpl == 0) ? RGBA_COLOR(0, 0, 0, 0) : pal[tmpl];
574 if(k >= width) break;
578 if(k >= width) break;
580 for(int j = 0; j < magx; j++) {
584 if(k >= width) break;
586 if(k >= width) break;
587 for(int j = 0; j < magx; j++) {
591 if(k >= width) break;
593 if(k >= width) break;
599 void TOWNS_CRTC::draw_screen()
601 if(linebuffers[trans] == NULL) return;
602 if(d_vram == NULL) return;
603 __DECL_ALIGNED(32) scrntype_t apal16[2][16];
604 __DECL_ALIGNED(32) scrntype_t apal256[256];
608 d_vram->get_analog_palette(0, &(apal16[0][0]));
609 d_vram->get_analog_palette(0, &(apal16[1][0]));
610 d_vram->get_analog_palette(2, apal256);
613 int lines = d_vram->get_screen_height();
614 int width = d_vram->get_screen_width();
615 if(lines > TOWNS_CRTC_MAX_LINES) lines = TOWNS_CRTC_MAX_LINES;
616 if(width > TOWNS_CRTC_MAX_PIXELS) width = TOWNS_CRTC_MAX_PIXELS;
617 // ToDo: faster alpha blending.
618 __DECL_ALIGNED(32) scrntype_t lbuffer0[TOWNS_CRTC_MAX_PIXELS + 16];
619 __DECL_ALIGNED(32) scrntype_t lbuffer1[TOWNS_CRTC_MAX_PIXELS + 16];
620 __DECL_ALIGNED(32) scrntype_t abuffer0[TOWNS_CRTC_MAX_PIXELS + 16];
623 for(int y = 0; y < lines; y++) {
624 // memset(lbuffer0, 0x00, sizeof(lbuffer0));
625 memset(lbuffer1, 0x00, sizeof(lbuffer1));
626 // memset(abuffer0, 0x00, sizeof(abuffer0));
628 if(linebuffers[trans].mode[0] == DISPMODE_256) {
630 int magx = linebuffers[trans].mag[0];
631 int pwidth = linebuffers[trans].pixels[0];
632 int num = linebuffers[trans].num[0];
633 uint8_t *p = linebuffers[trans].pixels_layer[0];
634 __DECL_ALIGNED(16) uint8_t pbuf[16];
635 __DECL_ALIGNED(32) scrntype_t sbuf[16];
638 if(pwidth > width) pwidth = width;
639 for(int x = 0; x < (pwidth >> 4); x++) {
640 // ToDo: Start position
641 for(int i = 0; i < 16; i++) {
645 for(int i = 0; i < 16; i++) {
646 lbuffer1[xx++] = apal256[pbuf[i]];
649 if((pwidth & 15) != 0) {
650 int xx = pwidth & ~15;
652 for(int i = 0; i < w; i++) {
655 for(int i = 0; i < w; i++) {
656 lbuffer1[xx++] = apal256[pbuf[i]];
660 if((pwidth * magx) > width) {
661 pwidth = width / magx;
662 if((width % magx) != 0) pwidth++;
665 for(int x = 0; x < (pwidth >> 4); x++) {
666 // ToDo: Start position
667 for(int i = 0; i < 16; i++) {
670 for(int i = 0; i < 16; i++) {
671 sbuf[i] = apal256[pbuf[i]];
673 for(int i = 0; i < 16; i++) {
674 scrntype_t s = sbuf[i];
675 for(int j = 0; j < magx; j++) {
680 if((pwidth & 15) != 0) {
681 for(int i = 0; i < (pwidth & 15); i++) {
684 for(int i = 0; i < (pwidth & 15); i++) {
685 sbuf[i] = apal256[pbuf[i]];
687 for(int i = 0; i < (pwidth & 15); i++) {
688 scrntype_t s = sbuf[i];
689 for(int j = 0; j < magx; j++) {
691 if(k >= width) break;
698 int magx = linebuffers[trans].mag[1];
699 int pwidth = linebuffers[trans].pixels[1];
700 int num = linebuffers[trans].num[1];
701 uint8_t *p = linebuffers[trans].pixels_layer[1];
702 __DECL_ALIGNED(16) uint16_t rbuf[16];
703 __DECL_ALIGNED(16) uint16_t gbuf[16];
704 __DECL_ALIGNED(16) uint16_t bbuf[16];
705 __DECL_ALIGNED(16) uint8_t p8buf[16];
706 __DECL_ALIGNED(16) uint8_t hlbuf[32];
707 __DECL_ALIGNED(32) scrntype_t sbuf[16];
709 if(pwidth > width) pwidth = width;
710 if(linebuffers[trans].mode[1] == DISPMODE_16) { // Lower layer
712 for(int x = 0; x < (pwidth >> 5); x++) {
713 for(int i = 0; i < 16; i++) {
716 for(int i = 0; i < 32; i += 2) {
717 hlbuf[i + 0] = p8buf[i >> 1] >> 4;
718 hlbuf[i + 1] = p8buf[i >> 1] & 0x0f;
720 for(int i = 0; i < 32; i++) {
721 sbuf[i] = apal16[num][hlbuf[i]];
724 for(int i = 0; i < 32; i++) {
725 lbuffer1[k++] = sbuf[i];
729 for(int i = 0; i < 32; i++) {
730 for(int j = 0; j < magx; j++) {
731 lbuffer1[k++] = sbuf[i];
738 if((pwidth & 31) >= 2) {
739 for(int x = 0; x < ((pwidth & 31) >> 1); x++) {
742 for(int i = 0; i < (pwidth & 0x1e); i += 2) {
743 hlbuf[i + 0] = p8buf[i >> 1] >> 4;
744 hlbuf[i + 1] = p8buf[i >> 1] & 0x0f;
746 for(int i = 0; i < (pwidth & 0x1f); i++) {
747 sbuf[i] = apal16[num][hlbuf[i]];
750 for(int i = 0; i < (pwidth & 0x1f); i++) {
751 lbuffer1[k++] = sbuf[i];
755 for(int i = 0; i < (pwidth & 0x1f); i++) {
756 for(int j = 0; j < magx; j++) {
757 lbuffer1[k++] = sbuf[i];
764 } else if(linebuffers[trans].mode[1] == DISPMODE_32768) { // Lower layer
765 uint16_t* q = (uint16_t*)p;
768 for(int x = 0; x < (pwidth >> 4); x++) {
769 for(int i = 0; i < 16; i++) {
770 rbuf[i] = read_2bytes_le_from(p);
773 for(int i = 0; i < 16; i++) {
778 for(int i = 0; i < 16; i++) {
779 gbuf[i] = (gbuf[i] >> 10) & 0x1f;
780 bbuf[i] = bbuf[i] & 0x1f;
781 rbuf[i] = (rbuf[i] >> 5) & 0x1f;
782 abuf[i] = (abuf[i] & 0x8000) ? 0 : 255;
785 for(int i = 0; i < 16; i++) {
786 lbuffer1[k++] = RGBA_COLOR(rbuf[i], gbuf[i], bbuf[i], abuf[i]);
788 } else if(magx > 0) {
789 for(int i = 0; i < 16; i++) {
790 scrntype_t s = RGBA_COLOR(rbuf[i], gbuf[i], bbuf[i], abuf[i]);
791 for(int j = 0; j < magx; j++) {
799 for(int x = 0; x < (pwidth >> 4); x++) {
800 for(int i = 0; i < 16; i++) {
801 rbuf[i] = read_2bytes_le_from(p);
804 for(int i = 0; i < 16; i++) {
809 for(int i = 0; i < 16; i++) {
810 gbuf[i] = (gbuf[i] >> 10) & 0x1f;
811 bbuf[i] = bbuf[i] & 0x1f;
812 rbuf[i] = (rbuf[i] >> 5) & 0x1f;
813 abuf[i] = (abuf[i] & 0x8000) ? 0 : 255;
816 for(int i = 0; i < 16; i++) {
817 lbuffer1[k++] = RGBA_COLOR(rbuf[i], gbuf[i], bbuf[i], abuf[i]);
819 } else if(magx > 0) {
820 for(int i = 0; i < 16; i++) {
821 scrntype_t s = RGBA_COLOR(rbuf[i], gbuf[i], bbuf[i], abuf[i]);
822 for(int j = 0; j < magx; j++) {
832 magx = linebuffers[trans].mag[0];
833 pwidth = linebuffers[trans].pixels[0];
834 num = linebuffers[trans].num[0];
835 p = linebuffers[trans].pixels_layer[0];
837 if(pwidth > width) pwidth = width;
838 // ToDo: alpha blending by GPU
839 if(linebuffers[trans].mode[0] == DISPMODE_16) { // Upper layer
841 for(int x = 0; x < (pwidth >> 5); x++) {
842 for(int i = 0; i < 16; i++) {
845 for(int i = 0; i < 32; i += 2) {
846 hlbuf[i + 0] = p8buf[i >> 1] >> 4;
847 hlbuf[i + 1] = p8buf[i >> 1] & 0x0f;
849 for(int i = 0; i < 32; i++) {
850 sbuf[i] = apal16[num][hlbuf[i]];
853 for(int i = 0; i < 32; i++) {
854 lbuffer1[k] = (hlbuf[i] == 0) ? lbuffer1[k] : sbuf[i];
859 for(int i = 0; i < 32; i++) {
860 for(int j = 0; j < magx; j++) {
861 lbuffer1[k] = (hlbuf[i] == 0) ? lbuffer1[k] : sbuf[i];
869 if((pwidth & 31) >= 2) {
870 for(int x = 0; x < ((pwidth & 31) >> 1); x++) {
873 for(int i = 0; i < (pwidth & 0x1e); i += 2) {
874 hlbuf[i + 0] = p8buf[i >> 1] >> 4;
875 hlbuf[i + 1] = p8buf[i >> 1] & 0x0f;
877 for(int i = 0; i < (pwidth & 0x1f); i++) {
878 sbuf[i] = apal16[num][hlbuf[i]];
881 for(int i = 0; i < (pwidth & 0x1f); i++) {
882 lbuffer1[k] = (hlbuf[i] == 0) ? lbuffer1[k] : sbuf[i];
887 for(int i = 0; i < (pwidth & 0x1f); i++) {
888 for(int j = 0; j < magx; j++) {
889 lbuffer1[k] = (hlbuf[i] == 0) ? lbuffer1[k] : sbuf[i];
897 } else if(linebuffers[trans].mode[0] == DISPMODE_32768) { // upper layer
898 uint16_t* q = (uint16_t*)p;
901 for(int x = 0; x < (pwidth >> 4); x++) {
902 for(int i = 0; i < 16; i++) {
903 rbuf[i] = read_2bytes_le_from(p);
906 for(int i = 0; i < 16; i++) {
911 for(int i = 0; i < 16; i++) {
912 gbuf[i] = (gbuf[i] >> 10) & 0x1f;
913 bbuf[i] = bbuf[i] & 0x1f;
914 rbuf[i] = (rbuf[i] >> 5) & 0x1f;
915 abuf[i] = (abuf[i] & 0x8000) ? 0 : 255;
918 for(int i = 0; i < 16; i++) {
919 lbuffer1[k] = (abuf[i] == 0) ? lbuffer1[k] : RGBA_COLOR(rbuf[i], gbuf[i], bbuf[i], abuf[i]);
922 } else if(magx > 0) {
923 for(int i = 0; i < 16; i++) {
924 if(!(abuf[i] == 0)) {
925 scrntype_t s = RGBA_COLOR(rbuf[i], gbuf[i], bbuf[i], abuf[i]);
926 for(int j = 0; j < magx; j++) {
937 for(int x = 0; x < (pwidth >> 4); x++) {
938 for(int i = 0; i < 16; i++) {
939 rbuf[i] = read_2bytes_le_from(p);
942 for(int i = 0; i < 16; i++) {
947 for(int i = 0; i < 16; i++) {
948 gbuf[i] = (gbuf[i] >> 10) & 0x1f;
949 bbuf[i] = bbuf[i] & 0x1f;
950 rbuf[i] = (rbuf[i] >> 5) & 0x1f;
951 abuf[i] = (abuf[i] & 0x8000) ? 0 : 255;
954 for(int i = 0; i < 16; i++) {
955 lbuffer1[k] = (abuf[i] == 0) ? lbuffer1[k] : RGBA_COLOR(rbuf[i], gbuf[i], bbuf[i], abuf[i]);
958 } else if(magx > 0) {
959 for(int i = 0; i < 16; i++) {
961 scrntype_t s = RGBA_COLOR(rbuf[i], gbuf[i], bbuf[i], abuf[i]);
962 for(int j = 0; j < magx; j++) {
975 // ToDo: alpha blending
978 scrntype_t *pp = emu->get_screen_buffer(y);
980 my_memcpy(pp, lbuffer1, width * sizeof(scrntype_t));
987 void TOWNS_CRTC::transfer_line(int line)
990 if(line >= TOWNS_CRTC_MAX_LINES) return;
991 if(d_vram == NULL) return;
992 uint8_t ctrl, prio, outc;
993 d_vram->get_vramctrl_regs(ctrl, prio, outc);
995 int trans = ((display_linebuf & 1) == 0) ? 1 : 0;
996 if(linebuffers[trans] == NULL) return;
997 for(int i = 0; i < 2; i++) {
998 linebuffers[trans][line].mode[i] = 0;
999 linebuffers[trans][line].pixels[i] = 0;
1000 linebuffers[trans][line].mag[i] = 0;
1001 linebuffers[trans][line].num[i] = -1;
1004 linebuffers[trans][line].prio = prio;
1005 if((prio & 0x01) == 0) {
1012 if((ctrl & 0x10) == 0) { // One layer mode
1013 bool to_disp = false;
1014 linebuffers[trans][line].num[0] = 0;
1015 if(!(frame_in[0])) return;
1016 switch(ctrl & 0x0f) {
1018 linebuffers[trans][line].mode[0] = DISPMODE_256;
1022 linebuffers[trans][line].mode[0] = DISPMODE_32768;
1027 uint32_t offset = vstart_addr[0];
1028 offset = offset + head_address[0];
1029 if(hstart_words[0] >= regs[9]) {
1030 offset = offset + hstart_words[0] - regs[9];
1033 offset = offset & 0x7ffff; // OK?
1035 uint16_t _begin = regs[9]; // HDS0
1036 uint16_t _end = regs[10]; // HDE0
1038 int words = _end - _begin;
1039 if(hstart_words[0] >= regs[9]) {
1040 words = words - (hstart_words[0] - regs[9]);
1042 uint8_t magx = zoom_factor_horiz[0];
1043 uint8_t *p = d_vram->get_vram_address(offset);
1044 if((p != NULL) && (words >= magx) && (magx != 0)){
1045 memcpy(linebuffers[trans][line].pixels_layer[0], p, words / magx);
1046 switch(linebuffers[trans][line].mode[0]) {
1047 case DISPMODE_32768:
1048 linebuffers[trans][line].pixels[0] = words / (magx * 2);
1049 linebuffers[trans][line].mag[0] = magx;
1052 linebuffers[trans][line].pixels[0] = words / (magx * 1);
1053 linebuffers[trans][line].mag[0] = magx;
1059 if(zoom_count_vert[0] > 0) {
1060 zoom_count_vert[0]--;
1062 if(zoom_count_vert[0] == 0) {
1063 zoom_count_vert[0] = zoom_factor_vert[0];
1064 head_address[0] += frame_offset[0];
1066 } else { // Two layers.
1067 bool to_disp[2] = {false, false};
1068 uint8_t ctrl_b = ctrl;
1069 linebuffers[trans][line].num[0] = page0;
1070 linebuffers[trans][line].num[1] = page1;
1071 for(int l = 0; l < 1; l++) {
1073 switch(ctrl_b & 0x03) {
1075 linebuffers[trans][line].mode[l] = DISPMODE_16;
1079 linebuffers[trans][line].mode[l] = DISPMODE_32768;
1086 for(int l = 0; l < 1; l++) {
1087 if((to_disp[l]) && (frame_in[l])) {
1088 uint32_t offset = vstart_addr[l];
1089 offset = offset + head_address[l];
1090 if(hstart_words[l] >= regs[9 + l * 2]) {
1091 offset = offset + (hstart_words[l] - regs[9 + l * 2]);
1094 offset = offset & 0x3ffff; // OK?
1095 if(l != 0) offset += 0x40000;
1097 uint16_t _begin = regs[9 + l * 2]; // HDSx
1098 uint16_t _end = regs[10 + l * 2]; // HDEx
1100 int words = _end - _begin;
1101 if(hstart_words[l] >= regs[9 + l * 2]) {
1102 words = words - (hstart_words[l] - regs[9 + l * 2]);
1104 uint8_t magx = zoom_factor_horiz[l];
1105 uint8_t *p = d_vram->get_vram_address(offset);
1106 if((p != NULL) && (words >= magx) && (magx != 0)){
1107 memcpy(linebuffers[trans][line].pixels_layer[l], p, words / magx);
1108 switch(linebuffers[trans][line].mode[l]) {
1109 case DISPMODE_32768:
1110 linebuffers[trans][line].pixels[l] = words / (magx * 2);
1111 linebuffers[trans][line].mag[l] = magx;
1114 linebuffers[trans][line].pixels[l] = (words * 2) / (magx * 1);
1115 linebuffers[trans][line].mag[l] = magx;
1122 if(zoom_count_vert[l] > 0) {
1123 zoom_count_vert[l]--;
1125 if(zoom_count_vert[l] == 0) {
1126 zoom_count_vert[l] = zoom_factor_vert[l];
1127 head_address[l] += frame_offset[l];
1134 void TOWNS_CRTC::event_pre_frame()
1136 // ToDo: Resize frame buffer.
1139 void TOWNS_CRTC::update_timing(int new_clocks, double new_frames_per_sec, int new_lines_per_frame)
1141 cpu_clocks = new_clocks;
1142 frames_per_sec = new_frames_per_sec;
1143 max_lines = new_lines_per_frame;
1144 max_frame_usec = 1.0e6 / frames_per_sec;
1147 void TOWNS_CRTC::event_callback(int event_id, int err)
1150 * Related CRTC registers:
1151 * HST, HSW1, HSW2 : HSYNC
1152 * VST, VST1, VST2 : VSYNC
1153 * (EET: for interlace : still not implement)
1154 * VDS0, VDE0, HDS0, HDE0 : Display timing for Layer0
1155 * VDS1, VDE1, HDS1, HDE1 : Display timing for Layer1
1156 * FA0, HAJ0, LO0, FO0 : ToDo (For calculating address)
1157 * FA1, HAJ1, LO1, FO1 : ToDo (For calculating address)
1160 int eid2 = (event_id / 2) * 2;
1161 if(event_id == EVENT_CRTC_VSTART) {
1162 d_vram->write_signal(SIG_TOWNS_VRAM_VSTART, 0x01, 0x01);
1163 line_count[0] = line_count[1] = 0;
1164 if((horiz_us != next_horiz_us) || (vert_us != next_vert_us)) {
1165 horiz_us = next_horiz_us;
1166 vert_us = next_vert_us;
1169 for(int i = 0; i < 2; i++) {
1171 zoom_count_vert[i] = zoom_factor_vert[i];
1173 major_line_count = -1;
1175 register_event(this, EVENT_CRTC_VSTART, frame_us, false, &event_id_frame);
1176 if(vert_sync_pre_us >= 0.0) {
1178 register_event(this, EVENT_CRTC_VST1, vert_sync_pre_us, false, &event_id_vst1); // VST1
1182 register_event(this, EVENT_CRTC_VST2, vst2_us, false, &event_id_vst2);
1183 for(int i = 0; i < 2; i++) {
1184 frame_in[i] = false;
1185 if(event_id_vds[i] != -1) {
1186 cancel_event(this, event_id_vds[i]);
1188 if(event_id_vde[i] != -1) {
1189 cancel_event(this, event_id_vde[i]);
1191 if(vert_start_us[i] > 0.0) {
1192 register_event(this, EVENT_CRTC_VDS + i, vert_start_us[i], false, &event_id_vds[i]); // VDSx
1196 if(vert_end_us[i] > 0.0) {
1197 register_event(this, EVENT_CRTC_VDE + i, vert_end_us[i], false, &event_id_vde[i]); // VDEx
1199 head_address[i] = 0;
1202 if(event_id_hstart != -1) {
1203 cancel_event(this, event_id_hstart);
1204 event_id_hstart = -1;
1206 if(event_id_hsw != -1) {
1207 cancel_event(this, event_id_hsw);
1210 register_event(this, EVENT_CRTC_HSTART, horiz_us, false, &event_id_hstart); // HSTART
1211 } else if(event_id == EVENT_CRTC_VST1) { // VSYNC
1213 } else if (event_id == EVENT_CRTC_VST2) {
1216 } else if(eid2 == EVENT_CRTC_VDS) { // Display start
1217 int layer = event_id & 1;
1218 frame_in[layer] = true;
1220 event_id_vstart[layer] = -1;
1221 zoom_count_vert[layer] = zoom_factor_vert[layer];
1222 } else if(eid2 == EVENT_CRTC_VDE) { // Display end
1223 int layer = event_id & 1;
1224 frame_in[layer] = false;
1225 event_id_vend[layer] = -1;
1227 } else if(event_id == EVENT_CRTC_HSTART) {
1229 event_id_hstart = -1;
1233 if(event_id_hsw != -1) {
1234 cancel_event(this, event_id_hsw);
1239 register_event(this, EVENT_CRTC_HSW, horiz_width_posi_us, false, &event_id_hsw); // VDEx
1242 register_event(this, EVENT_CRTC_HSW, horiz_width_nega_us, false, &event_id_hsw); // VDEx
1244 for(int i = 0; i < 2; i++) {
1245 if(event_id_hds[i] != -1) {
1246 cancel_event(this, event_id_hds[i]);
1248 event_id_hds[i] = -1;
1249 if(event_id_hde[i] != -1) {
1250 cancel_event(this, event_id_hde[i]);
1252 event_id_hde[i] = -1;
1254 if(horiz_start_us[i] > 0.0) {
1255 register_event(this, EVENT_CRTC_HDS + i, horiz_start_us[i], false, &event_id_hds[i]); // HDS0
1259 if((horiz_end_us[i] > 0.0) && (horiz_end_us[i] > horiz_start_us[i])) {
1260 register_event(this, EVENT_CRTC_HDE + i, horiz_end_us[i], false, &event_id_hde[i]); // HDS0
1263 register_event(this, EVENT_CRTC_HSTART, horiz_us, false, &event_id_hstart); // HSTART
1264 } else if(event_id == EVENT_CRTC_HSW) {
1267 transfer_line(major_line_count - 1);
1268 } else if(eid2 == EVENT_CRTC_HDS) {
1269 int layer = event_id & 1;
1270 hdisp[layer] = true;
1271 if((horiz_end_us[i] <= 0.0) || (horiz_end_us[i] <= horiz_start_us[i])) {
1272 hdisp[layer] = false;
1274 event_id_hds[layer] = -1;
1275 } else if(eid2 == EVENT_CRTC_HDE) {
1276 int layer = event_id & 1;
1277 hdisp[layer] = false;
1278 event_id_hde[layer] = -1;
1283 void TOWNS_CRTC::write_signal(int ch, uint32_t data, uint32_t mask)
1285 if(ch == SIG_TONWS_CRTC_SINGLE_LAYER) {
1286 one_layer_mode = ((data & mask) == 0);
1290 #define STATE_VERSION 1
1292 void TOWNS_CRTC::save_state(FILEIO* state_fio)
1294 state_fio->FputUint32(STATE_VERSION);
1295 state_fio->FputInt32(this_device_id);
1296 state_fio->Fwrite(regs, sizeof(regs), 1);
1297 state_fio->Fwrite(regs_written, sizeof(regs_written), 1);
1298 state_fio->FputInt32(ch);
1299 state_fio->FputBool(timing_changed);
1300 state_fio->FputInt32(cpu_clocks);
1301 #if defined(TOWNS_CRTC_CHAR_CLOCK)
1302 state_fio->FputDouble(char_clock);
1303 state_fio->FputDouble(next_char_clock);
1304 #elif defined(TOWNS_CRTC_HORIZ_FREQ)
1305 state_fio->FputDouble(horiz_freq);
1306 state_fio->FputDouble(next_horiz_freq);
1308 state_fio->FputDouble(frames_per_sec);
1309 state_fio->FputInt32(hz_total);
1310 state_fio->FputInt32(hz_disp);
1311 state_fio->FputInt32(hs_start);
1312 state_fio->FputInt32(hs_end);
1313 state_fio->FputInt32(vt_total);
1314 state_fio->FputInt32(vt_disp);
1315 state_fio->FputInt32(vs_start);
1316 state_fio->FputInt32(vs_end);
1317 state_fio->FputInt32(disp_end_clock);
1318 state_fio->FputInt32(hs_start_clock);
1319 state_fio->FputInt32(hs_end_clock);
1320 state_fio->FputBool(display);
1321 state_fio->FputBool(vblank);
1322 state_fio->FputBool(vsync);
1323 state_fio->FputBool(hsync);
1326 bool TOWNS_CRTC::load_state(FILEIO* state_fio)
1328 if(state_fio->FgetUint32() != STATE_VERSION) {
1331 if(state_fio->FgetInt32() != this_device_id) {
1334 state_fio->Fread(regs, sizeof(regs), 1);
1335 state_fio->Fread(regs_written, sizeof(regs_written), 1);
1336 ch = state_fio->FgetInt32();
1337 timing_changed = state_fio->FgetBool();
1338 cpu_clocks = state_fio->FgetInt32();
1339 #if defined(TOWNS_CRTC_CHAR_CLOCK)
1340 char_clock = state_fio->FgetDouble();
1341 next_char_clock = state_fio->FgetDouble();
1342 #elif defined(TOWNS_CRTC_HORIZ_FREQ)
1343 horiz_freq = state_fio->FgetDouble();
1344 next_horiz_freq = state_fio->FgetDouble();
1346 frames_per_sec = state_fio->FgetDouble();
1347 hz_total = state_fio->FgetInt32();
1348 hz_disp = state_fio->FgetInt32();
1349 hs_start = state_fio->FgetInt32();
1350 hs_end = state_fio->FgetInt32();
1351 vt_total = state_fio->FgetInt32();
1352 vt_disp = state_fio->FgetInt32();
1353 vs_start = state_fio->FgetInt32();
1354 vs_end = state_fio->FgetInt32();
1355 disp_end_clock = state_fio->FgetInt32();
1356 hs_start_clock = state_fio->FgetInt32();
1357 hs_end_clock = state_fio->FgetInt32();
1358 display = state_fio->FgetBool();
1359 vblank = state_fio->FgetBool();
1360 vsync = state_fio->FgetBool();
1361 hsync = state_fio->FgetBool();