+ u16 *d = (u16 *)((long)dst & ~1);
+ u16 *s = (u16 *)((long)src & ~1);
+
+ // XXX: optimize
+ for (; w > 0; d++, s++, w--)
+ if (*s != trc)
+ *d = *s;
+}
+
+#define dump_blitter() \
+{ \
+ u32 *r = &blitter.dstctrl; \
+ int i; \
+ for (i = 0; i < 4*4; i++, r++) { \
+ printf("%08x ", *r); \
+ if ((i & 3) == 3) \
+ printf("\n"); \
+ } \
+}
+
+static void *upper_lookup(u32 addr, u8 **mem_end, int *stride_override)
+{
+ struct uppermem_block *ub;
+
+ // maybe the screen?
+ if (mmsp2.mlc_stl_eadr <= addr && addr < mmsp2.mlc_stl_eadr + 320*240*2) {
+ host_screen = host_video_flip(); // HACK
+ *mem_end = (u8 *)host_screen + host_stride * 240;
+ *stride_override = host_stride;
+ return (u8 *)host_screen + addr - mmsp2.mlc_stl_eadr;
+ }
+
+ for (ub = upper_mem; ub != NULL; ub = ub->next) {
+ if (ub->addr <= addr && addr < ub->addr + ub->size) {
+ *mem_end = (u8 *)ub->mem + ub->size;
+ return (u8 *)ub->mem + addr - ub->addr;
+ }
+ }
+
+ return NULL;
+}
+
+static void blitter_do(void)
+{
+ u8 *dst, *dste, *src = NULL, *srce = NULL;
+ int w, h, sstrd, dstrd;
+ u32 addr;
+
+ w = blitter.size & 0x7ff;
+ h = (blitter.size >> 16) & 0x7ff;
+ sstrd = blitter.srcstride;
+ dstrd = blitter.dststride;
+
+ // XXX: need to confirm this..
+ addr = (blitter.dstaddr & ~3) | ((blitter.dstctrl & 0x1f) >> 3);
+ dst = upper_lookup(addr, &dste, &dstrd);
+ if (dst == NULL)
+ goto bad_blit;
+
+ // XXX: assume fill if no SRCENB, but it could be pattern blit..
+ if (blitter.srcctrl & SRCCTRL_SRCENB) {
+ if (!(blitter.srcctrl & SRCCTRL_INVIDEO))
+ goto bad_blit;
+
+ addr = (blitter.srcaddr & ~3) | ((blitter.srcctrl & 0x1f) >> 3);
+ src = upper_lookup(addr, &srce, &sstrd);
+ if (src == NULL)
+ goto bad_blit;
+
+ if (src + sstrd * h > srce) {
+ printf("blit %08x->%08x %dx%d did not fit src\n",
+ blitter.srcaddr, blitter.dstaddr, w, h);
+ h = (srce - src) / sstrd;
+ }
+ }
+
+ if (dst + dstrd * h > dste) {
+ printf("blit %08x->%08x %dx%d did not fit dst\n",
+ blitter.srcaddr, blitter.dstaddr, w, h);
+ h = (dste - dst) / dstrd;
+ }
+
+ if (src != NULL) {
+ // copy
+ if (blitter.ctrl & CTRL_TRANSPARENCYENB) {
+ u32 trc = blitter.ctrl >> 16;
+ for (; h > 0; h--, dst += dstrd, src += sstrd)
+ blt_tr(dst, src, trc, w);
+ }
+ else {
+ for (; h > 0; h--, dst += dstrd, src += sstrd)
+ memcpy(dst, src, w * 2);
+ }
+ }
+ else {
+ // fill. Assume the pattern is cleared and bg color is used
+ u32 bgc = blitter.patbackcolor & 0xffff;
+ for (; h > 0; h--, dst += dstrd)
+ memset16(dst, bgc, w);
+ }
+ return;