From: Toni Wilen Date: Wed, 13 Mar 2024 18:26:02 +0000 (+0200) Subject: Permedia 2 2D blitter emulation. X-Git-Tag: 5300~95 X-Git-Url: https://git.unchartedbackwaters.co.uk/w/?a=commitdiff_plain;h=3bbc3ed2730d0ed3aec194de0b07cef695e981b7;p=francis%2Fwinuae.git Permedia 2 2D blitter emulation. --- diff --git a/pcem/vid_permedia2.cpp b/pcem/vid_permedia2.cpp index 55f94180..26bdb410 100644 --- a/pcem/vid_permedia2.cpp +++ b/pcem/vid_permedia2.cpp @@ -1,24 +1,20 @@ /* -Preliminary Permedia 2 (Amiga CyberVision/BlizzardVision PPC) emulation by Toni Wilen 2024 +Basic Permedia 2 (Amiga CyberVision/BlizzardVision PPC) emulation by Toni Wilen 2024 Emulated: -- Standard Graphics processor modes supported (8/15/16/24/32 bits). Other weird modes are not supported. +- Graphics processor mode standard screen modes supported (8/15/16/24/32 bits). Other weird modes are not supported. - VRAM aperture byte swapping and RAMDAC red/blue swapping modes. (Used at least by Picasso96 driver) - Hardware cursor. - -Not emulated but planned: - -- 2D blitter. NOBLITTER=YES required in Picasso96 tool types -- Overlay +- Most of 2D blitter operations. Amiga Picasso96 and CGX4 drivers work. NOTE: Trapezoid primitive is simply assumed to be Rectangle. Not emulated and Someone Else's Problem: - SVGA core. Amiga programs seem to always use Graphics processor mode. - 3D. 3D is someone else's problem. (Maybe some PCem or x86Box developer is interested?) -- Other Permedia 2 special features (front/back buffer swapping, stereo support etc) +- Other Permedia 2 special features (front/back buffer swapping, local buffer/DMA, stereo support etc) */ @@ -36,6 +32,51 @@ Not emulated and Someone Else's Problem: #include "vid_svga_render.h" #include "vid_sdac_ramdac.h" +#define BLIT_LOG 0 + +#define REG_STARTXDOM 0x0000 +#define REG_DXDOM 0x0008 +#define REG_STARTXSUB 0x0010 +#define REG_DXSUB 0x0018 +#define REG_STARTY 0x0020 +#define REG_DY 0x0028 +#define REG_COUNT 0x0030 +#define REG_RENDER 0x0038 +#define REG_CONTINUENEWLINE 0x0040 +#define REG_CONTINUENEWSUB 0x0050 +#define REG_BITMASKPATTERN 0x0068 +#define REG_RASTERIZERMODE 0x00a0 +#define REG_RECTANGLEORIGIN 0x00d0 +#define REG_RECTANGLESIZE 0x00d8 +#define REG_PACKEDDATALIMITS 0x0150 +#define REG_SCISSORMODE 0x0180 +#define REG_SCISSORMINXY 0x0188 +#define REG_SCISSORMAXXY 0x0190 +#define REG_SCREENSIZE 0x0198 +#define REG_AREASTIPPLEMODE 0x01a0 +#define REG_WINDOWORIGIN 0x01c8 +#define REG_AREASTIPPLEPATTERN0 0x0200 +#define REG_TEXEL0 0x0600 +#define REG_COLORDDAMODE 0x07e0 +#define REG_CONSTANTCOLOR 0x07e8 +#define REG_FBSOFTWRITEMASK 0x0820 +#define REG_LOGICALOPMODE 0x0828 +#define REG_FBWRITEDATA 0x0830 +#define REG_WINDOW 0x0980 +#define REG_FBREADMODE 0x0a80 +#define REG_FBSOURCEOFFSET 0x0a88 +#define REG_FBPIXELOFFSET 0x0a90 +#define REG_FBSOURCEDATA 0x0aa8 +#define REG_FBWINDOWBASE 0x0ab0 +#define REG_FBWRITEMODE 0x0ab8 +#define REG_FBHARDWRITEMASK 0x0ac0 +#define REG_FBBLOCKCOLOR 0x0ac8 +#define REG_FBREADPIXEL 0x0ad0 +#define REG_SYNC 0x0c40 +#define REG_FBSOURCEBASE 0x0d80 +#define REG_FBSOURCEDELTA 0x0d88 +#define REG_CONFIG 0x0d90 + extern void activate_debugger(void); typedef struct permedia2_t @@ -79,7 +120,52 @@ typedef struct permedia2_t uint8_t ramdac_cram[1024]; uint8_t linear_byte_control[2]; - + + uint32_t gp_regs[0x2000 / 4]; + int gp_pitch; + int gp_bpp; + int gp_type; + bool gp_astipple, gp_texena, gp_fogena, gp_fastfill; + bool gp_synconbitmask, gp_reusebitmask, gp_colordda; + int gp_incx, gp_incy; + bool gp_readsrc, gp_readdst, gp_writedst; + bool gp_doswmask, gp_dohwmask; + bool gp_ropena, gp_constfbdata; + bool gp_packeddata; + uint32_t gp_color; + uint8_t gp_rop; + int gp_x, gp_y, gp_x1, gp_y1, gp_x2, gp_y2; + int gp_dx, gp_dy, gp_sx, gp_sy; + int gp_len; + uint32_t gp_bitmaskpattern; + uint32_t gp_src, gp_dst; + bool gp_scissor_screen; + bool gp_scissor_user; + uint32_t gp_scissor_screen_w, gp_scissor_screen_h; + int gp_scissor_min_x, gp_scissor_min_y; + int gp_scissor_max_x, gp_scissor_max_y; + + bool gp_asena; + bool gp_asmirrorx, gp_asmirrory; + uint8_t gp_asinvert; + bool gp_asforcebackgroundcolor; + uint8_t gp_asxoffset, gp_asyoffset; + + bool gp_bitmaskena; + bool gp_bitmaskrelative; + int gp_bitmaskoffset; + bool gp_bitmaskpacking; + bool gp_bmforcebackgroundcolor; + bool gp_mirrorbitmask; + bool gp_waitbitmask; + int gp_bitmaskpatterncnt; + bool gp_bmcheckresult; + + int gp_packedlimitxstart, gp_packedlimitxend; + + uint32_t gp_outfifocnt; + uint32_t gp_outfifodata; + } permedia2_t; static __inline uint32_t do_byteswap_32(uint32_t v) @@ -238,7 +324,7 @@ void permedia2_recalctimings(svga_t *svga) } else { // graphics processor mode - svga->ma_latch = permedia2->vc_regs[0 / 4] & 0xfffff; + svga->ma_latch = (permedia2->vc_regs[0 / 4] & 0xfffff) * 2; svga->rowoffset = permedia2->vc_regs[8 / 4] & 0xfffff; svga->htotal = (((permedia2->vc_regs[0x10 / 4] & 2047) - (permedia2->vc_regs[0x20 / 4] & 2047)) + 1) * 4; svga->vtotal = permedia2->vc_regs[0x38 / 4] & 2047; @@ -287,6 +373,8 @@ void permedia2_recalctimings(svga_t *svga) void pcemvideorbswap(bool swapped); pcemvideorbswap(svga->swaprb); } + + svga->fullchange = changeframecount; } @@ -580,6 +668,634 @@ static uint32_t permedia2_ramdac_read(int reg, void *p) return v; } +static __inline int TOFRACT1215(uint32_t v) +{ + int vv = v & 0x7fffffe; + if (v & 0x8000000) { + vv = vv - 0x8000000; + } + return vv; +} +static __inline int TOFRACT1114(uint32_t v) +{ + int vv = v & 0x3fffffc; + if (v & 0x4000000) { + vv = vv - 0x4000000; + } + return vv; +} +static __inline int TOSIGN24(uint32_t v) +{ + int vv = v & 0x7fffff; + if (v & 0x800000) { + vv = vv - 0x800000; + } + return vv; +} +static __inline int TOSIGN12(uint32_t v) +{ + int vv = v & 0x7ff; + if (v & 0x800) { + vv = vv - 0x800; + } + return vv; +} +static __inline int TOSIGN3(uint32_t v) +{ + int vv = v & 0x3; + if (v & 0x4) { + vv = vv - 0x4; + } + return vv; +} +static __inline int FTOINT(int f) +{ + return f >> 16; +} + +static void writefb(struct permedia2_t *permedia2, uint32_t dst, uint32_t color, int bpp) +{ + dst &= permedia2->svga.vram_mask; + uint8_t *dstp = permedia2->svga.vram + dst; + switch (bpp) + { + case 1: + *((uint8_t*)dstp) = color; + break; + case 2: + *((uint16_t*)dstp) = color; + break; + case 3: + ((uint8_t*)dstp)[0] = color; + ((uint8_t*)dstp)[1] = color >> 8; + ((uint8_t*)dstp)[2] = color >> 16; + break; + case 4: + *((uint32_t*)dstp) = color; + break; + } + permedia2->svga.changedvram[dst >> 12] = changeframecount; +} +static uint32_t readfb(struct permedia2_t *permedia2, uint32_t dst, int bpp) +{ + dst &= permedia2->svga.vram_mask; + uint8_t *dstp = permedia2->svga.vram + dst; + uint32_t color; + switch (bpp) + { + default: + case 1: + color = *((uint8_t*)dstp); + break; + case 2: + color = *((uint16_t*)dstp); + break; + case 3: + color = ((uint8_t*)dstp)[0]; + color |= ((uint8_t*)dstp)[1] << 8; + color |= ((uint8_t*)dstp)[2] << 16; + break; + case 4: + color = *((uint32_t*)dstp); + break; + } + return color; +} + +static uint32_t dorop(uint8_t rop, uint32_t s, uint32_t d) +{ + uint32_t out = 0; + switch(rop) + { + case 0: + default: + out = 0x00000000; + break; + case 15: + out = 0xffffffff; + break; + case 1: + out = s & d; + break; + case 2: + out = s & ~d; + break; + case 3: + out = s; + break; + case 4: + out = ~s & d; + break; + case 5: + out = d; + break; + case 6: + out = s ^ d; + break; + case 7: + out = s | d; + break; + case 8: + out = ~(s | d); + break; + case 9: + out = ~(s ^ d); + break; + case 10: + out = ~d; + break; + case 11: + out = s | ~d; + break; + case 12: + out = ~s; + break; + case 13: + out = ~s | d; + break; + case 14: + out = ~(s & d); + break; + } + return out; +} + +static void do_stipple(permedia2_t *permedia2, uint32_t *cp, int *pxmode) +{ + int offx = (permedia2->gp_asxoffset + permedia2->gp_x) & 7; + int offy = (permedia2->gp_asyoffset + permedia2->gp_y) & 7; + if (permedia2->gp_asmirrorx) { + offx = 7 - offx; + } + if (permedia2->gp_asmirrory) { + offy = 7 - offy; + } + uint8_t mask = permedia2->gp_regs[(REG_AREASTIPPLEPATTERN0 >> 3) + offy]; + if (!((mask ^ permedia2->gp_asinvert) & (1 << offx))) { + if (permedia2->gp_asforcebackgroundcolor) { + *cp = permedia2->gp_regs[REG_TEXEL0 >> 3]; + *pxmode = 1; + } else { + *pxmode = -1; + } + } +} + +static bool do_bitmask_check(permedia2_t *permedia2) +{ + if (permedia2->gp_bitmaskoffset > 31) { + permedia2->gp_bitmaskoffset = 0; + if (permedia2->gp_synconbitmask) { + permedia2->gp_waitbitmask = true; + return false; + } + } + int offset = permedia2->gp_bitmaskoffset; + if (permedia2->gp_mirrorbitmask) { + offset = 31 - offset; + } + permedia2->gp_bmcheckresult = (permedia2->gp_bitmaskpattern & (1 << offset)) != 0; + permedia2->gp_bitmaskoffset++; + return true; +} +static void do_bitmask_do(permedia2_t *permedia2, uint32_t *cp, int *pxmode) +{ + if (!permedia2->gp_bmcheckresult) { + if (permedia2->gp_bmforcebackgroundcolor) { + *cp = permedia2->gp_regs[REG_TEXEL0 >> 3]; + *pxmode = 1; + } else { + *pxmode = -1; + } + } +} + +static bool next_bitmask(permedia2_t *permedia2) +{ + if (permedia2->gp_bitmaskpacking && permedia2->gp_bitmaskoffset > 0) { + permedia2->gp_bitmaskoffset = 0; + if (permedia2->gp_synconbitmask) { + permedia2->gp_waitbitmask = true; + return false; + } + } + return true; +} + +static void do_blit_rect(permedia2_t *permedia2) +{ + if (permedia2->gp_waitbitmask) { + return; + } + + if (permedia2->gp_fastfill) { + while (permedia2->gp_y >= permedia2->gp_y1 && permedia2->gp_y < permedia2->gp_y2) { + uint32_t d = permedia2->gp_dst + permedia2->gp_y * permedia2->gp_pitch * permedia2->gp_bpp + permedia2->gp_x * permedia2->gp_bpp; + if (!permedia2->gp_scissor_user || (permedia2->gp_y >= permedia2->gp_scissor_min_y && permedia2->gp_y < permedia2->gp_scissor_max_y)) { + while (permedia2->gp_x >= permedia2->gp_x1 && permedia2->gp_x < permedia2->gp_x2) { + // TODO: FBBlockColorL and FBBlockColorU + uint32_t c = permedia2->gp_regs[REG_FBBLOCKCOLOR >> 3]; + int pxmode = 0; + if (permedia2->gp_asena) { + do_stipple(permedia2, &c, &pxmode); + } + if (permedia2->gp_bitmaskena) { + if (!do_bitmask_check(permedia2)) { + return; + } + if (pxmode >= 0) { + do_bitmask_do(permedia2, &c, &pxmode); + } + } + if (pxmode >= 0) { + if (!permedia2->gp_scissor_user || (permedia2->gp_x >= permedia2->gp_scissor_min_x && permedia2->gp_x < permedia2->gp_scissor_max_x)) { + if (permedia2->gp_dohwmask) { + uint32_t cd = readfb(permedia2, d, permedia2->gp_bpp); + c = (c & permedia2->gp_regs[REG_FBHARDWRITEMASK >> 3]) | (cd & ~permedia2->gp_regs[REG_FBHARDWRITEMASK >> 3]); + } + writefb(permedia2, d, c, permedia2->gp_bpp); + } + } + d += permedia2->gp_dx; + permedia2->gp_x += permedia2->gp_incx; + } + } + permedia2->gp_x = permedia2->gp_incx > 0 ? permedia2->gp_x1 : permedia2->gp_x2 - 1; + permedia2->gp_y += permedia2->gp_incy; + if (permedia2->gp_bitmaskena) { + if (!next_bitmask(permedia2)) { + return; + } + } + } + } else { + while (permedia2->gp_y >= permedia2->gp_y1 && permedia2->gp_y < permedia2->gp_y2) { + if (!permedia2->gp_scissor_user || (permedia2->gp_y >= permedia2->gp_scissor_min_y && permedia2->gp_y < permedia2->gp_scissor_max_y)) { + uint32_t d = permedia2->gp_dst + permedia2->gp_y * permedia2->gp_pitch * permedia2->gp_bpp + permedia2->gp_x * permedia2->gp_bpp; + uint32_t s = permedia2->gp_src + permedia2->gp_y * permedia2->gp_pitch * permedia2->gp_bpp + permedia2->gp_x * permedia2->gp_bpp; + while (permedia2->gp_x >= permedia2->gp_x1 && permedia2->gp_x < permedia2->gp_x2) { + uint32_t c = permedia2->gp_color, cd = permedia2->gp_color; + int pxmode = 0; + if (permedia2->gp_asena) { + do_stipple(permedia2, &c, &pxmode); + } + if (permedia2->gp_bitmaskena) { + if (!do_bitmask_check(permedia2)) { + return; + } + if (pxmode >= 0) { + do_bitmask_do(permedia2, &c, &pxmode); + } + } + if (permedia2->gp_x >= permedia2->gp_packedlimitxstart && permedia2->gp_x < permedia2->gp_packedlimitxend) { + if (permedia2->gp_readsrc && !pxmode) { + c = readfb(permedia2, s, permedia2->gp_bpp); + } + if (pxmode >=0) { + if (permedia2->gp_readdst) { + cd = readfb(permedia2, d, permedia2->gp_bpp); + } + if (permedia2->gp_ropena) { + c = dorop(permedia2->gp_rop, c, cd); + } else if (permedia2->gp_constfbdata) { + c = permedia2->gp_regs[REG_FBWRITEDATA >> 3]; + } + if (permedia2->gp_writedst) { + if (!permedia2->gp_scissor_user || (permedia2->gp_x >= permedia2->gp_scissor_min_x && permedia2->gp_x < permedia2->gp_scissor_max_x)) { + if (permedia2->gp_doswmask) { + c = (c & permedia2->gp_regs[REG_FBSOFTWRITEMASK >> 3]) | (cd & ~permedia2->gp_regs[REG_FBSOFTWRITEMASK >> 3]); + } + if (permedia2->gp_dohwmask) { + cd = readfb(permedia2, d, permedia2->gp_bpp); + c = (c & permedia2->gp_regs[REG_FBHARDWRITEMASK >> 3]) | (cd & ~permedia2->gp_regs[REG_FBHARDWRITEMASK >> 3]); + } + writefb(permedia2, d, c, permedia2->gp_bpp); + } + } + } + } + permedia2->gp_x += permedia2->gp_incx; + d += permedia2->gp_dx; + s += permedia2->gp_sx; + } + } + permedia2->gp_x = permedia2->gp_incx > 0 ? permedia2->gp_x1 : permedia2->gp_x2 - 1; + permedia2->gp_y += permedia2->gp_incy; + if (permedia2->gp_bitmaskena) { + if (!next_bitmask(permedia2)) { + return; + } + } + } + } +} + +static void do_blit_line(permedia2_t *permedia2) +{ + if (permedia2->gp_type != 0 && permedia2->gp_type != 1) { + pclog("do_blit_line but type is not point or line!? was %d\n", permedia2->gp_type); + return; + } + if (permedia2->gp_waitbitmask) { + return; + } + while (permedia2->gp_len) { + int x = FTOINT(permedia2->gp_x1); + int y = FTOINT(permedia2->gp_y1); + + uint32_t d = permedia2->gp_dst + y * permedia2->gp_pitch * permedia2->gp_bpp + x * permedia2->gp_bpp; + uint32_t s = permedia2->gp_src + y * permedia2->gp_pitch * permedia2->gp_bpp + x * permedia2->gp_bpp; + + if (!permedia2->gp_scissor_user || (y >= permedia2->gp_scissor_min_y && y < permedia2->gp_scissor_max_y)) { + uint32_t c = permedia2->gp_color, cd = permedia2->gp_color; + int pxmode = 0; + if (permedia2->gp_asena) { + do_stipple(permedia2, &c, &pxmode); + } + // is this allowed in line mode? + if (permedia2->gp_bitmaskena) { + if (!do_bitmask_check(permedia2)) { + return; + } + if (pxmode >= 0) { + do_bitmask_do(permedia2, &c, &pxmode); + } + } + if (permedia2->gp_readsrc && !pxmode) { + c = readfb(permedia2, s, permedia2->gp_bpp); + } + if (pxmode >= 0) { + if (permedia2->gp_readdst) { + cd = readfb(permedia2, d, permedia2->gp_bpp); + } + if (permedia2->gp_ropena) { + c = dorop(permedia2->gp_rop, c, permedia2->gp_constfbdata ? permedia2->gp_regs[REG_FBWRITEDATA >> 3] : cd); + } + if (permedia2->gp_writedst) { + if (!permedia2->gp_scissor_user || (x >= permedia2->gp_scissor_min_x && x < permedia2->gp_scissor_max_x)) { + if (permedia2->gp_doswmask) { + c = (c & permedia2->gp_regs[REG_FBSOFTWRITEMASK >> 3]) | (cd & ~permedia2->gp_regs[REG_FBSOFTWRITEMASK >> 3]); + } + if (permedia2->gp_dohwmask) { + cd = readfb(permedia2, d, permedia2->gp_bpp); + c = (c & permedia2->gp_regs[REG_FBHARDWRITEMASK >> 3]) | (cd & ~permedia2->gp_regs[REG_FBHARDWRITEMASK >> 3]); + } + writefb(permedia2, d, c, permedia2->gp_bpp); + } + } + } + } + permedia2->gp_x1 += permedia2->gp_dx; + permedia2->gp_y1 += permedia2->gp_dy; + permedia2->gp_len--; + } +} + +static void do_blit(permedia2_t *permedia2) +{ + switch(permedia2->gp_type) + { + case 0: + do_blit_line(permedia2); + break; + case 3: + do_blit_rect(permedia2); + break; + } +} + +static void permedia2_blit(permedia2_t *permedia2) +{ + uint32_t cmd = permedia2->gp_regs[REG_RENDER >> 3]; + permedia2->gp_type = (cmd >> 6) & 3; + permedia2->gp_astipple = (cmd >> 0) & 1; + permedia2->gp_texena = (cmd >> 13) & 1; + permedia2->gp_fogena = (cmd >> 14) & 1; + permedia2->gp_incx = ((cmd >> 21) & 1) ? 1 : -1; + permedia2->gp_incy = ((cmd >> 22) & 1) ? 1 : -1; + permedia2->gp_fastfill = (cmd >> 3) & 1; + permedia2->gp_synconbitmask = (cmd >> 11) & 1; + permedia2->gp_reusebitmask = (cmd >> 17) & 1; + +#if BLIT_LOG + pclog("Permedia2 render %08x as=%d ff=%d incx=%d incy=%d type=%d te=%d fe=%d\n", + cmd, permedia2->gp_astipple, permedia2->gp_fastfill, permedia2->gp_incx, permedia2->gp_incy, + permedia2->gp_type, permedia2->gp_texena, permedia2->gp_fogena); +#endif + int readpixel = (permedia2->gp_regs[REG_FBREADPIXEL >> 3] & 7); + permedia2->gp_bpp = 1; + switch(readpixel) + { + case 0: + permedia2->gp_bpp = 1; + break; + case 1: + permedia2->gp_bpp = 2; + break; + case 2: + permedia2->gp_bpp = 4; + break; + case 4: + permedia2->gp_bpp = 3; + break; + } + + uint32_t stipplemode = permedia2->gp_regs[REG_AREASTIPPLEMODE >> 3]; + permedia2->gp_asena = permedia2->gp_astipple && ((stipplemode >> 0) & 1); + if (permedia2->gp_asena) { + permedia2->gp_asxoffset = (stipplemode >> 7) & 7; + permedia2->gp_asyoffset = (stipplemode >> 12) & 7; + permedia2->gp_asinvert = ((stipplemode >> 17) & 1) ? 0xff : 0x00; + permedia2->gp_asmirrorx = (stipplemode >> 18) & 1; + permedia2->gp_asmirrory = (stipplemode >> 19) & 1; + permedia2->gp_asforcebackgroundcolor = (stipplemode >> 20) & 1; +#if BLIT_LOG + pclog("Areastipplemode: XOFF=%d YOFF=%d INV=%d MIRX=%d MIRY=%d FBG=%d\n", + permedia2->gp_asxoffset, permedia2->gp_asyoffset, permedia2->gp_asinvert, + permedia2->gp_asmirrorx, permedia2->gp_asmirrory, permedia2->gp_asforcebackgroundcolor); +#endif + } + + uint32_t rasterizer = permedia2->gp_regs[REG_RASTERIZERMODE >> 3]; + permedia2->gp_bitmaskrelative = (rasterizer >> 19) & 1; + permedia2->gp_bitmaskoffset = (rasterizer >> 10) & 31; + permedia2->gp_bitmaskpacking = (rasterizer >> 9) & 1; + permedia2->gp_bmforcebackgroundcolor = (rasterizer >> 6) & 1; + permedia2->gp_mirrorbitmask = (rasterizer >> 0) & 1; + permedia2->gp_bitmaskpattern = permedia2->gp_regs[REG_BITMASKPATTERN >> 3]; + if ((rasterizer >> 1) & 1) { + permedia2->gp_bitmaskpattern ^= 0xffffffff; + } + permedia2->gp_waitbitmask = permedia2->gp_synconbitmask; + permedia2->gp_bitmaskpatterncnt = 0; + permedia2->gp_bitmaskena = permedia2->gp_synconbitmask || permedia2->gp_reusebitmask; +#if BLIT_LOG + if (permedia2->gp_bitmaskena) { + pclog("Bitmaskpattern: REL=%d OFF=%d PACK=%d FBG=%d MIRROR=%d\n", + permedia2->gp_bitmaskrelative, permedia2->gp_bitmaskoffset, permedia2->gp_bitmaskpacking, + permedia2->gp_bmforcebackgroundcolor, permedia2->gp_mirrorbitmask); + } +#endif + + uint32_t readmode = permedia2->gp_regs[REG_FBREADMODE >> 3]; + permedia2->gp_readsrc = ((readmode >> 9) & 1) != 0; + permedia2->gp_readdst = ((readmode >> 10) & 1) != 0; + permedia2->gp_packeddata = ((readmode >> 19) & 1) != 0; + bool gp_origin = ((readmode >> 16) & 1) != 0; + permedia2->gp_writedst = (permedia2->gp_regs[REG_FBWRITEMODE >> 3] & 1) != 0; + permedia2->gp_colordda = (permedia2->gp_regs[REG_COLORDDAMODE >> 3] & 1) != 0; +#if BLIT_LOG + pclog("FBREADMODE: RSRC=%d RDST=%d WDST=%d PACKED=%d ORIGIN=%d CDDA=%d\n", + permedia2->gp_readsrc, permedia2->gp_readdst, permedia2->gp_writedst, + permedia2->gp_packeddata, gp_origin, permedia2->gp_colordda); +#endif + + uint32_t scissormode = permedia2->gp_regs[REG_SCISSORMODE >> 3]; + permedia2->gp_scissor_user = (scissormode & 1) != 0; + permedia2->gp_scissor_screen = (scissormode & 2) != 0; + permedia2->gp_scissor_min_x = (permedia2->gp_regs[REG_SCISSORMINXY >> 3] >> 0) & 0xfff; + permedia2->gp_scissor_min_y = (permedia2->gp_regs[REG_SCISSORMINXY >> 3] >> 16) & 0xfff; + permedia2->gp_scissor_max_x = (permedia2->gp_regs[REG_SCISSORMAXXY >> 3] >> 0) & 0xfff; + permedia2->gp_scissor_max_y = (permedia2->gp_regs[REG_SCISSORMAXXY >> 3] >> 16) & 0xfff; + +#if BLIT_LOG + if (permedia2->gp_scissor_user) { + pclog("SCISSOR: %d-%d %d-%d\n", + permedia2->gp_scissor_min_x, permedia2->gp_scissor_min_y, + permedia2->gp_scissor_max_x, permedia2->gp_scissor_max_y); + } +#endif + + permedia2->gp_doswmask = (permedia2->gp_regs[REG_FBSOFTWRITEMASK >> 3] != 0xffffffff) && permedia2->gp_readdst; + permedia2->gp_dohwmask = (permedia2->gp_regs[REG_FBHARDWRITEMASK >> 3] != 0xffffffff); + permedia2->gp_rop = permedia2->gp_regs[REG_LOGICALOPMODE >> 3] >> 1 & 15; + permedia2->gp_ropena = (permedia2->gp_regs[REG_LOGICALOPMODE >> 3] & 1) != 0; + permedia2->gp_constfbdata = ((permedia2->gp_regs[REG_LOGICALOPMODE >> 3] >> 5) & 1) != 0; + int gp_srcoffset = TOSIGN24(permedia2->gp_regs[REG_FBSOURCEOFFSET >> 3]); + int gp_pixeloffset = TOSIGN24(permedia2->gp_regs[REG_FBPIXELOFFSET >> 3]); + int gp_packedlimitrel = 0; + +#if BLIT_LOG + pclog("SWMASK: %d %08x HWMASK %d %08x\n", + permedia2->gp_doswmask, permedia2->gp_regs[REG_FBSOFTWRITEMASK >> 3], + permedia2->gp_dohwmask, permedia2->gp_regs[REG_FBHARDWRITEMASK >> 3]); +#endif + + if (permedia2->gp_fastfill) { + permedia2->gp_asforcebackgroundcolor = false; + permedia2->gp_bmforcebackgroundcolor = false; + } + + permedia2->gp_dst = (permedia2->gp_regs[REG_FBWINDOWBASE >> 3] + gp_pixeloffset) * permedia2->gp_bpp; + permedia2->gp_src = (permedia2->gp_regs[REG_FBSOURCEBASE >> 3] + gp_pixeloffset + gp_srcoffset - gp_packedlimitrel) * permedia2->gp_bpp; + + permedia2->gp_color = permedia2->gp_colordda ? permedia2->gp_regs[REG_CONSTANTCOLOR >> 3] : permedia2->gp_regs[REG_FBSOURCEDATA >> 3]; + + if (permedia2->gp_type == 0) { + + // LINE + permedia2->gp_x1 = TOFRACT1215(permedia2->gp_regs[REG_STARTXDOM >> 3]); + permedia2->gp_y1 = TOFRACT1215(permedia2->gp_regs[REG_STARTY >> 3]); + permedia2->gp_dx = TOFRACT1215(permedia2->gp_regs[REG_DXDOM >> 3]); + permedia2->gp_dy = TOFRACT1215(permedia2->gp_regs[REG_DY >> 3]); + permedia2->gp_len = permedia2->gp_regs[REG_COUNT >> 3] & 0xfff; + do_blit_line(permedia2); + return; + + } else if (permedia2->gp_type == 2) { + + // POINT + permedia2->gp_x1 = TOFRACT1215(permedia2->gp_regs[REG_STARTXDOM >> 3]); + permedia2->gp_y1 = TOFRACT1215(permedia2->gp_regs[REG_STARTY >> 3]); + permedia2->gp_len = 1; + do_blit_line(permedia2); + return; + + } else if (permedia2->gp_type == 1) { + + // TRAPEZOID. FIXME: Currently assumes RECTANGLE! + permedia2->gp_x1 = TOFRACT1215(permedia2->gp_regs[REG_STARTXDOM >> 3]); + permedia2->gp_y1 = TOFRACT1215(permedia2->gp_regs[REG_STARTY >> 3]); + permedia2->gp_x2 = TOFRACT1215(permedia2->gp_regs[REG_STARTXSUB >> 3]); + int dxsub = TOFRACT1215(permedia2->gp_regs[REG_DXSUB >> 3]); + int dxdom = TOFRACT1215(permedia2->gp_regs[REG_DXDOM >> 3]); + int dy = TOFRACT1114(permedia2->gp_regs[REG_DY >> 3]); + if (dxsub || dxdom || (dy != 0x10000 && dy != 0xffff0000)) { + pclog("Not yet supported: trapezoid not rectangle!\n"); + } + permedia2->gp_len = permedia2->gp_regs[REG_COUNT >> 3] & 0xfff; + + if (permedia2->gp_x2 >= permedia2->gp_x1) { + permedia2->gp_incx = 1; + } else { + permedia2->gp_incx = -1; + } + permedia2->gp_incy = dy < 0 ? - 1 : 1; + permedia2->gp_type = 3; + + permedia2->gp_x1 = permedia2->gp_x1 >> 16; + permedia2->gp_x2 = permedia2->gp_x2 >> 16; + permedia2->gp_y1 = permedia2->gp_y1 >> 16; + permedia2->gp_y2 = permedia2->gp_y1 + permedia2->gp_len; + + } else { + + // RECTANGLE + permedia2->gp_x1 = TOSIGN12(permedia2->gp_regs[REG_RECTANGLEORIGIN >> 3] >> 0); + permedia2->gp_y1 = TOSIGN12(permedia2->gp_regs[REG_RECTANGLEORIGIN >> 3] >> 16); + int w = TOSIGN12(permedia2->gp_regs[REG_RECTANGLESIZE >> 3] >> 0); + int h = TOSIGN12(permedia2->gp_regs[REG_RECTANGLESIZE >> 3] >> 16); + + if (permedia2->gp_packeddata) { + permedia2->gp_packedlimitxstart = TOSIGN12(permedia2->gp_regs[REG_PACKEDDATALIMITS >> 3] >> 16); + permedia2->gp_packedlimitxend = TOSIGN12(permedia2->gp_regs[REG_PACKEDDATALIMITS >> 3] >> 0); + gp_packedlimitrel = TOSIGN3(permedia2->gp_regs[REG_PACKEDDATALIMITS >> 3] >> 29); + // "undo" packed data mode width modification. Not worth the trouble to really use packed mode. + if (permedia2->gp_bpp == 1) { + permedia2->gp_x1 <<= 2; + w <<= 2; + } else if (permedia2->gp_bpp == 2) { + permedia2->gp_x1 <<= 1; + w <<= 1; + } + permedia2->gp_src -= gp_packedlimitrel * permedia2->gp_bpp; + } else { + permedia2->gp_packedlimitxstart = -2048; + permedia2->gp_packedlimitxend = 2047; + } + + permedia2->gp_x2 = permedia2->gp_x1 + w; + permedia2->gp_y2 = permedia2->gp_y1 + h; + } + + permedia2->gp_dx = permedia2->gp_bpp; + permedia2->gp_sx = permedia2->gp_bpp; + + permedia2->gp_x = permedia2->gp_x1; + if (permedia2->gp_incx < 0) { + permedia2->gp_x = permedia2->gp_x2 - 1; + permedia2->gp_dx = -permedia2->gp_dx; + permedia2->gp_sx = -permedia2->gp_sx; + } + permedia2->gp_y = permedia2->gp_y1; + if (permedia2->gp_incy < 0) { + permedia2->gp_y = permedia2->gp_y2 - 1; + } + + if (permedia2->gp_bitmaskrelative) { + permedia2->gp_bitmaskoffset = permedia2->gp_x & 31; + } + +#if BLIT_LOG + pclog("X1=%d Y1=%d X2=%d Y2=%d BPP=%d PITCH=%d SOFF=%08x ROP=%02X SRC=%08x DST=%08x\n", + permedia2->gp_x1, permedia2->gp_y1, permedia2->gp_x2, permedia2->gp_y2, permedia2->gp_bpp, + permedia2->gp_pitch, gp_srcoffset, permedia2->gp_rop, + permedia2->gp_src, permedia2->gp_dst); +#endif + + do_blit(permedia2); +} + static void permedia2_mmio_write(uint32_t addr, uint8_t val, void *p) { permedia2_t *permedia2 = (permedia2_t*)p; @@ -600,7 +1316,82 @@ static void permedia2_mmio_write_l(uint32_t addr, uint32_t val, void *p) if (addr & 0x10000) { val = do_byteswap_32(val); } - if (reg >= 0x4000 && reg < 0x5000) { + + //pclog("PM2 MMIO Write %08x = %08x\n", addr, val); + + if (reg >= 0x8000 && reg < 0xa000) { + //pclog("PM2 GP MMIO Write %08x = %08x\n", addr, val); + reg &= 0x7fff; + int tag = reg >> 3; + permedia2->gp_regs[tag] = val; + if (reg == REG_RENDER) { + permedia2_blit(permedia2); + } else if (reg == REG_FBSOURCEDELTA) { + int x = TOSIGN12(val >> 0); + int y = TOSIGN12(val >> 16); + int offset = y * permedia2->gp_pitch + x; + offset += permedia2->gp_regs[REG_FBSOURCEBASE >> 3] & 0xffffff; + offset -= permedia2->gp_regs[REG_FBWINDOWBASE >> 3] & 0xffffff; + permedia2->gp_regs[REG_FBSOURCEOFFSET >> 3] = offset; + } else if (reg == REG_FBWINDOWBASE) { + permedia2->gp_regs[REG_FBSOURCEBASE >> 3] = val & 0xffffff; + } else if (reg == REG_CONFIG) { + int config = val; + // TODO + + } else if (reg == REG_FBREADMODE) { + int readmode = val; + int ppv0 = (readmode >> 0) & 7; + int ppv1 = (readmode >> 3) & 7; + int ppv2 = (readmode >> 6) & 7; + int pp0 = ppv0 ? 1 << (ppv0 - 1) : 0; + int pp1 = ppv1 ? 1 << (ppv1 - 1) : 0; + int pp2 = ppv2 ? 1 << (ppv2 - 1) : 0; + permedia2->gp_pitch = (pp0 + pp1 + pp2) * 32; + } else if (reg == REG_BITMASKPATTERN) { + permedia2->gp_bitmaskpattern = val; + uint32_t rasterizer = permedia2->gp_regs[REG_RASTERIZERMODE >> 3]; + //pclog("REG_BITMASKPATTERN %08x %d\n", permedia2->gp_bitmaskpattern, permedia2->gp_bitmaskpatterncnt++); + if ((rasterizer >> 1) & 1) { + permedia2->gp_bitmaskpattern ^= 0xffffffff; + } + if (permedia2->gp_waitbitmask) { + permedia2->gp_waitbitmask = false; + do_blit(permedia2); + } else { + pclog("REG_BITMASKPATTERN when not waiting!?\n"); + } + } else if (reg == REG_CONTINUENEWLINE) { + uint32_t rasterizer = permedia2->gp_regs[REG_RASTERIZERMODE >> 3]; + permedia2->gp_len = val & 0xfff; + // FractionAdjust + switch ((rasterizer >> 2) & 3) + { + case 1: + permedia2->gp_x &= 0xffff0000; + permedia2->gp_y &= 0xffff0000; + break; + case 2: + permedia2->gp_x &= 0xffff0000; + permedia2->gp_y &= 0xffff0000; + permedia2->gp_x |= 0x00008000; + permedia2->gp_y |= 0x00008000; + break; + case 3: + permedia2->gp_x &= 0xffff0000; + permedia2->gp_y &= 0xffff0000; + permedia2->gp_x |= 0x00007fff; + permedia2->gp_y |= 0x00007fff; + break; + } + do_blit(permedia2); + } else if (reg == REG_CONTINUENEWSUB) { + pclog("unimplemented\n"); + } else if (reg == REG_SYNC) { + permedia2->gp_outfifodata = tag; + permedia2->gp_outfifocnt = 1; + } + } else if (reg >= 0x4000 && reg < 0x5000) { permedia2_ramdac_write(reg & 0xff, val, p); } else if (reg >= 0x3000 && reg < 0x4000) { int vcreg = reg & 0xff; @@ -639,8 +1430,14 @@ static uint32_t permedia2_mmio_readl(uint32_t addr, void *p) uint32_t v = 0; int reg = (addr & 0xffff); - if (reg >= 0x4000 && reg < 0x5000) { + if (reg >= 0x8000 && reg < 0xa000) { + int tag = reg >> 3; + v = permedia2->gp_regs[tag]; + } else if (reg >= 0x4000 && reg < 0x5000) { v = permedia2_ramdac_read(reg & 0xff, p); + } else if (reg >= 0x2000 && reg < 0x3000) { + v = permedia2->gp_outfifodata; + permedia2->gp_outfifocnt = 0; } else if (reg >= 0x3000 && reg < 0x4000) { int vcreg = reg & 0xff; v = permedia2->vc_regs[vcreg / 4]; @@ -656,6 +1453,9 @@ static uint32_t permedia2_mmio_readl(uint32_t addr, void *p) case 0x18: v = 0x100; break; + case 0x20: + v = permedia2->gp_outfifocnt; + break; } //pclog("control read %08x = %08x\n", addr, v); } else {