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)
22 MB61VH010::~MB61VH010()
26 uint8_t MB61VH010::do_read(uint32_t addr, uint32_t bank)
30 if(((1 << bank) & multi_page) != 0) return 0xff;
32 if((addr & 0xffff) < 0x8000) {
33 raddr = (addr & 0x7fff) | (0x8000 * bank);
34 return target->read_data8(raddr + DISPLAY_VRAM_DIRECT_ACCESS);
37 raddr = (addr & 0x3fff) | (0x4000 * bank);
38 return target->read_data8(raddr + DISPLAY_VRAM_DIRECT_ACCESS);
43 uint8_t MB61VH010::do_write(uint32_t addr, uint32_t bank, uint8_t data)
48 if(((1 << bank) & multi_page) != 0) return 0xff;
49 if((command_reg & 0x40) != 0) { // Calculate before writing
50 readdata = do_read(addr, bank);
52 if((command_reg & 0x20) != 0) { // NAND
53 readdata = readdata & cmp_status_reg;
54 data = data & (~cmp_status_reg);
56 readdata = readdata & (~cmp_status_reg);
57 data = data & cmp_status_reg;
59 readdata = readdata | data;
64 if((addr & 0xffff) < 0x8000) {
65 raddr = (addr & 0x7fff) | (0x8000 * bank);
66 target->write_data8(raddr + DISPLAY_VRAM_DIRECT_ACCESS, readdata);
69 raddr = (addr & 0x3fff) | (0x4000 * bank);
70 target->write_data8(raddr + DISPLAY_VRAM_DIRECT_ACCESS, readdata);
76 uint8_t MB61VH010::do_pset(uint32_t addr)
79 uint32_t raddr = addr; // Use banked ram.
82 int planes_b = planes;
83 if(planes_b >= 4) planes_b = 4;
84 for(i = 0; i < planes_b; i++) {
85 if((bank_disable_reg & (1 << i)) != 0) {
88 if((color_reg & (1 << i)) == 0) {
94 srcdata = do_read(addr, i);
95 bitmask = bitmask & (~mask_reg);
96 srcdata = srcdata & mask_reg;
97 srcdata = srcdata | bitmask;
98 do_write(addr, i, srcdata);
103 uint8_t MB61VH010::do_blank(uint32_t addr)
108 if(planes >= 4) planes = 4;
109 for(i = 0; i < planes; i++) {
110 if((bank_disable_reg & (1 << i)) != 0) {
113 srcdata = do_read(addr, i);
114 srcdata = srcdata & mask_reg;
115 do_write(addr, i, srcdata);
120 uint8_t MB61VH010::do_or(uint32_t addr)
126 if(planes >= 4) planes = 4;
127 for(i = 0; i < planes; i++) {
128 if((bank_disable_reg & (1 << i)) != 0) {
131 srcdata = do_read(addr, i);
132 if((color_reg & (1 << i)) == 0) {
133 bitmask = srcdata; // srcdata | 0x00
135 bitmask = 0xff; // srcdata | 0xff
137 bitmask = bitmask & ~mask_reg;
138 srcdata = (srcdata & mask_reg) | bitmask;
139 do_write(addr, i, srcdata);
144 uint8_t MB61VH010::do_and(uint32_t addr)
150 if(planes >= 4) planes = 4;
151 for(i = 0; i < planes; i++) {
152 if((bank_disable_reg & (1 << i)) != 0) {
155 srcdata = do_read(addr, i);
156 if((color_reg & (1 << i)) == 0) {
157 bitmask = 0x00; // srcdata & 0x00
159 bitmask = srcdata; // srcdata & 0xff;
161 bitmask = bitmask & ~mask_reg;
162 srcdata = (srcdata & mask_reg) | bitmask;
163 do_write(addr, i, srcdata);
168 uint8_t MB61VH010::do_xor(uint32_t addr)
174 if(planes >= 4) planes = 4;
175 for(i = 0; i < planes; i++) {
176 if((bank_disable_reg & (1 << i)) != 0) {
179 srcdata = do_read(addr, i);
180 if((color_reg & (1 << i)) == 0) {
181 bitmask = srcdata ^ 0x00;
183 bitmask = srcdata ^ 0xff;
185 bitmask = bitmask & ~mask_reg;
186 srcdata = (srcdata & mask_reg) | bitmask;
187 do_write(addr, i, srcdata);
192 uint8_t MB61VH010::do_not(uint32_t addr)
198 if(planes >= 4) planes = 4;
199 for(i = 0; i < planes; i++) {
200 if((bank_disable_reg & (1 << i)) != 0) {
203 srcdata = do_read(addr, i);
206 bitmask = bitmask & ~mask_reg;
207 srcdata = (srcdata & mask_reg) | bitmask;
208 do_write(addr, i, srcdata);
214 uint8_t MB61VH010::do_tilepaint(uint32_t addr)
220 if(planes > 4) planes = 4;
221 for(i = 0; i < planes; i++) {
222 if((bank_disable_reg & (1 << i)) != 0) {
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);
233 uint8_t MB61VH010::do_compare(uint32_t addr)
235 uint32_t offset = 0x4000;
237 uint8_t disables = ~bank_disable_reg;
240 uint8_t tmp_stat = 0;
241 uint8_t cmp_reg_bak[8];
246 disables = disables & 0x07;
248 for(j = 0; j < 8; j++) {
249 if((cmp_color_data[j] & 0x80) == 0) {
250 cmp_reg_bak[k] = cmp_color_data[j] & disables;
254 cmp_status_reg = 0x00;
255 if(k <= 0) return 0xff;
256 b = do_read(addr, 0);
257 r = do_read(addr, 1);
258 g = do_read(addr, 2);
259 for(i = 0; i < 8; i++) {
261 tmpcol = (b & 0x80) >> 7;
262 tmpcol = tmpcol | ((r & 0x80) >> 6);
263 tmpcol = tmpcol | ((g & 0x80) >> 5);
264 //tmpcol |= ((t & 0x80) != 0) ? 8 : 0;
265 tmpcol = tmpcol & disables;
266 for(j = 0; j < k; j++) {
267 if(cmp_reg_bak[j] == tmpcol) {
268 tmp_stat = tmp_stat | 0x01;
277 cmp_status_reg = tmp_stat;
281 void MB61VH010::do_alucmds_dmyread(uint32_t addr)
284 addr = addr & 0x3fff;
290 addr = addr & 0x7fff;
292 if((command_reg & 0x80) == 0) {
296 //cmp_status_reg = 0x00;
297 if((command_reg & 0x40) != 0) do_compare(addr);
298 switch(command_reg & 0x07) {
324 //p_emu->out_debug_log("ALU DMYREAD ADDR=%04x, CMD=%02x CMP STATUS=%02x\n", addr, command_reg, cmp_status_reg);
325 //if(eventid_busy >= 0) cancel_event(this, eventid_busy) ;
326 //register_event(this, EVENT_MB61VH010_BUSY_OFF, 1.0 / 16.0, false, &eventid_busy) ;
329 uint8_t MB61VH010::do_alucmds(uint32_t addr)
332 addr = addr & 0x3fff;
338 addr = addr & 0x7fff;
340 //cmp_status_reg = 0x00;
341 if((command_reg & 0x40) != 0) do_compare(addr);
342 switch(command_reg & 0x07) {
344 return do_pset(addr);
347 return do_blank(addr);
362 return do_tilepaint(addr);
365 return do_compare(addr);
371 void MB61VH010::do_line(void)
373 uint32_t x_begin = line_xbegin.w.l;
374 uint32_t x_end = line_xend.w.l;
375 uint32_t y_begin = line_ybegin.w.l;
376 uint32_t y_end = line_yend.w.l;
377 int cpx_t = (int)x_begin;
378 int cpy_t = (int)y_begin;
379 int ax = (int)x_end - (int)x_begin;
380 int ay = (int)y_end - (int)y_begin;
385 //uint8_t mask_bak = mask_reg;
387 uint8_t vmask[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
389 bool lastflag = false;
392 oldaddr = 0xffffffff;
393 alu_addr = 0xffffffff;
394 //if ((x_begin >= screen_width) && (x_end >= screen_width)) return;
395 //if ((y_begin >= screen_height) && (y_end >= screen_height)) return;
396 line_style = line_pattern;
401 if ((line_style.b.h & 0x80) != 0) {
402 mask_reg &= ~vmask[cpx_t & 7];
406 //p_emu->out_debug_log("LINE: (%d,%d)-(%d,%d)\n", x_begin, y_begin, x_end , y_end);
409 if((cpx_t & 0x07) != 7) total_bytes = 1;
410 //if((x_end >= screen_width) && (x_begin < screen_width)) x_end = screen_width - 1;
411 for(; cpx_t <= (int)x_end; cpx_t++) {
412 if(cpy_t >= screen_width) break;
413 lastflag = put_dot(cpx_t, cpy_t);
414 if((cpx_t & 0x07) == 7) total_bytes++;
417 if((cpx_t & 0x07) != 0) total_bytes = 1;
418 for(; cpx_t >= (int)x_end; cpx_t--) {
420 if((cpx_t & 0x07) == 0) total_bytes++;
421 lastflag = put_dot(cpx_t, cpy_t);
424 } else if(xcount == 0) {
426 for(; cpy_t <= (int)y_end; cpy_t++) {
427 if(cpy_t >= screen_height) break;
428 lastflag = put_dot(cpx_t, cpy_t);
432 for(; cpy_t >= (int)y_end; cpy_t--) {
434 lastflag = put_dot(cpx_t, cpy_t);
438 } else if(xcount >= ycount) {
439 diff = (ycount * 32768) / xcount;
441 //if(x_end == 0) xcount = x_begin;
442 if((cpx_t & 0x07) != 0) total_bytes = 1;
444 if(x_end >= screen_width) xcount = (int)screen_width - (int)x_begin - 1;
445 if((cpx_t & 0x07) == 0) total_bytes = 1;
447 for(; xcount >= 0; xcount-- ) {
448 lastflag = put_dot(cpx_t, cpy_t);
456 if(cpy_t >= screen_height) break;
463 if((cpx_t & 0x07) == 0) total_bytes++;
464 if(cpx_t >= screen_width) break;
466 if((cpx_t & 0x07) == 0) total_bytes++;
471 } else { // (abs(ax) <= abs(ay)
472 diff = (xcount * 32768) / ycount;
474 //if(y_end < 0) ycount = y_begin;
476 if(y_end >= screen_height) ycount = screen_height - y_begin - 1;
478 for(; ycount >= 0; ycount--) {
479 lastflag = put_dot(cpx_t, cpy_t);
487 if(cpx_t > screen_width) break;
494 if(cpy_t >= screen_height) break;
501 //if(!lastflag) total_bytes++;
502 if(alu_addr < 0x8000) do_alucmds(alu_addr);
504 //if(total_bytes > 16) { // Over 1.0us
505 usec = (double)total_bytes / 16.0;
506 if(eventid_busy >= 0) cancel_event(this, eventid_busy) ;
507 register_event(this, EVENT_MB61VH010_BUSY_OFF, usec, false, &eventid_busy) ;
509 // busy_flag = false;
513 bool MB61VH010::put_dot(int x, int y)
515 uint8_t vmask[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
519 if((x < 0) || (y < 0)) return false;
520 if(y >= (int)screen_height) return false;
521 if((command_reg & 0x80) == 0) return false;
523 alu_addr = (y * screen_width + x) >> 3;
524 alu_addr = alu_addr + line_addr_offset.w.l;
525 alu_addr = alu_addr & 0x7fff;
526 if(!is_400line) alu_addr = alu_addr & 0x3fff;
528 if(oldaddr != alu_addr) {
529 if(oldaddr == 0xffffffff) {
530 if((line_style.b.h & 0x80) != 0) {
531 mask_reg &= ~vmask[x & 7];
541 if((line_style.b.h & 0x80) != 0) {
542 mask_reg &= ~vmask[x & 7];
544 tmp8a = ((line_style.b.h & 0x80) >> 7) & 0x01;
545 line_style.w.l = (line_style.w.l << 1) | tmp8a;
549 void MB61VH010::write_data8(uint32_t id, uint32_t data)
551 //p_emu->out_debug_log("ALU: ADDR=%02x DATA=%02x\n", id, data);
552 if(id == ALU_CMDREG) {
557 case ALU_LOGICAL_COLOR:
560 case ALU_WRITE_MASKREG:
563 case ALU_BANK_DISABLE:
564 bank_disable_reg = data;
566 case ALU_TILEPAINT_B:
569 case ALU_TILEPAINT_R:
572 case ALU_TILEPAINT_G:
575 case ALU_TILEPAINT_L:
578 case ALU_OFFSET_REG_HIGH:
579 line_addr_offset.b.h &= 0x01;
580 line_addr_offset.b.h = line_addr_offset.b.h | ((data << 1) & 0x3e);
582 case ALU_OFFSET_REG_LO:
583 line_addr_offset.b.l = data << 1;
584 line_addr_offset.b.h &= 0xfe;
585 line_addr_offset.b.h = line_addr_offset.b.h | ((data >> 7) & 0x01);
587 case ALU_LINEPATTERN_REG_HIGH:
588 line_pattern.b.h = data;
590 case ALU_LINEPATTERN_REG_LO:
591 line_pattern.b.l = data;
593 case ALU_LINEPOS_START_X_HIGH:
594 line_xbegin.b.h = data & 0x03;
596 case ALU_LINEPOS_START_X_LOW:
597 line_xbegin.b.l = data;
599 case ALU_LINEPOS_START_Y_HIGH:
600 line_ybegin.b.h = data & 0x01;
602 case ALU_LINEPOS_START_Y_LOW:
603 line_ybegin.b.l = data;
605 case ALU_LINEPOS_END_X_HIGH:
606 line_xend.b.h = data & 0x03;
608 case ALU_LINEPOS_END_X_LOW:
609 line_xend.b.l = data;
611 case ALU_LINEPOS_END_Y_HIGH:
612 line_yend.b.h = data & 0x01;
614 case ALU_LINEPOS_END_Y_LOW:
615 line_yend.b.l = data;
619 if((id >= (ALU_CMPDATA_REG + 0)) && (id < (ALU_CMPDATA_REG + 8))) {
620 cmp_color_data[id - ALU_CMPDATA_REG] = data;
621 } else if((id >= ALU_WRITE_PROXY) && (id < (ALU_WRITE_PROXY + 0xc000))) {
622 uint32_t raddr = id - ALU_WRITE_PROXY;
624 if(raddr >= 0x8000) return;
626 raddr = raddr & 0x3fff;
628 do_alucmds_dmyread(raddr);
634 uint32_t MB61VH010::read_data8(uint32_t id)
639 return (uint32_t)command_reg;
641 case ALU_LOGICAL_COLOR:
642 return (uint32_t)color_reg;
644 case ALU_WRITE_MASKREG:
645 return (uint32_t)mask_reg;
647 case ALU_CMP_STATUS_REG:
648 return (uint32_t)cmp_status_reg;
650 case ALU_BANK_DISABLE:
651 return (uint32_t)bank_disable_reg;
654 if((id >= ALU_WRITE_PROXY) && (id < (ALU_WRITE_PROXY + 0xc000))) {
656 raddr = id - ALU_WRITE_PROXY;
658 if(raddr >= 0x8000) return 0xffffffff;
660 raddr = raddr & 0x3fff;
662 //dmydata = target->read_data8(raddr + DISPLAY_VRAM_DIRECT_ACCESS);
663 do_alucmds_dmyread(raddr);
664 raddr = (id - ALU_WRITE_PROXY) % 0xc000;
665 dmydata = target->read_data8(raddr + DISPLAY_VRAM_DIRECT_ACCESS);
673 uint32_t MB61VH010::read_signal(int id)
675 uint32_t val = 0x00000000;
677 case SIG_ALU_BUSYSTAT:
678 if(busy_flag) val = 0xffffffff;
680 case SIG_ALU_ENABLED:
681 val = ((command_reg & 0x80) != 0) ? 0xffffffff : 0;
687 void MB61VH010::write_signal(int id, uint32_t data, uint32_t mask)
689 bool flag = ((data & mask) != 0);
691 case SIG_ALU_400LINE:
694 case SIG_ALU_MULTIPAGE:
695 multi_page = (data & mask) & 0x07;
698 planes = (data & mask) & 0x07;
699 if(planes >= 4) planes = 4;
701 case SIG_ALU_X_WIDTH:
702 screen_width = (data << 3) & 0x3ff;
704 case SIG_ALU_Y_HEIGHT:
705 screen_height = data & 0x3ff;
710 void MB61VH010::event_callback(int event_id, int err)
713 case EVENT_MB61VH010_BUSY_ON:
715 if(eventid_busy >= 0) cancel_event(this, eventid_busy);
718 case EVENT_MB61VH010_BUSY_OFF:
725 void MB61VH010::initialize(void)
736 command_reg = 0; // D410 (RW)
737 color_reg = 0; // D411 (RW)
738 mask_reg = 0; // D412 (RW)
739 cmp_status_reg = 0; // D413 (RO)
740 for(i = 0; i < 8; i++) cmp_color_data[i] = 0x80; // D413-D41A (WO)
741 bank_disable_reg = 0; // D41B (RW)
742 for(i = 0; i < 4; i++) tile_reg[i] = 0; // D41C-D41F (WO)
744 line_addr_offset.d = 0; // D420-D421 (WO)
745 line_pattern.d = 0; // D422-D423 (WO)
746 line_xbegin.d = 0; // D424-D425 (WO)
747 line_ybegin.d = 0; // D426-D427 (WO)
748 line_xend.d = 0; // D428-D429 (WO)
749 line_yend.d = 0; // D42A-D42B (WO)
753 void MB61VH010::reset(void)
757 if(eventid_busy >= 0) cancel_event(this, eventid_busy);
760 command_reg = 0; // D410 (RW)
761 color_reg = 0; // D411 (RW)
762 mask_reg = 0; // D412 (RW)
763 cmp_status_reg = 0; // D413 (RO)
764 for(i = 0; i < 8; i++) cmp_color_data[i] = 0x80; // D413-D41A (WO)
765 bank_disable_reg = 0; // D41B (RW)
766 for(i = 0; i < 4; i++) tile_reg[i] = 0; // D41C-D41F (WO)
768 line_addr_offset.d = 0; // D420-D421 (WO)
769 line_pattern.d = 0; // D422-D423 (WO)
770 line_xbegin.d = 0; // D424-D425 (WO)
771 line_ybegin.d = 0; // D426-D427 (WO)
772 line_xend.d = 0; // D428-D429 (WO)
773 line_yend.d = 0; // D42A-D42B (WO)
775 oldaddr = 0xffffffff;
777 if(planes >= 4) planes = 4;
780 #define STATE_VERSION 1
781 void MB61VH010::save_state(FILEIO *state_fio)
784 state_fio->FputUint32(STATE_VERSION);
785 state_fio->FputInt32(this_device_id);
786 p_emu->out_debug_log("Save State: MB61VH010 : id=%d ver=%d\n", this_device_id, STATE_VERSION);
789 state_fio->FputUint8(command_reg);
790 state_fio->FputUint8(color_reg);
791 state_fio->FputUint8(mask_reg);
792 state_fio->FputUint8(cmp_status_reg);
793 for(i = 0; i < 8; i++) state_fio->FputUint8(cmp_color_data[i]);
794 state_fio->FputUint8(bank_disable_reg);
795 for(i = 0; i < 4; i++) state_fio->FputUint8(tile_reg[i]);
796 state_fio->FputUint8(multi_page);
798 state_fio->FputUint32_BE(line_addr_offset.d);
799 state_fio->FputUint16_BE(line_pattern.w.l);
800 state_fio->FputUint16_BE(line_xbegin.w.l);
801 state_fio->FputUint16_BE(line_ybegin.w.l);
802 state_fio->FputUint16_BE(line_xend.w.l);
803 state_fio->FputUint16_BE(line_yend.w.l);
805 state_fio->FputBool(busy_flag);
806 state_fio->FputInt32_BE(eventid_busy);
808 state_fio->FputUint32_BE(total_bytes);
809 state_fio->FputUint32_BE(oldaddr);
810 state_fio->FputUint32_BE(alu_addr);
812 state_fio->FputUint32_BE(planes);
813 state_fio->FputBool(is_400line);
814 state_fio->FputUint32_BE(screen_width);
815 state_fio->FputUint32_BE(screen_height);
817 state_fio->FputUint16_BE(line_style.w.l);
822 bool MB61VH010::load_state(FILEIO *state_fio)
824 uint32_t version = state_fio->FgetUint32();
826 p_emu->out_debug_log("Load State: MB61VH010 : id=%d ver=%d\n", this_device_id, version);
827 if(this_device_id != state_fio->FgetInt32()) return false;
829 command_reg = state_fio->FgetUint8();
830 color_reg = state_fio->FgetUint8();
831 mask_reg = state_fio->FgetUint8();
832 cmp_status_reg = state_fio->FgetUint8();
833 for(i = 0; i < 8; i++) cmp_color_data[i] = state_fio->FgetUint8();
834 bank_disable_reg = state_fio->FgetUint8();
835 for(i = 0; i < 4; i++) tile_reg[i] = state_fio->FgetUint8();
836 multi_page = state_fio->FgetUint8();
838 line_addr_offset.d = state_fio->FgetUint32_BE();
845 line_pattern.w.l = state_fio->FgetUint16_BE();
846 line_xbegin.w.l = state_fio->FgetUint16_BE();
847 line_ybegin.w.l = state_fio->FgetUint16_BE();
848 line_xend.w.l = state_fio->FgetUint16_BE();
849 line_yend.w.l = state_fio->FgetUint16_BE();
851 busy_flag = state_fio->FgetBool();
852 eventid_busy = state_fio->FgetInt32_BE();
854 total_bytes = state_fio->FgetUint32_BE();
855 oldaddr = state_fio->FgetUint32_BE();
856 alu_addr = state_fio->FgetUint32_BE();
858 planes = state_fio->FgetUint32_BE();
859 is_400line = state_fio->FgetBool();
860 screen_width = state_fio->FgetUint32_BE();
861 screen_height = state_fio->FgetUint32_BE();
864 line_style.w.l = state_fio->FgetUint16_BE();
866 if(version != STATE_VERSION) return false;