OSDN Git Service

[VM][FM7][LIBNEWDEV] Add some devices to libCSPcommon_dev.
[csp-qt/common_source_project-fm7.git] / source / src / vm / fm7 / mb61vh010.cpp
1 /*
2  * FM77AV/FM16β ALU [mb61vh010.cpp]
3  *  of Fujitsu MB61VH010/011
4  *
5  * Author: K.Ohta <whatisthis.sowhat _at_ gmail.com>
6  * License: GPLv2
7  * History:
8  *   Mar 28, 2015 : Initial
9  *
10  */
11
12 #include "mb61vh010.h"
13
14 uint8_t MB61VH010::do_read(uint32_t addr, uint32_t bank)
15 {
16         uint32_t raddr;
17         
18         if(((1 << bank) & multi_page) != 0) return 0xff;
19         if(is_400line) {
20                 if((addr & 0xffff) < 0x8000) {
21                         raddr = (addr  & 0x7fff) | (0x8000 * bank);
22                         return target->read_data8(raddr + direct_access_offset);
23                 }
24         } else {
25                 raddr = (addr & 0x3fff) | (0x4000 * bank);
26                 return target->read_data8(raddr + direct_access_offset);
27         }
28         return 0xff;
29 }
30
31 void MB61VH010::do_write(uint32_t addr, uint32_t bank, uint8_t data)
32 {
33         uint32_t raddr;
34         uint8_t readdata;
35
36         if(((1 << bank) & multi_page) != 0) return;
37         if((command_reg & 0x40) != 0) { // Calculate before writing
38                 readdata = do_read(addr, bank);
39                 //readdata = data;
40                 if((command_reg & 0x20) != 0) { // NAND
41                         readdata = readdata & cmp_status_reg;
42                         data = data & (~cmp_status_reg);
43                 } else { // AND
44                         readdata = readdata & (~cmp_status_reg);
45                         data = data & cmp_status_reg;
46                 }
47                 readdata = readdata | data;
48         } else {
49                 readdata = data;
50         }
51         if(is_400line) {
52                 if((addr & 0xffff) < 0x8000) {
53                         raddr = (addr & 0x7fff) | (0x8000 * bank);
54                         target->write_data8(raddr + direct_access_offset, readdata);
55                 }
56         } else {
57                 raddr = (addr & 0x3fff) | (0x4000 * bank);
58                 target->write_data8(raddr + direct_access_offset, readdata);
59         }
60         return;
61 }
62
63
64 void MB61VH010::do_pset(uint32_t addr)
65 {
66         int i;
67         uint32_t raddr = addr;  // Use banked ram.
68         uint8_t bitmask[4] = {0};
69         uint8_t srcdata[4] = {0};
70         uint8_t mask_p[4] = {mask_reg, mask_reg, mask_reg, mask_reg};
71         int planes_b = planes;
72         
73         if(planes_b >= 4) planes_b = 4;
74         for(i = 0; i < planes_b; i++) {
75                 if((bank_disable_reg & (1 << i)) != 0) {
76                         continue;
77                 }
78                 if((color_reg & (1 << i)) == 0) {
79                         bitmask[i] = 0x00;
80                 } else {
81                         bitmask[i] = ~mask_reg;
82                 }
83                 //srcdata[i] = do_read(addr, i) & mask_reg;
84                 srcdata[i] = do_read(addr, i);
85         }
86         srcdata[0] = (srcdata[0] & mask_p[0]) | bitmask[0];
87         srcdata[1] = (srcdata[1] & mask_p[1]) | bitmask[1];
88         srcdata[2] = (srcdata[2] & mask_p[2]) | bitmask[2];
89         srcdata[3] = (srcdata[3] & mask_p[3]) | bitmask[3];
90
91         for(i = 0; i < planes_b; i++) {
92                 if((bank_disable_reg & (1 << i)) != 0) {
93                         continue;
94                 }
95                 do_write(addr, i, srcdata[i]);
96         }
97         return;
98 }
99
100 void MB61VH010::do_blank(uint32_t addr)
101 {
102         uint32_t i;
103         uint8_t srcdata;
104
105         if(planes >= 4) planes = 4;
106         for(i = 0; i < planes; i++) {
107                 if((bank_disable_reg & (1 << i)) != 0) {
108                         continue;
109                 }
110                 srcdata = do_read(addr, i);
111                 srcdata = srcdata & mask_reg;
112                 do_write(addr, i, srcdata);
113         }
114         return;
115 }
116
117 void MB61VH010::do_or(uint32_t addr)
118 {
119         uint32_t i;
120         uint8_t bitmask[4] = {0};
121         uint8_t srcdata[4] = {0};
122         uint8_t mask_p[4] = {mask_reg, mask_reg, mask_reg, mask_reg};
123         uint8_t mask_n[4] = {(uint8_t)~mask_reg, (uint8_t)~mask_reg, (uint8_t)~mask_reg, (uint8_t)~mask_reg};
124         
125         if(planes >= 4) planes = 4;
126         for(i = 0; i < planes; i++) {
127                 if((bank_disable_reg & (1 << i)) != 0) {
128                         continue;
129                 }
130                 srcdata[i] = do_read(addr, i);
131                 if((color_reg & (1 << i)) == 0) {
132                         bitmask[i] = srcdata[i]; // srcdata | 0x00
133                 } else {
134                         bitmask[i] = 0xff; // srcdata | 0xff
135                 }
136                 //bitmask = bitmask & ~mask_reg;
137                 //srcdata = (srcdata & mask_reg) | bitmask;
138                 //do_write(addr, i, srcdata);
139         }
140         srcdata[0] = (srcdata[0] & mask_p[0]) | (bitmask[0] & mask_n[0]);
141         srcdata[1] = (srcdata[1] & mask_p[1]) | (bitmask[1] & mask_n[1]);
142         srcdata[2] = (srcdata[2] & mask_p[2]) | (bitmask[2] & mask_n[2]);
143         srcdata[3] = (srcdata[3] & mask_p[3]) | (bitmask[3] & mask_n[3]);
144         for(i = 0; i < planes; i++) {
145                 if((bank_disable_reg & (1 << i)) != 0) {
146                         continue;
147                 }
148                 do_write(addr, i, srcdata[i]);
149         }
150         return;
151 }
152
153 void MB61VH010::do_and(uint32_t addr)
154 {
155         uint32_t i;
156         uint8_t bitmask[4] = {0};
157         uint8_t srcdata[4] = {0};
158         uint8_t mask_p[4] = {mask_reg, mask_reg, mask_reg, mask_reg};
159         uint8_t mask_n[4] = {(uint8_t)~mask_reg, (uint8_t)~mask_reg, (uint8_t)~mask_reg, (uint8_t)~mask_reg};
160
161         if(planes >= 4) planes = 4;
162         for(i = 0; i < planes; i++) {
163                 if((bank_disable_reg & (1 << i)) != 0) {
164                         continue;
165                 }
166                 srcdata[i] = do_read(addr, i);
167                 if((color_reg & (1 << i)) == 0) {
168                         bitmask[i] = 0x00; // srcdata & 0x00
169                 } else {
170                         bitmask[i] = srcdata[i]; // srcdata & 0xff;
171                 }
172                 //bitmask = bitmask & ~mask_reg;
173                 //srcdata = (srcdata & mask_reg) | bitmask;
174                 //do_write(addr, i, srcdata);
175         }
176         srcdata[0] = (srcdata[0] & mask_p[0]) | (bitmask[0] & mask_n[0]);
177         srcdata[1] = (srcdata[1] & mask_p[1]) | (bitmask[1] & mask_n[1]);
178         srcdata[2] = (srcdata[2] & mask_p[2]) | (bitmask[2] & mask_n[2]);
179         srcdata[3] = (srcdata[3] & mask_p[3]) | (bitmask[3] & mask_n[3]);
180         for(i = 0; i < planes; i++) {
181                 if((bank_disable_reg & (1 << i)) != 0) {
182                         continue;
183                 }
184                 do_write(addr, i, srcdata[i]);
185         }
186         return;
187 }
188
189 void MB61VH010::do_xor(uint32_t addr)
190 {
191         uint32_t i;
192         //uint8_t bitmask;
193         //uint8_t srcdata;
194         uint8_t bitmask[4] = {0};
195         uint8_t srcdata[4] = {0};
196         uint8_t mask_p[4] = {mask_reg, mask_reg, mask_reg, mask_reg};
197         uint8_t mask_n[4] = {(uint8_t)~mask_reg, (uint8_t)~mask_reg, (uint8_t)~mask_reg, (uint8_t)~mask_reg};
198
199         if(planes >= 4) planes = 4;
200         for(i = 0; i < planes; i++) {
201                 if((bank_disable_reg & (1 << i)) != 0) {
202                         continue;
203                 }
204                 if((color_reg & (1 << i)) == 0) {
205                         bitmask[i] = 0x00;
206                 } else {
207                         bitmask[i] = 0xff;
208                 }
209                 
210                 srcdata[i] = do_read(addr, i);
211                 //bitmask = bitmask ^ srcdata;
212                 //bitmask = bitmask & (~mask_reg);
213                 //srcdata = srcdata & mask_reg;
214                 //srcdata = srcdata | bitmask;
215                 //do_write(addr, i, srcdata);
216         }
217         bitmask[0] = bitmask[0] ^ srcdata[0];
218         bitmask[1] = bitmask[1] ^ srcdata[1];
219         bitmask[2] = bitmask[2] ^ srcdata[2];
220         bitmask[3] = bitmask[3] ^ srcdata[3];
221         
222         srcdata[0] = (srcdata[0] & mask_p[0]) | (bitmask[0] & mask_n[0]);
223         srcdata[1] = (srcdata[1] & mask_p[1]) | (bitmask[1] & mask_n[1]);
224         srcdata[2] = (srcdata[2] & mask_p[2]) | (bitmask[2] & mask_n[2]);
225         srcdata[3] = (srcdata[3] & mask_p[3]) | (bitmask[3] & mask_n[3]);
226         for(i = 0; i < planes; i++) {
227                 if((bank_disable_reg & (1 << i)) != 0) {
228                         continue;
229                 }
230                 do_write(addr, i, srcdata[i]);
231         }
232         return;
233 }
234
235 void MB61VH010::do_not(uint32_t addr)
236 {
237         uint32_t i;
238         uint8_t bitmask[4] = {0};
239         uint8_t srcdata[4] = {0};
240         uint8_t mask_p[4] = {mask_reg, mask_reg, mask_reg, mask_reg};
241         uint8_t mask_n[4] = {(uint8_t)~mask_reg, (uint8_t)~mask_reg, (uint8_t)~mask_reg, (uint8_t)~mask_reg};
242
243         if(planes >= 4) planes = 4;
244         for(i = 0; i < planes; i++) {
245                 if((bank_disable_reg & (1 << i)) != 0) {
246                         continue;
247                 }
248                 srcdata[i] = do_read(addr, i);
249                 bitmask[i] = ~srcdata[i];
250                 //bitmask = bitmask & ~mask_reg;
251                 //srcdata = (srcdata & mask_reg) | bitmask;
252                 //do_write(addr, i, srcdata);
253         }
254         srcdata[0] = (srcdata[0] & mask_p[0]) | (bitmask[0] & mask_n[0]);
255         srcdata[1] = (srcdata[1] & mask_p[1]) | (bitmask[1] & mask_n[1]);
256         srcdata[2] = (srcdata[2] & mask_p[2]) | (bitmask[2] & mask_n[2]);
257         srcdata[3] = (srcdata[3] & mask_p[3]) | (bitmask[3] & mask_n[3]);
258         for(i = 0; i < planes; i++) {
259                 if((bank_disable_reg & (1 << i)) != 0) {
260                         continue;
261                 }
262                 do_write(addr, i, srcdata[i]);
263         }
264         return;
265 }
266
267
268 void MB61VH010::do_tilepaint(uint32_t addr)
269 {
270         uint32_t i;
271         uint8_t bitmask[4] = {0};
272         uint8_t srcdata[4] = {0};
273         uint8_t mask_p[4] = {mask_reg, mask_reg, mask_reg, mask_reg};
274         uint8_t mask_n[4] = {(uint8_t)~mask_reg, (uint8_t)~mask_reg, (uint8_t)~mask_reg, (uint8_t)~mask_reg};
275
276         if(planes > 4) planes = 4;
277         for(i = 0; i < planes; i++) {
278                 if((bank_disable_reg & (1 << i)) != 0) {
279                         continue;
280                 }
281                 srcdata[i] = do_read(addr, i);
282                 bitmask[i] = tile_reg[i];
283                 //bitmask = tile_reg[i] & (~mask_reg);
284                 //srcdata = (srcdata & mask_reg) | bitmask;
285                 //do_write(addr, i, srcdata);
286         }
287         srcdata[0] = (srcdata[0] & mask_p[0]) | (bitmask[0] & mask_n[0]);
288         srcdata[1] = (srcdata[1] & mask_p[1]) | (bitmask[1] & mask_n[1]);
289         srcdata[2] = (srcdata[2] & mask_p[2]) | (bitmask[2] & mask_n[2]);
290         srcdata[3] = (srcdata[3] & mask_p[3]) | (bitmask[3] & mask_n[3]);
291         for(i = 0; i < planes; i++) {
292                 if((bank_disable_reg & (1 << i)) != 0) {
293                         continue;
294                 }
295                 do_write(addr, i, srcdata[i]);
296         }
297         return;
298 }
299
300 void MB61VH010::do_compare(uint32_t addr)
301 {
302         uint32_t offset = 0x4000;
303         uint8_t r, g, b;
304         uint8_t disables = ~bank_disable_reg;
305
306         uint8_t tmpcol;
307         uint8_t tmp_stat = 0;
308         uint8_t cmp_reg_bak[8];
309         int k;
310         int i;
311         int j;
312         
313         disables = disables & 0x07;
314         k = 0;
315         for(j = 0; j < 8; j++) {
316                 if((cmp_color_data[j] & 0x80) == 0) {
317                         cmp_reg_bak[k] = cmp_color_data[j] & disables;
318                         k++;
319                 }
320         }
321         cmp_status_reg = 0x00;
322         if(k <= 0) return;
323         b = do_read(addr, 0);
324         r = do_read(addr, 1);
325         g = do_read(addr, 2);
326         for(i = 0; i < 8; i++) {
327                 tmp_stat <<= 1;
328                 tmpcol  = (b & 0x80) >> 7;
329                 tmpcol  = tmpcol | ((r & 0x80) >> 6);
330                 tmpcol  = tmpcol | ((g & 0x80) >> 5);
331                 tmpcol = tmpcol & disables;
332                 for(j = 0; j < k; j++) {
333                         if(cmp_reg_bak[j] == tmpcol) {
334                                 tmp_stat = tmp_stat | 0x01;
335                                 goto _l0;
336                         }
337                 }
338 _l0:       
339                 b <<= 1;
340                 r <<= 1;
341                 g <<= 1;
342         }
343         cmp_status_reg = tmp_stat;
344         return;
345 }
346
347 void MB61VH010::do_alucmds_dmyread(uint32_t addr)
348 {
349         if(!is_400line) {
350                 addr = addr & 0x3fff;
351         } else {
352                 if(addr >= 0x8000) {
353                         mask_reg = 0xff;
354                         return;
355                 }
356                 addr = addr & 0x7fff;
357         }
358         if((command_reg & 0x80) == 0) {
359                 return;
360         }
361         //busy_flag = true;
362         //cmp_status_reg = 0x00;
363         if((command_reg & 0x40) != 0) do_compare(addr);
364         switch(command_reg & 0x07) {
365                 case 0:
366                         do_pset(addr);
367                         break;
368                 case 1:
369                         do_blank(addr);
370                         break;
371                 case 2:
372                         do_or(addr);
373                         break;
374                 case 3:
375                         do_and(addr);
376                         break;
377                 case 4:
378                         do_xor(addr);
379                         break;
380                 case 5:
381                         do_not(addr);
382                         break;
383                 case 6:
384                         do_tilepaint(addr);
385                         break;
386                 case 7:
387                         do_compare(addr);
388                         break;
389         }
390         //printf("ALU DMYREAD ADDR=%04x, CMD=%02x CMP STATUS=%02x DISABLE=%01x\n", addr, command_reg, cmp_status_reg, bank_disable_reg);
391         //if(eventid_busy >= 0) cancel_event(this, eventid_busy) ;
392         //register_event(this, EVENT_MB61VH010_BUSY_OFF, 1.0 / 16.0, false, &eventid_busy) ;
393 }  
394
395 void MB61VH010::do_alucmds(uint32_t addr)
396 {
397         if(addr >= 0x8000) {
398                 mask_reg = 0xff;
399                 return;
400         }
401
402         //cmp_status_reg = 0xff;
403         if((command_reg & 0x40) != 0) do_compare(addr);
404         switch(command_reg & 0x07) {
405                 case 0:
406                         do_pset(addr);
407                         break;
408                 case 1:
409                         do_blank(addr);
410                         break;
411                 case 2:
412                         do_or(addr);
413                         break;
414                 case 3:
415                         do_and(addr);
416                         break;
417                 case 4:
418                         do_xor(addr);
419                         break;
420                 case 5:
421                         do_not(addr);
422                         break;
423                 case 6:
424                         do_tilepaint(addr);
425                         break;
426                 case 7:
427                         do_compare(addr);
428                         break;
429         }
430         //printf("ALU CMDS ADDR=%04x, CMD=%02x CMP STATUS=%02x\n", addr, command_reg, cmp_status_reg);
431         return;
432 }
433
434 void MB61VH010::do_line(void)
435 {
436         uint32_t x_begin = line_xbegin.w.l;
437         uint32_t x_end = line_xend.w.l;
438         uint32_t y_begin = line_ybegin.w.l;
439         uint32_t y_end = line_yend.w.l;
440         int cpx_t = (int)x_begin;
441         int cpy_t = (int)y_begin;
442         int ax = (int)x_end - (int)x_begin;
443         int ay = (int)y_end - (int)y_begin;
444         int diff = 0;
445         int diff8 = 0;
446         int count = 0;
447         int xcount;
448         int ycount;
449         bool updated = false;
450         uint16_t tmp8a;
451         uint8_t vmask[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
452         double usec;
453         oldaddr = 0xffffffff;
454         alu_addr = 0xffffffff;
455         line_style = line_pattern;
456         busy_flag = true;
457         total_bytes = 0;
458         
459         mask_reg = 0xff;
460         if ((line_style.b.h & 0x80) != 0) {
461                 mask_reg &= ~vmask[cpx_t & 7];
462         }
463         xcount = abs(ax);
464         ycount = abs(ay);
465         //this->out_debug_log("LINE: (%d,%d)-(%d,%d) CMD=%02x STYLE=%04x, \n", x_begin, y_begin, x_end , y_end, command_reg, line_style.w.l); 
466         if(ycount == 0) {
467                 if((cpy_t < 0) || (cpy_t >= 512)) goto _finish;
468                 if(xcount == 0) {
469                         updated = put_dot(cpx_t, cpy_t);
470                         goto _finish;
471                 }
472                 if(ax > 0) {
473                         int left = x_end - cpx_t;
474                         if((cpx_t & 0x07) != 7) total_bytes = 1;
475                         for(; cpx_t <= (int)x_end;) {
476                                 if((cpx_t & 7) == 0) {
477                                         if(left >= 8) {
478                                                 updated = put_dot8(cpx_t, cpy_t);
479                                                 cpx_t += 8;
480                                                 left -= 8;
481                                                 total_bytes++;
482                                                 continue;
483                                         }
484                                 }
485                                 {
486                                         updated = put_dot(cpx_t, cpy_t);
487                                         cpx_t++;
488                                         left--;
489                                         if((cpx_t & 0x07) == 7) total_bytes++;
490                                 }
491                         }
492                 } else {
493                         int left = cpx_t - x_end;
494                         if((cpx_t & 0x07) != 0) total_bytes = 1;
495                         for(; cpx_t >= (int)x_end;) {
496                                 if(cpx_t < 0) break; // Comment out for Amnork.
497                                 if((cpx_t & 7) == 7) {
498                                         if(left >= 8) {
499                                                 updated = put_dot8(cpx_t, cpy_t);
500                                                 cpx_t -= 8;
501                                                 left -= 8;
502                                                 total_bytes++;
503                                                 continue;
504                                         }
505                                 }
506                                 {
507                                         if((cpx_t & 7) == 0) total_bytes++;
508                                         updated = put_dot(cpx_t, cpy_t);
509                                         left--;
510                                         cpx_t--;
511                                 }
512                         }
513                 }
514         } else if(xcount == 0) {
515                 //if((cpx_t < 0) || (cpx_t >= screen_width)) goto _finish; // Okay?
516                 if(cpx_t < 0) goto _finish; // Okay?
517                 if(ay > 0) {
518                         for(; cpy_t <= (int)y_end; cpy_t++) {
519                                 if(cpy_t >= 512) break;
520                                 updated = put_dot(cpx_t, cpy_t);
521                                 total_bytes++;
522                         }
523                 } else {
524                         for(; cpy_t  >= (int)y_end; cpy_t--) {
525                                 if(cpy_t < 0) break;
526                                 updated = put_dot(cpx_t, cpy_t);
527                                 total_bytes++;
528                         }
529                 }
530         } else if(xcount > ycount) { // (abs(ax) > abs(ay)
531                 diff = (ycount * 32768) / xcount;
532                 diff8 = diff << 3;
533                 if(ax < 0) {
534                         if((cpx_t & 0x07) != 0) total_bytes = 1;
535                 } else {
536                         if((cpx_t & 0x07) == 0) total_bytes = 1;
537                 }
538                 for(; xcount >= 0; ) {
539                         if((diff8 + count) <= 16384) {
540                                 if(ax > 0) {
541                                         if((cpx_t & 0x07) == 0) {
542                                                 if(xcount >= 8) {
543                                                         updated = put_dot8(cpx_t, cpy_t);
544                                                         total_bytes++;
545                                                         count += diff8;
546                                                         xcount -= 8;
547                                                         cpx_t += 8;
548                                                         continue;
549                                                 }
550                                         }
551                                 } else { // ax < 0
552                                         if((cpx_t & 0x07) == 7) {
553                                                 if(xcount >= 8) {
554                                                         updated = put_dot8(cpx_t, cpy_t);
555                                                         total_bytes++;
556                                                         count += diff8;
557                                                         xcount -= 8;
558                                                         cpx_t -= 8;
559                                                         if(cpx_t < 0) break;
560                                                         continue;
561                                                 }
562                                         }
563                                 }
564                         }
565                         updated = put_dot(cpx_t, cpy_t);
566                         count += diff;
567                         if(count > 16384) {
568                                 if(ay < 0) {
569                                         cpy_t--;
570                                         if(cpy_t < 0) break;
571                                 } else {
572                                         cpy_t++;
573                                         if(cpy_t >= 512) break;
574                                 }
575                                 total_bytes++;
576                                 count -= 32768;
577                         }
578                         if(ax > 0) {
579                                 cpx_t++;
580                                 if((cpx_t & 0x07) == 0) total_bytes++;
581                         } else if(ax < 0) {
582                                 if((cpx_t & 0x07) == 0) total_bytes++;
583                                 cpx_t--;
584                                 if(cpx_t < 0) break; // Comment out for Amnork.
585                         }
586                         xcount--;
587                 }
588         } else if(xcount == ycount) { // (abs(ax) == abs(ay)
589                 diff = (ycount * 32768) / xcount;
590                 if(ax < 0) {
591                         if((cpx_t & 0x07) != 0) total_bytes = 1;
592                 } else {
593                         if((cpx_t & 0x07) == 0) total_bytes = 1;
594                 }
595                 for(; xcount >= 0; xcount-- ) {
596                         updated = put_dot(cpx_t, cpy_t);
597                         if(ay < 0) {
598                                 cpy_t--;
599                                 if(cpy_t < 0) break;
600                         } else {
601                                 cpy_t++;
602                                 if(cpy_t >= 512) break;
603                         }
604                         total_bytes++;
605                         if(ax > 0) {
606                                 cpx_t++;
607                         } else if(ax < 0) {
608                                 cpx_t--;
609                                 if(cpx_t < 0) break; // Comment out for Amnork.
610                         }
611                 }
612         } else { // (abs(ax) < abs(ay)
613                 diff = (xcount  * 32768) / ycount;
614                 for(; ycount >= 0; ycount--) {
615                         updated = put_dot(cpx_t, cpy_t);
616                         total_bytes++;
617                         count += diff;
618                         if(count > 16384) {
619                                 if(ax < 0) {
620                                         cpx_t--;
621                                         if(cpx_t < 0) break; // Comment out for Amnork.
622                                 } else if(ax > 0) {
623                                         cpx_t++;
624                                 }
625                                 count -= 32768;
626                         }
627                         if(ay > 0) {
628                                 cpy_t++;
629                                 if(cpy_t >= 512) {
630                                         break;
631                                 }
632                         } else {
633                                 cpy_t--;
634                                 if(cpy_t < 0) {
635                                         break;
636                                 }
637                         }
638                 }
639         }
640         // last byte
641         do_alucmds(alu_addr);
642         total_bytes++;
643 _finish:   
644         //if(total_bytes == 0) total_bytes = 1;
645         mask_reg = 0xff;
646         if(total_bytes >= 8) { // Only greater than 8bytes.
647                 usec = (double)total_bytes / 16.0;
648                 if(eventid_busy >= 0) cancel_event(this, eventid_busy) ;
649                 register_event(this, EVENT_MB61VH010_BUSY_OFF, usec, false, &eventid_busy);
650         } else {
651                 busy_flag = false;
652         }
653 }
654
655 inline bool MB61VH010::put_dot(int x, int y)
656 {
657         uint8_t vmask[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
658         uint16_t tmp16a;
659         uint8_t tmp8a;
660         uint8_t mask8;
661         
662         bool updated;
663    
664         if((command_reg & 0x80) == 0) return false; // Not compare.
665         if((x < 0) || (y < 0)) {
666                 return false; // Lower address
667         }
668    
669         //if(y >= (int)screen_height) return; // Workaround of overflow
670         
671         alu_addr = (y * screen_width + x)  >> 3;
672         alu_addr = alu_addr + line_addr_offset.w.l;
673         if(!is_400line) {
674                 alu_addr = alu_addr & 0x3fff;
675         } else {
676                 alu_addr = alu_addr & 0x7fff;
677         }
678         
679         mask8 = ~vmask[x & 7];
680         updated = false;
681         tmp8a = line_style.b.h & 0x80;
682         
683         if(oldaddr != alu_addr) {
684                 if(oldaddr == 0xffffffff) {
685                         if(tmp8a != 0) {
686                                 mask_reg &= mask8;
687                         }
688                         oldaddr = alu_addr;
689                 }
690                 do_alucmds(oldaddr);
691                 mask_reg = 0xff;
692                 oldaddr = alu_addr;
693                 updated = true;
694         }
695         if(tmp8a != 0) {
696                 mask_reg &= mask8;
697         }
698         line_style.w.l <<= 1;
699         if(tmp8a != 0) line_style.w.l |= 0x01; 
700         return updated;
701 }
702
703 inline bool MB61VH010::put_dot8(int x, int y)
704 {
705         uint8_t vmask[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
706         uint8_t tmp8a;
707         int xx;
708         uint16_t tmp16a;
709         bool updated;
710    
711         if((command_reg & 0x80) == 0) return false; // Not compare.
712         if((x < 0) || (y < 0)) {
713                 return false; // Lower address
714         }
715    
716         //if(y >= (int)screen_height) return; // Workaround of overflow
717         
718         alu_addr = (y * screen_width + x)  >> 3;
719         alu_addr = alu_addr + line_addr_offset.w.l;
720         if(!is_400line) {
721                 alu_addr = alu_addr & 0x3fff;
722         } else {
723                 alu_addr = alu_addr & 0x7fff;
724         }
725         updated = false;
726         if(oldaddr != alu_addr) {
727                 if(oldaddr == 0xffffffff) {
728                         if((line_style.b.h & 0x80) != 0) {
729                                 mask_reg &= ~vmask[x & 7];
730                         }
731                         oldaddr = alu_addr;
732                 }
733                 do_alucmds(oldaddr);
734                 mask_reg = 0xff;
735                 oldaddr = alu_addr;
736                 updated = true;
737         }
738         tmp8a = line_style.b.h;
739         mask_reg = mask_reg & ~tmp8a;
740         tmp8a = line_style.b.l;
741         line_style.b.l = line_style.b.h;
742         line_style.b.h = tmp8a;
743         return updated;
744 }
745
746 void MB61VH010::write_data8(uint32_t id, uint32_t data)
747 {
748         //this->out_debug_log("ALU: ADDR=%02x DATA=%02x\n", id, data);
749         if(id == ALU_CMDREG) {
750                 command_reg = data;
751                 return;
752         }
753         switch(id) {
754                 case ALU_LOGICAL_COLOR:
755                         color_reg = data;
756                         break;
757                 case ALU_WRITE_MASKREG:
758                         mask_reg = data;
759                         break;
760                 case ALU_BANK_DISABLE:
761                         bank_disable_reg = data;
762                         break;
763                 case ALU_TILEPAINT_B:
764                         tile_reg[0] = data;
765                         break;
766                 case ALU_TILEPAINT_R:
767                         tile_reg[1] = data;
768                         break;
769                 case ALU_TILEPAINT_G:
770                         tile_reg[2] = data;
771                         break;
772                 case ALU_TILEPAINT_L:
773                         tile_reg[3] = data;
774                         break;
775                 case ALU_OFFSET_REG_HIGH:
776                         line_addr_offset.b.h &= 0x01;
777                         line_addr_offset.b.h = line_addr_offset.b.h | ((data << 1) & 0x3e);
778                         break;
779                 case ALU_OFFSET_REG_LO:
780                         line_addr_offset.b.l = data << 1;
781                         line_addr_offset.b.h &= 0xfe;
782                         line_addr_offset.b.h = line_addr_offset.b.h | ((data >> 7) & 0x01);
783                         break;
784                 case ALU_LINEPATTERN_REG_HIGH:
785                         line_pattern.b.h = data;
786                         break;
787                 case ALU_LINEPATTERN_REG_LO:
788                         line_pattern.b.l = data;
789                         break;
790                 case ALU_LINEPOS_START_X_HIGH:
791                         line_xbegin.b.h = data & 0x03;
792                         break;
793                 case ALU_LINEPOS_START_X_LOW:  
794                         line_xbegin.b.l = data;
795                         break;
796                 case ALU_LINEPOS_START_Y_HIGH:
797                         line_ybegin.b.h = data & 0x01;
798                         break;
799                 case ALU_LINEPOS_START_Y_LOW:  
800                         line_ybegin.b.l = data;
801                         break;
802                 case ALU_LINEPOS_END_X_HIGH:
803                         line_xend.b.h = data & 0x03;
804                         break;
805                 case ALU_LINEPOS_END_X_LOW:  
806                         line_xend.b.l = data;
807                         break;
808                 case ALU_LINEPOS_END_Y_HIGH:
809                         line_yend.b.h = data & 0x01;
810                         break;
811                 case ALU_LINEPOS_END_Y_LOW:
812                         line_yend.b.l = data;
813                         do_line();
814                         break;
815                 default:
816                         if((id >= (ALU_CMPDATA_REG + 0)) && (id < (ALU_CMPDATA_REG + 8))) {
817                                 cmp_color_data[id - ALU_CMPDATA_REG] = data;
818                         } else  if((id >= ALU_WRITE_PROXY) && (id < (ALU_WRITE_PROXY + 0xc000))) {
819                                 uint32_t raddr = id - ALU_WRITE_PROXY;
820                                 if(is_400line) {
821                                         if(raddr >= 0x8000) return;
822                                 } else {
823                                         raddr = raddr & 0x3fff;
824                                 }
825                                 do_alucmds_dmyread(raddr);
826                         }
827                         break;
828         }
829 }
830
831 uint32_t MB61VH010::read_data8(uint32_t id)
832 {
833         uint32_t raddr;  
834         switch(id) {
835                 case ALU_CMDREG:
836                         return (uint32_t)command_reg;
837                         break;
838                 case ALU_LOGICAL_COLOR:
839                         return (uint32_t)color_reg;
840                         break;
841                 case ALU_WRITE_MASKREG:
842                         return (uint32_t)mask_reg;
843                         break;
844                 case ALU_CMP_STATUS_REG:
845                         return (uint32_t)cmp_status_reg;
846                         break;
847                 case ALU_BANK_DISABLE:
848                         return (uint32_t)bank_disable_reg;
849                         break;
850                 default:
851                         if((id >= ALU_WRITE_PROXY) && (id < (ALU_WRITE_PROXY + 0xc000))) {
852                                 uint32_t dmydata;
853                                 raddr = id - ALU_WRITE_PROXY;
854                                 if(is_400line) {
855                                         if(raddr >= 0x8000) return 0xffffffff;
856                                 } else {
857                                         raddr = raddr & 0x3fff;
858                                 }
859                                 do_alucmds_dmyread(raddr);
860                                 raddr = (id - ALU_WRITE_PROXY) % 0xc000;
861                                 dmydata = target->read_data8(raddr + direct_access_offset);
862                                 return dmydata;
863                         }
864                         return 0xffffffff;
865                         break;
866         }
867 }
868
869 uint32_t MB61VH010::read_signal(int id)
870 {
871         uint32_t val = 0x00000000;
872         switch(id) {
873                 case SIG_ALU_BUSYSTAT:
874                         if(busy_flag) val = 0xffffffff;
875                         break;
876                 case SIG_ALU_ENABLED:
877                         if((command_reg & 0x80) != 0) val = 0xffffffff;
878                         break;
879         }
880         return val;
881 }
882
883 void MB61VH010::write_signal(int id, uint32_t data, uint32_t mask)
884 {
885         bool flag = ((data & mask) != 0);
886         switch(id) {
887                 case SIG_ALU_400LINE:
888                         is_400line = flag;
889                         break;
890                 case SIG_ALU_MULTIPAGE:
891                         multi_page = (data & mask) & 0x07;
892                         break;
893                 case SIG_ALU_PLANES:
894                         planes = (data & mask) & 0x07;
895                         if(planes >= 4) planes = 4;
896                         break;
897                 case SIG_ALU_X_WIDTH:
898                         screen_width = (data << 3) & 0x3ff;
899                         break;
900                 case SIG_ALU_Y_HEIGHT:
901                         screen_height = data & 0x3ff;
902                         break;
903         }
904 }
905
906 void MB61VH010::event_callback(int event_id, int err)
907 {
908         switch(event_id) {
909                 case EVENT_MB61VH010_BUSY_ON:
910                         busy_flag = true;
911                         if(eventid_busy >= 0) cancel_event(this, eventid_busy);
912                         eventid_busy = -1;
913                         break;
914                 case EVENT_MB61VH010_BUSY_OFF:
915                         busy_flag = false;
916                         eventid_busy = -1;
917                         break;
918         }
919 }
920
921 void MB61VH010::initialize(void)
922 {
923         int i;
924         busy_flag = false;
925         is_400line = false;
926         eventid_busy = -1;
927         multi_page = 0x00;
928         planes = 3;
929         screen_width = 640;
930         screen_height = 200;
931         command_reg = 0;        // D410 (RW)
932         color_reg = 0;          // D411 (RW)
933         mask_reg = 0;           // D412 (RW)
934         cmp_status_reg = 0;     // D413 (RO)
935         for(i = 0; i < 8; i++) cmp_color_data[i] = 0x80; // D413-D41A (WO)
936         bank_disable_reg = 0;   // D41B (RW)
937         for(i = 0; i < 4; i++) tile_reg[i] = 0;        // D41C-D41F (WO)
938         
939         line_addr_offset.d = 0; // D420-D421 (WO)
940         line_pattern.d = 0;     // D422-D423 (WO)
941         line_xbegin.d = 0;      // D424-D425 (WO)
942         line_ybegin.d = 0;      // D426-D427 (WO)
943         line_xend.d = 0;        // D428-D429 (WO)
944         line_yend.d = 0;        // D42A-D42B (WO)
945 }
946
947 void MB61VH010::reset(void)
948 {
949         int i;
950         busy_flag = false;
951         if(eventid_busy >= 0) cancel_event(this, eventid_busy);
952         eventid_busy = -1;
953         command_reg = 0;        // D410 (RW)
954         color_reg = 0;          // D411 (RW)
955         mask_reg = 0;           // D412 (RW)
956         cmp_status_reg = 0;     // D413 (RO)
957         for(i = 0; i < 8; i++) cmp_color_data[i] = 0x80; // D413-D41A (WO)
958         bank_disable_reg = 0;   // D41B (RW)
959         for(i = 0; i < 4; i++) tile_reg[i] = 0;        // D41C-D41F (WO)
960         
961         line_addr_offset.d = 0; // D420-D421 (WO)
962         line_pattern.d = 0;     // D422-D423 (WO)
963         line_xbegin.d = 0;      // D424-D425 (WO)
964         line_ybegin.d = 0;      // D426-D427 (WO)
965         line_xend.d = 0;        // D428-D429 (WO)
966         line_yend.d = 0;        // D42A-D42B (WO)
967         oldaddr = 0xffffffff;
968         
969         if(planes >= 4) planes = 4;
970 }
971
972 #define STATE_VERSION 1
973 void MB61VH010::save_state(FILEIO *state_fio)
974 {
975         int i;
976         state_fio->FputUint32(STATE_VERSION);
977         state_fio->FputInt32(this_device_id);
978         this->out_debug_log("Save State: MB61VH010 : id=%d ver=%d\n", this_device_id, STATE_VERSION);
979
980         { // V1
981                 state_fio->FputUint8(command_reg);
982                 state_fio->FputUint8(color_reg);
983                 state_fio->FputUint8(mask_reg);
984                 state_fio->FputUint8(cmp_status_reg);
985                 for(i = 0; i < 8; i++)  state_fio->FputUint8(cmp_color_data[i]);
986                 state_fio->FputUint8(bank_disable_reg);
987                 for(i = 0; i < 4; i++)  state_fio->FputUint8(tile_reg[i]);
988                 state_fio->FputUint8(multi_page);
989                 
990                 state_fio->FputUint32_BE(line_addr_offset.d);
991                 state_fio->FputUint16_BE(line_pattern.w.l);
992                 state_fio->FputUint16_BE(line_xbegin.w.l);
993                 state_fio->FputUint16_BE(line_ybegin.w.l);
994                 state_fio->FputUint16_BE(line_xend.w.l);
995                 state_fio->FputUint16_BE(line_yend.w.l);
996                 
997                 state_fio->FputBool(busy_flag);
998                 state_fio->FputInt32_BE(eventid_busy);
999
1000                 state_fio->FputUint32_BE(total_bytes);
1001                 state_fio->FputUint32_BE(oldaddr);
1002                 state_fio->FputUint32_BE(alu_addr);
1003
1004                 state_fio->FputUint32_BE(planes);
1005                 state_fio->FputBool(is_400line);
1006                 state_fio->FputUint32_BE(screen_width);
1007                 state_fio->FputUint32_BE(screen_height);
1008
1009                 state_fio->FputUint16_BE(line_style.w.l);
1010         }
1011    
1012 }
1013
1014 bool MB61VH010::load_state(FILEIO *state_fio)
1015 {
1016         uint32_t version = state_fio->FgetUint32();
1017         int i;
1018         this->out_debug_log("Load State: MB61VH010 : id=%d ver=%d\n", this_device_id, version);
1019         if(this_device_id != state_fio->FgetInt32()) return false;
1020         if(version >= 1) {
1021                 command_reg = state_fio->FgetUint8();
1022                 color_reg = state_fio->FgetUint8();
1023                 mask_reg = state_fio->FgetUint8();
1024                 cmp_status_reg = state_fio->FgetUint8();
1025                 for(i = 0; i < 8; i++)  cmp_color_data[i] = state_fio->FgetUint8();
1026                 bank_disable_reg = state_fio->FgetUint8();
1027                 for(i = 0; i < 4; i++)  tile_reg[i] = state_fio->FgetUint8();
1028                 multi_page = state_fio->FgetUint8();
1029
1030                 line_addr_offset.d = state_fio->FgetUint32_BE();
1031                 line_pattern.d = 0;
1032                 line_xbegin.d = 0;
1033                 line_ybegin.d = 0;
1034                 line_xend.d = 0;
1035                 line_yend.d = 0;
1036            
1037                 line_pattern.w.l = state_fio->FgetUint16_BE();
1038                 line_xbegin.w.l = state_fio->FgetUint16_BE();
1039                 line_ybegin.w.l = state_fio->FgetUint16_BE();
1040                 line_xend.w.l = state_fio->FgetUint16_BE();
1041                 line_yend.w.l = state_fio->FgetUint16_BE();
1042
1043                 busy_flag = state_fio->FgetBool();
1044                 eventid_busy = state_fio->FgetInt32_BE();
1045                 
1046                 total_bytes = state_fio->FgetUint32_BE();
1047                 oldaddr = state_fio->FgetUint32_BE();
1048                 alu_addr = state_fio->FgetUint32_BE();
1049
1050                 planes = state_fio->FgetUint32_BE();
1051                 is_400line = state_fio->FgetBool();
1052                 screen_width = state_fio->FgetUint32_BE();
1053                 screen_height = state_fio->FgetUint32_BE();
1054
1055                 line_style.d = 0;
1056                 line_style.w.l = state_fio->FgetUint16_BE();
1057         }
1058         if(version != STATE_VERSION) return false;
1059         return true;
1060 }