OSDN Git Service

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