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)
30 if(((1 << bank) & read_signal(SIG_DISPLAY_MULTIPAGE)) != 0) return 0xff;
31 //if(is_400line) offset = 0x8000;
34 if((addr & 0xffff) < 0x8000) {
35 raddr = (addr & 0x7fff) | (0x8000 * bank);
36 return target->read_data8(raddr + DISPLAY_VRAM_DIRECT_ACCESS);
40 raddr = (addr & 0x3fff) | (0x4000 * bank);
41 return target->read_data8(raddr + DISPLAY_VRAM_DIRECT_ACCESS);
46 uint8 MB61VH010::do_write(uint32 addr, uint32 bank, uint8 data)
51 if(((1 << bank) & read_signal(SIG_DISPLAY_MULTIPAGE)) != 0) return 0xff;
52 if((command_reg & 0x40) != 0) { // Calculate before writing
53 readdata = do_read(addr, bank);
55 if((command_reg & 0x20) != 0) { // NAND
56 readdata = readdata & cmp_status_reg;
57 data = data & ~cmp_status_reg;
58 readdata = readdata | data;
60 readdata = readdata & ~cmp_status_reg;
61 data = data & cmp_status_reg;
62 readdata = readdata | data;
68 if((addr & 0xffff) < 0x8000) {
69 raddr = (addr & 0x7fff) | (0x8000 * bank);
70 target->write_data8(raddr + DISPLAY_VRAM_DIRECT_ACCESS, readdata);
73 raddr = (addr & 0x3fff) | (0x4000 * bank);
74 target->write_data8(raddr + DISPLAY_VRAM_DIRECT_ACCESS, readdata);
80 uint8 MB61VH010::do_pset(uint32 addr)
83 uint32 raddr = addr; // Use banked ram.
86 int planes_b = planes;
88 if(planes_b >= 4) planes_b = 4;
89 for(i = 0; i < planes_b; i++) {
90 if((bank_disable_reg & (1 << i)) != 0) {
93 if((color_reg & (1 << i)) == 0) {
99 srcdata = do_read(addr, i);
100 bitmask = bitmask & ~mask_reg;
101 srcdata = srcdata & mask_reg;
102 srcdata = srcdata | bitmask;
103 do_write(addr, i, srcdata);
108 uint8 MB61VH010::do_blank(uint32 addr)
113 if(planes >= 4) planes = 4;
114 for(i = 0; i < planes; i++) {
115 if((bank_disable_reg & (1 << i)) != 0) {
118 srcdata = do_read(addr, i);
119 srcdata = srcdata & mask_reg;
120 do_write(addr, i, srcdata);
125 uint8 MB61VH010::do_or(uint32 addr)
131 if(planes >= 4) planes = 4;
132 for(i = 0; i < planes; i++) {
133 if((bank_disable_reg & (1 << i)) != 0) {
136 srcdata = do_read(addr, i);
137 if((color_reg & (1 << i)) == 0) {
138 bitmask = srcdata; // srcdata | 0x00
140 bitmask = 0xff; // srcdata | 0xff
142 bitmask = bitmask & ~mask_reg;
143 srcdata = (srcdata & mask_reg) | bitmask;
144 do_write(addr, i, srcdata);
149 uint8 MB61VH010::do_and(uint32 addr)
155 if(planes >= 4) planes = 4;
156 for(i = 0; i < planes; i++) {
157 if((bank_disable_reg & (1 << i)) != 0) {
160 srcdata = do_read(addr, i);
161 if((color_reg & (1 << i)) == 0) {
162 bitmask = 0x00; // srcdata & 0x00
164 bitmask = srcdata; // srcdata & 0xff;
166 bitmask = bitmask & ~mask_reg;
167 srcdata = (srcdata & mask_reg) | bitmask;
168 do_write(addr, i, srcdata);
173 uint8 MB61VH010::do_xor(uint32 addr)
179 if(planes >= 4) planes = 4;
180 for(i = 0; i < planes; i++) {
181 if((bank_disable_reg & (1 << i)) != 0) {
184 srcdata = do_read(addr, i);
185 if((color_reg & (1 << i)) == 0) {
186 bitmask = srcdata ^ 0x00;
188 bitmask = srcdata ^ 0xff;
190 bitmask = bitmask & ~mask_reg;
191 srcdata = (srcdata & mask_reg) | bitmask;
192 do_write(addr, i, srcdata);
197 uint8 MB61VH010::do_not(uint32 addr)
203 if(planes >= 4) planes = 4;
204 for(i = 0; i < planes; i++) {
205 if((bank_disable_reg & (1 << i)) != 0) {
208 srcdata = do_read(addr, i);
211 bitmask = bitmask & ~mask_reg;
212 srcdata = (srcdata & mask_reg) | bitmask;
213 do_write(addr, i, srcdata);
219 uint8 MB61VH010::do_tilepaint(uint32 addr)
224 //printf("Tilepaint CMD=%02x, ADDR=%04x\n", command_reg, addr);
225 if(planes >= 4) planes = 4;
226 for(i = 0; i < planes; i++) {
227 if((bank_disable_reg & (1 << i)) != 0) {
230 srcdata = do_read(addr, i);
231 bitmask = tile_reg[i] & ~mask_reg;
232 srcdata = (srcdata & mask_reg) | bitmask;
233 do_write(addr, i, srcdata);
238 uint8 MB61VH010::do_compare(uint32 addr)
240 uint32 offset = 0x4000;
242 uint8 disables = ~bank_disable_reg;
246 //printf("Compare CMD=%02x, ADDR=%04x\n", command_reg, addr);
248 b = do_read(addr, 0);
249 r = do_read(addr, 1);
250 g = do_read(addr, 2);
252 t = do_read(addr, 3);
253 disables = disables & 0x0f;
256 disables = disables & 0x07;
258 cmp_status_reg = 0x00;
259 for(i = 7; i >= 0; i--) {
260 tmpcol = ((b & 0x80) != 0) ? 1 : 0;
261 tmpcol |= ((r & 0x80) != 0) ? 2 : 0;
262 tmpcol |= ((g & 0x80) != 0) ? 4 : 0;
263 //tmpcol |= ((t & 0x80) != 0) ? 8 : 0;
264 tmpcol = tmpcol & disables;
265 for(j = 0; j < 8; j++) {
266 if((cmp_color_data[j] & 0x80) != 0) continue;
267 if((cmp_color_data[j] & disables) == tmpcol) {
268 cmp_status_reg = cmp_status_reg | (1 << i);
280 void MB61VH010::do_alucmds_dmyread(uint32 addr)
283 addr = addr & 0x3fff;
289 addr = addr & 0x7fff;
291 //printf("ALU DMYREAD: CMD %02x ADDR=%08x\n", command_reg, addr);
292 if((command_reg & 0x80) == 0) return;
293 if(((command_reg & 0x40) != 0) && ((command_reg & 0x07) != 7)) do_compare(addr);
294 switch(command_reg & 0x07) {
322 uint8 MB61VH010::do_alucmds(uint32 addr)
325 addr = addr & 0x3fff;
331 addr = addr & 0x7fff;
333 //if((command_reg & 0x07) != 0x00) printf("ALU: CMD %02x ADDR=%08x\n", command_reg, addr);
334 if(((command_reg & 0x40) != 0) && ((command_reg & 0x07) != 7)) do_compare(addr);
335 switch(command_reg & 0x07) {
337 return do_pset(addr);
340 return do_blank(addr);
355 return do_tilepaint(addr);
358 return do_compare(addr);
364 void MB61VH010::do_line(void)
366 int x_begin = line_xbegin.w.l;
367 int x_end = line_xend.w.l;
368 int y_begin = line_ybegin.w.l;
369 int y_end = line_yend.w.l;
371 uint8 lmask[8] = {0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01};
372 uint8 rmask[8] = {0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff};
373 uint8 vmask[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
376 int ax = x_end - x_begin;
377 int ay = y_end - y_begin;
380 uint8 mask_bak = mask_reg;
381 //printf("Line: (%d,%d) - (%d,%d) CMD=%02x\n", x_begin, y_begin, x_end, y_end, command_reg);
384 is_400line = (target->read_signal(SIG_DISPLAY_MODE_IS_400LINE) != 0) ? true : false;
385 planes = target->read_signal(SIG_DISPLAY_PLANES) & 0x07;
386 screen_width = target->read_signal(SIG_DISPLAY_X_WIDTH) * 8;
387 screen_height = target->read_signal(SIG_DISPLAY_Y_HEIGHT);
389 //if((command_reg & 0x80) == 0) return;
390 oldaddr = 0xffffffff;
391 alu_addr = 0xffffffff;
394 line_style = line_pattern;
399 mask_reg = 0xff & vmask[x_begin & 7];
400 // Got from HD63484.cpp .
401 if(abs(ax) >= abs(ay)) {
403 diff = ((abs(ay) + 1) * 1024) / abs(ax);
404 for(; cpx_t != x_end; ) {
405 put_dot(cpx_t, cpy_t);
409 put_dot(cpx_t + 1, cpy_t);
411 put_dot(cpx_t - 1, cpy_t);
427 } else { // (abs(ax) < abs(ay)
428 diff = ((abs(ax) + 1)* 1024) / abs(ay);
429 for(; cpy_t != y_end; ) {
430 put_dot(cpx_t, cpy_t);
434 put_dot(cpx_t, cpy_t + 1);
436 put_dot(cpx_t, cpy_t - 1);
452 if(!put_dot(cpx_t, cpy_t)) total_bytes++;
453 do_alucmds(alu_addr);
455 usec = (double)total_bytes / 16.0;
456 if(usec >= 1.0) { // 1MHz
457 register_event(this, EVENT_MB61VH010_BUSY_OFF, usec, false, &eventid_busy) ;
464 bool MB61VH010::put_dot(int x, int y)
466 uint8 vmask[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
471 if((x < 0) || (y < 0)) return flag;
472 if((x >= screen_width) || (y >= screen_height)) return flag;
473 if((command_reg & 0x80) == 0) return flag;
475 alu_addr = ((y * screen_width) >> 3) + (x >> 3);
476 alu_addr = alu_addr + (line_addr_offset.w.l << 1);
477 alu_addr = alu_addr & 0x7fff;
478 if(!is_400line) alu_addr = alu_addr & 0x3fff;
479 if(oldaddr == 0xffffffff) oldaddr = alu_addr;
481 if(oldaddr != alu_addr) {
489 if((line_style.b.h & 0x80) != 0) {
490 mask_reg &= ~vmask[x & 7];
492 tmp8a = (line_style.w.l & 0x8000) >> 15;
493 line_style.w.l = (line_pattern.w.l << 1) | tmp8a;
497 void MB61VH010::write_data8(uint32 id, uint32 data)
499 //printf("ALU: ADDR=%02x DATA=%02x\n", id, data);
500 if(id == ALU_CMDREG) {
504 //if((command_reg & 0x80) == 0) return;
506 case ALU_LOGICAL_COLOR:
509 case ALU_WRITE_MASKREG:
512 case ALU_BANK_DISABLE:
513 bank_disable_reg = data;
515 case ALU_TILEPAINT_B:
518 case ALU_TILEPAINT_R:
521 case ALU_TILEPAINT_G:
524 case ALU_TILEPAINT_L:
527 case ALU_OFFSET_REG_HIGH:
528 line_addr_offset.b.h = data;
530 case ALU_OFFSET_REG_LO:
531 line_addr_offset.b.l = data;
533 case ALU_LINEPATTERN_REG_HIGH:
534 line_pattern.b.h = data;
536 case ALU_LINEPATTERN_REG_LO:
537 line_pattern.b.l = data;
539 case ALU_LINEPOS_START_X_HIGH:
540 line_xbegin.b.h = data;
542 case ALU_LINEPOS_START_X_LOW:
543 line_xbegin.b.l = data;
545 case ALU_LINEPOS_START_Y_HIGH:
546 line_ybegin.b.h = data;
548 case ALU_LINEPOS_START_Y_LOW:
549 line_ybegin.b.l = data;
551 case ALU_LINEPOS_END_X_HIGH:
552 line_xend.b.h = data;
554 case ALU_LINEPOS_END_X_LOW:
555 line_xend.b.l = data;
557 case ALU_LINEPOS_END_Y_HIGH:
558 line_yend.b.h = data;
560 case ALU_LINEPOS_END_Y_LOW:
561 line_yend.b.l = data;
565 if((id >= (ALU_CMPDATA_REG + 0)) && (id < (ALU_CMPDATA_REG + 8))) {
566 cmp_color_data[id - ALU_CMPDATA_REG] = data;
567 } else if((id >= ALU_WRITE_PROXY) && (id < (ALU_WRITE_PROXY + 0x18000))) {
568 is_400line = (target->read_signal(SIG_DISPLAY_MODE_IS_400LINE) != 0) ? true : false;
569 do_alucmds_dmyread(id - ALU_WRITE_PROXY);
575 uint32 MB61VH010::read_data8(uint32 id)
580 return (uint32)command_reg;
582 case ALU_LOGICAL_COLOR:
583 return (uint32)color_reg;
585 case ALU_WRITE_MASKREG:
586 return (uint32)mask_reg;
588 case ALU_CMP_STATUS_REG:
589 return (uint32)cmp_status_reg;
591 case ALU_BANK_DISABLE:
592 return (uint32)bank_disable_reg;
595 if((id >= ALU_WRITE_PROXY) && (id < (ALU_WRITE_PROXY + 0x18000))) {
596 is_400line = (target->read_signal(SIG_DISPLAY_MODE_IS_400LINE) != 0) ? true : false;
597 do_alucmds_dmyread(id - ALU_WRITE_PROXY);
604 uint32 MB61VH010::read_signal(int id)
606 uint32 val = 0x00000000;
608 case SIG_ALU_BUSYSTAT:
609 if(busy_flag) val = 0xffffffff;
615 void MB61VH010::event_callback(int event_id, int err)
618 case EVENT_MB61VH010_BUSY_ON:
620 if(eventid_busy >= 0) cancel_event(this, eventid_busy);
623 case EVENT_MB61VH010_BUSY_OFF:
630 void MB61VH010::initialize(void)
636 void MB61VH010::reset(void)
640 if(eventid_busy >= 0) cancel_event(this, eventid_busy);
643 command_reg = 0; // D410 (RW)
644 color_reg = 0; // D411 (RW)
645 mask_reg = 0; // D412 (RW)
646 cmp_status_reg = 0; // D413 (RO)
647 for(i = 0; i < 8; i++) cmp_color_data[i] = 0x80; // D413-D41A (WO)
648 bank_disable_reg = 0; // D41B (RW)
649 for(i = 0; i < 4; i++) tile_reg[i] = 0; // D41C-D41F (WO)
651 line_addr_offset.d = 0; // D420-D421 (WO)
652 line_pattern.d = 0; // D422-D423 (WO)
653 line_xbegin.d = 0; // D424-D425 (WO)
654 line_ybegin.d = 0; // D426-D427 (WO)
655 line_xend.d = 0; // D428-D429 (WO)
656 line_yend.d = 0; // D42A-D42B (WO)
658 oldaddr = 0xffffffff;
660 planes = target->read_signal(SIG_DISPLAY_PLANES) & 0x07;
661 is_400line = (target->read_signal(SIG_DISPLAY_MODE_IS_400LINE) != 0) ? true : false;
663 screen_width = target->read_signal(SIG_DISPLAY_X_WIDTH) * 8;
664 screen_height = target->read_signal(SIG_DISPLAY_Y_HEIGHT);