OSDN Git Service

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