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 + 0x8000 * bank;
36 return target->read_data8(raddr + DISPLAY_VRAM_DIRECT_ACCESS);
40 raddr = addr + 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);
54 if((command_reg & 0x20) != 0) { // NAND
55 readdata = readdata & cmp_status_reg;
56 readdata = readdata | (data & ~cmp_status_reg);
58 readdata = readdata & ~cmp_status_reg;
59 readdata = readdata | (data & cmp_status_reg);
65 if((addr & 0xffff) < 0x8000) {
66 raddr = addr + 0x8000 * bank;
67 target->write_data8(raddr + DISPLAY_VRAM_DIRECT_ACCESS, readdata);
70 raddr = addr + 0x4000 * bank;
71 target->write_data8(raddr + DISPLAY_VRAM_DIRECT_ACCESS, readdata);
77 uint8 MB61VH010::do_pset(uint32 addr)
80 uint32 raddr = addr; // Use banked ram.
83 int planes_b = planes;
85 if(planes_b >= 4) planes = 4;
86 for(i = 0; i < planes; i++) {
87 if((bank_disable_reg & (1 << i)) != 0) {
90 if((color_reg & (1 << i)) == 0) {
95 srcdata = do_read(addr, i);
96 srcdata = srcdata & mask_reg;
97 srcdata = srcdata | bitmask;
98 do_write(addr, i, srcdata);
103 uint8 MB61VH010::do_blank(uint32 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 MB61VH010::do_or(uint32 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 MB61VH010::do_and(uint32 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 MB61VH010::do_xor(uint32 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 MB61VH010::do_not(uint32 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 MB61VH010::do_tilepaint(uint32 addr)
219 //printf("Tilepaint CMD=%02x, ADDR=%04x\n", command_reg, 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 MB61VH010::do_compare(uint32 addr)
235 uint32 offset = 0x4000;
237 uint8 disables = ~bank_disable_reg & 0x0f;
241 //printf("Compare CMD=%02x, ADDR=%04x\n", command_reg, addr);
243 b = do_read(addr, 0);
244 r = do_read(addr, 1);
245 g = do_read(addr, 2);
247 t = do_read(addr, 3);
250 disables = disables & 0x07;
252 cmp_status_reg = 0x00;
253 for(i = 7; i >= 0; i--) {
254 tmpcol = (b & 0x80) ? 1 : 0;
255 tmpcol |= (r & 0x80) ? 2 : 0;
256 tmpcol |= (g & 0x80) ? 4 : 0;
257 tmpcol |= (t & 0x80) ? 8 : 0;
258 tmpcol = tmpcol & disables;
259 for(j = 0; j < 8; j++) {
260 if((cmp_color_data[j] & 0x80) != 0) continue;
261 if((cmp_color_data[j] & disables) == tmpcol) {
262 cmp_status_reg = cmp_status_reg | (1 << i);
274 uint8 MB61VH010::do_alucmds(uint32 addr)
277 addr = addr & 0x3fff;
283 addr = addr & 0x7fff;
285 if(((command_reg & 0x40) != 0) && ((command_reg & 0x07) != 7)) do_compare(addr);
286 //printf("ALU: ADDR=%04x, cmd = %02x\n", addr, command_reg);
287 //printf("ALU: CMD %02x ADDR=%08x\n", command_reg, addr);
288 switch(command_reg & 0x07) {
290 return do_pset(addr);
293 return do_blank(addr);
308 return do_tilepaint(addr);
311 return do_compare(addr);
317 void MB61VH010::do_line(void)
319 int x_begin = line_xbegin.w.l;
320 int x_end = line_xend.w.l;
321 int y_begin = line_ybegin.w.l;
322 int y_end = line_yend.w.l;
324 uint8 lmask[8] = {0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01};
325 uint8 rmask[8] = {0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff};
326 uint8 vmask[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
329 int ax = x_end - x_begin;
330 int ay = y_end - y_begin;
333 uint8 mask_bak = mask_reg;
334 //printf("Line: (%d,%d) - (%d,%d) CMD=%02x\n", x_begin, y_begin, x_end, y_end, command_reg);
337 is_400line = (target->read_signal(SIG_DISPLAY_MODE_IS_400LINE) != 0) ? true : false;
338 planes = target->read_signal(SIG_DISPLAY_PLANES) & 0x07;
339 screen_width = target->read_signal(SIG_DISPLAY_X_WIDTH) * 8;
340 screen_height = target->read_signal(SIG_DISPLAY_Y_HEIGHT);
342 //if((command_reg & 0x80) == 0) return;
343 oldaddr = 0xffffffff;
346 line_style = line_pattern;
351 mask_reg = 0xff & vmask[x_begin & 7];
352 // Got from HD63484.cpp .
353 if(abs(ax) >= abs(ay)) {
354 total_bytes = abs(ax) >> 3;
356 diff = (abs(ay) * 1024) / abs(ax);
358 for(; cpx_t != x_end; cpx_t++) {
359 put_dot(cpx_t, cpy_t);
363 put_dot(cpx_t + 1, cpy_t);
369 put_dot(cpx_t + 1, cpy_t);
376 for(; cpx_t != x_end; cpx_t--) {
377 put_dot(cpx_t, cpy_t);
381 put_dot(cpx_t - 1, cpy_t);
387 put_dot(cpx_t - 1, cpy_t);
397 diff = (abs(ax) * 1024) / abs(ay);
399 for(; cpy_t != y_end; cpy_t++) {
400 put_dot(cpx_t, cpy_t);
404 put_dot(cpx_t, cpy_t + 1);
410 put_dot(cpx_t, cpy_t + 1);
417 for(; cpy_t != y_end; cpy_t--) {
418 put_dot(cpx_t, cpy_t);
422 put_dot(cpx_t, cpy_t - 1);
428 put_dot(cpx_t, cpy_t - 1);
437 put_dot(cpx_t, cpy_t);
440 usec = (double)total_bytes / 16.0;
441 if(usec >= 1.0) { // 1MHz
442 register_event(this, EVENT_MB61VH010_BUSY_OFF, usec, false, &eventid_busy) ;
449 void MB61VH010::put_dot(int x, int y)
452 uint8 vmask[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
456 if((x < 0) || (y < 0)) return;
457 if((x >= screen_width) || (y >= screen_height)) return;
458 if((command_reg & 0x80) == 0) return;
460 addr = ((y * screen_width) >> 3) + (x >> 3);
461 addr = addr + (line_addr_offset.w.l << 1);
462 addr = addr & 0x7fff;
463 if(!is_400line) addr = addr & 0x3fff;
464 if((line_style.b.h & 0x80) != 0) {
465 mask_reg &= ~vmask[x & 7];
467 // if(oldaddr != addr) {
473 tmp8a = (line_style.w.l & 0x8000) >> 15;
474 line_style.w.l = (line_pattern.w.l << 1) | tmp8a;
477 void MB61VH010::write_data8(uint32 id, uint32 data)
479 //printf("ALU: ADDR=%02x DATA=%02x\n", id, data);
480 if(id == ALU_CMDREG) {
484 //if((command_reg & 0x80) == 0) return;
486 case ALU_LOGICAL_COLOR:
489 case ALU_WRITE_MASKREG:
492 case ALU_BANK_DISABLE:
493 bank_disable_reg = data;
495 case ALU_TILEPAINT_B:
498 case ALU_TILEPAINT_R:
501 case ALU_TILEPAINT_G:
504 case ALU_TILEPAINT_L:
507 case ALU_OFFSET_REG_HIGH:
508 is_400line = (target->read_signal(SIG_DISPLAY_MODE_IS_400LINE) != 0) ? true : false;
510 line_addr_offset.b.h = data & 0x3f;
512 line_addr_offset.b.h = data & 0x1f;
515 case ALU_OFFSET_REG_LO:
516 line_addr_offset.b.l = data;
518 case ALU_LINEPATTERN_REG_HIGH:
519 line_pattern.b.h = data;
521 case ALU_LINEPATTERN_REG_LO:
522 line_pattern.b.l = data;
524 case ALU_LINEPOS_START_X_HIGH:
525 line_xbegin.b.h = data;
527 case ALU_LINEPOS_START_X_LOW:
528 line_xbegin.b.l = data;
530 case ALU_LINEPOS_START_Y_HIGH:
531 line_ybegin.b.h = data;
533 case ALU_LINEPOS_START_Y_LOW:
534 line_ybegin.b.l = data;
536 case ALU_LINEPOS_END_X_HIGH:
537 line_xend.b.h = data;
539 case ALU_LINEPOS_END_X_LOW:
540 line_xend.b.l = data;
542 case ALU_LINEPOS_END_Y_HIGH:
543 line_yend.b.h = data;
545 case ALU_LINEPOS_END_Y_LOW:
546 line_yend.b.l = data;
550 if((id >= (ALU_CMPDATA_REG + 0)) && (id < (ALU_CMPDATA_REG + 8))) {
551 cmp_color_data[id - ALU_CMPDATA_REG] = data;
552 } else if((id >= ALU_WRITE_PROXY) && (id < (ALU_WRITE_PROXY + 0x18000))) {
553 is_400line = (target->read_signal(SIG_DISPLAY_MODE_IS_400LINE) != 0) ? true : false;
554 do_alucmds(id - ALU_WRITE_PROXY);
560 uint32 MB61VH010::read_data8(uint32 id)
565 return (uint32)command_reg;
567 case ALU_LOGICAL_COLOR:
568 return (uint32)color_reg;
570 case ALU_WRITE_MASKREG:
571 return (uint32)mask_reg;
573 case ALU_CMP_STATUS_REG:
574 return (uint32)cmp_status_reg;
576 case ALU_BANK_DISABLE:
577 return (uint32)bank_disable_reg;
580 if((id >= ALU_WRITE_PROXY) && (id < (ALU_WRITE_PROXY + 0x18000))) {
581 return do_alucmds(id - ALU_WRITE_PROXY);
588 uint32 MB61VH010::read_signal(int id)
590 uint32 val = 0x00000000;
592 case SIG_ALU_BUSYSTAT:
593 if(busy_flag) val = 0xffffffff;
599 void MB61VH010::event_callback(int event_id, int err)
602 case EVENT_MB61VH010_BUSY_ON:
604 if(eventid_busy >= 0) cancel_event(this, eventid_busy);
607 case EVENT_MB61VH010_BUSY_OFF:
614 void MB61VH010::initialize(void)
620 void MB61VH010::reset(void)
624 if(eventid_busy >= 0) cancel_event(this, eventid_busy);
627 command_reg = 0; // D410 (RW)
628 color_reg = 0; // D411 (RW)
629 mask_reg = 0; // D412 (RW)
630 cmp_status_reg = 0; // D413 (RO)
631 for(i = 0; i < 8; i++) cmp_color_data[i] = 0x80; // D413-D41A (WO)
632 bank_disable_reg = 0; // D41B (RW)
633 for(i = 0; i < 4; i++) tile_reg[i] = 0; // D41C-D41F (WO)
635 line_addr_offset.d = 0; // D420-D421 (WO)
636 line_pattern.d = 0; // D422-D423 (WO)
637 line_xbegin.d = 0; // D424-D425 (WO)
638 line_ybegin.d = 0; // D426-D427 (WO)
639 line_xend.d = 0; // D428-D429 (WO)
640 line_yend.d = 0; // D42A-D42B (WO)
642 oldaddr = 0xffffffff;
644 planes = target->read_signal(SIG_DISPLAY_PLANES) & 0x07;
645 is_400line = (target->read_signal(SIG_DISPLAY_MODE_IS_400LINE) != 0) ? true : false;
647 screen_width = target->read_signal(SIG_DISPLAY_X_WIDTH) * 8;
648 screen_height = target->read_signal(SIG_DISPLAY_Y_HEIGHT);