OSDN Git Service

720086ddf953b90dcb175a4d8b9658bd55170d84
[csp-qt/common_source_project-fm7.git] / source / src / vm / jx / display.cpp
1 /*
2         IBM Japan Ltd PC/JX Emulator 'eJX'
3
4         Author : Takeda.Toshiya
5         Date   : 2011.05.09-
6
7         [ display ]
8 */
9
10
11 #include "display.h"
12 #include "../memory.h"
13
14 void DISPLAY::initialize()
15 {
16         // create pc palette
17         for(int i = 0; i < 16; i++) {
18                 int val = (i & 8) ? 127 : 0;
19                 palette_pc[i] = RGB_COLOR((i & 4) ? 255 : val, (i & 2) ? 255 : val, (i & 1) ? 255 : val);
20         }
21         palette_pc[8] = RGB_COLOR(127, 127, 127);
22         
23         hires_mode = 1;
24 //      prev_width = 640;
25 //      prev_height = 400;
26         
27         cblink = 0;
28         register_frame_event(this);
29 }
30
31 void DISPLAY::reset()
32 {
33         memset(vgarray, 0, sizeof(vgarray));
34         memset(palette, 0, sizeof(palette));
35         vgarray_num = -1;
36         
37         memset(bankreg, 0, sizeof(bankreg));
38         bankreg_num = 0;
39         d_mem->set_memory_r(0x80000, 0xb7fff, kanji);
40         
41         page = 0;
42         d_mem->set_memory_rw(0xb8000, 0xbbfff, vram);
43         d_mem->set_memory_rw(0xbc000, 0xbffff, vram);
44         
45         status = 0x04;
46 }
47
48 void DISPLAY::write_io8(uint32_t addr, uint32_t data)
49 {
50         switch(addr) {
51         case 0x1ff:
52                 if(data & 0xf0) {
53                         if(bankreg_num == 7 && (bankreg[7] & 0x80) != (data & 0x80)) {
54                                 if(data & 0x80) {
55                                         // open kanji rom
56                                 } else {
57                                         // close kanji rom
58                                 }
59                         } else if(bankreg_num == 10 && (bankreg[10] & 0x80) != (data & 0x80)) {
60                                 if(data & 0x80) {
61                                         // open ext-vram
62                                         d_mem->set_memory_rw(0xa0000, 0xaffff, extvram);
63                                 } else {
64                                         // close ext-vram
65                                         d_mem->set_memory_r(0xa0000, 0xaffff, kanji + 0x20000);
66                                         d_mem->unset_memory_w(0xa0000, 0xaffff);
67                                 }
68                         }
69                         bankreg[bankreg_num] = data;
70                 } else {
71                         bankreg_num = data;
72                 }
73                 break;
74         case 0x3da:
75                 if(vgarray_num == -1) {
76                         vgarray_num = data & 0x1f;
77                         break;
78                 } else {
79                         if(vgarray_num < 0x10) {
80                                 vgarray[vgarray_num] = data;
81                         } else {
82                                 palette[vgarray_num & 0x0f] = data & 0x0f;
83                         }
84                         vgarray_num = -1;
85                 }
86                 break;
87         case 0x3dd:
88                 hires_mode = data;
89                 break;
90         case 0x3df:
91                 if((page & 0xb8) != (data & 0xb8)) {
92                         int page1 = data >> 3;
93                         int page2 = (data & 0x80) ? (page1 + 1) : page1;
94                         d_mem->set_memory_rw(0xb8000, 0xbbfff, vram + 0x4000 * (page1 & 7));
95                         d_mem->set_memory_rw(0xbc000, 0xbffff, vram + 0x4000 * (page2 & 7));
96                 }
97                 page = data;
98                 break;
99         }
100 }
101
102 uint32_t DISPLAY::read_io8(uint32_t addr)
103 {
104         switch(addr) {
105         case 0x1ff:
106                 return 0x69;//0x7f;
107         case 0x3da:
108                 vgarray_num = -1; // okay ???
109                 return status;
110         case 0x3dd:
111                 return hires_mode;
112         case 0x3df:
113                 return page;
114         }
115         return 0xff;
116 }
117
118 void DISPLAY::write_signal(int id, uint32_t data, uint32_t mask)
119 {
120         if(id == SIG_DISPLAY_ENABLE) {
121                 if(data & mask) {
122                         status |= 0x11;
123                 } else {
124                         status &= ~0x11;
125                 }
126         } else if(id == SIG_DISPLAY_VBLANK) {
127                 if(data & mask) {
128                         status &= ~0x08;
129                 } else {
130                         status |= 0x08;
131                 }
132         }
133 }
134
135 void DISPLAY::event_frame()
136 {
137         cblink = (cblink + 1) & 0x1f;
138 }
139
140 void DISPLAY::draw_screen()
141 {
142         int mode1 = vgarray[0];
143         int mode2 = vgarray[3];
144         int screen_width, screen_height, window_height_aspect, width;
145         
146         memset(screen, 0, sizeof(screen));
147         
148         // change screen size
149         if((hires_mode & 3) == 1) {
150                 screen_width = width = 640;
151                 screen_height = 400;
152                 window_height_aspect = 480;
153         } else {
154                 screen_width = width = 720;
155                 screen_height = 512;
156                 window_height_aspect = 540;
157         }
158 //      if(!(prev_width == screen_width && prev_height == screen_height)) {
159                 emu->set_vm_screen_size(screen_width, screen_height, screen_width, screen_height, screen_width, window_height_aspect);
160 //              prev_width = screen_width;
161 //              prev_height = screen_height;
162                 
163                 // we need to wait until screen manager updates buffer size
164 //              return;
165 //      }
166         
167         // render screen
168         if((hires_mode & 3) == 1) {
169                 switch(mode1 & 0x1a) {
170                 case 0x08:
171                         if(!(mode1 & 1)) {
172                                 width = 320;    // 40column
173                         }
174                         draw_alpha();
175                         break;
176                 case 0x0a:
177                         if((mode1 & 4) && (mode2 & 8)) {
178                                 draw_graph_640x200_2col();
179                         } else if((page & 0xc0) == 0xc0) {
180                                 draw_graph_640x200_4col();
181                         } else {
182                                 draw_graph_320x200_4col();
183                                 width = 320;
184                         }
185                         break;
186                 case 0x1a:
187                         if(mode1 & 1) {
188                                 draw_graph_320x200_16col();
189                                 width = 320;
190                         } else {
191                                 draw_graph_160x200_16col();
192                                 width = 160;
193                         }
194                         break;
195                 }
196         } else {
197                 switch(hires_mode & 3) {
198                 case 0:
199                         if(!(mode1 & 1)) {
200                                 width = 360;    // 40column
201                         }
202                         draw_alpha();
203                         break;
204                 case 2:
205                         draw_graph_720x512_2col();
206                         break;
207                 case 3:
208 //                      draw_graph_360x512_4col();
209 //                      width = 360;
210                         draw_graph_720x512_2col();
211                         break;
212                 }
213         }
214         
215         // copy to real screen
216         if((hires_mode & 3) == 1) {
217                 for(int y = 0; y < 200; y++) {
218                         scrntype_t* dest0 = emu->get_screen_buffer(y * 2 + 0);
219                         scrntype_t* dest1 = emu->get_screen_buffer(y * 2 + 1);
220                         uint8_t *src = screen[y];
221                         
222                         if(width == 640) {
223                                 for(int x = 0; x < 640; x++) {
224                                         dest0[x] = palette_pc[src[x]];
225                                 }
226                         } else if(width == 320) {
227                                 for(int x = 0, x2 = 0; x < 320; x++, x2 += 2) {
228                                         dest0[x2] = dest0[x2 + 1] = palette_pc[src[x]];
229                                 }
230                         } else if(width == 160) {
231                                 for(int x = 0, x4 = 0; x < 160; x++, x4 += 4) {
232                                         dest0[x4] = dest0[x4 + 1] = dest0[x4 + 2] = dest0[x4 + 3] = palette_pc[src[x]];
233                                 }
234                         }
235                         if(!config.scan_line) {
236                                 my_memcpy(dest1, dest0, 640 * sizeof(scrntype_t));
237                         } else {
238                                 memset(dest1, 0, 640 * sizeof(scrntype_t));
239                         }
240                 }
241                 emu->screen_skip_line(true);
242         } else {
243                 for(int y = 0; y < 512; y++) {
244                         scrntype_t* dest = emu->get_screen_buffer(y);
245                         uint8_t *src = screen[y];
246                         
247                         if(width == 720) {
248                                 for(int x = 0; x < 720; x++) {
249                                         dest[x] = palette_pc[src[x]];
250                                 }
251                         } else if(width == 360) {
252                                 for(int x = 0, x2 = 0; x < 360; x++, x2 += 2) {
253                                         dest[x2] = dest[x2 + 1] = palette_pc[src[x]];
254                                 }
255                         }
256                 }
257                 emu->screen_skip_line(false);
258         }
259 }
260
261 void DISPLAY::draw_alpha()
262 {
263         int src = ((regs[12] << 8) | regs[13]) * 2;
264         int cursor = ((regs[8] & 0xc0) == 0xc0) ? -1 : ((regs[14] << 8) | regs[15]) * 2;
265         int hz_disp = regs[1];
266         int vt_disp = regs[6] & 0x7f;
267         int ch_height = (regs[9] & 0x1f) + 1;
268         int ymax = (ch_height < 16) ? 8 : 16;
269         int shift = (ch_height < 16) ? 0 : 1;
270         int bp = regs[10] & 0x60;
271         
272         uint8_t *vram_ptr = vram + (page & 7) * 0x4000;
273         uint8_t pal_mask = vgarray[1] & 0x0f;
274         
275         int prev_code = 0;
276         
277         for(int y = 0; y < vt_disp; y++) {
278                 int ytop = y * ch_height;
279                 
280                 for(int x = 0; x < hz_disp; x++) {
281                         bool draw_cursor = ((src & 0x3fff) == (cursor & 0x3fff));
282                         int code = vram_ptr[(src++) & 0x3fff];
283                         int attr = vram_ptr[(src++) & 0x3fff];
284                         if(x >= 90) {   // 720dot / 8dot
285                                 continue;
286                         }
287                         int fore_color = palette[(attr     ) & pal_mask];
288                         int back_color = palette[(attr >> 4) & pal_mask];
289                         if((hires_mode & 3) != 1) {
290                                 // hires
291                                 fore_color = (attr & 4) ? 0 : 7;
292                                 back_color = (attr & 4) ? 7 : 0;
293                                 attr = ((attr & 1) ? 0x80 : 0) | ((attr & 2) ? 8 : 0) | 7;
294                         }
295                         int lr = 0, hi, lo;
296                         
297                         if(attr & 0x80) {
298                                 // kanji character
299                                 if(attr & 8) {
300                                         // right side
301                                         hi = prev_code;
302                                         lo = code;
303                                         prev_code = 0;
304                                         lr = 1;
305                                 } else {
306                                         // left side
307                                         hi = code;
308                                         lo = vram_ptr[src & 0x3fff];
309                                         prev_code = code;
310                                 }
311                                 
312                                 // shift-jis -> addr
313                                 code = (hi << 8) | lo;
314                                 if(code < 0x9900) {
315                                         code &= 0x1fff;
316                                 } else {
317                                         code &= 0x1ff;
318                                         code |= 0x400;
319                                 }
320                         }
321                         
322                         uint8_t *pattern;
323                         if(ch_height < 16) {
324                                 pattern = &font[code * 8];
325                         } else {
326                                 pattern = &kanji[code * 32];
327                         }
328                         
329                         for(int l = 0; l < ch_height; l++) {
330                                 if(ytop + l >= 512) {
331                                         break;
332                                 }
333                                 uint8_t pat = (l < ymax) ? pattern[(l << shift) | lr] : 0;
334                                 uint8_t *dest = &screen[ytop + l][x * 8];
335                                 
336                                 dest[0] = (pat & 0x80) ? fore_color : back_color;
337                                 dest[1] = (pat & 0x40) ? fore_color : back_color;
338                                 dest[2] = (pat & 0x20) ? fore_color : back_color;
339                                 dest[3] = (pat & 0x10) ? fore_color : back_color;
340                                 dest[4] = (pat & 0x08) ? fore_color : back_color;
341                                 dest[5] = (pat & 0x04) ? fore_color : back_color;
342                                 dest[6] = (pat & 0x02) ? fore_color : back_color;
343                                 dest[7] = (pat & 0x01) ? fore_color : back_color;
344                         }
345                         
346                         // draw cursor
347                         if(draw_cursor) {
348                                 int s = regs[10] & 0x1f;
349                                 int e = regs[11] & 0x1f;
350                                 if(bp == 0 || (bp == 0x40 && (cblink & 8)) || (bp == 0x60 && (cblink & 0x10))) {
351                                         for(int l = s; l <= e && l < ch_height; l++) {
352                                                 if(ytop + l < 512) {
353                                                         memset(&screen[ytop + l][x * 8], 7, 8);
354                                                 }
355                                         }
356                                 }
357                         }
358                 }
359         }
360 }
361
362 void DISPLAY::draw_graph_160x200_16col()
363 {
364         int src = (regs[12] << 8) | regs[13];
365         
366         uint8_t mask = vgarray[1] & 0x0f;
367         
368         for(int l = 0; l < 2; l++) {
369                 uint8_t *vram_ptr = vram + (page & 7) * 0x4000 + l * 0x2000;
370                 int src2 = src;
371                 
372                 for(int y = 0; y < 200; y += 2) {
373                         uint8_t *dest = screen[y + l];
374                         
375                         for(int x = 0; x < 160; x += 2) {
376                                 uint8_t pat = vram_ptr[(src2++) & 0x1fff];
377                                 
378                                 dest[x    ] = palette[(pat >> 4) & mask];
379                                 dest[x + 1] = palette[(pat     ) & mask];
380                         }
381                 }
382         }
383 }
384
385 void DISPLAY::draw_graph_320x200_4col()
386 {
387         int src = (regs[12] << 8) | regs[13];
388         
389         uint8_t mask = vgarray[1] & 3;
390         
391         for(int l = 0; l < 2; l++) {
392                 uint8_t *vram_ptr = vram + (page & 7) * 0x4000 + l * 0x2000;
393                 int src2 = src;
394                 
395                 for(int y = 0; y < 200; y += 2) {
396                         uint8_t *dest = screen[y + l];
397                         
398                         for(int x = 0; x < 320; x += 4) {
399                                 uint8_t pat = vram_ptr[(src2++) & 0x1fff];
400                                 
401                                 dest[x    ] = palette[(pat >> 6) & mask];
402                                 dest[x + 1] = palette[(pat >> 4) & mask];
403                                 dest[x + 2] = palette[(pat >> 2) & mask];
404                                 dest[x + 3] = palette[(pat     ) & mask];
405                         }
406                 }
407         }
408 }
409
410 void DISPLAY::draw_graph_320x200_16col()
411 {
412         int src = (regs[12] << 8) | regs[13];
413         
414         uint8_t mask = vgarray[1] & 0x0f;
415         
416         for(int l = 0; l < 4; l++) {
417                 uint8_t *vram_ptr = vram + ((page >> 1) & 3) * 0x8000 + l * 0x2000;
418                 int src2 = src;
419                 
420                 for(int y = 0; y < 200; y += 4) {
421                         uint8_t *dest = screen[y + l];
422                         
423                         for(int x = 0; x < 320; x += 2) {
424                                 uint8_t pat = vram_ptr[(src2++) & 0x1fff];
425                                 
426                                 dest[x    ] = palette[(pat >> 4) & mask];
427                                 dest[x + 1] = palette[(pat     ) & mask];
428                         }
429                 }
430         }
431 }
432
433 void DISPLAY::draw_graph_640x200_2col()
434 {
435         int src = (regs[12] << 8) | regs[13];
436         
437         uint8_t mask = vgarray[1] & 1;
438         
439         for(int l = 0; l < 2; l++) {
440                 uint8_t *vram_ptr = vram + (page & 7) * 0x4000 + l * 0x2000;
441                 int src2 = src;
442                 
443                 for(int y = 0; y < 200; y += 2) {
444                         uint8_t *dest = screen[y + l];
445                         
446                         for(int x = 0; x < 640; x += 8) {
447                                 uint8_t pat = vram_ptr[(src2++) & 0x1fff];
448                                 
449                                 dest[x    ] = palette[(pat >> 7) & mask];
450                                 dest[x + 1] = palette[(pat >> 6) & mask];
451                                 dest[x + 2] = palette[(pat >> 5) & mask];
452                                 dest[x + 3] = palette[(pat >> 4) & mask];
453                                 dest[x + 4] = palette[(pat >> 3) & mask];
454                                 dest[x + 5] = palette[(pat >> 2) & mask];
455                                 dest[x + 6] = palette[(pat >> 1) & mask];
456                                 dest[x + 7] = palette[(pat     ) & mask];
457                         }
458                 }
459         }
460 }
461
462 void DISPLAY::draw_graph_640x200_4col()
463 {
464         int src = (regs[12] << 8) | regs[13];
465         
466         uint8_t mask = vgarray[1] & 3;
467         
468         for(int l = 0; l < 4; l++) {
469                 uint8_t *vram_ptr = vram + ((page >> 1) & 3) * 0x8000 + l * 0x2000;
470                 int src2 = src;
471                 
472                 for(int y = 0; y < 200; y += 4) {
473                         uint8_t *dest = screen[y + l];
474                         
475                         for(int x = 0; x < 640; x += 8) {
476                                 uint8_t pat0 = vram_ptr[(src2++) & 0x1fff];
477                                 uint8_t pat1 = vram_ptr[(src2++) & 0x1fff];
478                                 
479                                 dest[x    ] = palette[(((pat0 >> 7) & 1) | ((pat1 >> 6) & 2)) & mask];
480                                 dest[x + 1] = palette[(((pat0 >> 6) & 1) | ((pat1 >> 5) & 2)) & mask];
481                                 dest[x + 2] = palette[(((pat0 >> 5) & 1) | ((pat1 >> 4) & 2)) & mask];
482                                 dest[x + 3] = palette[(((pat0 >> 4) & 1) | ((pat1 >> 3) & 2)) & mask];
483                                 dest[x + 4] = palette[(((pat0 >> 3) & 1) | ((pat1 >> 2) & 2)) & mask];
484                                 dest[x + 5] = palette[(((pat0 >> 2) & 1) | ((pat1 >> 1) & 2)) & mask];
485                                 dest[x + 6] = palette[(((pat0 >> 1) & 1) | ((pat1     ) & 2)) & mask];
486                                 dest[x + 7] = palette[(((pat0 >> 0) & 1) | ((pat1 << 1) & 2)) & mask];
487                         }
488                 }
489         }
490 }
491
492 void DISPLAY::draw_graph_720x512_2col()
493 {
494         static const uint8_t palette2[2] = {0, 7};
495         
496         int src = (regs[12] << 8) | regs[13];
497         
498         uint8_t mask = 1;//vgarray[1] & 1;
499         
500         for(int l = 0; l < 2; l++) {
501                 uint8_t *vram_ptr = extvram + l * 0x8000;
502                 int src2 = src;
503                 
504                 for(int y = 0; y < 512; y += 2) {
505                         uint8_t *dest = screen[y + l];
506                         
507                         for(int x = 0; x < 720; x += 8) {
508                                 uint8_t pat = vram_ptr[(src2++) & 0x7fff];
509                                 
510                                 dest[x    ] = palette2[(pat >> 7) & mask];
511                                 dest[x + 1] = palette2[(pat >> 6) & mask];
512                                 dest[x + 2] = palette2[(pat >> 5) & mask];
513                                 dest[x + 3] = palette2[(pat >> 4) & mask];
514                                 dest[x + 4] = palette2[(pat >> 3) & mask];
515                                 dest[x + 5] = palette2[(pat >> 2) & mask];
516                                 dest[x + 6] = palette2[(pat >> 1) & mask];
517                                 dest[x + 7] = palette2[(pat     ) & mask];
518                         }
519                 }
520         }
521 }
522
523 void DISPLAY::draw_graph_360x512_4col()
524 {
525         // TODO
526 }
527
528 #define STATE_VERSION   1
529
530 bool DISPLAY::process_state(FILEIO* state_fio, bool loading)
531 {
532         if(!state_fio->StateCheckUint32(STATE_VERSION)) {
533                 return false;
534         }
535         if(!state_fio->StateCheckInt32(this_device_id)) {
536                 return false;
537         }
538         state_fio->StateBuffer(vram, sizeof(vram), 1);
539         state_fio->StateBuffer(extvram, sizeof(extvram), 1);
540         state_fio->StateBuffer(vgarray, sizeof(vgarray), 1);
541         state_fio->StateBuffer(palette, sizeof(palette), 1);
542         state_fio->StateInt32(vgarray_num);
543         state_fio->StateBuffer(bankreg, sizeof(bankreg), 1);
544         state_fio->StateInt32(bankreg_num);
545         state_fio->StateUint8(hires_mode);
546         state_fio->StateUint8(page);
547         state_fio->StateUint8(status);
548         state_fio->StateInt32(cblink);
549         return true;
550 }
551
552 bool DISPLAY::process_state(FILEIO* state_fio, bool loading)
553 {
554         if(!state_fio->StateCheckUint32(STATE_VERSION)) {
555                 return false;
556         }
557         if(!state_fio->StateCheckInt32(this_device_id)) {
558                 return false;
559         }
560         state_fio->StateBuffer(vram, sizeof(vram), 1);
561         state_fio->StateBuffer(extvram, sizeof(extvram), 1);
562         state_fio->StateBuffer(vgarray, sizeof(vgarray), 1);
563         state_fio->StateBuffer(palette, sizeof(palette), 1);
564         state_fio->StateInt32(vgarray_num);
565         state_fio->StateBuffer(bankreg, sizeof(bankreg), 1);
566         state_fio->StateInt32(bankreg_num);
567         state_fio->StateUint8(hires_mode);
568         state_fio->StateUint8(page);
569         state_fio->StateUint8(status);
570         state_fio->StateInt32(cblink);
571         return true;
572 }