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];
404 tmp8a = ((line_style.b.h & 0x80) >> 7) & 0x01;
405 line_style.w.l = (line_style.w.l << 1) | tmp8a;
409 //p_emu->out_debug_log("LINE: (%d,%d)-(%d,%d)\n", x_begin, y_begin, x_end , y_end);
412 if((cpx_t & 0x07) != 7) total_bytes = 1;
413 //if((x_end >= screen_width) && (x_begin < screen_width)) x_end = screen_width - 1;
414 for(; cpx_t <= (int)x_end; cpx_t++) {
415 if(cpy_t >= screen_width) break;
416 lastflag = put_dot(cpx_t, cpy_t);
417 if((cpx_t & 0x07) == 7) total_bytes++;
420 if((cpx_t & 0x07) != 0) total_bytes = 1;
421 for(; cpx_t >= (int)x_end; cpx_t--) {
423 if((cpx_t & 0x07) == 0) total_bytes++;
424 lastflag = put_dot(cpx_t, cpy_t);
427 } else if(xcount == 0) {
429 for(; cpy_t <= (int)y_end; cpy_t++) {
430 if(cpy_t >= screen_height) break;
431 lastflag = put_dot(cpx_t, cpy_t);
435 for(; cpy_t >= (int)y_end; cpy_t--) {
437 lastflag = put_dot(cpx_t, cpy_t);
441 } else if(xcount >= ycount) {
442 diff = (ycount * 32768) / xcount;
444 //if(x_end == 0) xcount = x_begin;
445 if((cpx_t & 0x07) != 0) total_bytes = 1;
447 if(x_end >= screen_width) xcount = (int)screen_width - (int)x_begin - 1;
448 if((cpx_t & 0x07) == 0) total_bytes = 1;
450 for(; xcount >= 0; xcount-- ) {
451 lastflag = put_dot(cpx_t, cpy_t);
459 if(cpy_t >= screen_height) break;
466 if((cpx_t & 0x07) == 0) total_bytes++;
467 if(cpx_t >= screen_width) break;
469 if((cpx_t & 0x07) == 0) total_bytes++;
474 } else { // (abs(ax) <= abs(ay)
475 diff = (xcount * 32768) / ycount;
477 //if(y_end < 0) ycount = y_begin;
479 if(y_end >= screen_height) ycount = screen_height - y_begin - 1;
481 for(; ycount >= 0; ycount--) {
482 lastflag = put_dot(cpx_t, cpy_t);
490 if(cpx_t > screen_width) break;
497 if(cpy_t >= screen_height) break;
504 //if(!lastflag) total_bytes++;
505 if(alu_addr < 0x8000) do_alucmds(alu_addr);
507 //if(total_bytes > 16) { // Over 1.0us
508 usec = (double)total_bytes / 16.0;
509 if(eventid_busy >= 0) cancel_event(this, eventid_busy) ;
510 register_event(this, EVENT_MB61VH010_BUSY_OFF, usec, false, &eventid_busy) ;
512 // busy_flag = false;
516 bool MB61VH010::put_dot(int x, int y)
518 uint8_t vmask[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
522 if((x < 0) || (y < 0)) return false;
523 if(y >= (int)screen_height) return false;
524 if((command_reg & 0x80) == 0) return false;
526 alu_addr = (y * screen_width + x) >> 3;
527 alu_addr = alu_addr + line_addr_offset.w.l;
528 alu_addr = alu_addr & 0x7fff;
529 if(!is_400line) alu_addr = alu_addr & 0x3fff;
531 if(oldaddr != alu_addr) {
532 if(oldaddr == 0xffffffff) oldaddr = alu_addr;
539 if((line_style.b.h & 0x80) != 0) {
540 mask_reg &= ~vmask[x & 7];
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_t id, uint32_t data)
549 //p_emu->out_debug_log("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_t raddr = id - ALU_WRITE_PROXY;
622 if(raddr >= 0x8000) return;
624 raddr = raddr & 0x3fff;
626 do_alucmds_dmyread(raddr);
632 uint32_t MB61VH010::read_data8(uint32_t id)
637 return (uint32_t)command_reg;
639 case ALU_LOGICAL_COLOR:
640 return (uint32_t)color_reg;
642 case ALU_WRITE_MASKREG:
643 return (uint32_t)mask_reg;
645 case ALU_CMP_STATUS_REG:
646 return (uint32_t)cmp_status_reg;
648 case ALU_BANK_DISABLE:
649 return (uint32_t)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_t MB61VH010::read_signal(int id)
673 uint32_t val = 0x00000000;
675 case SIG_ALU_BUSYSTAT:
676 if(busy_flag) val = 0xffffffff;
678 case SIG_ALU_ENABLED:
679 val = ((command_reg & 0x80) != 0) ? 0xffffffff : 0;
685 void MB61VH010::write_signal(int id, uint32_t data, uint32_t mask)
687 bool flag = ((data & mask) != 0);
689 case SIG_ALU_400LINE:
692 case SIG_ALU_MULTIPAGE:
693 multi_page = (data & mask) & 0x07;
696 planes = (data & mask) & 0x07;
697 if(planes >= 4) planes = 4;
699 case SIG_ALU_X_WIDTH:
700 screen_width = (data << 3) & 0x3ff;
702 case SIG_ALU_Y_HEIGHT:
703 screen_height = data & 0x3ff;
708 void MB61VH010::event_callback(int event_id, int err)
711 case EVENT_MB61VH010_BUSY_ON:
713 if(eventid_busy >= 0) cancel_event(this, eventid_busy);
716 case EVENT_MB61VH010_BUSY_OFF:
723 void MB61VH010::initialize(void)
734 command_reg = 0; // D410 (RW)
735 color_reg = 0; // D411 (RW)
736 mask_reg = 0; // D412 (RW)
737 cmp_status_reg = 0; // D413 (RO)
738 for(i = 0; i < 8; i++) cmp_color_data[i] = 0x80; // D413-D41A (WO)
739 bank_disable_reg = 0; // D41B (RW)
740 for(i = 0; i < 4; i++) tile_reg[i] = 0; // D41C-D41F (WO)
742 line_addr_offset.d = 0; // D420-D421 (WO)
743 line_pattern.d = 0; // D422-D423 (WO)
744 line_xbegin.d = 0; // D424-D425 (WO)
745 line_ybegin.d = 0; // D426-D427 (WO)
746 line_xend.d = 0; // D428-D429 (WO)
747 line_yend.d = 0; // D42A-D42B (WO)
751 void MB61VH010::reset(void)
755 if(eventid_busy >= 0) cancel_event(this, eventid_busy);
758 command_reg = 0; // D410 (RW)
759 color_reg = 0; // D411 (RW)
760 mask_reg = 0; // D412 (RW)
761 cmp_status_reg = 0; // D413 (RO)
762 for(i = 0; i < 8; i++) cmp_color_data[i] = 0x80; // D413-D41A (WO)
763 bank_disable_reg = 0; // D41B (RW)
764 for(i = 0; i < 4; i++) tile_reg[i] = 0; // D41C-D41F (WO)
766 line_addr_offset.d = 0; // D420-D421 (WO)
767 line_pattern.d = 0; // D422-D423 (WO)
768 line_xbegin.d = 0; // D424-D425 (WO)
769 line_ybegin.d = 0; // D426-D427 (WO)
770 line_xend.d = 0; // D428-D429 (WO)
771 line_yend.d = 0; // D42A-D42B (WO)
773 oldaddr = 0xffffffff;
775 if(planes >= 4) planes = 4;
778 #define STATE_VERSION 1
779 void MB61VH010::save_state(FILEIO *state_fio)
782 state_fio->FputUint32(STATE_VERSION);
783 state_fio->FputInt32(this_device_id);
784 p_emu->out_debug_log("Save State: MB61VH010 : id=%d ver=%d\n", this_device_id, STATE_VERSION);
787 state_fio->FputUint8(command_reg);
788 state_fio->FputUint8(color_reg);
789 state_fio->FputUint8(mask_reg);
790 state_fio->FputUint8(cmp_status_reg);
791 for(i = 0; i < 8; i++) state_fio->FputUint8(cmp_color_data[i]);
792 state_fio->FputUint8(bank_disable_reg);
793 for(i = 0; i < 4; i++) state_fio->FputUint8(tile_reg[i]);
794 state_fio->FputUint8(multi_page);
796 state_fio->FputUint32_BE(line_addr_offset.d);
797 state_fio->FputUint16_BE(line_pattern.w.l);
798 state_fio->FputUint16_BE(line_xbegin.w.l);
799 state_fio->FputUint16_BE(line_ybegin.w.l);
800 state_fio->FputUint16_BE(line_xend.w.l);
801 state_fio->FputUint16_BE(line_yend.w.l);
803 state_fio->FputBool(busy_flag);
804 state_fio->FputInt32_BE(eventid_busy);
806 state_fio->FputUint32_BE(total_bytes);
807 state_fio->FputUint32_BE(oldaddr);
808 state_fio->FputUint32_BE(alu_addr);
810 state_fio->FputUint32_BE(planes);
811 state_fio->FputBool(is_400line);
812 state_fio->FputUint32_BE(screen_width);
813 state_fio->FputUint32_BE(screen_height);
815 state_fio->FputUint16_BE(line_style.w.l);
820 bool MB61VH010::load_state(FILEIO *state_fio)
822 uint32_t version = state_fio->FgetUint32();
824 p_emu->out_debug_log("Load State: MB61VH010 : id=%d ver=%d\n", this_device_id, version);
825 if(this_device_id != state_fio->FgetInt32()) return false;
827 command_reg = state_fio->FgetUint8();
828 color_reg = state_fio->FgetUint8();
829 mask_reg = state_fio->FgetUint8();
830 cmp_status_reg = state_fio->FgetUint8();
831 for(i = 0; i < 8; i++) cmp_color_data[i] = state_fio->FgetUint8();
832 bank_disable_reg = state_fio->FgetUint8();
833 for(i = 0; i < 4; i++) tile_reg[i] = state_fio->FgetUint8();
834 multi_page = state_fio->FgetUint8();
836 line_addr_offset.d = state_fio->FgetUint32_BE();
843 line_pattern.w.l = state_fio->FgetUint16_BE();
844 line_xbegin.w.l = state_fio->FgetUint16_BE();
845 line_ybegin.w.l = state_fio->FgetUint16_BE();
846 line_xend.w.l = state_fio->FgetUint16_BE();
847 line_yend.w.l = state_fio->FgetUint16_BE();
849 busy_flag = state_fio->FgetBool();
850 eventid_busy = state_fio->FgetInt32_BE();
852 total_bytes = state_fio->FgetUint32_BE();
853 oldaddr = state_fio->FgetUint32_BE();
854 alu_addr = state_fio->FgetUint32_BE();
856 planes = state_fio->FgetUint32_BE();
857 is_400line = state_fio->FgetBool();
858 screen_width = state_fio->FgetUint32_BE();
859 screen_height = state_fio->FgetUint32_BE();
862 line_style.w.l = state_fio->FgetUint16_BE();
864 if(version != STATE_VERSION) return false;