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) & read_signal(SIG_DISPLAY_MULTIPAGE)) != 0) return 0xff;
30 //if(is_400line) offset = 0x8000;
33 if((addr & 0xffff) < 0x8000) {
34 //raddr = ((addr + (line_addr_offset.w.l << 1)) & 0x7fff) | (0x8000 * bank);
35 raddr = (addr & 0x7fff) | (0x8000 * bank);
36 return target->read_data8(raddr + DISPLAY_VRAM_DIRECT_ACCESS);
40 //raddr = ((addr + (line_addr_offset.w.l << 1)) & 0x3fff) | (0x4000 * bank);
41 raddr = (addr & 0x3fff) | (0x4000 * bank);
42 return target->read_data8(raddr + DISPLAY_VRAM_DIRECT_ACCESS);
47 uint8 MB61VH010::do_write(uint32 addr, uint32 bank, uint8 data)
52 if(((1 << bank) & read_signal(SIG_DISPLAY_MULTIPAGE)) != 0) return 0xff;
53 if((command_reg & 0x40) != 0) { // Calculate before writing
54 readdata = do_read(addr, bank);
56 if((command_reg & 0x20) != 0) { // NAND
57 readdata = readdata & cmp_status_reg;
58 data = data & (~cmp_status_reg);
59 readdata = readdata | data;
61 readdata = readdata & (~cmp_status_reg);
62 data = data & cmp_status_reg;
63 readdata = readdata | data;
69 if((addr & 0xffff) < 0x8000) {
70 //raddr = ((addr + (line_addr_offset.w.l << 1)) & 0x7fff) | (0x8000 * bank);
71 raddr = (addr & 0x7fff) | (0x8000 * bank);
72 target->write_data8(raddr + DISPLAY_VRAM_DIRECT_ACCESS, readdata);
75 //raddr = ((addr + (line_addr_offset.w.l << 1)) & 0x3fff) | (0x4000 * bank);
76 raddr = (addr & 0x3fff) | (0x4000 * bank);
77 target->write_data8(raddr + DISPLAY_VRAM_DIRECT_ACCESS, readdata);
83 uint8 MB61VH010::do_pset(uint32 addr)
86 uint32 raddr = addr; // Use banked ram.
89 int planes_b = planes;
91 if(planes_b >= 4) planes_b = 4;
92 for(i = 0; i < planes_b; i++) {
93 if((bank_disable_reg & (1 << i)) != 0) {
96 if((color_reg & (1 << i)) == 0) {
102 srcdata = do_read(addr, i);
103 bitmask = bitmask & (~mask_reg);
104 srcdata = srcdata & mask_reg;
105 srcdata = srcdata | bitmask;
106 do_write(addr, i, srcdata);
111 uint8 MB61VH010::do_blank(uint32 addr)
116 if(planes >= 4) planes = 4;
117 for(i = 0; i < planes; i++) {
118 if((bank_disable_reg & (1 << i)) != 0) {
121 srcdata = do_read(addr, i);
122 srcdata = srcdata & mask_reg;
123 do_write(addr, i, srcdata);
128 uint8 MB61VH010::do_or(uint32 addr)
134 if(planes >= 4) planes = 4;
135 for(i = 0; i < planes; i++) {
136 if((bank_disable_reg & (1 << i)) != 0) {
139 srcdata = do_read(addr, i);
140 if((color_reg & (1 << i)) == 0) {
141 bitmask = srcdata; // srcdata | 0x00
143 bitmask = 0xff; // srcdata | 0xff
145 bitmask = bitmask & ~mask_reg;
146 srcdata = (srcdata & mask_reg) | bitmask;
147 do_write(addr, i, srcdata);
152 uint8 MB61VH010::do_and(uint32 addr)
158 if(planes >= 4) planes = 4;
159 for(i = 0; i < planes; i++) {
160 if((bank_disable_reg & (1 << i)) != 0) {
163 srcdata = do_read(addr, i);
164 if((color_reg & (1 << i)) == 0) {
165 bitmask = 0x00; // srcdata & 0x00
167 bitmask = srcdata; // srcdata & 0xff;
169 bitmask = bitmask & ~mask_reg;
170 srcdata = (srcdata & mask_reg) | bitmask;
171 do_write(addr, i, srcdata);
176 uint8 MB61VH010::do_xor(uint32 addr)
182 if(planes >= 4) planes = 4;
183 for(i = 0; i < planes; i++) {
184 if((bank_disable_reg & (1 << i)) != 0) {
187 srcdata = do_read(addr, i);
188 if((color_reg & (1 << i)) == 0) {
189 bitmask = srcdata ^ 0x00;
191 bitmask = srcdata ^ 0xff;
193 bitmask = bitmask & ~mask_reg;
194 srcdata = (srcdata & mask_reg) | bitmask;
195 do_write(addr, i, srcdata);
200 uint8 MB61VH010::do_not(uint32 addr)
206 if(planes >= 4) planes = 4;
207 for(i = 0; i < planes; i++) {
208 if((bank_disable_reg & (1 << i)) != 0) {
211 srcdata = do_read(addr, i);
214 bitmask = bitmask & ~mask_reg;
215 srcdata = (srcdata & mask_reg) | bitmask;
216 do_write(addr, i, srcdata);
222 uint8 MB61VH010::do_tilepaint(uint32 addr)
227 //printf("Tilepaint CMD=%02x, ADDR=%04x Planes=%d, disable=%d, tile_reg=(%02x %02x %02x %02x)\n",
228 // command_reg, addr, planes, bank_disable_reg, tile_reg[0], tile_reg[1], tile_reg[2], tile_reg[3]);
229 if(planes > 4) planes = 4;
230 for(i = 0; i < planes; i++) {
231 if((bank_disable_reg & (1 << i)) != 0) {
234 srcdata = do_read(addr, i);
235 bitmask = tile_reg[i] & (~mask_reg);
236 srcdata = (srcdata & mask_reg) | bitmask;
237 do_write(addr, i, srcdata);
242 uint8 MB61VH010::do_compare(uint32 addr)
244 uint32 offset = 0x4000;
246 uint8 disables = ~bank_disable_reg;
251 //printf("Compare CMD=%02x, ADDR=%04x", command_reg, addr);
252 b = do_read(addr, 0);
253 r = do_read(addr, 1);
254 g = do_read(addr, 2);
256 // t = do_read(addr, 3);
257 // disables = disables & 0x0f;
260 disables = disables & 0x07;
262 for(i = 0; i < 8; i++) {
264 tmpcol = (b & 0x80) >> 7;
265 tmpcol |= ((r & 0x80) >> 6);
266 tmpcol |= ((g & 0x80) >> 5);
267 //tmpcol |= ((t & 0x80) != 0) ? 8 : 0;
268 tmpcol = tmpcol & disables;
269 for(j = 0; j < 8; j++) {
270 if((cmp_color_data[j] & 0x80) == 0) {
271 if((cmp_color_data[j] & disables) == tmpcol) {
272 tmp_stat = tmp_stat | 0x01;
282 cmp_status_reg = tmp_stat;
283 //printf(",Status=%02x\n", cmp_status_reg);
287 void MB61VH010::do_alucmds_dmyread(uint32 addr)
290 addr = addr & 0x3fff;
296 addr = addr & 0x7fff;
298 //printf("ALU DMYREAD: CMD %02x ADDR=%04x CMP[]=", command_reg, addr);
299 //for(i = 0; i < 8; i++) printf("[%02x]", cmp_color_data[i]);
300 if((command_reg & 0x80) == 0) {
304 if(((command_reg & 0x40) != 0) && ((command_reg & 0x07) != 7)) do_compare(addr);
305 switch(command_reg & 0x07) {
331 //printf("ALU DMYREAD ADDR=%04x, CMD=%02x CMP STATUS=%02x\n", addr, command_reg, cmp_status_reg);
334 uint8 MB61VH010::do_alucmds(uint32 addr)
337 addr = addr & 0x3fff;
343 addr = addr & 0x7fff;
345 //if((command_reg & 0x07) != 0x00) printf("ALU: CMD %02x ADDR=%08x\n", command_reg, addr);
346 if(((command_reg & 0x40) != 0) && ((command_reg & 0x07) != 7)) do_compare(addr);
347 //printf("ALU ADDR=%04x, CMD=%02x CMP STATUS=%02x\n", addr, command_reg, cmp_status_reg);
348 switch(command_reg & 0x07) {
350 return do_pset(addr);
353 return do_blank(addr);
368 return do_tilepaint(addr);
371 return do_compare(addr);
377 void MB61VH010::do_line(void)
379 int x_begin = line_xbegin.w.l;
380 int x_end = line_xend.w.l;
381 int y_begin = line_ybegin.w.l;
382 int y_end = line_yend.w.l;
385 int ax = x_end - x_begin;
386 int ay = y_end - y_begin;
391 uint8 mask_bak = mask_reg;
393 uint8 vmask[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
394 //printf("Line: (%d,%d) - (%d,%d) CMD=%02x\n", x_begin, y_begin, x_end, y_end, command_reg);
396 bool lastflag = false;
398 is_400line = (target->read_signal(SIG_DISPLAY_MODE_IS_400LINE) != 0) ? true : false;
399 planes = target->read_signal(SIG_DISPLAY_PLANES) & 0x07;
400 screen_width = target->read_signal(SIG_DISPLAY_X_WIDTH) * 8;
401 screen_height = target->read_signal(SIG_DISPLAY_Y_HEIGHT);
403 //if((command_reg & 0x80) == 0) return;
404 oldaddr = 0xffffffff;
405 alu_addr = 0xffffffff;
408 line_style = line_pattern;
412 //mask_reg = 0xff & ~vmask[x_begin & 7];
414 if((line_style.b.h & 0x80) != 0) {
415 mask_reg &= ~vmask[cpx_t & 7];
417 tmp8a = (line_style.w.l & 0x8000) >> 15;
418 line_style.w.l = (line_style.w.l << 1) | tmp8a;
421 if(xcount >= ycount) {
424 diff = ((ycount + 1) * 1024) / xcount;
426 for(; xcount >= 0; xcount-- ) {
427 lastflag = put_dot(cpx_t, cpy_t);
431 lastflag = put_dot(cpx_t, cpy_t + 1);
433 lastflag = put_dot(cpx_t, cpy_t - 1);
448 } else { // ax = ay = 0
449 lastflag = put_dot(cpx_t, cpy_t);
452 } else { // (abs(ax) < abs(ay)
454 diff = ((xcount + 1) * 1024) / ycount;
456 for(; ycount >= 0; ycount--) {
457 lastflag = put_dot(cpx_t, cpy_t);
461 lastflag = put_dot(cpx_t + 1, cpy_t);
463 lastflag = put_dot(cpx_t - 1, cpy_t);
482 if(!lastflag) total_bytes++;
483 do_alucmds(alu_addr);
485 if(total_bytes > 8) { // Over 0.5us
486 usec = (double)total_bytes / 16.0;
487 register_event(this, EVENT_MB61VH010_BUSY_OFF, usec, false, &eventid_busy) ;
491 //mask_reg = mask_bak;
492 //line_pattern = line_style;
495 bool MB61VH010::put_dot(int x, int y)
497 uint8 vmask[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
501 if((x < 0) || (y < 0)) return flag;
502 if((x >= screen_width) || (y >= screen_height)) return flag;
503 if((command_reg & 0x80) == 0) return flag;
505 alu_addr = ((y * screen_width) >> 3) + (x >> 3);
506 alu_addr = alu_addr + (line_addr_offset.w.l << 1);
507 alu_addr = alu_addr & 0x7fff;
508 if(!is_400line) alu_addr = alu_addr & 0x3fff;
509 if(oldaddr == 0xffffffff) oldaddr = alu_addr;
511 if(oldaddr != alu_addr) {
519 if((line_style.b.h & 0x80) != 0) {
520 mask_reg &= ~vmask[x & 7];
522 tmp8a = (line_style.w.l & 0x8000) >> 15;
523 line_style.w.l = (line_style.w.l << 1) | tmp8a;
527 void MB61VH010::write_data8(uint32 id, uint32 data)
529 //printf("ALU: ADDR=%02x DATA=%02x\n", id, data);
530 if(id == ALU_CMDREG) {
534 //if((command_reg & 0x80) == 0) return;
536 case ALU_LOGICAL_COLOR:
539 case ALU_WRITE_MASKREG:
542 case ALU_BANK_DISABLE:
543 bank_disable_reg = data;
545 case ALU_TILEPAINT_B:
548 case ALU_TILEPAINT_R:
551 case ALU_TILEPAINT_G:
554 case ALU_TILEPAINT_L:
557 case ALU_OFFSET_REG_HIGH:
558 line_addr_offset.b.h = data;
560 case ALU_OFFSET_REG_LO:
561 line_addr_offset.b.l = data;
563 case ALU_LINEPATTERN_REG_HIGH:
564 line_pattern.b.h = data;
566 case ALU_LINEPATTERN_REG_LO:
567 line_pattern.b.l = data;
569 case ALU_LINEPOS_START_X_HIGH:
570 line_xbegin.b.h = data;
572 case ALU_LINEPOS_START_X_LOW:
573 line_xbegin.b.l = data;
575 case ALU_LINEPOS_START_Y_HIGH:
576 line_ybegin.b.h = data;
578 case ALU_LINEPOS_START_Y_LOW:
579 line_ybegin.b.l = data;
581 case ALU_LINEPOS_END_X_HIGH:
582 line_xend.b.h = data;
584 case ALU_LINEPOS_END_X_LOW:
585 line_xend.b.l = data;
587 case ALU_LINEPOS_END_Y_HIGH:
588 line_yend.b.h = data;
590 case ALU_LINEPOS_END_Y_LOW:
591 line_yend.b.l = data;
595 if((id >= (ALU_CMPDATA_REG + 0)) && (id < (ALU_CMPDATA_REG + 8))) {
596 cmp_color_data[id - ALU_CMPDATA_REG] = data;
597 } else if((id >= ALU_WRITE_PROXY) && (id < (ALU_WRITE_PROXY + 0x18000))) {
598 is_400line = (target->read_signal(SIG_DISPLAY_MODE_IS_400LINE) != 0) ? true : false;
599 do_alucmds_dmyread(id - ALU_WRITE_PROXY);
605 uint32 MB61VH010::read_data8(uint32 id)
610 return (uint32)command_reg;
612 case ALU_LOGICAL_COLOR:
613 return (uint32)color_reg;
615 case ALU_WRITE_MASKREG:
616 return (uint32)mask_reg;
618 case ALU_CMP_STATUS_REG:
619 return (uint32)cmp_status_reg;
621 case ALU_BANK_DISABLE:
622 return (uint32)bank_disable_reg;
625 if((id >= ALU_WRITE_PROXY) && (id < (ALU_WRITE_PROXY + 0x18000))) {
626 raddr = (id - ALU_WRITE_PROXY) & 0xbfff;
627 is_400line = (target->read_signal(SIG_DISPLAY_MODE_IS_400LINE) != 0) ? true : false;
628 do_alucmds_dmyread(id - ALU_WRITE_PROXY);
629 if(is_400line) raddr = raddr & 0x7fff;
630 return target->read_data8(raddr + DISPLAY_VRAM_DIRECT_ACCESS);
637 uint32 MB61VH010::read_signal(int id)
639 uint32 val = 0x00000000;
641 case SIG_ALU_BUSYSTAT:
642 if(busy_flag) val = 0xffffffff;
648 void MB61VH010::event_callback(int event_id, int err)
651 case EVENT_MB61VH010_BUSY_ON:
653 if(eventid_busy >= 0) cancel_event(this, eventid_busy);
656 case EVENT_MB61VH010_BUSY_OFF:
663 void MB61VH010::initialize(void)
669 void MB61VH010::reset(void)
673 if(eventid_busy >= 0) cancel_event(this, eventid_busy);
676 command_reg = 0; // D410 (RW)
677 color_reg = 0; // D411 (RW)
678 mask_reg = 0; // D412 (RW)
679 cmp_status_reg = 0; // D413 (RO)
680 for(i = 0; i < 8; i++) cmp_color_data[i] = 0x80; // D413-D41A (WO)
681 bank_disable_reg = 0; // D41B (RW)
682 for(i = 0; i < 4; i++) tile_reg[i] = 0; // D41C-D41F (WO)
684 line_addr_offset.d = 0; // D420-D421 (WO)
685 line_pattern.d = 0; // D422-D423 (WO)
686 line_xbegin.d = 0; // D424-D425 (WO)
687 line_ybegin.d = 0; // D426-D427 (WO)
688 line_xend.d = 0; // D428-D429 (WO)
689 line_yend.d = 0; // D42A-D42B (WO)
691 oldaddr = 0xffffffff;
693 planes = target->read_signal(SIG_DISPLAY_PLANES) & 0x07;
694 if(planes >= 4) planes = 4;
695 is_400line = (target->read_signal(SIG_DISPLAY_MODE_IS_400LINE) != 0) ? true : false;
697 screen_width = target->read_signal(SIG_DISPLAY_X_WIDTH) * 8;
698 screen_height = target->read_signal(SIG_DISPLAY_Y_HEIGHT);