OSDN Git Service

4524b8a4212c405b9d4920843b4588eebcd8d648
[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
15 MB61VH010::MB61VH010(VM *parent_vm, EMU *parent_emu) : DEVICE(parent_vm, parent_emu)
16 {
17         p_emu = parent_emu;
18         p_vm = parent_vm;
19 }
20
21 MB61VH010::~MB61VH010()
22 {
23 }
24
25 uint8 MB61VH010::do_read(uint32 addr, uint32 bank)
26 {
27         uint32 raddr;
28         uint32 offset;
29         
30         if(((1 << bank) & read_signal(SIG_DISPLAY_MULTIPAGE)) != 0) return 0xff;
31         //if(is_400line) offset = 0x8000;
32         
33         if(is_400line) {
34                 if((addr & 0xffff) < 0x8000) {
35                         raddr = (addr & 0x7fff) | (0x8000 * bank);
36                         return target->read_data8(raddr + DISPLAY_VRAM_DIRECT_ACCESS);
37                 }
38                 return 0xff;
39         } else {
40                 raddr = (addr & 0x3fff) | (0x4000 * bank);
41                 return target->read_data8(raddr + DISPLAY_VRAM_DIRECT_ACCESS);
42         }
43         return 0xff;
44 }
45
46 uint8 MB61VH010::do_write(uint32 addr, uint32 bank, uint8 data)
47 {
48         uint32 raddr;
49         uint8 readdata;
50
51         if(((1 << bank) & read_signal(SIG_DISPLAY_MULTIPAGE)) != 0) return 0xff;
52         if((command_reg & 0x40) != 0) { // Calculate before writing
53                 readdata = do_read(addr, bank);
54                 //readdata = data;
55                 if((command_reg & 0x20) != 0) { // NAND
56                         readdata = readdata & cmp_status_reg;
57                         data = data & ~cmp_status_reg;
58                         readdata = readdata | data;
59                 } else { // AND
60                         readdata = readdata & ~cmp_status_reg;
61                         data = data & cmp_status_reg;
62                         readdata = readdata | data;
63                 }
64         } else {
65                 readdata = data;
66         }
67         if(is_400line) {
68                 if((addr & 0xffff) < 0x8000) {
69                         raddr = (addr & 0x7fff) | (0x8000 * bank);
70                         target->write_data8(raddr + DISPLAY_VRAM_DIRECT_ACCESS, readdata);
71                 }
72         } else {
73                 raddr = (addr & 0x3fff) | (0x4000 * bank);
74                 target->write_data8(raddr + DISPLAY_VRAM_DIRECT_ACCESS, readdata);
75         }
76         return readdata;
77 }
78
79
80 uint8 MB61VH010::do_pset(uint32 addr)
81 {
82         uint32 i;
83         uint32 raddr = addr;  // Use banked ram.
84         uint8 bitmask;
85         uint8 srcdata;
86         int planes_b = planes;
87
88         if(planes_b >= 4) planes_b = 4;
89         for(i = 0; i < planes_b; i++) {
90                 if((bank_disable_reg & (1 << i)) != 0) {
91                                 continue;
92                 }
93                 if((color_reg & (1 << i)) == 0) {
94                         bitmask = 0x00;
95                 } else {
96                         bitmask = 0xff;
97                 }
98                 
99                 srcdata = do_read(addr, i);
100                 bitmask = bitmask & ~mask_reg;
101                 srcdata = srcdata & mask_reg;
102                 srcdata = srcdata | bitmask;
103                 do_write(addr, i, srcdata);
104         }
105         return 0xff;
106 }
107
108 uint8 MB61VH010::do_blank(uint32 addr)
109 {
110         uint32 i;
111         uint8 srcdata;
112
113         if(planes >= 4) planes = 4;
114         for(i = 0; i < planes; i++) {
115                 if((bank_disable_reg & (1 << i)) != 0) {
116                         continue;
117                 }
118                 srcdata = do_read(addr, i);
119                 srcdata = srcdata & mask_reg;
120                 do_write(addr, i, srcdata);
121         }
122         return 0xff;
123 }
124
125 uint8 MB61VH010::do_or(uint32 addr)
126 {
127         uint32 i;
128         uint8 bitmask;
129         uint8 srcdata;
130         
131         if(planes >= 4) planes = 4;
132         for(i = 0; i < planes; i++) {
133                 if((bank_disable_reg & (1 << i)) != 0) {
134                         continue;
135                 }
136                 srcdata = do_read(addr, i);
137                 if((color_reg & (1 << i)) == 0) {
138                         bitmask = srcdata; // srcdata | 0x00
139                 } else {
140                         bitmask = 0xff; // srcdata | 0xff
141                 }
142                 bitmask = bitmask & ~mask_reg;
143                 srcdata = (srcdata & mask_reg) | bitmask;
144                 do_write(addr, i, srcdata);
145         }
146         return 0xff;
147 }
148
149 uint8 MB61VH010::do_and(uint32 addr)
150 {
151         uint32 i;
152         uint8 bitmask;
153         uint8 srcdata;
154
155         if(planes >= 4) planes = 4;
156         for(i = 0; i < planes; i++) {
157                 if((bank_disable_reg & (1 << i)) != 0) {
158                         continue;
159                 }
160                 srcdata = do_read(addr, i);
161                 if((color_reg & (1 << i)) == 0) {
162                         bitmask = 0x00; // srcdata & 0x00
163                 } else {
164                         bitmask = srcdata; // srcdata & 0xff;
165                 }
166                 bitmask = bitmask & ~mask_reg;
167                 srcdata = (srcdata & mask_reg) | bitmask;
168                 do_write(addr, i, srcdata);
169         }
170         return 0xff;
171 }
172
173 uint8 MB61VH010::do_xor(uint32 addr)
174 {
175         uint32 i;
176         uint8 bitmask;
177         uint8 srcdata;
178
179         if(planes >= 4) planes = 4;
180         for(i = 0; i < planes; i++) {
181                 if((bank_disable_reg & (1 << i)) != 0) {
182                         continue;
183                 }
184                 srcdata = do_read(addr, i);
185                 if((color_reg & (1 << i)) == 0) {
186                         bitmask = srcdata ^ 0x00;
187                 } else {
188                         bitmask = srcdata ^ 0xff;
189                 }
190                 bitmask = bitmask & ~mask_reg;
191                 srcdata = (srcdata & mask_reg) | bitmask;
192                 do_write(addr, i, srcdata);
193         }
194         return 0xff;
195 }
196
197 uint8 MB61VH010::do_not(uint32 addr)
198 {
199         uint32 i;
200         uint8 bitmask;
201         uint8 srcdata;
202
203         if(planes >= 4) planes = 4;
204         for(i = 0; i < planes; i++) {
205                 if((bank_disable_reg & (1 << i)) != 0) {
206                         continue;
207                 }
208                 srcdata = do_read(addr, i);
209                 bitmask = ~srcdata;
210                 
211                 bitmask = bitmask & ~mask_reg;
212                 srcdata = (srcdata & mask_reg) | bitmask;
213                 do_write(addr, i, srcdata);
214         }
215         return 0xff;
216 }
217
218
219 uint8 MB61VH010::do_tilepaint(uint32 addr)
220 {
221         uint32 i;
222         uint8 bitmask;
223         uint8 srcdata;
224         //printf("Tilepaint CMD=%02x, ADDR=%04x Planes=%d, tile_reg=(%02x %02x %02x %02x)\n",
225         //       command_reg, addr, planes, tile_reg[0], tile_reg[1], tile_reg[2], tile_reg[3]);
226         if(planes >= 4) planes = 4;
227         for(i = 0; i < planes; i++) {
228                 if((bank_disable_reg & (1 << i)) != 0) {
229                         continue;
230                 }
231                 srcdata = do_read(addr, i);
232                 bitmask = tile_reg[i] & ~mask_reg;
233                 srcdata = (srcdata & mask_reg) | bitmask;
234                 do_write(addr, i, srcdata);
235         }
236         return 0xff;
237 }
238
239 uint8 MB61VH010::do_compare(uint32 addr)
240 {
241         uint32 offset = 0x4000;
242         uint8 r, g, b, t;
243         uint8 disables = ~bank_disable_reg;
244         uint8 tmpcol;
245         uint8 tmp_stat = 0;
246         int i;
247         int j;
248         //printf("Compare CMD=%02x, ADDR=%04x\n", command_reg, addr);
249         b = do_read(addr, 0);
250         r = do_read(addr, 1);
251         g = do_read(addr, 2);
252         if(planes >= 4) {
253                 t = do_read(addr, 3);
254                 disables = disables & 0x0f;
255         } else {
256                 t = 0;
257                 disables = disables & 0x07;
258         }
259         for(i = 7; i >= 0; i--) {
260                 tmpcol  = ((b & 0x80) != 0) ? 1 : 0;
261                 tmpcol |= ((r & 0x80) != 0) ? 2 : 0;
262                 tmpcol |= ((g & 0x80) != 0) ? 4 : 0;
263                 tmpcol |= ((t & 0x80) != 0) ? 8 : 0;
264                 tmpcol = tmpcol & disables;
265                 for(j = 0; j < 8; j++) {
266                         if((cmp_color_data[j] & 0x80) == 0) {
267                                 if((cmp_color_data[j] & disables) == tmpcol) {
268                                         tmp_stat = tmp_stat | (1 << i);
269                                         break;
270                                 }
271                         }
272                 }
273                 b <<= 1;
274                 r <<= 1;
275                 g <<= 1;
276                 t <<= 1;
277         }
278         cmp_status_reg = tmp_stat;
279         return 0xff;
280 }
281
282 void MB61VH010::do_alucmds_dmyread(uint32 addr)
283 {
284         int i;
285         if(!is_400line) {
286                 addr = addr & 0x3fff;
287         } else {
288                 if(addr >= 0x8000) {
289                         mask_reg = 0xff;
290                         return;
291                 }
292                 addr = addr & 0x7fff;
293         }
294         printf("ALU DMYREAD: CMD %02x ADDR=%04x CMP[]=", command_reg, addr);
295         for(i = 0; i < 8; i++) printf("[%02x]", cmp_color_data[i]);
296         if((command_reg & 0x80) == 0) {
297                 printf("\n");
298                 return;
299         }
300         if(((command_reg & 0x40) != 0) && ((command_reg & 0x07) != 7)) do_compare(addr);
301         switch(command_reg & 0x07) {
302                 case 0:
303                         do_pset(addr);
304                         break;
305                 case 1:
306                         do_blank(addr);
307                         break;
308                 case 2:
309                         do_or(addr);
310                         break;
311                 case 3:
312                         do_and(addr);
313                         break;
314                 case 4:
315                         do_xor(addr);
316                         break;
317                 case 5:
318                         do_not(addr);
319                         break;
320                 case 6:
321                         do_tilepaint(addr);
322                         break;
323                 case 7:
324                         do_compare(addr);
325                         break;
326         }
327         printf(" CMP STATUS=%02x\n", cmp_status_reg);
328 }  
329
330 uint8 MB61VH010::do_alucmds(uint32 addr)
331 {
332         if(!is_400line) {
333                 addr = addr & 0x3fff;
334         } else {
335                 if(addr >= 0x8000) {
336                         mask_reg = 0xff;
337                         return 0xff;
338                 }
339                 addr = addr & 0x7fff;
340         }
341         if((command_reg & 0x07) != 0x00) printf("ALU: CMD %02x ADDR=%08x\n", command_reg, addr);
342         if(((command_reg & 0x40) != 0) && ((command_reg & 0x07) != 7)) do_compare(addr);
343         switch(command_reg & 0x07) {
344                 case 0:
345                         return do_pset(addr);
346                         break;
347                 case 1:
348                         return do_blank(addr);
349                         break;
350                 case 2:
351                         return do_or(addr);
352                         break;
353                 case 3:
354                         return do_and(addr);
355                         break;
356                 case 4:
357                         return do_xor(addr);
358                         break;
359                 case 5:
360                         return do_not(addr);
361                         break;
362                 case 6:
363                         return do_tilepaint(addr);
364                         break;
365                 case 7:
366                         return do_compare(addr);
367                         break;
368         }
369         return 0xff;
370 }
371
372 void MB61VH010::do_line(void)
373 {
374         int x_begin = line_xbegin.w.l;
375         int x_end = line_xend.w.l;
376         int y_begin = line_ybegin.w.l;
377         int y_end = line_yend.w.l;
378         uint32 addr;
379         int cpx_t = x_begin;
380         int cpy_t = y_begin;
381         int ax = x_end - x_begin;
382         int ay = y_end - y_begin;
383         int diff;
384         int count = 0;
385         uint8 mask_bak = mask_reg;
386         //printf("Line: (%d,%d) - (%d,%d) CMD=%02x\n", x_begin, y_begin, x_end, y_end, command_reg);  
387         double usec;
388         bool lastflag = false;
389
390         is_400line = (target->read_signal(SIG_DISPLAY_MODE_IS_400LINE) != 0) ? true : false;
391         planes = target->read_signal(SIG_DISPLAY_PLANES) & 0x07;
392         screen_width = target->read_signal(SIG_DISPLAY_X_WIDTH) * 8;
393         screen_height = target->read_signal(SIG_DISPLAY_Y_HEIGHT);
394
395         //if((command_reg & 0x80) == 0) return;
396         oldaddr = 0xffffffff;
397         alu_addr = 0xffffffff;
398
399         
400         line_style = line_pattern;
401         oldaddr = 0xffff;
402         busy_flag = true;
403         total_bytes = 1;
404         
405         //mask_reg = 0xff & ~vmask[x_begin & 7];
406         mask_reg = 0xff;
407         // Got from HD63484.cpp .
408         if(abs(ax) >= abs(ay)) {
409                 if(ax != 0) {
410                         diff = ((abs(ay) + 1) * 1024) / abs(ax);
411                         for(; cpx_t != x_end; ) {
412                                 lastflag = put_dot(cpx_t, cpy_t);
413                                 count += diff;
414                                 if(count >= 1024) {
415                                         if(ax > 0) {
416                                                 lastflag = put_dot(cpx_t + 1, cpy_t);
417                                         } else if(ax < 0) {
418                                                 lastflag = put_dot(cpx_t - 1, cpy_t);
419                                         }
420                                         if(ay < 0) {
421                                                 cpy_t--;
422                                         } else {
423                                                 cpy_t++;
424                                         }
425                                         count -= 1024;
426                                 }
427                                 if(ax > 0) {
428                                         cpx_t++;
429                                 } else if(ax < 0) {
430                                         cpx_t--;
431                                 }
432                         }
433                         lastflag = put_dot(cpx_t, cpy_t);
434                 } else { // ax = ay = 0
435                         lastflag = put_dot(cpx_t, cpy_t);
436                         total_bytes++;
437                 }
438         } else { // (abs(ax) < abs(ay) 
439                 diff = ((abs(ax) + 1) * 1024) / abs(ay);
440                 for(; cpy_t != y_end; ) {
441                         lastflag = put_dot(cpx_t, cpy_t);
442                         count += diff;
443                         if(count >= 1024) {
444                                 if(ay > 0) {
445                                         lastflag = put_dot(cpx_t, cpy_t + 1);
446                                 } else if(ay < 0) {
447                                         lastflag = put_dot(cpx_t, cpy_t - 1);
448                                 }                                 
449                                 if(ax < 0) {
450                                         cpx_t--;
451                                 } else if(ax > 0) {
452                                         cpx_t++;
453                                 }
454                                 count -= 1024;
455                         }
456                         if(ay > 0) {
457                                 cpy_t++;
458                         } else {
459                                 cpy_t--;
460                         }
461                 }
462                 lastflag = put_dot(cpx_t, cpy_t);
463         }
464         do_alucmds(alu_addr);
465
466         usec = (double)total_bytes / 16.0;
467         //if(usec >= 1.0) { // 1MHz
468         register_event(this, EVENT_MB61VH010_BUSY_OFF, usec, false, &eventid_busy) ;
469                 //} else {
470                 //busy_flag = false;
471                 //}
472         mask_reg = mask_bak;
473         line_pattern = line_style;
474 }
475
476 bool MB61VH010::put_dot(int x, int y)
477 {
478         uint8 vmask[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
479         uint16 tmp8a;
480         uint8 mask;
481         bool flag = false;
482         
483         if((x < 0) || (y < 0)) return flag;
484         if((x >= screen_width) || (y >= screen_height)) return flag;
485         if((command_reg & 0x80) == 0) return flag;
486         
487         alu_addr = ((y * screen_width) >> 3) + (x >> 3);
488         alu_addr = alu_addr + (line_addr_offset.w.l << 1);
489         alu_addr = alu_addr & 0x7fff;
490         if(!is_400line) alu_addr = alu_addr & 0x3fff;
491         if(oldaddr == 0xffffffff) oldaddr = alu_addr;
492         
493         if(oldaddr != alu_addr) {
494                 do_alucmds(oldaddr);
495                 mask_reg = 0xff;
496                 oldaddr = alu_addr;
497                 flag = true;
498                 total_bytes++;
499         }
500         
501         if((line_style.b.h & 0x80) != 0) {
502                 mask_reg &= ~vmask[x & 7];
503         }
504         tmp8a = (line_style.w.l & 0x8000) >> 15;
505         line_style.w.l = (line_style.w.l << 1) | tmp8a;
506         return flag;
507 }
508
509 void MB61VH010::write_data8(uint32 id, uint32 data)
510 {
511         //printf("ALU: ADDR=%02x DATA=%02x\n", id, data);
512         if(id == ALU_CMDREG) {
513                 command_reg = data;
514                 return;
515         }
516         //if((command_reg & 0x80) == 0) return;
517         switch(id) {
518                 case ALU_LOGICAL_COLOR:
519                         color_reg = data;
520                         break;
521                 case ALU_WRITE_MASKREG:
522                         mask_reg = data;
523                         break;
524                 case ALU_BANK_DISABLE:
525                         bank_disable_reg = data;
526                         break;
527                 case ALU_TILEPAINT_B:
528                         tile_reg[0] = data;
529                         break;
530                 case ALU_TILEPAINT_R:
531                         tile_reg[1] = data;
532                         break;
533                 case ALU_TILEPAINT_G:
534                         tile_reg[2] = data;
535                         break;
536                 case ALU_TILEPAINT_L:
537                         tile_reg[3] = data;
538                         break;
539                 case ALU_OFFSET_REG_HIGH:
540                         line_addr_offset.b.h = data;
541                         break;
542                 case ALU_OFFSET_REG_LO:
543                         line_addr_offset.b.l = data;
544                         break;
545                 case ALU_LINEPATTERN_REG_HIGH:
546                         line_pattern.b.h = data;
547                         break;
548                 case ALU_LINEPATTERN_REG_LO:
549                         line_pattern.b.l = data;
550                         break;
551                 case ALU_LINEPOS_START_X_HIGH:
552                         line_xbegin.b.h = data;
553                         break;
554                 case ALU_LINEPOS_START_X_LOW:  
555                         line_xbegin.b.l = data;
556                         break;
557                 case ALU_LINEPOS_START_Y_HIGH:
558                         line_ybegin.b.h = data;
559                         break;
560                 case ALU_LINEPOS_START_Y_LOW:  
561                         line_ybegin.b.l = data;
562                         break;
563                 case ALU_LINEPOS_END_X_HIGH:
564                         line_xend.b.h = data;
565                         break;
566                 case ALU_LINEPOS_END_X_LOW:  
567                         line_xend.b.l = data;
568                         break;
569                 case ALU_LINEPOS_END_Y_HIGH:
570                         line_yend.b.h = data;
571                         break;
572                 case ALU_LINEPOS_END_Y_LOW:
573                         line_yend.b.l = data;
574                         do_line();
575                         break;
576                 default:
577                         if((id >= (ALU_CMPDATA_REG + 0)) && (id < (ALU_CMPDATA_REG + 8))) {
578                                 cmp_color_data[id - ALU_CMPDATA_REG] = data;
579                         } else  if((id >= ALU_WRITE_PROXY) && (id < (ALU_WRITE_PROXY + 0x18000))) {
580                                 is_400line = (target->read_signal(SIG_DISPLAY_MODE_IS_400LINE) != 0) ? true : false;
581                                 do_alucmds_dmyread(id - ALU_WRITE_PROXY);
582                         }
583                         break;
584         }
585 }
586
587 uint32 MB61VH010::read_data8(uint32 id)
588 {
589   
590         switch(id) {
591                 case ALU_CMDREG:
592                         return (uint32)command_reg;
593                         break;
594                 case ALU_LOGICAL_COLOR:
595                         return (uint32)color_reg;
596                         break;
597                 case ALU_WRITE_MASKREG:
598                         return (uint32)mask_reg;
599                         break;
600                 case ALU_CMP_STATUS_REG:
601                         return (uint32)cmp_status_reg;
602                         break;
603                 case ALU_BANK_DISABLE:
604                         return (uint32)bank_disable_reg;
605                         break;
606                 default:
607                         if((id >= ALU_WRITE_PROXY) && (id < (ALU_WRITE_PROXY + 0x18000))) {
608                                 is_400line = (target->read_signal(SIG_DISPLAY_MODE_IS_400LINE) != 0) ? true : false;
609                                 do_alucmds_dmyread(id - ALU_WRITE_PROXY);
610                         }
611                         return 0xffffffff;
612                         break;
613         }
614 }
615
616 uint32 MB61VH010::read_signal(int id)
617 {
618         uint32 val = 0x00000000;
619         switch(id) {
620                 case SIG_ALU_BUSYSTAT:
621                         if(busy_flag) val = 0xffffffff;
622                         break;
623         }
624         return val;
625 }
626
627 void MB61VH010::event_callback(int event_id, int err)
628 {
629         switch(event_id) {
630                 case EVENT_MB61VH010_BUSY_ON:
631                         busy_flag = true;
632                         if(eventid_busy >= 0) cancel_event(this, eventid_busy);
633                         eventid_busy = -1;
634                         break;
635                 case EVENT_MB61VH010_BUSY_OFF:
636                         busy_flag = false;
637                         eventid_busy = -1;
638                         break;
639         }
640 }
641
642 void MB61VH010::initialize(void)
643 {
644         busy_flag = false;
645         eventid_busy = -1;
646 }
647
648 void MB61VH010::reset(void)
649 {
650         int i;
651         busy_flag = false;
652         if(eventid_busy >= 0) cancel_event(this, eventid_busy);
653         eventid_busy = -1;
654         
655         command_reg = 0;        // D410 (RW)
656         color_reg = 0;          // D411 (RW)
657         mask_reg = 0;           // D412 (RW)
658         cmp_status_reg = 0;     // D413 (RO)
659         for(i = 0; i < 8; i++) cmp_color_data[i] = 0x80; // D413-D41A (WO)
660         bank_disable_reg = 0;   // D41B (RW)
661         for(i = 0; i < 4; i++) tile_reg[i] = 0;        // D41C-D41F (WO)
662         
663         line_addr_offset.d = 0; // D420-D421 (WO)
664         line_pattern.d = 0;     // D422-D423 (WO)
665         line_xbegin.d = 0;      // D424-D425 (WO)
666         line_ybegin.d = 0;      // D426-D427 (WO)
667         line_xend.d = 0;        // D428-D429 (WO)
668         line_yend.d = 0;        // D42A-D42B (WO)
669
670         oldaddr = 0xffffffff;
671         
672         planes = target->read_signal(SIG_DISPLAY_PLANES) & 0x07;
673         is_400line = (target->read_signal(SIG_DISPLAY_MODE_IS_400LINE) != 0) ? true : false;
674         
675         screen_width = target->read_signal(SIG_DISPLAY_X_WIDTH) * 8;
676         screen_height = target->read_signal(SIG_DISPLAY_Y_HEIGHT);
677 }