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 & 0x7fff) | (0x8000 * bank);
65 target->write_data8(raddr + DISPLAY_VRAM_DIRECT_ACCESS, readdata);
68 raddr = (addr & 0x3fff) | (0x4000 * bank);
69 target->write_data8(raddr + DISPLAY_VRAM_DIRECT_ACCESS, readdata);
75 uint8 MB61VH010::do_pset(uint32 addr)
78 uint32 raddr = addr; // Use banked ram.
81 int planes_b = planes;
82 if(planes_b >= 4) planes_b = 4;
83 for(i = 0; i < planes_b; i++) {
84 if((bank_disable_reg & (1 << i)) != 0) {
87 if((color_reg & (1 << i)) == 0) {
93 srcdata = do_read(addr, i);
94 bitmask = bitmask & (~mask_reg);
95 srcdata = srcdata & mask_reg;
96 srcdata = srcdata | bitmask;
97 do_write(addr, i, srcdata);
102 uint8 MB61VH010::do_blank(uint32 addr)
107 if(planes >= 4) planes = 4;
108 for(i = 0; i < planes; i++) {
109 if((bank_disable_reg & (1 << i)) != 0) {
112 srcdata = do_read(addr, i);
113 srcdata = srcdata & mask_reg;
114 do_write(addr, i, srcdata);
119 uint8 MB61VH010::do_or(uint32 addr)
125 if(planes >= 4) planes = 4;
126 for(i = 0; i < planes; i++) {
127 if((bank_disable_reg & (1 << i)) != 0) {
130 srcdata = do_read(addr, i);
131 if((color_reg & (1 << i)) == 0) {
132 bitmask = srcdata; // srcdata | 0x00
134 bitmask = 0xff; // srcdata | 0xff
136 bitmask = bitmask & ~mask_reg;
137 srcdata = (srcdata & mask_reg) | bitmask;
138 do_write(addr, i, srcdata);
143 uint8 MB61VH010::do_and(uint32 addr)
149 if(planes >= 4) planes = 4;
150 for(i = 0; i < planes; i++) {
151 if((bank_disable_reg & (1 << i)) != 0) {
154 srcdata = do_read(addr, i);
155 if((color_reg & (1 << i)) == 0) {
156 bitmask = 0x00; // srcdata & 0x00
158 bitmask = srcdata; // srcdata & 0xff;
160 bitmask = bitmask & ~mask_reg;
161 srcdata = (srcdata & mask_reg) | bitmask;
162 do_write(addr, i, srcdata);
167 uint8 MB61VH010::do_xor(uint32 addr)
173 if(planes >= 4) planes = 4;
174 for(i = 0; i < planes; i++) {
175 if((bank_disable_reg & (1 << i)) != 0) {
178 srcdata = do_read(addr, i);
179 if((color_reg & (1 << i)) == 0) {
180 bitmask = srcdata ^ 0x00;
182 bitmask = srcdata ^ 0xff;
184 bitmask = bitmask & ~mask_reg;
185 srcdata = (srcdata & mask_reg) | bitmask;
186 do_write(addr, i, srcdata);
191 uint8 MB61VH010::do_not(uint32 addr)
197 if(planes >= 4) planes = 4;
198 for(i = 0; i < planes; i++) {
199 if((bank_disable_reg & (1 << i)) != 0) {
202 srcdata = do_read(addr, i);
205 bitmask = bitmask & ~mask_reg;
206 srcdata = (srcdata & mask_reg) | bitmask;
207 do_write(addr, i, srcdata);
213 uint8 MB61VH010::do_tilepaint(uint32 addr)
219 if(planes > 4) planes = 4;
220 for(i = 0; i < planes; i++) {
221 if((bank_disable_reg & (1 << i)) != 0) {
224 srcdata = do_read(addr, i);
225 bitmask = tile_reg[i] & (~mask_reg);
226 srcdata = (srcdata & mask_reg) | bitmask;
227 do_write(addr, i, srcdata);
232 uint8 MB61VH010::do_compare(uint32 addr)
234 uint32 offset = 0x4000;
236 uint8 disables = ~bank_disable_reg;
240 uint8 cmp_reg_bak[8];
245 disables = disables & 0x07;
247 for(j = 0; j < 8; j++) {
248 if((cmp_color_data[j] & 0x80) == 0) {
249 cmp_reg_bak[k] = cmp_color_data[j] & disables;
253 cmp_status_reg = 0x00;
254 if(k <= 0) return 0xff;
255 b = do_read(addr, 0);
256 r = do_read(addr, 1);
257 g = do_read(addr, 2);
258 for(i = 0; i < 8; i++) {
260 tmpcol = (b & 0x80) >> 7;
261 tmpcol = tmpcol | ((r & 0x80) >> 6);
262 tmpcol = tmpcol | ((g & 0x80) >> 5);
263 //tmpcol |= ((t & 0x80) != 0) ? 8 : 0;
264 tmpcol = tmpcol & disables;
265 for(j = 0; j < k; j++) {
266 if(cmp_reg_bak[j] == tmpcol) {
267 tmp_stat = tmp_stat | 0x01;
276 cmp_status_reg = tmp_stat;
280 void MB61VH010::do_alucmds_dmyread(uint32 addr)
283 addr = addr & 0x3fff;
289 addr = addr & 0x7fff;
291 if((command_reg & 0x80) == 0) {
295 //cmp_status_reg = 0x00;
296 if((command_reg & 0x40) != 0) do_compare(addr);
297 switch(command_reg & 0x07) {
323 //printf("ALU DMYREAD ADDR=%04x, CMD=%02x CMP STATUS=%02x\n", addr, command_reg, cmp_status_reg);
324 //if(eventid_busy >= 0) cancel_event(this, eventid_busy) ;
325 //register_event(this, EVENT_MB61VH010_BUSY_OFF, 1.0 / 16.0, false, &eventid_busy) ;
328 uint8 MB61VH010::do_alucmds(uint32 addr)
331 addr = addr & 0x3fff;
337 addr = addr & 0x7fff;
339 //cmp_status_reg = 0x00;
340 if((command_reg & 0x40) != 0) do_compare(addr);
341 switch(command_reg & 0x07) {
343 return do_pset(addr);
346 return do_blank(addr);
361 return do_tilepaint(addr);
364 return do_compare(addr);
370 void MB61VH010::do_line(void)
372 uint32 x_begin = line_xbegin.w.l;
373 uint32 x_end = line_xend.w.l;
374 uint32 y_begin = line_ybegin.w.l;
375 uint32 y_end = line_yend.w.l;
376 int cpx_t = (int)x_begin;
377 int cpy_t = (int)y_begin;
378 int ax = (int)x_end - (int)x_begin;
379 int ay = (int)y_end - (int)y_begin;
384 //uint8 mask_bak = mask_reg;
386 uint8 vmask[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
388 bool lastflag = false;
391 oldaddr = 0xffffffff;
392 alu_addr = 0xffffffff;
393 //if ((x_begin >= screen_width) && (x_end >= screen_width)) return;
394 //if ((y_begin >= screen_height) && (y_end >= screen_height)) return;
395 line_style = line_pattern;
400 if ((line_style.b.h & 0x80) != 0) {
401 mask_reg &= ~vmask[cpx_t & 7];
403 tmp8a = ((line_style.b.h & 0x80) >> 7) & 0x01;
404 line_style.w.l = (line_style.w.l << 1) | tmp8a;
408 //printf("LINE: (%d,%d)-(%d,%d)\n", x_begin, y_begin, x_end , y_end);
411 //if((x_end >= screen_width) && (x_begin < screen_width)) x_end = screen_width - 1;
412 //printf("LINE: (%d,%d)-(%d,%d)\n", x_begin, y_begin, x_end , y_end);
413 for(; cpx_t <= (int)x_end; cpx_t++) {
414 lastflag = put_dot(cpx_t, cpy_t);
417 for(; cpx_t >= (int)x_end; cpx_t--) {
418 lastflag = put_dot(cpx_t, cpy_t);
421 } else if(xcount == 0) {
423 if((y_end >= screen_height) && (y_begin < screen_height)) y_end = screen_height - 1;
424 for(; cpy_t <= (int)y_end; cpy_t++) {
425 lastflag = put_dot(cpx_t, cpy_t);
428 for(; cpy_t >= (int)y_end; cpy_t--) {
429 lastflag = put_dot(cpx_t, cpy_t);
432 } else if(xcount >= ycount) {
433 diff = (ycount * 32768) / xcount;
435 //if(x_end == 0) xcount = x_begin;
437 if(x_end >= screen_width) xcount = (int)screen_width - (int)x_begin - 1;
439 for(; xcount >= 0; xcount-- ) {
440 lastflag = put_dot(cpx_t, cpy_t);
444 if(cpy_t > (int)y_end) cpy_t--;
446 if(cpy_t < (int)y_end) cpy_t++;
456 } else if(xcount == ycount) {
460 if(x_end >= screen_width) xcount = (int)screen_width - (int)x_begin - 1;
462 for(; xcount >= 0; xcount-- ) {
463 lastflag = put_dot(cpx_t, cpy_t);
475 } else { // (abs(ax) <= abs(ay)
476 diff = (xcount * 32768) / ycount;
478 //if(y_end < 0) ycount = y_begin;
480 if(y_end >= screen_height) ycount = screen_height - y_begin - 1;
482 for(; ycount >= 0; ycount--) {
483 lastflag = put_dot(cpx_t, cpy_t);
487 if(cpx_t > (int)x_end) cpx_t--;
489 if(cpx_t < (int)x_end) cpx_t++;
500 if(!lastflag) total_bytes++;
501 if(alu_addr != 0xffffffff) do_alucmds(alu_addr);
502 if(total_bytes > 16) { // Over 1.0us
503 usec = (double)total_bytes / 16.0;
504 if(eventid_busy >= 0) cancel_event(this, eventid_busy) ;
505 register_event(this, EVENT_MB61VH010_BUSY_OFF, usec, false, &eventid_busy) ;
509 //mask_reg = mask_bak;
512 bool MB61VH010::put_dot(int x, int y)
514 uint8 vmask[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
518 if((x < 0) || (y < 0)) return flag;
519 if(y >= (int)screen_height) return flag;
520 //if((command_reg & 0x80) == 0) return flag;
522 alu_addr = (y * screen_width + x) >> 3;
523 alu_addr = alu_addr + line_addr_offset.w.l;
524 alu_addr = alu_addr & 0x7fff;
525 if(!is_400line) alu_addr = alu_addr & 0x3fff;
527 if(oldaddr != alu_addr) {
528 if(oldaddr == 0xffffffff) oldaddr = alu_addr;
529 //printf("** %d %d %04x %04x %02x\n", x, y, line_addr_offset.w, alu_addr, command_reg );
536 //printf("** %d %d %04x %04x %02x\n", x, y, line_addr_offset.w, alu_addr, command_reg );
538 if((line_style.b.h & 0x80) != 0) {
539 mask_reg &= ~vmask[x & 7];
541 //tmp8a = (line_style.w.l & 0x8000) >> 15;
542 tmp8a = ((line_style.b.h & 0x80) >> 7) & 0x01;
543 line_style.w.l = (line_style.w.l << 1) | tmp8a;
547 void MB61VH010::write_data8(uint32 id, uint32 data)
549 //printf("ALU: ADDR=%02x DATA=%02x\n", id, data);
550 if(id == ALU_CMDREG) {
555 case ALU_LOGICAL_COLOR:
558 case ALU_WRITE_MASKREG:
561 case ALU_BANK_DISABLE:
562 bank_disable_reg = data;
564 case ALU_TILEPAINT_B:
567 case ALU_TILEPAINT_R:
570 case ALU_TILEPAINT_G:
573 case ALU_TILEPAINT_L:
576 case ALU_OFFSET_REG_HIGH:
577 line_addr_offset.b.h &= 0x01;
578 line_addr_offset.b.h = line_addr_offset.b.h | ((data << 1) & 0x3e);
580 case ALU_OFFSET_REG_LO:
581 line_addr_offset.b.l = data << 1;
582 line_addr_offset.b.h &= 0xfe;
583 line_addr_offset.b.h = line_addr_offset.b.h | ((data >> 7) & 0x01);
585 case ALU_LINEPATTERN_REG_HIGH:
586 line_pattern.b.h = data;
588 case ALU_LINEPATTERN_REG_LO:
589 line_pattern.b.l = data;
591 case ALU_LINEPOS_START_X_HIGH:
592 line_xbegin.b.h = data & 0x03;
594 case ALU_LINEPOS_START_X_LOW:
595 line_xbegin.b.l = data;
597 case ALU_LINEPOS_START_Y_HIGH:
598 line_ybegin.b.h = data & 0x01;
600 case ALU_LINEPOS_START_Y_LOW:
601 line_ybegin.b.l = data;
603 case ALU_LINEPOS_END_X_HIGH:
604 line_xend.b.h = data & 0x03;
606 case ALU_LINEPOS_END_X_LOW:
607 line_xend.b.l = data;
609 case ALU_LINEPOS_END_Y_HIGH:
610 line_yend.b.h = data & 0x01;
612 case ALU_LINEPOS_END_Y_LOW:
613 line_yend.b.l = data;
617 if((id >= (ALU_CMPDATA_REG + 0)) && (id < (ALU_CMPDATA_REG + 8))) {
618 cmp_color_data[id - ALU_CMPDATA_REG] = data;
619 } else if((id >= ALU_WRITE_PROXY) && (id < (ALU_WRITE_PROXY + 0xc000))) {
620 uint32 raddr = id - ALU_WRITE_PROXY;
622 if(raddr >= 0x8000) return;
624 raddr = raddr & 0x3fff;
626 do_alucmds_dmyread(raddr);
632 uint32 MB61VH010::read_data8(uint32 id)
637 return (uint32)command_reg;
639 case ALU_LOGICAL_COLOR:
640 return (uint32)color_reg;
642 case ALU_WRITE_MASKREG:
643 return (uint32)mask_reg;
645 case ALU_CMP_STATUS_REG:
646 return (uint32)cmp_status_reg;
648 case ALU_BANK_DISABLE:
649 return (uint32)bank_disable_reg;
652 if((id >= ALU_WRITE_PROXY) && (id < (ALU_WRITE_PROXY + 0xc000))) {
654 raddr = id - ALU_WRITE_PROXY;
656 if(raddr >= 0x8000) return 0xffffffff;
658 raddr = raddr & 0x3fff;
660 //dmydata = target->read_data8(raddr + DISPLAY_VRAM_DIRECT_ACCESS);
661 do_alucmds_dmyread(raddr);
662 raddr = (id - ALU_WRITE_PROXY) % 0xc000;
663 dmydata = target->read_data8(raddr + DISPLAY_VRAM_DIRECT_ACCESS);
671 uint32 MB61VH010::read_signal(int id)
673 uint32 val = 0x00000000;
675 case SIG_ALU_BUSYSTAT:
676 if(busy_flag) val = 0xffffffff;
682 void MB61VH010::write_signal(int id, uint32 data, uint32 mask)
684 bool flag = ((data & mask) != 0);
686 case SIG_ALU_400LINE:
689 case SIG_ALU_MULTIPAGE:
690 multi_page = (data & mask) & 0x07;
693 planes = (data & mask) & 0x07;
694 if(planes >= 4) planes = 4;
696 case SIG_ALU_X_WIDTH:
697 screen_width = (data << 3) & 0x3ff;
699 case SIG_ALU_Y_HEIGHT:
700 screen_height = data & 0x3ff;
705 void MB61VH010::event_callback(int event_id, int err)
708 case EVENT_MB61VH010_BUSY_ON:
710 if(eventid_busy >= 0) cancel_event(this, eventid_busy);
713 case EVENT_MB61VH010_BUSY_OFF:
720 void MB61VH010::initialize(void)
731 command_reg = 0; // D410 (RW)
732 color_reg = 0; // D411 (RW)
733 mask_reg = 0; // D412 (RW)
734 cmp_status_reg = 0; // D413 (RO)
735 for(i = 0; i < 8; i++) cmp_color_data[i] = 0x80; // D413-D41A (WO)
736 bank_disable_reg = 0; // D41B (RW)
737 for(i = 0; i < 4; i++) tile_reg[i] = 0; // D41C-D41F (WO)
739 line_addr_offset.d = 0; // D420-D421 (WO)
740 line_pattern.d = 0; // D422-D423 (WO)
741 line_xbegin.d = 0; // D424-D425 (WO)
742 line_ybegin.d = 0; // D426-D427 (WO)
743 line_xend.d = 0; // D428-D429 (WO)
744 line_yend.d = 0; // D42A-D42B (WO)
748 void MB61VH010::reset(void)
752 if(eventid_busy >= 0) cancel_event(this, eventid_busy);
755 command_reg = 0; // D410 (RW)
756 color_reg = 0; // D411 (RW)
757 mask_reg = 0; // D412 (RW)
758 cmp_status_reg = 0; // D413 (RO)
759 for(i = 0; i < 8; i++) cmp_color_data[i] = 0x80; // D413-D41A (WO)
760 bank_disable_reg = 0; // D41B (RW)
761 for(i = 0; i < 4; i++) tile_reg[i] = 0; // D41C-D41F (WO)
763 line_addr_offset.d = 0; // D420-D421 (WO)
764 line_pattern.d = 0; // D422-D423 (WO)
765 line_xbegin.d = 0; // D424-D425 (WO)
766 line_ybegin.d = 0; // D426-D427 (WO)
767 line_xend.d = 0; // D428-D429 (WO)
768 line_yend.d = 0; // D42A-D42B (WO)
770 oldaddr = 0xffffffff;
772 if(planes >= 4) planes = 4;
775 #define STATE_VERSION 1
776 void MB61VH010::save_state(FILEIO *state_fio)
779 state_fio->FputUint32(STATE_VERSION);
780 state_fio->FputInt32(this_device_id);
783 state_fio->FputUint8(command_reg);
784 state_fio->FputUint8(color_reg);
785 state_fio->FputUint8(mask_reg);
786 state_fio->FputUint8(cmp_status_reg);
787 for(i = 0; i < 8; i++) state_fio->FputUint8(cmp_color_data[i]);
788 state_fio->FputUint8(bank_disable_reg);
789 for(i = 0; i < 4; i++) state_fio->FputUint8(tile_reg[i]);
790 state_fio->FputUint8(multi_page);
792 state_fio->FputUint32_BE(line_addr_offset.d);
793 state_fio->FputUint16_BE(line_pattern.w.l);
794 state_fio->FputUint16_BE(line_xbegin.w.l);
795 state_fio->FputUint16_BE(line_ybegin.w.l);
796 state_fio->FputUint16_BE(line_xend.w.l);
797 state_fio->FputUint16_BE(line_yend.w.l);
799 state_fio->FputBool(busy_flag);
800 state_fio->FputInt32_BE(eventid_busy);
802 state_fio->FputUint32_BE(total_bytes);
803 state_fio->FputUint32_BE(oldaddr);
804 state_fio->FputUint32_BE(alu_addr);
806 state_fio->FputUint32_BE(planes);
807 state_fio->FputBool(is_400line);
808 state_fio->FputUint32_BE(screen_width);
809 state_fio->FputUint32_BE(screen_height);
811 state_fio->FputUint16_BE(line_style.w.l);
816 bool MB61VH010::load_state(FILEIO *state_fio)
818 uint32 version = state_fio->FgetUint32();
821 if(this_device_id != state_fio->FgetInt32()) return false;
823 command_reg = state_fio->FgetUint8();
824 color_reg = state_fio->FgetUint8();
825 mask_reg = state_fio->FgetUint8();
826 cmp_status_reg = state_fio->FgetUint8();
827 for(i = 0; i < 8; i++) cmp_color_data[i] = state_fio->FgetUint8();
828 bank_disable_reg = state_fio->FgetUint8();
829 for(i = 0; i < 4; i++) tile_reg[i] = state_fio->FgetUint8();
830 multi_page = state_fio->FgetUint8();
832 line_addr_offset.d = state_fio->FgetUint32_BE();
839 line_pattern.w.l = state_fio->FgetUint16_BE();
840 line_xbegin.w.l = state_fio->FgetUint16_BE();
841 line_ybegin.w.l = state_fio->FgetUint16_BE();
842 line_xend.w.l = state_fio->FgetUint16_BE();
843 line_yend.w.l = state_fio->FgetUint16_BE();
845 busy_flag = state_fio->FgetBool();
846 eventid_busy = state_fio->FgetInt32_BE();
848 total_bytes = state_fio->FgetUint32_BE();
849 oldaddr = state_fio->FgetUint32_BE();
850 alu_addr = state_fio->FgetUint32_BE();
852 planes = state_fio->FgetUint32_BE();
853 is_400line = state_fio->FgetBool();
854 screen_width = state_fio->FgetUint32_BE();
855 screen_height = state_fio->FgetUint32_BE();
858 line_style.w.l = state_fio->FgetUint16_BE();