OSDN Git Service

[VM][DATAREC][FDD] Add sounds of SEEK/CMT, excepts either pseudo devices / bios.
[csp-qt/common_source_project-fm7.git] / source / src / vm / pasopia / display.cpp
1 /*
2         TOSHIBA PASOPIA Emulator 'EmuPIA'
3
4         Author : Takeda.Toshiya
5         Date   : 2007.02.08 -
6
7         [ display ]
8 */
9
10 #include "display.h"
11
12 void DISPLAY::initialize()
13 {
14         // load rom image
15         FILEIO* fio = new FILEIO();
16         if(fio->Fopen(create_local_path(_T("FONT.ROM")), FILEIO_READ_BINARY)) {
17                 fio->Fread(font, sizeof(font), 1);
18                 fio->Fclose();
19         }
20         delete fio;
21         
22         // create pc palette
23 #ifdef _LCD
24         for(int i = 1; i < 8; i++) {
25                 palette_pc[i] = RGB_COLOR(48, 56, 16);
26         }
27         palette_pc[0] = RGB_COLOR(160, 168, 160);
28 #else
29         for(int i = 0; i < 8; i++) {
30                 palette_pc[i] = RGB_COLOR((i & 2) ? 255 : 0, (i & 4) ? 255 : 0, (i & 1) ? 255 : 0);
31         }
32 #endif
33         
34         // init pasopia own
35         mode = 0;
36         cblink = 0;
37         
38         // register event
39         register_frame_event(this);
40 }
41
42 void DISPLAY::write_io8(uint32_t addr, uint32_t data)
43 {
44         switch(addr & 0xff) {
45         case 0x10:
46                 d_crtc->write_io8(addr, data);
47                 break;
48         case 0x11:
49                 d_crtc->write_io8(addr, data);
50                 break;
51         }
52 }
53
54 void DISPLAY::write_signal(int id, uint32_t data, uint32_t mask)
55 {
56         // from 8255-1 port.a
57         mode = data;
58 }
59
60 void DISPLAY::event_frame()
61 {
62         cblink = (cblink + 1) & 0x1f;
63 }
64
65 void DISPLAY::draw_screen()
66 {
67         if((regs[8] & 0x30) != 0x30) {
68                 uint16_t src = ((regs[12] << 8) | regs[13]) & 0x7ff;
69                 if((regs[8] & 0xc0) == 0xc0) {
70                         cursor = -1;
71                 } else {
72                         cursor = ((regs[14] << 8) | regs[15]) & 0x7ff;
73                 }
74                 
75                 // render screen
76                 memset(screen, mode & 7, sizeof(screen));
77                 
78                 switch(mode & 0xe0) {
79                 case 0x00:      // screen 0, wide
80                         draw_screen0_wide(src);
81                         break;
82                 case 0x20:      // screen 0, normal
83                         draw_screen0_normal(src);
84                         break;
85                 case 0x40:      // screen 1, wide
86                         draw_screen1_wide(src);
87                         break;
88                 case 0x60:      // screen 1, normal
89                         draw_screen1_normal(src);
90                         break;
91                 case 0x80:      // screen 2, wide
92                         draw_screen2_wide(src);
93                         break;
94                 case 0xa0:      // screen 2, normal
95                         draw_screen2_normal(src);
96                         break;
97                 case 0xc0:      // screen 1.5, wide
98                         draw_screen15_wide(src);
99                         break;
100                 case 0xe0:      // screen 1.5, normal
101                         draw_screen15_normal(src);
102                         break;
103                 }
104         } else {
105                 memset(screen, 0, sizeof(screen));
106         }
107         
108         // copy to real screen
109         uint16_t bcol = palette_pc[mode & 7];
110         for(int y = 0; y < 200; y++) {
111                 scrntype_t* dest0 = emu->get_screen_buffer(y * 2 + 0);
112                 scrntype_t* dest1 = emu->get_screen_buffer(y * 2 + 1);
113                 uint8_t* src = screen[y];
114                 
115                 for(int x = 0; x < 640; x++) {
116                         dest0[x] = palette_pc[src[x] & 7];
117                 }
118                 if(config.scan_line) {
119                         memset(dest1, 0, 640 * sizeof(scrntype_t));
120                 } else {
121                         memcpy(dest1, dest0, 640 * sizeof(scrntype_t));
122                 }
123         }
124         emu->screen_skip_line(true);
125 }
126
127 #define IS_ATTRIB(d) (((d) & 0xf8) == 0xf8)
128
129 void DISPLAY::draw_screen0_normal(uint16_t src)
130 {
131         // screen 0, normal char (80chars)
132         uint16_t src_t = src & 0x7ff;
133         uint8_t c_b = mode & 7;
134         int width = regs[1] - 1;
135         
136         for(int y = 0; y < 200; y += 8) {
137                 uint8_t c_t = IS_ATTRIB(vram[src_t]) ? (vram[src_t] & 7) : 7;
138                 src_t = (src_t & 0x3800) | ((src_t + 1) & 0x7ff);
139                 
140                 for(int x = 0; x < width; x++) {
141                         uint8_t code = vram[src_t];
142                         if(IS_ATTRIB(code)) {
143                                 c_t = code & 7;
144                         }
145                         uint8_t* font_base = &font[code << 3];
146                         
147                         for(int l = 0; l < 8; l++) {
148                                 uint8_t p = font_base[l];
149                                 uint8_t* d = &screen[y + l][x << 3];
150                                 
151                                 d[0] = (p & 0x80) ? c_t : c_b;
152                                 d[1] = (p & 0x40) ? c_t : c_b;
153                                 d[2] = (p & 0x20) ? c_t : c_b;
154                                 d[3] = (p & 0x10) ? c_t : c_b;
155                                 d[4] = (p & 0x08) ? c_t : c_b;
156                                 d[5] = (p & 0x04) ? c_t : c_b;
157                                 d[6] = (p & 0x02) ? c_t : c_b;
158                                 d[7] = (p & 0x01) ? c_t : c_b;
159                         }
160                         if(src_t == cursor) {
161                                 int bp = regs[10] & 0x60;
162                                 if((bp == 0x40 && (cblink & 8)) || (bp == 0x60 && (cblink & 0x10))) {
163                                         for(int i = (regs[10] & 7); i < 8; i++) {
164                                                 memset(&screen[y + i][x << 3], 7, 8);
165                                         }
166                                 }
167                         }
168                         src_t = (src_t & 0x3800) | ((src_t + 1) & 0x7ff);
169                 }
170         }
171 }
172
173 void DISPLAY::draw_screen0_wide(uint16_t src)
174 {
175         // screen 0, wide char (36chars)
176         uint16_t src_t = src & 0x7ff;
177         uint8_t c_b = mode & 7;
178         int width = regs[1] - 1;
179         
180         for(int y = 0; y < 192; y += 8) {
181                 uint8_t c_t = IS_ATTRIB(vram[src_t]) ? (vram[src_t] & 7) : 7;
182                 src_t = (src_t & 0x3800) | ((src_t + 1) & 0x7ff);
183                 
184                 for(int x = 0; x < width; x++) {
185                         uint8_t code = vram[src_t];
186                         if(IS_ATTRIB(code)) {
187                                 c_t = code & 7;
188                         }
189                         uint8_t* font_base = &font[code << 3];
190                         
191                         for(int l = 0; l < 8; l++) {
192                                 uint8_t p = font_base[l];
193                                 uint8_t* d = &screen[y + l][x << 4];
194                                 
195                                 d[ 0] = d[ 1] = (p & 0x80) ? c_t : c_b;
196                                 d[ 2] = d[ 3] = (p & 0x40) ? c_t : c_b;
197                                 d[ 4] = d[ 5] = (p & 0x20) ? c_t : c_b;
198                                 d[ 6] = d[ 7] = (p & 0x10) ? c_t : c_b;
199                                 d[ 8] = d[ 9] = (p & 0x08) ? c_t : c_b;
200                                 d[10] = d[11] = (p & 0x04) ? c_t : c_b;
201                                 d[12] = d[13] = (p & 0x02) ? c_t : c_b;
202                                 d[14] = d[15] = (p & 0x01) ? c_t : c_b;
203                         }
204                         if(src_t == cursor) {
205                                 int bp = regs[10] & 0x60;
206                                 if((bp == 0x40 && (cblink & 8)) || (bp == 0x60 && (cblink & 0x10))) {
207                                         for(int i = (regs[10] & 7); i < 8; i++) {
208                                                 memset(&screen[y + i][x << 4], 7, 16);
209                                         }
210                                 }
211                         }
212                         src_t = (src_t & 0x3800) | ((src_t + 1) & 0x7ff);
213                 }
214         }
215 }
216
217 void DISPLAY::draw_screen1_normal(uint16_t src)
218 {
219         // screen 1, normal char (80chars)
220         uint16_t src_t = src & 0x7ff;
221         uint8_t c_b = mode & 7;
222         int width = regs[1] - 1;
223         uint8_t c_t[8] = {7, 7, 7, 7, 7, 7, 7, 7};
224         
225         for(int y = 0; y < 200; y += 8) {
226                 // character data is set for every other line in scren 1
227                 for(int i = 0; i < 8; i += 2) {
228                         uint8_t t = vram[src_t + (i * 0x800)];
229                         if(IS_ATTRIB(t)) {
230                                 c_t[i] = c_t[i + 1] = t & 7;
231                         }
232                 }
233                 src_t = (src_t & 0x3800) | ((src_t + 1) & 0x7ff);
234                 
235                 for(int x = 0; x < width; x++) {
236                         bool is_graph[8];
237                         uint8_t attr_t[8];
238                         uint8_t code[8];
239                         for(int i = 0; i < 8; i += 2) {
240                                 uint16_t t = (src_t + (i * 0x800)) & 0x3fff;
241                                 is_graph[i] = is_graph[i + 1] = (attr[t] != 0);
242                                 attr_t[i] = attr_t[i + 1] = attr[t];
243                                 code[i] = code[i + 1] = vram[t];
244                         }
245                         
246                         for(int l = 0; l < 8; l++) {
247                                 // change line color if vram data is text and is attribute character
248                                 // note: check only first line
249                                 uint8_t code_t = code[l];
250                                 if(!is_graph[l] && IS_ATTRIB(code_t)) {
251                                         c_t[l] = code_t & 7;
252                                 }
253                                 uint8_t* font_base = &font[code_t << 3];
254                                 uint8_t c_l = c_t[l], c_r = c_t[l], p = font_base[l];
255                                 if(is_graph[l]) {
256                                         if(attr_t[l]) {
257                                                 p = code_t;
258                                                 c_l = (p >> 4) & 7;
259                                                 c_r = p & 7;
260                                                 p = (p & 0xf0 ? 0xf0 : 0) | (p & 0x0f ? 0x0f : 0);
261                                         } else {
262                                                 p = 0;
263                                         }
264                                 }
265                                 uint8_t* d = &screen[y + l][x << 3];
266                                 
267                                 d[0] = (p & 0x80) ? c_l : c_b;
268                                 d[1] = (p & 0x40) ? c_l : c_b;
269                                 d[2] = (p & 0x20) ? c_l : c_b;
270                                 d[3] = (p & 0x10) ? c_l : c_b;
271                                 d[4] = (p & 0x08) ? c_r : c_b;
272                                 d[5] = (p & 0x04) ? c_r : c_b;
273                                 d[6] = (p & 0x02) ? c_r : c_b;
274                                 d[7] = (p & 0x01) ? c_r : c_b;
275                         }
276                         if(src_t == cursor) {
277                                 int bp = regs[10] & 0x60;
278                                 if((bp == 0x40 && (cblink & 8)) || (bp == 0x60 && (cblink & 0x10))) {
279                                         for(int i = (regs[10] & 7); i < 8; i++) {
280                                                 memset(&screen[y + i][x << 3], 7, 8);
281                                         }
282                                 }
283                         }
284                         src_t = (src_t & 0x3800) | ((src_t + 1) & 0x7ff);
285                 }
286         }
287 }
288
289 void DISPLAY::draw_screen1_wide(uint16_t src)
290 {
291         // screen 1, wide char (36chars)
292         uint16_t src_t = src & 0x7ff;
293         uint8_t c_b = mode & 7;
294         int width = regs[1] - 1;
295         uint8_t c_t[8] = {7, 7, 7, 7, 7, 7, 7, 7};
296         
297         for(int y = 0; y < 192; y += 8) {
298                 // character data is set for every other line in scren 1
299                 for(int i = 0; i < 8; i += 2) {
300                         uint8_t t = vram[src_t + (i * 0x800)];
301                         if(IS_ATTRIB(t)) {
302                                 c_t[i] = c_t[i + 1] = t & 7;
303                         }
304                 }
305                 src_t = (src_t & 0x3800) | ((src_t + 1) & 0x7ff);
306                 
307                 for(int x = 0; x < width; x++) {
308                         bool is_graph[8];
309                         uint8_t attr_t[8];
310                         uint8_t code[8];
311                         for(int i = 0; i < 8; i += 2) {
312                                 uint16_t t = (src_t + (i * 0x800)) & 0x3fff;
313                                 is_graph[i] = is_graph[i + 1] = (attr[t] != 0);
314                                 attr_t[i] = attr_t[i + 1] = attr[t];
315                                 code[i] = code[i + 1] = vram[t];
316                         }
317                         
318                         for(int l = 0; l < 8; l++) {
319                                 // change line color if vram data is text and is attribute character
320                                 // note: check only first line
321                                 uint8_t code_t = code[l];
322                                 if(!is_graph[l] && IS_ATTRIB(code_t)) {
323                                         c_t[l] = code_t & 7;
324                                 }
325                                 uint8_t* font_base = &font[code_t << 3];
326                                 uint8_t c_l = c_t[l], c_r = c_t[l], p = font_base[l];
327                                 if(is_graph[l]) {
328                                         if(attr_t[l]) {
329                                                 p = code_t;
330                                                 c_l = (p >> 4) & 7;
331                                                 c_r = p & 7;
332                                                 p = (p & 0xf0 ? 0xf0 : 0) | (p & 0x0f ? 0x0f : 0);
333                                         } else {
334                                                 p = 0;
335                                         }
336                                 }
337                                 uint8_t* d = &screen[y + l][x << 4];
338                                 
339                                 d[ 0] = d[ 1] = (p & 0x80) ? c_l : c_b;
340                                 d[ 2] = d[ 3] = (p & 0x40) ? c_l : c_b;
341                                 d[ 4] = d[ 5] = (p & 0x20) ? c_l : c_b;
342                                 d[ 6] = d[ 7] = (p & 0x10) ? c_l : c_b;
343                                 d[ 8] = d[ 9] = (p & 0x08) ? c_r : c_b;
344                                 d[10] = d[11] = (p & 0x04) ? c_r : c_b;
345                                 d[12] = d[13] = (p & 0x02) ? c_r : c_b;
346                                 d[14] = d[15] = (p & 0x01) ? c_r : c_b;
347                         }
348                         if(src_t == cursor) {
349                                 int bp = regs[10] & 0x60;
350                                 if((bp == 0x40 && (cblink & 8)) || (bp == 0x60 && (cblink & 0x10))) {
351                                         for(int i = (regs[10] & 7); i < 8; i++) {
352                                                 memset(&screen[y + i][x << 4], 7, 16);
353                                         }
354                                 }
355                         }
356                         src_t = (src_t & 0x3800) | ((src_t + 1) & 0x7ff);
357                 }
358         }
359 }
360
361 void DISPLAY::draw_screen2_normal(uint16_t src)
362 {
363         // screen 2, normal char (80chars)
364         uint16_t src_t = src & 0x7ff;
365         uint8_t c_b = mode & 7;
366         int width = regs[1] - 1;
367         uint8_t c_t[8] = {7, 7, 7, 7, 7, 7, 7, 7};
368         
369         for(int y = 0; y < 200; y += 8) {
370                 // character data is set for every line in scren 2
371                 for(int i = 0; i < 8; i++) {
372                         uint8_t t = vram[src_t + (i * 0x800)];
373                         if(IS_ATTRIB(t)) {
374                                 c_t[i] = t & 7;
375                         }
376                 }
377                 src_t = (src_t & 0x3800) | ((src_t + 1) & 0x7ff);
378                 
379                 for(int x = 0; x < width; x++) {
380                         uint16_t src_g = src_t;
381                         bool is_graph[8];
382                         uint8_t code[8];
383                         for(int i = 0; i < 8; i++) {
384                                 uint16_t t = (src_t + (i * 0x800)) & 0x3fff;
385                                 is_graph[i] = (attr[t] != 0);
386                                 code[i] = vram[t];
387                         }
388                         
389                         for(int l = 0; l < 8; l++) {
390                                 // change line color if vram data is text and is attribute character
391                                 uint8_t code_t = code[l];
392                                 if(!is_graph[l] && (0xf8 <= code_t) && (code_t <= 0xff)) {
393                                         c_t[l] = code_t & 7;
394                                 }
395                                 uint8_t c_l = c_t[l], c_r = c_t[l];
396                                 
397                                 uint8_t* font_base = &font[code_t << 3];
398                                 uint8_t p = is_graph[l] ? (attr[src_g] ? vram[src_g] : 0) : font_base[l];
399                                 src_g = (src_g + 0x800) & 0x3fff;
400                                 uint8_t c_p = is_graph[l] ? 7 : c_t[l];
401                                 uint8_t* d = &screen[y + l][x << 3];
402                                 
403                                 d[0] = (p & 0x80) ? c_p : c_b;
404                                 d[1] = (p & 0x40) ? c_p : c_b;
405                                 d[2] = (p & 0x20) ? c_p : c_b;
406                                 d[3] = (p & 0x10) ? c_p : c_b;
407                                 d[4] = (p & 0x08) ? c_p : c_b;
408                                 d[5] = (p & 0x04) ? c_p : c_b;
409                                 d[6] = (p & 0x02) ? c_p : c_b;
410                                 d[7] = (p & 0x01) ? c_p : c_b;
411                         }
412                         if(src_t == cursor) {
413                                 int bp = regs[10] & 0x60;
414                                 if((bp == 0x40 && (cblink & 8)) || (bp == 0x60 && (cblink & 0x10))) {
415                                         for(int i = (regs[10] & 7); i < 8; i++) {
416                                                 memset(&screen[y + i][x << 3], 7, 8);
417                                         }
418                                 }
419                         }
420                         src_t = (src_t & 0x3800) | ((src_t + 1) & 0x7ff);
421                 }
422         }
423 }
424
425 void DISPLAY::draw_screen2_wide(uint16_t src)
426 {
427         // screen 0, wide char (36chars)
428         uint16_t src_t = src & 0x7ff;
429         uint8_t c_b = mode & 7;
430         int width = regs[1] - 1;
431         uint8_t c_t[8] = {7, 7, 7, 7, 7, 7, 7, 7};
432         
433         for(int y = 0; y < 192; y += 8) {
434                 // character data is set for every line in scren 2
435                 for(int i = 0; i < 8; i++) {
436                         uint8_t t = vram[src_t + (i * 0x800)];
437                         if(IS_ATTRIB(t)) {
438                                 c_t[i] = t & 7;
439                         }
440                 }
441                 src_t = (src_t & 0x3800) | ((src_t + 1) & 0x7ff);
442                 
443                 for(int x = 0; x < width; x++) {
444                         uint16_t src_g = src_t;
445                         bool is_graph[8];
446                         uint8_t code[8];
447                         for(int i = 0; i < 8; i++) {
448                                 uint16_t t = (src_t + (i * 0x800)) & 0x3fff;
449                                 is_graph[i] = (attr[t] != 0);
450                                 code[i] = vram[t];
451                         }
452                         for(int l = 0; l < 8; l++) {
453                                 // change line color if vram data is text and is attribute character
454                                 uint8_t code_t = code[l];
455                                 if(!is_graph[l] && IS_ATTRIB(code_t)) {
456                                         c_t[l] = code_t & 7;
457                                 }
458                                 uint8_t c_l = c_t[l], c_r = c_t[l];
459                                 
460                                 uint8_t* font_base = &font[code_t << 3];
461                                 uint8_t p = is_graph[l] ? (attr[src_g] ? vram[src_g] : 0) : font_base[l];
462                                 src_g = (src_g + 0x800) & 0x3fff;
463                                 uint8_t c_p = is_graph[l] ? 7 : c_t[l];
464                                 uint8_t* d = &screen[y + l][x << 4];
465                                 
466                                 d[ 0] = d[ 1] = (p & 0x80) ? c_p : c_b;
467                                 d[ 2] = d[ 3] = (p & 0x40) ? c_p : c_b;
468                                 d[ 4] = d[ 5] = (p & 0x20) ? c_p : c_b;
469                                 d[ 6] = d[ 7] = (p & 0x10) ? c_p : c_b;
470                                 d[ 8] = d[ 9] = (p & 0x08) ? c_p : c_b;
471                                 d[10] = d[11] = (p & 0x04) ? c_p : c_b;
472                                 d[12] = d[13] = (p & 0x02) ? c_p : c_b;
473                                 d[14] = d[15] = (p & 0x01) ? c_p : c_b;
474                         }
475                         if(src_t == cursor) {
476                                 int bp = regs[10] & 0x60;
477                                 if((bp == 0x40 && (cblink & 8)) || (bp == 0x60 && (cblink & 0x10))) {
478                                         for(int i = (regs[10] & 7); i < 8; i++) {
479                                                 memset(&screen[y + i][x << 4], 7, 16);
480                                         }
481                                 }
482                         }
483                         src_t = (src_t & 0x3800) | ((src_t + 1) & 0x7ff);
484                 }
485         }
486 }
487
488 void DISPLAY::draw_screen15_normal(uint16_t src)
489 {
490         // screen 2, normal char (80chars)
491         uint16_t src_t = src & 0x7ff;
492         uint8_t c_b = mode & 7;
493         int width = regs[1] - 1;
494         uint8_t c_t[8] = {7, 7, 7, 7, 7, 7, 7, 7};
495         
496         for(int y = 0; y < 200; y += 8) {
497                 // character data is set for every line in scren 1.5
498                 for(int i = 0; i < 8; i++) {
499                         uint8_t t = vram[src_t + (i * 0x800)];
500                         if(IS_ATTRIB(t)) {
501                                 c_t[i] = t & 7;
502                         }
503                 }
504                 src_t = (src_t & 0x3800) | ((src_t + 1) & 0x7ff);
505                 
506                 for(int x = 0; x < width; x++) {
507                         bool is_graph[8];
508                         uint8_t attr_t[8];
509                         uint8_t code[8];
510                         for(int i = 0; i < 8; i++) {
511                                 uint16_t t = (src_t + (i * 0x800)) & 0x3fff;
512                                 is_graph[i] = (attr[t] != 0);
513                                 attr_t[i] = attr[t];
514                                 code[i] = vram[t];
515                         }
516                         for(int l = 0; l < 8; l++) {
517                                 // change line color if vram data is text and is attribute character
518                                 uint8_t code_t = code[l];
519                                 if(!is_graph[l] && IS_ATTRIB(code_t)) {
520                                         c_t[l] = code_t & 7;
521                                 }
522                                 uint8_t* font_base = &font[code_t << 3];
523                                 uint8_t c_l = c_t[l], c_r = c_t[l], p = font_base[l];
524                                 if(is_graph[l]) {
525                                         if(attr_t[l]) {
526                                                 p = code_t;
527                                                 c_l = (p >> 4) & 7;
528                                                 c_r = p & 7;
529                                                 p = (p & 0xf0 ? 0xf0 : 0) | (p & 0x0f ? 0x0f : 0);
530                                         } else {
531                                                 p = 0;
532                                         }
533                                 }
534                                 uint8_t* d = &screen[y + l][x << 3];
535                                 
536                                 d[0] = (p & 0x80) ? c_l : c_b;
537                                 d[1] = (p & 0x40) ? c_l : c_b;
538                                 d[2] = (p & 0x20) ? c_l : c_b;
539                                 d[3] = (p & 0x10) ? c_l : c_b;
540                                 d[4] = (p & 0x08) ? c_r : c_b;
541                                 d[5] = (p & 0x04) ? c_r : c_b;
542                                 d[6] = (p & 0x02) ? c_r : c_b;
543                                 d[7] = (p & 0x01) ? c_r : c_b;
544                         }
545                         if(src_t == cursor) {
546                                 int bp = regs[10] & 0x60;
547                                 if((bp == 0x40 && (cblink & 8)) || (bp == 0x60 && (cblink & 0x10))) {
548                                         for(int i = (regs[10] & 7); i < 8; i++) {
549                                                 memset(&screen[y + i][x << 3], 7, 8);
550                                         }
551                                 }
552                         }
553                         src_t = (src_t & 0x3800) | ((src_t + 1) & 0x7ff);
554                 }
555         }
556 }
557
558 void DISPLAY::draw_screen15_wide(uint16_t src)
559 {
560         // screen 0, normal char (80chars)
561         uint16_t src_t = src & 0x7ff;
562         uint8_t c_b = mode & 7;
563         int width = regs[1] - 1;
564         uint8_t c_t[8] = {7, 7, 7, 7, 7, 7, 7, 7};
565         
566         for(int y = 0; y < 192; y += 8) {
567                 // character data is set for every line in scren 1.5
568                 for(int i = 0; i < 8; i++) {
569                         uint8_t t = vram[src_t + (i * 0x800)];
570                         if(IS_ATTRIB(t)) {
571                                 c_t[i] = t & 7;
572                         }
573                 }
574                 src_t = (src_t & 0x3800) | ((src_t + 1) & 0x7ff);
575                 
576                 for(int x = 0; x < width; x++) {
577                         bool is_graph[8];
578                         uint8_t attr_t[8];
579                         uint8_t code[8];
580                         for(int i = 0; i < 8; i++) {
581                                 uint16_t t = (src_t + (i * 0x800)) & 0x3fff;
582                                 is_graph[i] = (attr[t] != 0);
583                                 attr_t[i] = attr[t];
584                                 code[i] = vram[t];
585                         }
586                         
587                         for(int l = 0; l < 8; l++) {
588                                 // change line color if vram data is text and is attribute character
589                                 uint8_t code_t = code[l];
590                                 if(!is_graph[l] && IS_ATTRIB(code_t)) {
591                                         c_t[l] = code_t & 7;
592                                 }
593                                 uint8_t* font_base = &font[code_t << 3];
594                                 uint8_t c_l = c_t[l], c_r = c_t[l], p = font_base[l];
595                                 if(is_graph[l]) {
596                                         if(attr_t[l]) {
597                                                 p = code_t;
598                                                 c_l = (p >> 4) & 7;
599                                                 c_r = p & 7;
600                                                 p = (p & 0xf0 ? 0xf0 : 0) | (p & 0x0f ? 0x0f : 0);
601                                         } else {
602                                                 p = 0;
603                                         }
604                                 }
605                                 uint8_t* d = &screen[y + l][x << 4];
606                                 
607                                 d[ 0] = d[ 1] = (p & 0x80) ? c_l : c_b;
608                                 d[ 2] = d[ 3] = (p & 0x40) ? c_l : c_b;
609                                 d[ 4] = d[ 5] = (p & 0x20) ? c_l : c_b;
610                                 d[ 6] = d[ 7] = (p & 0x10) ? c_l : c_b;
611                                 d[ 8] = d[ 9] = (p & 0x08) ? c_r : c_b;
612                                 d[10] = d[11] = (p & 0x04) ? c_r : c_b;
613                                 d[12] = d[13] = (p & 0x02) ? c_r : c_b;
614                                 d[14] = d[15] = (p & 0x01) ? c_r : c_b;
615                         }
616                         if(src_t == cursor) {
617                                 int bp = regs[10] & 0x60;
618                                 if((bp == 0x40 && (cblink & 8)) || (bp == 0x60 && (cblink & 0x10))) {
619                                         for(int i = (regs[10] & 7); i < 8; i++) {
620                                                 memset(&screen[y + i][x << 4], 7, 16);
621                                         }
622                                 }
623                         }
624                         src_t = (src_t & 0x3800) | ((src_t + 1) & 0x7ff);
625                 }
626         }
627 }
628
629 #define STATE_VERSION   1
630
631 void DISPLAY::save_state(FILEIO* state_fio)
632 {
633         state_fio->FputUint32(STATE_VERSION);
634         state_fio->FputInt32(this_device_id);
635         
636         state_fio->FputUint8(mode);
637         state_fio->FputUint16(cursor);
638         state_fio->FputUint16(cblink);
639 }
640
641 bool DISPLAY::load_state(FILEIO* state_fio)
642 {
643         if(state_fio->FgetUint32() != STATE_VERSION) {
644                 return false;
645         }
646         if(state_fio->FgetInt32() != this_device_id) {
647                 return false;
648         }
649         mode = state_fio->FgetUint8();
650         cursor = state_fio->FgetUint16();
651         cblink = state_fio->FgetUint16();
652         return true;
653 }
654