OSDN Git Service

fix typo
[csp-qt/common_source_project-fm7.git] / source / src / vm / fmtowns / towns_crtc.cpp
1 /*
2         Skelton for retropc emulator
3
4         Author : Kyuma Ohta <whatisthis.sowhat _at_ gmail.com>
5         Date   : 2016.12.28 -
6
7         [ FM-Towns CRTC ]
8         History: 2016.12.28 Initial from HD46505 .
9 */
10
11 #include "towns_crtc.h"
12
13 namespace FMTOWNS {
14 enum {
15         EVENT_CRTC_VSTART = 1,
16         EVENT_CRTC_VST1   = 2,
17         EVENT_CRTC_VST2   = 3,
18         EVENT_CRTC_HSTART = 4,
19         EVENT_CRTC_HEND   = 5,
20         EVENT_CRTC_HSW    = 6,
21         EVENT_CRTC_EET    = 7,
22         EVENT_CRTC_VDS    = 32,
23         EVENT_CRTC_VDE    = 34,
24         EVENT_CRTC_HDS    = 36,
25         EVENT_CRTC_HDE    = 38,
26         
27 };
28
29
30 void TOWNS_CRTC::initialize()
31 {
32         memset(regs, 0, sizeof(regs));
33         memset(regs_written, 0, sizeof(regs_written));
34
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;
39         }
40         event_id_hsync = -1;
41         event_id_hsw = -1;
42         event_id_vsync = -1;
43         event_id_vstart = -1;
44         event_id_vst1 = -1;
45         event_id_vst2 = -1;
46         event_id_vblank = -1;
47
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));
54                         }
55                 }
56         }
57         // register events
58         //register_frame_event(this);
59         //register_vline_event(this);
60         
61 }
62
63 void TOWNS_CRTC::release()
64 {
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]);
68         }
69 }
70
71 void TOWNS_CRTC::reset()
72 {
73         // initialize
74         display = false;
75         vblank = vsync = hsync = true;
76         
77 //      memset(regs, 0, sizeof(regs));
78         ch = 0;
79         
80         // initial settings for 1st frame
81 #ifdef CHARS_PER_LINE
82         hz_total = (CHARS_PER_LINE > 54) ? CHARS_PER_LINE : 54;
83 #else
84         hz_total = 54;
85 #endif
86         hz_disp = (hz_total > 80) ? 80 : 40;
87         hs_start = hz_disp + 4;
88         hs_end = hs_start + 4;
89         
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;
94         
95         timing_changed = false;
96         disp_end_clock = 0;
97         
98 #if defined(TOWNS_CRTC_CHAR_CLOCK)
99         char_clock = 0;
100         next_char_clock = TOWNS_CRTC_CHAR_CLOCK;
101 #elif defined(TOWNS_CRTC_HORIZ_FREQ)
102         horiz_freq = 0;
103         next_horiz_freq = TOWNS_CRTC_HORIZ_FREQ;
104 #endif
105
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;
112         }
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);
120         
121         event_id_hsw = -1;
122         event_id_vsync = -1;
123         event_id_vstart = -1;
124         event_id_vst1 = -1;
125         event_id_vst2 = -1;
126         event_id_vblank = -1;
127
128         // Register vstart
129         register_event(this, EVENT_CRTC_VSTART, vstart_us, false, &event_id_vstart);
130 }
131 // CRTC register #29
132 void TOWNS_CRTC::set_crtc_clock(uint16_t val)
133 {
134         scsel = (val & 0x0c) >> 2;
135         clksel = val & 0x03;
136         static const double clocks[] = {
137                 28.6363e6, 24.5454e6, 25.175e6, 21.0525e6
138         };
139         if(crtc_clock[clksel] != crtc_clock) {
140                 crtc_clock = crtc_clock[clksel];
141                 force_recalc_crtc_param();
142         }
143 }
144
145 void TOWNS_CRTC::force_recalc_crtc_param(void)
146 {
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
151
152         double horiz_ref = horiz_us / 2.0;
153         
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
157
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
163         }
164                 
165 }
166
167
168 void TONWS_CRTC::write_io8(uint32_t addr, uint32_t data)
169 {
170         if(addr == 0x0440) {
171                 ch = data & 0x1f;
172         } else if(addr == 0x0442) {
173                 pair16_t rdata;
174                 rdata.w = regs[ch];
175                 rdata.l = (uint8_t)data;
176                 write_io16(addr, rdata.w);
177         } else if(addr == 0x0443) {
178                 pair16_t rdata;
179                 rdata.w = regs[ch];
180                 rdata.h = (uint8_t)data;
181                 write_io16(addr, rdata.w);
182         }               
183 }
184
185 void TOWNS_CRTC::write_io16(uint32_t addr, uint32_t data)
186 {
187         if((addr & 0xfffe) == 0x0442) {
188                 if(ch < 32) {
189                         if((ch < 0x09) && ((ch >= 0x04) || (ch <= 0x01))) { // HSW1..VST
190                                 if(regs[ch] != (uint16_t)data) {
191                                         force_recalc_crtc_param();
192                                 }
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();
199                                 }
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;
205                                         switch(localreg) {
206                                         case 0: // FAx
207                                                 vstart_addr[localch] = (uint32_t)(data & 0xffff);
208                                                 break;
209                                         case 1: // HAJx
210                                                 hstart_words[localch] = (uint32_t)(data & 0x07ff);
211                                                 break;
212                                         case 2: // FOx
213                                                 frame_offet[localch] = (uint32_t)(data & 0xffff);
214                                                 break;
215                                         case 3: // LOx
216                                                 line_offet[localch] = (uint32_t)(data & 0xffff);
217                                                 break;
218                                         }                                       
219                                 }
220                         } else  { // All reg
221                                 if(regs[ch] != (uint16_t)data) {
222                                         switch(ch - 0x19) {
223                                         case 0: // EHAJ
224                                         case 1: // EVAJ
225                                                 // ToDo: External SYNC.
226                                                 break;
227                                         case 2: // ZOOM
228                                                 {
229                                                         uint8_t zfv[2];
230                                                         uint8_t zfh[2];
231                                                         pair16_t pd;
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];
241                                                         }
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];
246                                                         }
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];
251                                                 }
252                                                 break;
253                                         case 3: // CR0
254                                                 if(regs[ch] != data) {
255                                                         if((data & 0x8000) == 0) {
256                                                                 // START BIT
257                                                                 restart_display();
258                                                         } else {
259                                                                 stop_display();
260                                                         }
261                                                         if((data & 0x4000) == 0) {
262                                                                 // ESYN BIT
263                                                                 // EXTERNAL SYNC OFF
264                                                         } else {
265                                                                 // EXTERNAL SYNC ON
266                                                         }
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);
271                                                         uint8_t dmode[2];
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]);
278                                                                 }
279                                                                 display_mode[i] = dmode[i];
280                                                         }
281                                                 }
282                                                 break;
283                                         case 4: // CR1
284                                                 set_crtc_clock((uint16_t)data);
285                                                 break;
286                                         case 5: // Reserved(REG#30)
287                                                 break;
288                                         case 6: // CR2
289                                                 // ToDo: External trigger.
290                                                 break;
291                                         }
292                                 }
293                         }
294                         regs[ch] = (uint16_t)data;
295                 }
296         } else if(addr == 0x0440) {
297                 ch = data & 0x1f;
298         }
299 }
300
301 uint16_t TOWNS_CRTC::read_reg30()
302 {
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);
316         
317 }
318
319 uint32_t TOWNS_CRTC::read_io16(uint32_t addr)
320 {
321         addr = addr & 0xfffe;
322         if(addr == 0x0440) {
323                 return (uint32_t)ch;
324         } else if(addr == 0x0442) {
325                 if(ch == 30) {
326                         return (uint32_t)read_reg30();
327                 } else {
328                         return regs[ch];
329                 }
330         }
331         return 0xffff;
332 }
333
334 uint32_t TOWNS_CRTC::read_io8(uint32_t addr)
335 {
336         if(addr == 0x0440) {
337                 return (uint32_t)ch;
338         } else if(addr == 0x0442) {
339                 pair16_t d;
340                 if(ch == 30) {
341                         d.w = read_reg32();
342                 } else {
343                         d.w = regs[ch];
344                 }
345                 return (uint32_t)(d.l);
346         } else if(addr == 0x0443) {
347                 pair16_t d;
348                 if(ch == 30) {
349                         d.w = read_reg32();
350                 } else {
351                         d.w = regs[ch];
352                 }
353                 return (uint32_t)(d.h);
354         }
355         return 0xff;
356 }
357
358 void TOWNS_CRTC::render_32768(scrntype_t* dst, scrntype_t *mask, uint8_t* src, int y, int width, int layer)
359 {
360         if(dst == NULL) return;
361         if(mask == NULL) return;
362         if(src == NULL) return;
363         
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];
368         scrntype_t *q = dst;
369         scrntype_t *r = mask;
370         if(magx < 1) return;
371         if((pwidth * magx) > width) {
372                 pwidth = width / magx;
373                 if((width % magx) != 0) {
374                         pwidth++;
375                 }
376         }
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];
384         
385         int k = 0;
386         for(x = 0; x < (pwidth >> 3); x++) {
387                 for(int i = 0; i < 8; i++) {
388                         pbuf[i] = read_2bytes_le_from(p);
389                         p += 2;
390                 }
391                 for(int i = 0; i < 8; i++) {
392                         rbuf[i] = pbuf[i];
393                         gbuf[i] = pbuf[i];
394                         bbuf[i] = pbuf[i];
395                 }                       
396                 for(int i = 0; i < 8; i++) {
397                         rbuf[i] = rbuf[i] >> 5;
398                         gbuf[i] = gbuf[i] >> 10;
399                 }                       
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;
404                 }
405                 for(int i = 0; i < 8; i++) {
406                         rbuf[i] <<= 3;
407                         gbuf[i] <<= 3;
408                         bbuf[i] <<= 3;
409                 }
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;
413                 }
414                 for(int i = 0; i < 8; i++) {
415                         sbuf[i] = RGBA_COLOR(rbuf[i], gbuf[i], bbuf[i], a2buf[i]);
416                 }
417                 if(magx == 1) {
418                         for(int i = 0; i < 8; i++) {
419                                 *q++ = sbuf[i];
420                         }
421                         for(int i = 0; i < rwidth; i++) {
422                                 *r++ = abuf[i];
423                         }
424                         k += 8;
425                         if(k >= width) break;
426                 } else {
427                         for(int i = 0; i < 8; i++) {
428                                 if(j = 0; j < magx; j++) {
429                                         *q++ = sbuf[i];
430                                         *r++ = abuf[i];
431                                         k++;
432                                         if(k >= width) break;
433                                 }
434                                 if(k >= width) break;
435                         }
436                 }
437         }
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);
443                         p += 2;
444                 }
445                 for(int i = 0; i < rwidth; i++) {
446                         rbuf[i] = pbuf[i];
447                         gbuf[i] = pbuf[i];
448                         bbuf[i] = pbuf[i];
449                 }                       
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;
454                 }
455                 for(int i = 0; i < rwidth; i++) {
456                         rbuf[i] <<= 3;
457                         gbuf[i] <<= 3;
458                         bbuf[i] <<= 3;
459                 }
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;
463                 }
464                 for(int i = 0; i < rwidth; i++) {
465                         sbuf[i] = RGBA_COLOR(rbuf[i], gbuf[i], bbuf[i], a2buf[i]);
466                 }
467                 if(magx == 1) {
468                         for(int i = 0; i < rwidth; i++) {
469                                 *q++ = sbuf[i];
470                         }
471                         for(int i = 0; i < rwidth; i++) {
472                                 *r++ = abuf[i];
473                         }
474                         k += 8;
475                         if(k >= width) break;
476                 } else {
477                         for(int i = 0; i < rwidth; i++) {
478                                 if(j = 0; j < magx; j++) {
479                                         *q++ = sbuf[i];
480                                         *r++ = abuf[i];
481                                         k++;
482                                         if(k >= width) break;
483                                 }
484                                 if(k >= width) break;
485                         }
486                 }
487         }
488 }
489
490 void TOWNS_CRTC::render_16(scrntype_t* dst, scrntype_t *mask, uint8_t* src, scrntype_t* pal, int y, int width, int layer)
491 {
492         if(dst == NULL) return;
493         if(mask == NULL) return;
494         if(src == NULL) return;
495         if(pal == NULL) return;
496         
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];
501         scrntype_t *q = dst;
502         scrntype_t *r = mask;
503         if(magx < 1) return;
504         if((pwidth * magx) > width) {
505                 pwidth = width / magx;
506                 if((width % magx) != 0) {
507                         pwidth++;
508                 }
509         }
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];
514         
515         int k = 0;
516         for(x = 0; x < (pwidth >> 3); x++) {
517                 for(int i = 0; i < 8; i++) {
518                         pbuf[i] = *p++;
519                 }
520                 for(int i = 0; i < 16; i += 2) {
521                         hlbuf[i] = pbuf[i >> 1];
522                         hlbuf[i + 1] = pbuf[i >> 1];
523                 }                       
524                 for(int i = 0; i < 16; i += 2) {
525                         hlbuf[i] >>= 4;;
526                         hlbuf[i + 1] = hlbuf[i + 1] & 15;
527                 }
528                 for(int i = 0; i < 16; i++) {
529                         abuf[i] = (hlbuf[ii] == 0) ? 0 : (scrntype_t)(-1);
530                 }
531                 for(int i = 0; i < 16; i++) {
532                         sbuf[i] = (hlbuf[i] == 0) ? RGBA_COLOR(0, 0, 0, 0) : pal[hlbuf[i]];
533                 }
534                 if(magx == 1) {
535                         for(int i = 0; i < 16; i++) {
536                                 *q++ = sbuf[i];
537                         }
538                         for(int i = 0; i < 16; i++) {
539                                 *r++ = abuf[i];
540                         }
541                         k += 16;
542                         if(k >= width) break;
543                 } else {
544                         for(int i = 0; i < 16; i++) {
545                                 if(j = 0; j < magx; j++) {
546                                         *q++ = sbuf[i];
547                                         *r++ = abuf[i];
548                                         k++;
549                                         if(k >= width) break;
550                                 }
551                                 if(k >= width) break;
552                         }
553                 }
554         }
555         if(k >= width) return;
556         int rwidth = pwidth & 7;
557         uint8_t tmpp;
558         uint8_t tmph;
559         uint8_t tmpl;
560         if(rwidth > 0) {
561                 for(x = 0; x < rwidth; x++) {
562                         tmpp = *p++;
563                         tmph = tmpp >> 4;
564                         tmpl = tmpp & 0x0f;
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];
569
570                         if(magx == 1) {
571                                 *q++ = sbuf[0];
572                                 *r++ = ah;
573                                 k++;
574                                 if(k >= width) break;
575                                 *q++ = sbuf[1];
576                                 *r++ = al;
577                                 k++;
578                                 if(k >= width) break;
579                         } else {
580                                 for(int j = 0; j < magx; j++) {
581                                         *q++ = sbuf[0];
582                                         *r++ = ah;
583                                         k++;
584                                         if(k >= width) break;
585                                 }
586                                 if(k >= width) break;
587                                 for(int j = 0; j < magx; j++) {
588                                         *q++ = sbuf[1];
589                                         *r++ = al;
590                                         k++;
591                                         if(k >= width) break;
592                                 }
593                                 if(k >= width) break;
594                         }
595                 }
596         }
597 }
598
599 void TOWNS_CRTC::draw_screen()
600 {
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];
605         
606         {
607                 vm->lock_vm();
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);
611                 vm->unlock_vm();
612         }
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];
621         
622         scrntype_t *dst;
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));
627
628                 if(linebuffers[trans].mode[0] == DISPMODE_256) {
629                         // 256 colors
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];
636                         if(magx < 1) return;
637                         if(magx == 1) {
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++) {
642                                                 pbuf[i] = *p++;
643                                         }
644                                         int xx = x << 4;
645                                         for(int i = 0; i < 16; i++) {
646                                                 lbuffer1[xx++] = apal256[pbuf[i]];
647                                         }
648                                 }
649                                 if((pwidth & 15) != 0) {
650                                         int xx = pwidth & ~15;
651                                         int w = pwidth & 15;
652                                         for(int i = 0; i < w; i++) {
653                                                 pbuf[i] = p++;
654                                         }
655                                         for(int i = 0; i < w; i++) {
656                                                 lbuffer1[xx++] = apal256[pbuf[i]];
657                                         }
658                                 }
659                         } else {
660                                 if((pwidth * magx) > width) {
661                                         pwidth = width / magx;
662                                         if((width % magx) != 0) pwidth++;
663                                 }
664                                 int k = 0;
665                                 for(int x = 0; x < (pwidth >> 4); x++) {
666                                         // ToDo: Start position
667                                         for(int i = 0; i < 16; i++) {
668                                                 pbuf[i] = *p++;
669                                         }
670                                         for(int i = 0; i < 16; i++) {
671                                             sbuf[i] = apal256[pbuf[i]];
672                                         }
673                                         for(int i = 0; i < 16; i++) {
674                                                 scrntype_t s = sbuf[i];
675                                                 for(int j = 0; j < magx; j++) {
676                                                         lbuffer1[k++] = s;
677                                                 }
678                                         }
679                                 }
680                                 if((pwidth & 15) != 0) {
681                                         for(int i = 0; i < (pwidth & 15); i++) {
682                                                 pbuf[i] = *p++;
683                                         }
684                                         for(int i = 0; i < (pwidth & 15); i++) {
685                                             sbuf[i] = apal256[pbuf[i]];
686                                         }
687                                         for(int i = 0; i < (pwidth & 15); i++) {
688                                                 scrntype_t s = sbuf[i];
689                                                 for(int j = 0; j < magx; j++) {
690                                                         lbuffer1[k++] = s;
691                                                         if(k >= width) break;
692                                                 }
693                                                 if(k > width) break;
694                                         }
695                                 }
696                         }
697                 } else {
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];
708                         if(magx < 1) return;
709                         if(pwidth > width) pwidth = width;
710                         if(linebuffers[trans].mode[1] == DISPMODE_16) { // Lower layer
711                                 int k = 0;
712                                 for(int x = 0; x < (pwidth >> 5); x++) {
713                                         for(int i = 0; i < 16; i++) {
714                                                 p8buf[i] = *p++;
715                                         }
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;
719                                         }
720                                         for(int i = 0; i < 32; i++) {
721                                                 sbuf[i] = apal16[num][hlbuf[i]];
722                                         }
723                                         if(magx == 1) {
724                                                 for(int i = 0; i < 32; i++) {
725                                                         lbuffer1[k++] = sbuf[i];
726                                                         if(k > width) break;
727                                                 }
728                                         } else {
729                                                 for(int i = 0; i < 32; i++) {
730                                                         for(int j = 0; j < magx; j++) {
731                                                                 lbuffer1[k++] = sbuf[i];
732                                                                 if(k > width) break;
733                                                         }
734                                                         if(k > width) break;
735                                                 }
736                                         }
737                                 }
738                                 if((pwidth & 31) >= 2) {
739                                         for(int x = 0; x < ((pwidth & 31) >> 1); x++) {
740                                                 p8buf[x] = *p++;
741                                         }
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;
745                                         }
746                                         for(int i = 0; i < (pwidth & 0x1f); i++) {
747                                                 sbuf[i] = apal16[num][hlbuf[i]];
748                                         }
749                                         if(magx == 1) {
750                                                 for(int i = 0; i < (pwidth & 0x1f); i++) {
751                                                         lbuffer1[k++] = sbuf[i];
752                                                         if(k > width) break;
753                                                 }
754                                         } else {
755                                                 for(int i = 0; i < (pwidth & 0x1f); i++) {
756                                                         for(int j = 0; j < magx; j++) {
757                                                                 lbuffer1[k++] = sbuf[i];
758                                                                 if(k > width) break;
759                                                         }
760                                                         if(k > width) break;
761                                                 }
762                                         }
763                                 }
764                         } else if(linebuffers[trans].mode[1] == DISPMODE_32768) { // Lower layer
765                                 uint16_t* q = (uint16_t*)p;
766                                 int k = 0;
767                                 pair16_t n;
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);
771                                                 p += 2;
772                                         }
773                                         for(int i = 0; i < 16; i++) {
774                                                 gbuf[i] = rbuf[i];
775                                                 bbuf[i] = rbuf[i];
776                                                 abuf[i] = rbuf[i];
777                                         }
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;
783                                         }
784                                         if(magx == 1) {
785                                                 for(int i = 0; i < 16; i++) {
786                                                         lbuffer1[k++] = RGBA_COLOR(rbuf[i], gbuf[i], bbuf[i], abuf[i]);
787                                                 }
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++) {
792                                                                 lbuffer1[k++] = s;
793                                                                 if(k > width) break;
794                                                         }
795                                                         if(k > width) break;
796                                                 }
797                                         }
798                                 }
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);
802                                                 p += 2;
803                                         }
804                                         for(int i = 0; i < 16; i++) {
805                                                 gbuf[i] = rbuf[i];
806                                                 bbuf[i] = rbuf[i];
807                                                 abuf[i] = rbuf[i];
808                                         }
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;
814                                         }
815                                         if(magx == 1) {
816                                                 for(int i = 0; i < 16; i++) {
817                                                         lbuffer1[k++] = RGBA_COLOR(rbuf[i], gbuf[i], bbuf[i], abuf[i]);
818                                                 }
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++) {
823                                                                 lbuffer1[k++] = s;
824                                                                 if(k > width) break;
825                                                         }
826                                                         if(k > width) break;
827                                                 }
828                                         }
829                                 }
830                         }
831                         // Upper layer
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];
836                         if(magx < 1) return;
837                         if(pwidth > width) pwidth = width;
838                         // ToDo: alpha blending by GPU
839                         if(linebuffers[trans].mode[0] == DISPMODE_16) { // Upper layer
840                                 int k = 0;
841                                 for(int x = 0; x < (pwidth >> 5); x++) {
842                                         for(int i = 0; i < 16; i++) {
843                                                 p8buf[i] = *p++;
844                                         }
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;
848                                         }
849                                         for(int i = 0; i < 32; i++) {
850                                                 sbuf[i] = apal16[num][hlbuf[i]];
851                                         }
852                                         if(magx == 1) {
853                                                 for(int i = 0; i < 32; i++) {
854                                                         lbuffer1[k] = (hlbuf[i] == 0) ? lbuffer1[k] : sbuf[i];
855                                                         k++;
856                                                         if(k > width) break;
857                                                 }
858                                         } else {
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];
862                                                                 k++;
863                                                                 if(k > width) break;
864                                                         }
865                                                         if(k > width) break;
866                                                 }
867                                         }
868                                 }
869                                 if((pwidth & 31) >= 2) {
870                                         for(int x = 0; x < ((pwidth & 31) >> 1); x++) {
871                                                 p8buf[x] = *p++;
872                                         }
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;
876                                         }
877                                         for(int i = 0; i < (pwidth & 0x1f); i++) {
878                                                 sbuf[i] = apal16[num][hlbuf[i]];
879                                         }
880                                         if(magx == 1) {
881                                                 for(int i = 0; i < (pwidth & 0x1f); i++) {
882                                                         lbuffer1[k] = (hlbuf[i] == 0) ? lbuffer1[k] : sbuf[i];
883                                                         k++;
884                                                         if(k > width) break;
885                                                 }
886                                         } else {
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];
890                                                                 k++;
891                                                                 if(k > width) break;
892                                                         }
893                                                         if(k > width) break;
894                                                 }
895                                         }
896                                 }
897                         } else if(linebuffers[trans].mode[0] == DISPMODE_32768) { // upper layer
898                                 uint16_t* q = (uint16_t*)p;
899                                 int k = 0;
900                                 pair16_t n;
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);
904                                                 p += 2;
905                                         }
906                                         for(int i = 0; i < 16; i++) {
907                                                 gbuf[i] = rbuf[i];
908                                                 bbuf[i] = rbuf[i];
909                                                 abuf[i] = rbuf[i];
910                                         }
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;
916                                         }
917                                         if(magx == 1) {
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]);
920                                                         k++;
921                                                 }
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++) {
927                                                                         lbuffer1[k++] = s;
928                                                                         if(k > width) break;
929                                                                 }
930                                                         } else {
931                                                                 k += magx;
932                                                         }
933                                                         if(k > width) break;
934                                                 }
935                                         }
936                                 }
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);
940                                                 p += 2;
941                                         }
942                                         for(int i = 0; i < 16; i++) {
943                                                 gbuf[i] = rbuf[i];
944                                                 bbuf[i] = rbuf[i];
945                                                 abuf[i] = rbuf[i];
946                                         }
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;
952                                         }
953                                         if(magx == 1) {
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]);
956                                                         k++;
957                                                 }
958                                         } else if(magx > 0) {
959                                                 for(int i = 0; i < 16; i++) {
960                                                         if(abuf[i] != 0) {
961                                                                 scrntype_t s = RGBA_COLOR(rbuf[i], gbuf[i], bbuf[i], abuf[i]);
962                                                                 for(int j = 0; j < magx; j++) {
963                                                                         lbuffer1[k++] = s;
964                                                                         if(k > width) break;
965                                                                 }
966                                                         } else {
967                                                                 k += magx;
968                                                         }
969                                                         if(k > width) break;
970                                                 }
971                                         }
972                                 }
973                         }
974                 }
975                 // ToDo: alpha blending
976                 {
977                         vm->lock_vm();
978                         scrntype_t *pp = emu->get_screen_buffer(y);
979                         if(pp != NULL) {
980                                 my_memcpy(pp, lbuffer1, width * sizeof(scrntype_t));
981                         }
982                         vm->unlock_vm();
983                 }
984         }
985 }
986         
987 void TOWNS_CRTC::transfer_line(int line)
988 {
989         if(line < 0) return;
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);
994         
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;
1002         }
1003         int page0, page1;
1004         linebuffers[trans][line].prio = prio;
1005         if((prio & 0x01) == 0) {
1006                 page0 = 0; // Front
1007                 page1 = 1; // Back
1008         } else {
1009                 page0 = 1;
1010                 page1 = 0;
1011         }
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) {
1017                 case 0x0a:
1018                         linebuffers[trans][line].mode[0] = DISPMODE_256;
1019                         to_disp = true;
1020                         break;
1021                 case 0x0f:
1022                         linebuffers[trans][line].mode[0] = DISPMODE_32768;
1023                         to_disp = true;
1024                         break;
1025                 }
1026                 if(to_disp) {
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];
1031                         }
1032                         offset <<= 3;
1033                         offset = offset & 0x7ffff; // OK?
1034                         // ToDo: HAJ0, LO0
1035                         uint16_t _begin = regs[9]; // HDS0
1036                         uint16_t _end = regs[10];  // HDE0
1037                         if(_begin < _end) {
1038                                 int words = _end - _begin;
1039                                 if(hstart_words[0] >= regs[9]) {
1040                                         words = words - (hstart_words[0] - regs[9]);
1041                                 }
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;
1050                                                 break;
1051                                         case DISPMODE_256:
1052                                                 linebuffers[trans][line].pixels[0] = words / (magx * 1);
1053                                                 linebuffers[trans][line].mag[0] = magx;
1054                                                 break;
1055                                         }
1056                                 }
1057                         }
1058                 }
1059                 if(zoom_count_vert[0] > 0) {
1060                         zoom_count_vert[0]--;
1061                 }
1062                 if(zoom_count_vert[0] == 0) {
1063                         zoom_count_vert[0] = zoom_factor_vert[0];
1064                         head_address[0] += frame_offset[0];
1065                 }
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++) {
1072                         if(frame_in[l]) {
1073                                 switch(ctrl_b & 0x03) {
1074                                 case 0x01:
1075                                         linebuffers[trans][line].mode[l] = DISPMODE_16;
1076                                         to_disp[l] = true;
1077                                         break;
1078                                 case 0x03:
1079                                         linebuffers[trans][line].mode[l] = DISPMODE_32768;
1080                                         to_disp[l] = true;
1081                                         break;
1082                                 }
1083                         }
1084                         ctrl_b >>= 2;
1085                 }
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]);
1092                                 }
1093                                 offset <<= 2;
1094                                 offset = offset & 0x3ffff; // OK?
1095                                 if(l != 0) offset += 0x40000;
1096                                 // ToDo: HAJ0, LO0
1097                                 uint16_t _begin = regs[9 + l * 2]; // HDSx
1098                                 uint16_t _end = regs[10 + l * 2];  // HDEx
1099                                 if(_begin < _end) {
1100                                         int words = _end - _begin;
1101                                         if(hstart_words[l] >= regs[9 + l * 2]) {
1102                                                 words = words - (hstart_words[l] - regs[9 + l * 2]);
1103                                         }
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;
1112                                                         break;
1113                                                 case DISPMODE_16:
1114                                                         linebuffers[trans][line].pixels[l] = (words * 2) / (magx * 1);
1115                                                         linebuffers[trans][line].mag[l] = magx;
1116                                                         break;
1117                                                 }
1118                                         }
1119                                 }
1120                         }
1121                         if(frame_in[l]) {
1122                                 if(zoom_count_vert[l] > 0) {
1123                                         zoom_count_vert[l]--;
1124                                 }
1125                                 if(zoom_count_vert[l] == 0) {
1126                                         zoom_count_vert[l] = zoom_factor_vert[l];
1127                                         head_address[l] += frame_offset[l];
1128                                 }
1129                         }
1130                 }
1131         }
1132 }
1133
1134 void TOWNS_CRTC::event_pre_frame()
1135 {
1136         // ToDo: Resize frame buffer.
1137 }
1138
1139 void TOWNS_CRTC::update_timing(int new_clocks, double new_frames_per_sec, int new_lines_per_frame)
1140 {
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;
1145 }
1146
1147 void TOWNS_CRTC::event_callback(int event_id, int err)
1148 {
1149         /*
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)
1158          * ZOOM (#27) : ToDo
1159          */
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;
1167                 }
1168                 hsync = false;
1169                 for(int i = 0; i < 2; i++) {
1170                         hdisp[i] = false;
1171                         zoom_count_vert[i] = zoom_factor_vert[i];
1172                 }
1173                 major_line_count = -1;
1174                 // ToDo: EET
1175                 register_event(this, EVENT_CRTC_VSTART, frame_us, false, &event_id_frame);
1176                 if(vert_sync_pre_us >= 0.0) {
1177                         vsync = false;
1178                         register_event(this, EVENT_CRTC_VST1, vert_sync_pre_us, false, &event_id_vst1); // VST1
1179                 } else {
1180                         vsync = true;
1181                 }
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]);
1187                         }
1188                         if(event_id_vde[i] != -1) {
1189                                 cancel_event(this, event_id_vde[i]);
1190                         }
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
1193                         } else {
1194                                 frame_in[i] = true;
1195                         }
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
1198                         }
1199                         head_address[i] = 0;
1200                 }
1201                 
1202                 if(event_id_hstart != -1) {
1203                         cancel_event(this, event_id_hstart);
1204                         event_id_hstart = -1;
1205                 }
1206                 if(event_id_hsw != -1) {
1207                         cancel_event(this, event_id_hsw);
1208                         event_id_hsw = -1;
1209                 }
1210                 register_event(this, EVENT_CRTC_HSTART, horiz_us, false, &event_id_hstart); // HSTART
1211         } else if(event_id == EVENT_CRTC_VST1) { // VSYNC
1212                 vsync = true;
1213         } else if (event_id == EVENT_CRTC_VST2) {
1214                 vsync = false;
1215                 event_id_vstn = -1;
1216         } else if(eid2 == EVENT_CRTC_VDS) { // Display start
1217                 int layer = event_id & 1;
1218                 frame_in[layer] = true;
1219                 // DO ofset line?
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;
1226                 // DO ofset line?
1227         } else if(event_id == EVENT_CRTC_HSTART) {
1228                 // Do render
1229                 event_id_hstart = -1;
1230                 major_line_count++;
1231                 hdisp[0] = false;
1232                 hdisp[1] = false;
1233                 if(event_id_hsw != -1) {
1234                         cancel_event(this, event_id_hsw);
1235                         event_id_hsw = -1;
1236                 }
1237                 if(!vsync) {
1238                         hsync = true;
1239                         register_event(this, EVENT_CRTC_HSW, horiz_width_posi_us, false, &event_id_hsw); // VDEx
1240                 } else {
1241                         hsync = true;
1242                         register_event(this, EVENT_CRTC_HSW, horiz_width_nega_us, false, &event_id_hsw); // VDEx
1243                 }
1244                 for(int i = 0; i < 2; i++) {
1245                         if(event_id_hds[i] != -1) {
1246                                 cancel_event(this, event_id_hds[i]);
1247                         }
1248                         event_id_hds[i] = -1;
1249                         if(event_id_hde[i] != -1) {
1250                                 cancel_event(this, event_id_hde[i]);
1251                         }
1252                         event_id_hde[i] = -1;
1253                         
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
1256                         } else {
1257                                 hdisp[i] = true;
1258                         }
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
1261                         }
1262                 }
1263                 register_event(this, EVENT_CRTC_HSTART, horiz_us, false, &event_id_hstart); // HSTART
1264         } else if(event_id == EVENT_CRTC_HSW) {
1265                 hsync = false;
1266                 event_id_hsw = -1;
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;
1273                 }
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;
1279         }
1280
1281 }
1282
1283 void TOWNS_CRTC::write_signal(int ch, uint32_t data, uint32_t mask)
1284 {
1285         if(ch == SIG_TONWS_CRTC_SINGLE_LAYER) {
1286                 one_layer_mode = ((data & mask) == 0);
1287         }
1288 }
1289
1290 #define STATE_VERSION   1
1291
1292 void TOWNS_CRTC::save_state(FILEIO* state_fio)
1293 {
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);
1307 #endif
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);
1324 }
1325
1326 bool TOWNS_CRTC::load_state(FILEIO* state_fio)
1327 {
1328         if(state_fio->FgetUint32() != STATE_VERSION) {
1329                 return false;
1330         }
1331         if(state_fio->FgetInt32() != this_device_id) {
1332                 return false;
1333         }
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();
1345 #endif
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();
1362
1363         return true;
1364 }
1365
1366 }