//controlbyte (0xCA00) bit definitions #define WMS_BLITTER_CONTROLBYTE_NO_EVEN 0x80 #define WMS_BLITTER_CONTROLBYTE_NO_ODD 0x40 #define WMS_BLITTER_CONTROLBYTE_SHIFT 0x20 #define WMS_BLITTER_CONTROLBYTE_SOLID 0x10 #define WMS_BLITTER_CONTROLBYTE_FOREGROUND_ONLY 0x08 #define WMS_BLITTER_CONTROLBYTE_SLOW 0x04 //2us blits instead of 1us #define WMS_BLITTER_CONTROLBYTE_DST_STRIDE_256 0x02 #define WMS_BLITTER_CONTROLBYTE_SRC_STRIDE_256 0x01 WRITE8_MEMBER(williams_state::williams_blitter_w) { int sstart, dstart, w, h, accesses; int estimated_clocks_at_4MHz; /* store the data */ m_blitterram[offset] = data; /* only writes to location 0 trigger the blit */ if (offset != 0) return; /* compute the starting locations */ sstart = (m_blitterram[2] << 8) + m_blitterram[3]; dstart = (m_blitterram[4] << 8) + m_blitterram[5]; /* compute the width and height */ w = m_blitterram[6] ^ m_blitter_xor; h = m_blitterram[7] ^ m_blitter_xor; /* adjust the width and height */ if (w == 0) w = 1; if (h == 0) h = 1; /* do the actual blit */ accesses = blitter_core(space, sstart, dstart, w, h, data); /* based on the number of memory accesses needed to do the blit, compute how long the blit will take */ if(data & WMS_BLITTER_CONTROLBYTE_SLOW) { estimated_clocks_at_4MHz = 4 + 4 * (accesses + 2); } else { estimated_clocks_at_4MHz = 4 + 2 * (accesses + 3); } space.device().execute().adjust_icount(-((estimated_clocks_at_4MHz + 3) / 4)); /* Log blits */ logerror("%04X:Blit @ %3d : %02X%02X -> %02X%02X, %3dx%3d, mask=%02X, flags=%02X, icount=%d, win=%d\n", space.device().safe_pc(), machine().primary_screen->vpos(), m_blitterram[2], m_blitterram[3], m_blitterram[4], m_blitterram[5], m_blitterram[6], m_blitterram[7], m_blitterram[1], m_blitterram[0], ((estimated_clocks_at_4MHz + 3) / 4), m_blitter_window_enable); } WRITE8_MEMBER(williams_state::williams2_blit_window_enable_w) { m_blitter_window_enable = data & 0x01; } /************************************* * * Blitter core * *************************************/ INLINE void blit_pixel(address_space &space, int dstaddr, int srcdata, int controlbyte) { williams_state *state = space.machine().driver_data(); /* always read from video RAM regardless of the bank setting */ int curpix = (dstaddr < 0xc000) ? state->m_videoram[dstaddr] : space.read_byte(dstaddr); //current pixel values at dest int solid = state->m_blitterram[1]; unsigned char keepmask = 0xff; //what part of original dst byte should be kept, based on NO_EVEN and NO_ODD flags //even pixel (D7-D4) if((controlbyte & WMS_BLITTER_CONTROLBYTE_FOREGROUND_ONLY) && !(srcdata & 0xf0)) //FG only and src even pixel=0 { if(controlbyte & WMS_BLITTER_CONTROLBYTE_NO_EVEN) keepmask &= 0x0f; } else { if(!(controlbyte & WMS_BLITTER_CONTROLBYTE_NO_EVEN)) keepmask &= 0x0f; } //odd pixel (D3-D0) if((controlbyte & WMS_BLITTER_CONTROLBYTE_FOREGROUND_ONLY) && !(srcdata & 0x0f)) //FG only and src odd pixel=0 { if(controlbyte & WMS_BLITTER_CONTROLBYTE_NO_ODD) keepmask &= 0xf0; } else { if(!(controlbyte & WMS_BLITTER_CONTROLBYTE_NO_ODD)) keepmask &= 0xf0; } curpix &= keepmask; if(controlbyte & WMS_BLITTER_CONTROLBYTE_SOLID) curpix |= (solid & ~keepmask); else curpix |= (srcdata & ~keepmask); /* if the window is enabled, only blit to videoram below the clipping address */ /* note that we have to allow blits to non-video RAM (e.g. tileram, Sinistar $DXXX SRAM) because those */ /* are not blocked by the window enable */ if (!state->m_blitter_window_enable || dstaddr < state->m_blitter_clip_address || dstaddr >= 0xc000) space.write_byte(dstaddr, curpix); } static int blitter_core(address_space &space, int sstart, int dstart, int w, int h, int controlbyte) { williams_state *state = space.machine().driver_data(); int source, sxadv, syadv; int dest, dxadv, dyadv; int x, y; int accesses = 0; /* compute how much to advance in the x and y loops */ sxadv = (controlbyte & WMS_BLITTER_CONTROLBYTE_SRC_STRIDE_256) ? 0x100 : 1; syadv = (controlbyte & WMS_BLITTER_CONTROLBYTE_SRC_STRIDE_256) ? 1 : w; dxadv = (controlbyte & WMS_BLITTER_CONTROLBYTE_DST_STRIDE_256) ? 0x100 : 1; dyadv = (controlbyte & WMS_BLITTER_CONTROLBYTE_DST_STRIDE_256) ? 1 : w; int pixdata=0; /* loop over the height */ for (y = 0; y < h; y++) { source = sstart & 0xffff; dest = dstart & 0xffff; /* loop over the width */ for (x = 0; x < w; x++) { if (!(controlbyte & WMS_BLITTER_CONTROLBYTE_SHIFT)) //no shift { blit_pixel(space, dest, state->m_blitter_remap[space.read_byte(source)], controlbyte); } else { //shift one pixel right pixdata = (pixdata << 8) | state->m_blitter_remap[space.read_byte(source)]; blit_pixel(space, dest, (pixdata >> 4) & 0xff, controlbyte); } accesses += 2; /* advance src and dst pointers */ source = (source + sxadv) & 0xffff; dest = (dest + dxadv) & 0xffff; } /* note that PlayBall! indicates the X coordinate doesn't wrap */ if (controlbyte & WMS_BLITTER_CONTROLBYTE_DST_STRIDE_256) dstart = (dstart & 0xff00) | ((dstart + dyadv) & 0xff); else dstart += dyadv; if (controlbyte & WMS_BLITTER_CONTROLBYTE_SRC_STRIDE_256) sstart = (sstart & 0xff00) | ((sstart + syadv) & 0xff); else sstart += syadv; } return accesses; }