+ 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);
+ }
+
+ if (to_screen)
+ host_screen = host_video_flip();
+ return;
+
+bad_blit:
+ err("blit %08x->%08x %dx%d translated to %p->%p\n",
+ blitter.srcaddr, blitter.dstaddr, w, h, src, dst);
+ dump_blitter();
+}
+
+// TODO: hw scaler stuff
+static void mlc_flip(u32 addr)
+{
+ int mode = (mmsp2.mlc_stl_cntl >> 9) & 3;
+ int bpp = mode ? mode * 8 : 4;
+ u16 *dst = host_screen;
+ u16 *hpal = mmsp2.host_pal;
+ u8 *src, *src_end;
+ int i, u;
+
+ src = uppermem_lookup(addr, &src_end);
+ if (src == NULL || src + 320*240 * bpp / 8 > src_end) {
+ err("mlc_flip: %08x is out of range\n", addr);
+ return;
+ }
+
+ if (bpp <= 8 && mmsp2.dirty_pal) {
+ u32 *srcp = mmsp2.mlc_stl_pallt_d32;
+ u16 *dstp = hpal;
+
+ for (i = 0; i < 256; i++, srcp++, dstp++) {
+ u32 t = *srcp;
+ *dstp = ((t >> 8) & 0xf800) | ((t >> 5) & 0x07e0) | ((t >> 3) & 0x001f);
+ }
+ mmsp2.dirty_pal = 0;
+ }
+
+ switch (bpp) {
+ case 4:
+ for (i = 0; i < 240; i++, dst += host_stride / 2 - 320) {
+ for (u = 320 / 2; u > 0; u--, src++) {
+ *dst++ = hpal[*src >> 4];
+ *dst++ = hpal[*src & 0x0f];
+ }
+ }
+ break;
+
+ case 8:
+ for (i = 0; i < 240; i++, dst += host_stride / 2 - 320) {
+ for (u = 320 / 4; u > 0; u--) {
+ *dst++ = hpal[*src++];
+ *dst++ = hpal[*src++];
+ *dst++ = hpal[*src++];
+ *dst++ = hpal[*src++];
+ }
+ }
+ break;
+
+ case 16:
+ for (i = 0; i < 240; i++, dst += host_stride / 2, src += 320*2)
+ memcpy(dst, src, 320*2);
+ break;
+
+ case 24:
+ // TODO
+ break;