2 * FM77AV/FM16β ALU [mb61vh010.cpp]
3 * of Fujitsu MB61VH010/011
5 * Author: K.Ohta <whatisthis.sowhat _at_ gmail.com>
8 * Mar 28, 2015 : Initial
12 #include "mb61vh010.h"
15 MB61VH010::MB61VH010(VM *parent_vm, EMU *parent_emu) : DEVICE(parent_vm, parent_emu)
21 MB61VH010::~MB61VH010()
25 uint8 MB61VH010::do_read(uint32 addr, uint32 bank)
29 if(((1 << bank) & multi_page) != 0) return 0xff;
31 if((addr & 0xffff) < 0x8000) {
32 raddr = (addr & 0x7fff) | (0x8000 * bank);
33 return target->read_data8(raddr + DISPLAY_VRAM_DIRECT_ACCESS);
36 raddr = (addr & 0x3fff) | (0x4000 * bank);
37 return target->read_data8(raddr + DISPLAY_VRAM_DIRECT_ACCESS);
42 uint8 MB61VH010::do_write(uint32 addr, uint32 bank, uint8 data)
47 if(((1 << bank) & multi_page) != 0) return 0xff;
48 if((command_reg & 0x40) != 0) { // Calculate before writing
49 readdata = do_read(addr, bank);
51 if((command_reg & 0x20) != 0) { // NAND
52 readdata = readdata & cmp_status_reg;
53 data = data & (~cmp_status_reg);
55 readdata = readdata & (~cmp_status_reg);
56 data = data & cmp_status_reg;
58 readdata = readdata | data;
63 if((addr & 0xffff) < 0x8000) {
64 //raddr = ((addr + (line_addr_offset.w.l << 1)) & 0x7fff) | (0x8000 * bank);
65 raddr = (addr & 0x7fff) | (0x8000 * bank);
66 target->write_data8(raddr + DISPLAY_VRAM_DIRECT_ACCESS, readdata);
69 //raddr = ((addr + (line_addr_offset.w.l << 1)) & 0x3fff) | (0x4000 * bank);
70 raddr = (addr & 0x3fff) | (0x4000 * bank);
71 target->write_data8(raddr + DISPLAY_VRAM_DIRECT_ACCESS, readdata);
77 uint8 MB61VH010::do_pset(uint32 addr)
80 uint32 raddr = addr; // Use banked ram.
83 int planes_b = planes;
84 if(planes_b >= 4) planes_b = 4;
85 for(i = 0; i < planes_b; i++) {
86 if((bank_disable_reg & (1 << i)) != 0) {
89 if((color_reg & (1 << i)) == 0) {
95 srcdata = do_read(addr, i);
96 bitmask = bitmask & (~mask_reg);
97 srcdata = srcdata & mask_reg;
98 srcdata = srcdata | bitmask;
99 do_write(addr, i, srcdata);
104 uint8 MB61VH010::do_blank(uint32 addr)
109 if(planes >= 4) planes = 4;
110 for(i = 0; i < planes; i++) {
111 if((bank_disable_reg & (1 << i)) != 0) {
114 srcdata = do_read(addr, i);
115 srcdata = srcdata & mask_reg;
116 do_write(addr, i, srcdata);
121 uint8 MB61VH010::do_or(uint32 addr)
127 if(planes >= 4) planes = 4;
128 for(i = 0; i < planes; i++) {
129 if((bank_disable_reg & (1 << i)) != 0) {
132 srcdata = do_read(addr, i);
133 if((color_reg & (1 << i)) == 0) {
134 bitmask = srcdata; // srcdata | 0x00
136 bitmask = 0xff; // srcdata | 0xff
138 bitmask = bitmask & ~mask_reg;
139 srcdata = (srcdata & mask_reg) | bitmask;
140 do_write(addr, i, srcdata);
145 uint8 MB61VH010::do_and(uint32 addr)
151 if(planes >= 4) planes = 4;
152 for(i = 0; i < planes; i++) {
153 if((bank_disable_reg & (1 << i)) != 0) {
156 srcdata = do_read(addr, i);
157 if((color_reg & (1 << i)) == 0) {
158 bitmask = 0x00; // srcdata & 0x00
160 bitmask = srcdata; // srcdata & 0xff;
162 bitmask = bitmask & ~mask_reg;
163 srcdata = (srcdata & mask_reg) | bitmask;
164 do_write(addr, i, srcdata);
169 uint8 MB61VH010::do_xor(uint32 addr)
175 if(planes >= 4) planes = 4;
176 for(i = 0; i < planes; i++) {
177 if((bank_disable_reg & (1 << i)) != 0) {
180 srcdata = do_read(addr, i);
181 if((color_reg & (1 << i)) == 0) {
182 bitmask = srcdata ^ 0x00;
184 bitmask = srcdata ^ 0xff;
186 bitmask = bitmask & ~mask_reg;
187 srcdata = (srcdata & mask_reg) | bitmask;
188 do_write(addr, i, srcdata);
193 uint8 MB61VH010::do_not(uint32 addr)
199 if(planes >= 4) planes = 4;
200 for(i = 0; i < planes; i++) {
201 if((bank_disable_reg & (1 << i)) != 0) {
204 srcdata = do_read(addr, i);
207 bitmask = bitmask & ~mask_reg;
208 srcdata = (srcdata & mask_reg) | bitmask;
209 do_write(addr, i, srcdata);
215 uint8 MB61VH010::do_tilepaint(uint32 addr)
220 //printf("Tilepaint CMD=%02x, ADDR=%04x Planes=%d, disable=%d, tile_reg=(%02x %02x %02x %02x)\n",
221 // command_reg, addr, planes, bank_disable_reg, tile_reg[0], tile_reg[1], tile_reg[2], tile_reg[3]);
222 if(planes > 4) planes = 4;
223 for(i = 0; i < planes; i++) {
224 if((bank_disable_reg & (1 << i)) != 0) {
227 srcdata = do_read(addr, i);
228 bitmask = tile_reg[i] & (~mask_reg);
229 srcdata = (srcdata & mask_reg) | bitmask;
230 do_write(addr, i, srcdata);
235 uint8 MB61VH010::do_compare(uint32 addr)
237 uint32 offset = 0x4000;
239 uint8 disables = ~bank_disable_reg;
240 //uint8 disables = bank_disable_reg;
243 uint8 cmp_reg_bak[8];
248 disables = disables & 0x07;
250 for(j = 0; j < 8; j++) {
251 if((cmp_color_data[j] & 0x80) == 0) {
252 cmp_reg_bak[k] = cmp_color_data[j] & disables;
256 cmp_status_reg = 0x00;
257 if(k <= 0) return 0xff;
259 b = do_read(addr, 0);
260 r = do_read(addr, 1);
261 g = do_read(addr, 2);
262 for(i = 0; i < 8; i++) {
264 tmpcol = (b & 0x80) >> 7;
265 tmpcol = tmpcol | ((r & 0x80) >> 6);
266 tmpcol = tmpcol | ((g & 0x80) >> 5);
267 //tmpcol |= ((t & 0x80) != 0) ? 8 : 0;
268 tmpcol = tmpcol & disables;
269 for(j = 0; j < k; j++) {
270 if(cmp_reg_bak[j] == tmpcol) {
271 tmp_stat = tmp_stat | 0x01;
280 cmp_status_reg = tmp_stat;
284 void MB61VH010::do_alucmds_dmyread(uint32 addr)
287 addr = addr & 0x3fff;
293 addr = addr & 0x7fff;
295 if((command_reg & 0x80) == 0) {
299 cmp_status_reg = 0x00;
300 if((command_reg & 0x40) != 0) do_compare(addr);
301 switch(command_reg & 0x07) {
327 //printf("ALU DMYREAD ADDR=%04x, CMD=%02x CMP STATUS=%02x\n", addr, command_reg, cmp_status_reg);
328 //if(eventid_busy >= 0) cancel_event(this, eventid_busy) ;
329 //register_event(this, EVENT_MB61VH010_BUSY_OFF, 1.0 / 16.0, false, &eventid_busy) ;
332 uint8 MB61VH010::do_alucmds(uint32 addr)
335 addr = addr & 0x3fff;
341 addr = addr & 0x7fff;
343 cmp_status_reg = 0x00;
344 if((command_reg & 0x40) != 0) do_compare(addr);
345 switch(command_reg & 0x07) {
347 return do_pset(addr);
350 return do_blank(addr);
365 return do_tilepaint(addr);
368 return do_compare(addr);
374 void MB61VH010::do_line(void)
376 uint32 x_begin = line_xbegin.w.l;
377 uint32 x_end = line_xend.w.l;
378 uint32 y_begin = line_ybegin.w.l;
379 uint32 y_end = line_yend.w.l;
380 int cpx_t = (int)x_begin;
381 int cpy_t = (int)y_begin;
382 int ax = (int)x_end - (int)x_begin;
383 int ay = (int)y_end - (int)y_begin;
388 uint8 mask_bak = mask_reg;
390 uint8 vmask[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
392 bool lastflag = false;
395 oldaddr = 0xffffffff;
396 if ((x_begin >= screen_width) && (x_end >= screen_width)) return;
397 if ((y_begin >= screen_height) && (y_end >= screen_height)) return;
399 line_style = line_pattern;
404 if ((line_style.b.h & 0x80) != 0) {
405 mask_reg &= ~vmask[cpx_t & 7];
407 tmp8a = ((line_style.b.h & 0x80) >> 7) & 0x01;
408 line_style.w.l = (line_style.w.l << 1) | tmp8a;
412 //lastflag = put_dot(x_begin, y_begin);
415 if(x_end >= screen_width) x_end = screen_width - 1;
416 for(; cpx_t <= (int)x_end; cpx_t++) {
417 lastflag = put_dot(cpx_t, cpy_t);
420 if(x_end < 0) x_end = 0;
421 for(; cpx_t >= (int)x_end; cpx_t--) {
422 lastflag = put_dot(cpx_t, cpy_t);
425 } else if(xcount == 0) {
427 if(y_end >= screen_height) y_end = screen_height - 1;
428 for(; cpy_t <= (int)y_end; cpy_t++) {
429 lastflag = put_dot(cpx_t, cpy_t);
432 //if(y_end < 0) y_end = 0;
433 for(; cpy_t >= (int)y_end; cpy_t--) {
434 lastflag = put_dot(cpx_t, cpy_t);
437 } else if(xcount >= ycount) {
438 diff = (ycount * 32768) / xcount;
440 if(x_end < 0) xcount = x_begin;
442 //if(x_end >= screen_width) xcount = screen_width - x_begin - 1;
443 if(x_end >= screen_width) xcount = (int)screen_width - (int)x_begin;
445 for(; xcount >= 0; xcount-- ) {
446 lastflag = put_dot(cpx_t, cpy_t);
450 if(cpy_t > (int)y_end) cpy_t--;
452 if(cpy_t < (int)y_end) cpy_t++;
462 } else if(xcount == ycount) {
467 //if(x_end >= screen_width) xcount = (int)(screen_width - x_begin) - 1;
468 if (x_end >= screen_width) xcount = (int)screen_width - (int)x_begin;
470 for(; xcount >= 0; xcount-- ) {
471 lastflag = put_dot(cpx_t, cpy_t);
484 } else { // (abs(ax) <= abs(ay)
485 diff = (xcount * 32768) / ycount;
487 if(y_end < 0) ycount = y_begin;
489 if(y_end >= screen_height) ycount = screen_height - y_begin - 1;
491 for(; ycount >= 0; ycount--) {
492 lastflag = put_dot(cpx_t, cpy_t);
496 if(cpx_t > (int)x_end) cpx_t--;
498 if(cpx_t < (int)x_end) cpx_t++;
510 //lastflag = put_dot(x_end, y_end);
511 if(!lastflag) total_bytes++;
512 do_alucmds(alu_addr);
514 if(total_bytes > 0) { // Over 0.5us
515 usec = (double)total_bytes / 16.0;
516 if(eventid_busy >= 0) cancel_event(this, eventid_busy) ;
517 register_event(this, EVENT_MB61VH010_BUSY_OFF, usec, false, &eventid_busy) ;
524 bool MB61VH010::put_dot(int x, int y)
526 uint8 vmask[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
530 if((x < 0) || (y < 0)) return flag;
531 if((x >= (int)screen_width) || (y >= (int)screen_height)) return flag;
532 if((command_reg & 0x80) == 0) return flag;
534 alu_addr = ((y * screen_width) >> 3) + (x >> 3);
535 alu_addr = alu_addr + ((line_addr_offset.w.l << 1) & 0x3ffe);
536 alu_addr = alu_addr & 0x7fff;
537 if(!is_400line) alu_addr = alu_addr & 0x3fff;
538 //if(oldaddr == 0xffffffff) oldaddr = alu_addr;
540 if(oldaddr != alu_addr) {
541 if(oldaddr == 0xffffffff) oldaddr = alu_addr;
542 //printf("** %d %d %04x %04x %02x\n", x, y, line_addr_offset.w, alu_addr, command_reg );
549 //printf("** %d %d %04x %04x %02x\n", x, y, line_addr_offset.w, alu_addr, command_reg );
551 if((line_style.b.h & 0x80) != 0) {
552 mask_reg &= ~vmask[x & 7];
554 //tmp8a = (line_style.w.l & 0x8000) >> 15;
555 tmp8a = ((line_style.b.h & 0x80) >> 7) & 0x01;
556 line_style.w.l = (line_style.w.l << 1) | tmp8a;
560 void MB61VH010::write_data8(uint32 id, uint32 data)
562 //printf("ALU: ADDR=%02x DATA=%02x\n", id, data);
563 if(id == ALU_CMDREG) {
568 case ALU_LOGICAL_COLOR:
571 case ALU_WRITE_MASKREG:
574 case ALU_BANK_DISABLE:
575 bank_disable_reg = data;
577 case ALU_TILEPAINT_B:
580 case ALU_TILEPAINT_R:
583 case ALU_TILEPAINT_G:
586 case ALU_TILEPAINT_L:
589 case ALU_OFFSET_REG_HIGH:
590 line_addr_offset.b.h = data;
592 case ALU_OFFSET_REG_LO:
593 line_addr_offset.b.l = data;
595 case ALU_LINEPATTERN_REG_HIGH:
596 line_pattern.b.h = data;
598 case ALU_LINEPATTERN_REG_LO:
599 line_pattern.b.l = data;
601 case ALU_LINEPOS_START_X_HIGH:
602 line_xbegin.b.h = data;
604 case ALU_LINEPOS_START_X_LOW:
605 line_xbegin.b.l = data;
607 case ALU_LINEPOS_START_Y_HIGH:
608 line_ybegin.b.h = data;
610 case ALU_LINEPOS_START_Y_LOW:
611 line_ybegin.b.l = data;
613 case ALU_LINEPOS_END_X_HIGH:
614 line_xend.b.h = data;
616 case ALU_LINEPOS_END_X_LOW:
617 line_xend.b.l = data;
619 case ALU_LINEPOS_END_Y_HIGH:
620 line_yend.b.h = data;
622 case ALU_LINEPOS_END_Y_LOW:
623 line_yend.b.l = data;
627 if((id >= (ALU_CMPDATA_REG + 0)) && (id < (ALU_CMPDATA_REG + 8))) {
628 cmp_color_data[id - ALU_CMPDATA_REG] = data;
629 } else if((id >= ALU_WRITE_PROXY) && (id < (ALU_WRITE_PROXY + 0x18000))) {
630 uint32 raddr = id - ALU_WRITE_PROXY;
632 // raddr = raddr & 0x7fff;
634 // raddr = raddr & 0x3fff;
636 do_alucmds_dmyread(raddr);
642 uint32 MB61VH010::read_data8(uint32 id)
647 return (uint32)command_reg;
649 case ALU_LOGICAL_COLOR:
650 return (uint32)color_reg;
652 case ALU_WRITE_MASKREG:
653 return (uint32)mask_reg;
655 case ALU_CMP_STATUS_REG:
656 return (uint32)cmp_status_reg;
658 case ALU_BANK_DISABLE:
659 return (uint32)bank_disable_reg;
662 if((id >= ALU_WRITE_PROXY) && (id < (ALU_WRITE_PROXY + 0x18000))) {
664 raddr = id - ALU_WRITE_PROXY;
666 raddr = raddr & 0x7fff;
668 raddr = raddr & 0x3fff;
670 //dmydata = target->read_data8(raddr + DISPLAY_VRAM_DIRECT_ACCESS);
671 do_alucmds_dmyread(raddr);
672 raddr = (id - ALU_WRITE_PROXY) & 0xbfff;
673 dmydata = target->read_data8(raddr + DISPLAY_VRAM_DIRECT_ACCESS);
681 uint32 MB61VH010::read_signal(int id)
683 uint32 val = 0x00000000;
685 case SIG_ALU_BUSYSTAT:
686 if(busy_flag) val = 0xffffffff;
692 void MB61VH010::write_signal(int id, uint32 data, uint32 mask)
694 bool flag = ((data & mask) != 0);
696 case SIG_ALU_400LINE:
699 case SIG_ALU_MULTIPAGE:
700 multi_page = (data & mask) & 0x07;
703 planes = (data & mask) & 0x07;
704 if(planes >= 4) planes = 4;
706 case SIG_ALU_X_WIDTH:
707 screen_width = (data << 3) & 0x3ff;
709 case SIG_ALU_Y_HEIGHT:
710 screen_height = data & 0x3ff;
715 void MB61VH010::event_callback(int event_id, int err)
718 case EVENT_MB61VH010_BUSY_ON:
720 if(eventid_busy >= 0) cancel_event(this, eventid_busy);
723 case EVENT_MB61VH010_BUSY_OFF:
730 void MB61VH010::initialize(void)
741 void MB61VH010::reset(void)
745 if(eventid_busy >= 0) cancel_event(this, eventid_busy);
748 command_reg = 0; // D410 (RW)
749 color_reg = 0; // D411 (RW)
750 mask_reg = 0; // D412 (RW)
751 cmp_status_reg = 0; // D413 (RO)
752 for(i = 0; i < 8; i++) cmp_color_data[i] = 0x80; // D413-D41A (WO)
753 bank_disable_reg = 0; // D41B (RW)
754 for(i = 0; i < 4; i++) tile_reg[i] = 0; // D41C-D41F (WO)
756 line_addr_offset.d = 0; // D420-D421 (WO)
757 line_pattern.d = 0; // D422-D423 (WO)
758 line_xbegin.d = 0; // D424-D425 (WO)
759 line_ybegin.d = 0; // D426-D427 (WO)
760 line_xend.d = 0; // D428-D429 (WO)
761 line_yend.d = 0; // D42A-D42B (WO)
762 oldaddr = 0xffffffff;
764 if(planes >= 4) planes = 4;
767 #define STATE_VERSION 1
768 void MB61VH010::save_state(FILEIO *state_fio)
771 state_fio->FputUint32(STATE_VERSION);
772 state_fio->FputInt32(this_device_id);
775 state_fio->FputUint8(command_reg);
776 state_fio->FputUint8(color_reg);
777 state_fio->FputUint8(mask_reg);
778 state_fio->FputUint8(cmp_status_reg);
779 for(i = 0; i < 8; i++) state_fio->FputUint8(cmp_color_data[i]);
780 state_fio->FputUint8(bank_disable_reg);
781 for(i = 0; i < 4; i++) state_fio->FputUint8(tile_reg[i]);
782 state_fio->FputUint8(multi_page);
784 state_fio->FputUint32_BE(line_addr_offset.d);
785 state_fio->FputUint16_BE(line_pattern.w.l);
786 state_fio->FputUint16_BE(line_xbegin.w.l);
787 state_fio->FputUint16_BE(line_ybegin.w.l);
788 state_fio->FputUint16_BE(line_xend.w.l);
789 state_fio->FputUint16_BE(line_yend.w.l);
791 state_fio->FputBool(busy_flag);
792 state_fio->FputInt32_BE(eventid_busy);
794 state_fio->FputUint32_BE(total_bytes);
795 state_fio->FputUint32_BE(oldaddr);
796 state_fio->FputUint32_BE(alu_addr);
798 state_fio->FputUint32_BE(planes);
799 state_fio->FputBool(is_400line);
800 state_fio->FputUint32_BE(screen_width);
801 state_fio->FputUint32_BE(screen_height);
803 state_fio->FputUint16_BE(line_style.w.l);
808 bool MB61VH010::load_state(FILEIO *state_fio)
810 uint32 version = state_fio->FgetUint32();
813 if(this_device_id != state_fio->FgetInt32()) return false;
815 command_reg = state_fio->FgetUint8();
816 color_reg = state_fio->FgetUint8();
817 mask_reg = state_fio->FgetUint8();
818 cmp_status_reg = state_fio->FgetUint8();
819 for(i = 0; i < 8; i++) cmp_color_data[i] = state_fio->FgetUint8();
820 bank_disable_reg = state_fio->FgetUint8();
821 for(i = 0; i < 4; i++) tile_reg[i] = state_fio->FgetUint8();
822 multi_page = state_fio->FgetUint8();
824 line_addr_offset.d = state_fio->FgetUint32_BE();
831 line_pattern.w.l = state_fio->FgetUint16_BE();
832 line_xbegin.w.l = state_fio->FgetUint16_BE();
833 line_ybegin.w.l = state_fio->FgetUint16_BE();
834 line_xend.w.l = state_fio->FgetUint16_BE();
835 line_yend.w.l = state_fio->FgetUint16_BE();
837 busy_flag = state_fio->FgetBool();
838 eventid_busy = state_fio->FgetInt32_BE();
840 total_bytes = state_fio->FgetUint32_BE();
841 oldaddr = state_fio->FgetUint32_BE();
842 alu_addr = state_fio->FgetUint32_BE();
844 planes = state_fio->FgetUint32_BE();
845 is_400line = state_fio->FgetBool();
846 screen_width = state_fio->FgetUint32_BE();
847 screen_height = state_fio->FgetUint32_BE();
850 line_style.w.l = state_fio->FgetUint16_BE();