diff --git a/src/ibm.h b/src/ibm.h index 86ac97a..02fb0fc 100644 --- a/src/ibm.h +++ b/src/ibm.h @@ -321,6 +321,7 @@ enum GFX_CL_GD5428, /*Cirrus Logic CL-GD5428*/ GFX_IBM_GD5428, /*IBM 1MB SVGA Adapter/A*/ GFX_TVGA9000B, /*Trident TVGA9000B*/ + GFX_BANSHEE, GFX_MAX }; diff --git a/src/vid_svga.c b/src/vid_svga.c index 7b0098e..b881dd0 100644 --- a/src/vid_svga.c +++ b/src/vid_svga.c @@ -667,36 +667,39 @@ void svga_poll(void *p) svga->maback <<= 2; svga->ca <<= 2; - svga->video_res_x = wx; - svga->video_res_y = wy + 1; -// pclog("%i %i %i\n", svga->video_res_x, svga->video_res_y, svga->lowres); - if (!(svga->gdcreg[6] & 1) && !(svga->attrregs[0x10] & 1)) /*Text mode*/ + if (!svga->video_res_override) { - svga->video_res_x /= svga->char_width; - svga->video_res_y /= (svga->crtc[9] & 31) + 1; - svga->video_bpp = 0; - } - else - { - if (svga->crtc[9] & 0x80) - svga->video_res_y /= 2; - if (!(svga->crtc[0x17] & 2)) - svga->video_res_y *= 4; - else if (!(svga->crtc[0x17] & 1)) - svga->video_res_y *= 2; - svga->video_res_y /= (svga->crtc[9] & 31) + 1; - if (svga->render == svga_render_8bpp_lowres || - svga->render == svga_render_15bpp_lowres || - svga->render == svga_render_16bpp_lowres || - svga->render == svga_render_24bpp_lowres || - svga->render == svga_render_32bpp_lowres) - svga->video_res_x /= 2; + svga->video_res_x = wx; + svga->video_res_y = wy + 1; - switch (svga->gdcreg[5] & 0x60) + if (!(svga->gdcreg[6] & 1) && !(svga->attrregs[0x10] & 1)) /*Text mode*/ { - case 0x00: svga->video_bpp = 4; break; - case 0x20: svga->video_bpp = 2; break; - case 0x40: case 0x60: svga->video_bpp = svga->bpp; break; + svga->video_res_x /= svga->char_width; + svga->video_res_y /= (svga->crtc[9] & 31) + 1; + svga->video_bpp = 0; + } + else + { + if (svga->crtc[9] & 0x80) + svga->video_res_y /= 2; + if (!(svga->crtc[0x17] & 2)) + svga->video_res_y *= 4; + else if (!(svga->crtc[0x17] & 1)) + svga->video_res_y *= 2; + svga->video_res_y /= (svga->crtc[9] & 31) + 1; + if (svga->render == svga_render_8bpp_lowres || + svga->render == svga_render_15bpp_lowres || + svga->render == svga_render_16bpp_lowres || + svga->render == svga_render_24bpp_lowres || + svga->render == svga_render_32bpp_lowres) + svga->video_res_x /= 2; + + switch (svga->gdcreg[5] & 0x60) + { + case 0x00: svga->video_bpp = 4; break; + case 0x20: svga->video_bpp = 2; break; + case 0x40: case 0x60: svga->video_bpp = svga->bpp; break; + } } } // if (svga_interlace && oddeven) ma=maback=ma+(svga_rowoffset<<2); @@ -767,7 +770,7 @@ int svga_init(svga_t *svga, void *p, int memsize, svga->vram_display_mask = memsize - 1; svga->vram_mask = memsize - 1; svga->decode_mask = 0x7fffff; - svga->changedvram = malloc(/*(memsize >> 12) << 1*/0x800000 >> 12); + svga->changedvram = malloc(/*(memsize >> 12) << 1*/0x1000000 >> 12); svga->recalctimings_ex = recalctimings_ex; svga->video_in = video_in; svga->video_out = video_out; diff --git a/src/vid_svga.h b/src/vid_svga.h index 3a0668b..9e49bfd 100644 --- a/src/vid_svga.h +++ b/src/vid_svga.h @@ -50,7 +50,7 @@ typedef struct svga_t int set_reset_disabled; uint8_t egapal[16]; - uint32_t pallook[256]; + uint32_t pallook[512]; PALETTE vgapal; int ramdac_type; @@ -93,6 +93,8 @@ typedef struct svga_t int fullchange; int video_res_x, video_res_y, video_bpp; + int video_res_override; /*If clear then SVGA code will set above variables, if + set then card code will*/ int frames, fps; struct diff --git a/src/vid_voodoo.c b/src/vid_voodoo.c index a59347f..79fac67 100644 --- a/src/vid_voodoo.c +++ b/src/vid_voodoo.c @@ -34,6 +34,9 @@ void voodoo_recalc(voodoo_t *voodoo) { uint32_t buffer_offset = ((voodoo->fbiInit2 >> 11) & 511) * 4096; + if (voodoo->type >= VOODOO_BANSHEE) + return; + voodoo->params.front_offset = voodoo->disp_buffer*buffer_offset; voodoo->back_offset = voodoo->draw_buffer*buffer_offset; @@ -1050,6 +1053,114 @@ void *voodoo_card_init() return voodoo; } +void *voodoo_2d3d_card_init(int type) +{ + int c; + voodoo_t *voodoo = malloc(sizeof(voodoo_t)); + memset(voodoo, 0, sizeof(voodoo_t)); + + voodoo->bilinear_enabled = device_get_config_int("bilinear"); + voodoo->scrfilter = 0; + voodoo->render_threads = device_get_config_int("render_threads"); + voodoo->odd_even_mask = voodoo->render_threads - 1; +#ifndef NO_CODEGEN + voodoo->use_recompiler = device_get_config_int("recompiler"); +#endif + voodoo->type = type; + voodoo->dual_tmus = 0; + + /*generate filter lookup tables*/ + voodoo_generate_filter_v2(voodoo); + + for (c = 0; c < TEX_CACHE_MAX; c++) + { + voodoo->texture_cache[0][c].data = malloc((256*256 + 256*256 + 128*128 + 64*64 + 32*32 + 16*16 + 8*8 + 4*4 + 2*2) * 4); + voodoo->texture_cache[0][c].base = -1; /*invalid*/ + voodoo->texture_cache[0][c].refcount = 0; + if (voodoo->dual_tmus) + { + voodoo->texture_cache[1][c].data = malloc((256*256 + 256*256 + 128*128 + 64*64 + 32*32 + 16*16 + 8*8 + 4*4 + 2*2) * 4); + voodoo->texture_cache[1][c].base = -1; /*invalid*/ + voodoo->texture_cache[1][c].refcount = 0; + } + } + + timer_add(&voodoo->timer, voodoo_callback, voodoo, 1); + + voodoo->fbiInit0 = 0; + + voodoo->wake_fifo_thread = thread_create_event(); + voodoo->wake_render_thread[0] = thread_create_event(); + voodoo->wake_render_thread[1] = thread_create_event(); + voodoo->wake_main_thread = thread_create_event(); + voodoo->fifo_not_full_event = thread_create_event(); + voodoo->render_not_full_event[0] = thread_create_event(); + voodoo->render_not_full_event[1] = thread_create_event(); + voodoo->fifo_thread = thread_create(voodoo_fifo_thread, voodoo); + voodoo->render_thread[0] = thread_create(voodoo_render_thread_1, voodoo); + if (voodoo->render_threads == 2) + voodoo->render_thread[1] = thread_create(voodoo_render_thread_2, voodoo); + + timer_add(&voodoo->wake_timer, voodoo_wake_timer, (void *)voodoo, 0); + + for (c = 0; c < 0x100; c++) + { + rgb332[c].r = c & 0xe0; + rgb332[c].g = (c << 3) & 0xe0; + rgb332[c].b = (c << 6) & 0xc0; + rgb332[c].r = rgb332[c].r | (rgb332[c].r >> 3) | (rgb332[c].r >> 6); + rgb332[c].g = rgb332[c].g | (rgb332[c].g >> 3) | (rgb332[c].g >> 6); + rgb332[c].b = rgb332[c].b | (rgb332[c].b >> 2); + rgb332[c].b = rgb332[c].b | (rgb332[c].b >> 4); + rgb332[c].a = 0xff; + + ai44[c].a = (c & 0xf0) | ((c & 0xf0) >> 4); + ai44[c].r = (c & 0x0f) | ((c & 0x0f) << 4); + ai44[c].g = ai44[c].b = ai44[c].r; + } + + for (c = 0; c < 0x10000; c++) + { + rgb565[c].r = (c >> 8) & 0xf8; + rgb565[c].g = (c >> 3) & 0xfc; + rgb565[c].b = (c << 3) & 0xf8; + rgb565[c].r |= (rgb565[c].r >> 5); + rgb565[c].g |= (rgb565[c].g >> 6); + rgb565[c].b |= (rgb565[c].b >> 5); + rgb565[c].a = 0xff; + + argb1555[c].r = (c >> 7) & 0xf8; + argb1555[c].g = (c >> 2) & 0xf8; + argb1555[c].b = (c << 3) & 0xf8; + argb1555[c].r |= (argb1555[c].r >> 5); + argb1555[c].g |= (argb1555[c].g >> 5); + argb1555[c].b |= (argb1555[c].b >> 5); + argb1555[c].a = (c & 0x8000) ? 0xff : 0; + + argb4444[c].a = (c >> 8) & 0xf0; + argb4444[c].r = (c >> 4) & 0xf0; + argb4444[c].g = c & 0xf0; + argb4444[c].b = (c << 4) & 0xf0; + argb4444[c].a |= (argb4444[c].a >> 4); + argb4444[c].r |= (argb4444[c].r >> 4); + argb4444[c].g |= (argb4444[c].g >> 4); + argb4444[c].b |= (argb4444[c].b >> 4); + + ai88[c].a = (c >> 8); + ai88[c].r = c & 0xff; + ai88[c].g = c & 0xff; + ai88[c].b = c & 0xff; + } +#ifndef NO_CODEGEN + voodoo_codegen_init(voodoo); +#endif + + voodoo->disp_buffer = 0; + voodoo->draw_buffer = 1; + + return voodoo; +} + void *voodoo_init() { voodoo_set_t *voodoo_set = malloc(sizeof(voodoo_set_t)); @@ -1116,14 +1227,17 @@ void voodoo_card_close(voodoo_t *voodoo) int c; #ifndef RELEASE_BUILD - f = romfopen("texram.dmp", "wb"); - fwrite(voodoo->tex_mem[0], voodoo->texture_size*1024*1024, 1, f); - fclose(f); - if (voodoo->dual_tmus) + if (voodoo->tex_mem[0]) { - f = romfopen("texram2.dmp", "wb"); - fwrite(voodoo->tex_mem[1], voodoo->texture_size*1024*1024, 1, f); + f = romfopen("texram.dmp", "wb"); + fwrite(voodoo->tex_mem[0], voodoo->texture_size*1024*1024, 1, f); fclose(f); + if (voodoo->dual_tmus) + { + f = romfopen("texram2.dmp", "wb"); + fwrite(voodoo->tex_mem[1], voodoo->texture_size*1024*1024, 1, f); + fclose(f); + } } #endif @@ -1148,10 +1262,13 @@ void voodoo_card_close(voodoo_t *voodoo) #ifndef NO_CODEGEN voodoo_codegen_close(voodoo); #endif - free(voodoo->fb_mem); - if (voodoo->dual_tmus) - free(voodoo->tex_mem[1]); - free(voodoo->tex_mem[0]); + if (voodoo->type != VOODOO_BANSHEE && voodoo->fb_mem) + { + free(voodoo->fb_mem); + if (voodoo->dual_tmus) + free(voodoo->tex_mem[1]); + free(voodoo->tex_mem[0]); + } free(voodoo); } diff --git a/src/vid_voodoo_banshee.c b/src/vid_voodoo_banshee.c new file mode 100644 index 0000000..26c14c8 --- /dev/null +++ b/src/vid_voodoo_banshee.c @@ -0,0 +1,1997 @@ +#include +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "mem.h" +#include "pci.h" +#include "rom.h" +#include "thread.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_svga_render.h" +#include "vid_voodoo_banshee.h" +#include "vid_voodoo_common.h" +#include "vid_voodoo_fifo.h" +#include "vid_voodoo_regs.h" +#include "vid_voodoo_render.h" +#include "x86.h" + +#ifdef CLAMP +#undef CLAMP +#endif + +typedef struct banshee_t +{ + svga_t svga; + + rom_t bios_rom; + + uint8_t pci_regs[256]; + + uint32_t memBaseAddr0; + uint32_t memBaseAddr1; + uint32_t ioBaseAddr; + + uint32_t agpInit0; + uint32_t dramInit0, dramInit1; + uint32_t lfbMemoryConfig; + uint32_t miscInit0, miscInit1; + uint32_t pciInit0; + uint32_t vgaInit0, vgaInit1; + + uint32_t command_2d; + uint32_t srcBaseAddr_2d; + + uint32_t pllCtrl0, pllCtrl1, pllCtrl2; + + uint32_t dacMode; + int dacAddr; + + uint32_t vidDesktopOverlayStride; + uint32_t vidDesktopStartAddr; + uint32_t vidProcCfg; + uint32_t vidScreenSize; + + int overlay_pix_fmt; + + uint32_t hwCurPatAddr, hwCurLoc, hwCurC0, hwCurC1; + + uint32_t intrCtrl; + + uint32_t overlay_buffer[4096]; + + mem_mapping_t linear_mapping; + + mem_mapping_t reg_mapping_low; /*0000000-07fffff*/ + mem_mapping_t reg_mapping_high; /*0c00000-1ffffff - Windows 2000 puts the BIOS ROM in between these two areas*/ + + voodoo_t *voodoo; +} banshee_t; + +enum +{ + Init_status = 0x00, + Init_pciInit0 = 0x04, + Init_lfbMemoryConfig = 0x0c, + Init_miscInit0 = 0x10, + Init_miscInit1 = 0x14, + Init_dramInit0 = 0x18, + Init_dramInit1 = 0x1c, + Init_agpInit0 = 0x20, + Init_vgaInit0 = 0x28, + Init_vgaInit1 = 0x2c, + Init_2dCommand = 0x30, + Init_2dSrcBaseAddr = 0x34, + Init_strapInfo = 0x38, + + PLL_pllCtrl0 = 0x40, + PLL_pllCtrl1 = 0x44, + PLL_pllCtrl2 = 0x48, + + DAC_dacMode = 0x4c, + DAC_dacAddr = 0x50, + DAC_dacData = 0x54, + + Video_vidProcCfg = 0x5c, + Video_hwCurPatAddr = 0x60, + Video_hwCurLoc = 0x64, + Video_hwCurC0 = 0x68, + Video_hwCurC1 = 0x6c, + Video_vidScreenSize = 0x98, + Video_vidOverlayStartCoords = 0x9c, + Video_vidOverlayEndScreenCoords = 0xa0, + Video_vidOverlayDudx = 0xa4, + Video_vidOverlayDudxOffsetSrcWidth = 0xa8, + Video_vidOverlayDvdy = 0xac, + Video_vidOverlayDvdyOffset = 0xe0, + Video_vidDesktopStartAddr = 0xe4, + Video_vidDesktopOverlayStride = 0xe8 +}; + +enum +{ + cmdBaseAddr0 = 0x20, + cmdBaseSize0 = 0x24, + cmdBump0 = 0x28, + cmdRdPtrL0 = 0x2c, + cmdRdPtrH0 = 0x30, + cmdAMin0 = 0x34, + cmdAMax0 = 0x3c, + cmdFifoDepth0 = 0x44, + cmdHoleCnt0 = 0x48 +}; + +#define VGAINIT0_EXTENDED_SHIFT_OUT (1 << 12) + +#define VIDPROCCFG_OVERLAY_ENABLE (1 << 8) +#define VIDPROCCFG_H_SCALE_ENABLE (1 << 14) +#define VIDPROCCFG_V_SCALE_ENABLE (1 << 15) +#define VIDPROCCFG_DESKTOP_PIX_FORMAT ((banshee->vidProcCfg >> 18) & 7) +#define VIDPROCCFG_OVERLAY_PIX_FORMAT ((banshee->vidProcCfg >> 21) & 7) +#define VIDPROCCFG_OVERLAY_PIX_FORMAT_SHIFT (21) +#define VIDPROCCFG_OVERLAY_PIX_FORMAT_MASK (7 << VIDPROCCFG_OVERLAY_PIX_FORMAT_SHIFT) +#define VIDPROCCFG_DESKTOP_TILE (1 << 24) +#define VIDPROCCFG_OVERLAY_TILE (1 << 25) +#define VIDPROCCFG_2X_MODE (1 << 26) +#define VIDPROCCFG_HWCURSOR_ENA (1 << 27) + +#define OVERLAY_FMT_YUYV422 (5) +#define OVERLAY_FMT_UYVY422 (6) +#define OVERLAY_FMT_565_DITHER (7) + +#define OVERLAY_START_X_MASK (0xfff) +#define OVERLAY_START_Y_SHIFT (12) +#define OVERLAY_START_Y_MASK (0xfff << OVERLAY_START_Y_SHIFT) + +#define OVERLAY_END_X_MASK (0xfff) +#define OVERLAY_END_Y_SHIFT (12) +#define OVERLAY_END_Y_MASK (0xfff << OVERLAY_END_Y_SHIFT) + +#define OVERLAY_SRC_WIDTH_SHIFT (19) +#define OVERLAY_SRC_WIDTH_MASK (0x1fff << OVERLAY_SRC_WIDTH_SHIFT) + +#define VID_STRIDE_OVERLAY_SHIFT (16) +#define VID_STRIDE_OVERLAY_MASK (0x7fff << VID_STRIDE_OVERLAY_SHIFT) + +#define VID_DUDX_MASK (0xffffff) +#define VID_DVDY_MASK (0xffffff) + +#define PIX_FORMAT_8 0 +#define PIX_FORMAT_RGB565 1 +#define PIX_FORMAT_RGB24 2 +#define PIX_FORMAT_RGB32 3 + + +static uint32_t banshee_status(banshee_t *banshee); + +static void banshee_out(uint16_t addr, uint8_t val, void *p) +{ + banshee_t *banshee = (banshee_t *)p; + svga_t *svga = &banshee->svga; + uint8_t old; + +// /*if (addr != 0x3c9) */pclog("banshee_out : %04X %02X %04X:%04X\n", addr, val, CS,cpu_state.pc); + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + + switch (addr) + { + case 0x3D4: + svga->crtcreg = val & 0x3f; + return; + case 0x3D5: + if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + old = svga->crtc[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; + if (old != val) + { + if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) + { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + break; + } + svga_out(addr, val, svga); +} + +static uint8_t banshee_in(uint16_t addr, void *p) +{ + banshee_t *banshee = (banshee_t *)p; + svga_t *svga = &banshee->svga; + uint8_t temp; + +// if (addr != 0x3da) pclog("banshee_in : %04X ", addr); + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + + switch (addr) + { + case 0x3c2: + if ((svga->vgapal[0].r + svga->vgapal[0].g + svga->vgapal[0].b) >= 0x40) + temp = 0; + else + temp = 0x10; + break; + case 0x3D4: + temp = svga->crtcreg; + break; + case 0x3D5: + temp = svga->crtc[svga->crtcreg]; + break; + default: + temp = svga_in(addr, svga); + break; + } +// if (addr != 0x3da) pclog("%02X %04X:%04X %i\n", temp, CS,cpu_state.pc, ins); + return temp; +} + +static void banshee_updatemapping(banshee_t *banshee) +{ + svga_t *svga = &banshee->svga; + + if (!(banshee->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_MEM)) + { +// pclog("Update mapping - PCI disabled\n"); + mem_mapping_disable(&svga->mapping); + mem_mapping_disable(&banshee->linear_mapping); + mem_mapping_disable(&banshee->reg_mapping_low); + mem_mapping_disable(&banshee->reg_mapping_high); + return; + } + + pclog("Update mapping - bank %02X ", svga->gdcreg[6] & 0xc); + switch (svga->gdcreg[6] & 0xc) /*Banked framebuffer*/ + { + case 0x0: /*128k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000); + svga->banked_mask = 0xffff; + break; + case 0x4: /*64k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); + svga->banked_mask = 0xffff; + break; + case 0x8: /*32k at B0000*/ + mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000); + svga->banked_mask = 0x7fff; + break; + case 0xC: /*32k at B8000*/ + mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000); + svga->banked_mask = 0x7fff; + break; + } + + pclog("Linear framebuffer %08X ", banshee->memBaseAddr1); + mem_mapping_set_addr(&banshee->linear_mapping, banshee->memBaseAddr1, 32 << 20); + pclog("registers %08X\n", banshee->memBaseAddr0); + mem_mapping_set_addr(&banshee->reg_mapping_low, banshee->memBaseAddr0, 8 << 20); + mem_mapping_set_addr(&banshee->reg_mapping_high, banshee->memBaseAddr0 + 0xc00000, 20 << 20); +} + +static void banshee_recalctimings(svga_t *svga) +{ + banshee_t *banshee = (banshee_t *)svga->p; + voodoo_t *voodoo = banshee->voodoo; + +/*7 R/W Horizontal Retrace End bit 5. - + 6 R/W Horizontal Retrace Start bit 8 0x4 + 5 R/W Horizontal Blank End bit 6. - + 4 R/W Horizontal Blank Start bit 8. 0x3 + 3 R/W Reserved. - + 2 R/W Horizontal Display Enable End bit 8. 0x1 + 1 R/W Reserved. - + 0 R/W Horizontal Total bit 8. 0x0*/ + if (svga->crtc[0x1a] & 0x01) svga->htotal += 0x100; + if (svga->crtc[0x1a] & 0x04) svga->hdisp += 0x100; +/*6 R/W Vertical Retrace Start bit 10 0x10 + 5 R/W Reserved. - + 4 R/W Vertical Blank Start bit 10. 0x15 + 3 R/W Reserved. - + 2 R/W Vertical Display Enable End bit 10 0x12 + 1 R/W Reserved. - + 0 R/W Vertical Total bit 10. 0x6*/ + if (svga->crtc[0x1b] & 0x01) svga->vtotal += 0x400; + if (svga->crtc[0x1b] & 0x04) svga->dispend += 0x400; + if (svga->crtc[0x1b] & 0x10) svga->vblankstart += 0x400; + if (svga->crtc[0x1b] & 0x40) svga->vsyncstart += 0x400; + pclog("svga->hdisp=%i\n", svga->hdisp); + + if (banshee->vgaInit0 & VGAINIT0_EXTENDED_SHIFT_OUT) + { + switch (VIDPROCCFG_DESKTOP_PIX_FORMAT) + { + case PIX_FORMAT_8: + svga->render = svga_render_8bpp_highres; + svga->bpp = 8; + break; + case PIX_FORMAT_RGB565: + svga->render = svga_render_16bpp_highres; + svga->bpp = 16; + break; + case PIX_FORMAT_RGB24: + svga->render = svga_render_24bpp_highres; + svga->bpp = 24; + break; + case PIX_FORMAT_RGB32: + svga->render = svga_render_32bpp_highres; + svga->bpp = 32; + break; + default: + fatal("Unknown pixel format %08x\n", banshee->vgaInit0); + } + if (banshee->vidProcCfg & VIDPROCCFG_DESKTOP_TILE) + svga->rowoffset = ((banshee->vidDesktopOverlayStride & 0x3fff) * 128) >> 3; + else + svga->rowoffset = (banshee->vidDesktopOverlayStride & 0x3fff) >> 3; + svga->ma_latch = banshee->vidDesktopStartAddr >> 2; + pclog("Extended shift out %i rowoffset=%i %02x\n", VIDPROCCFG_DESKTOP_PIX_FORMAT, svga->rowoffset, svga->crtc[1]); + + svga->char_width = 8; + svga->split = 99999; + + if (banshee->vidProcCfg & VIDPROCCFG_2X_MODE) + { + svga->hdisp *= 2; + svga->htotal *= 2; + } + + svga->overlay.ena = banshee->vidProcCfg & VIDPROCCFG_OVERLAY_ENABLE; + + svga->overlay.x = voodoo->overlay.start_x; + svga->overlay.y = voodoo->overlay.start_y; + svga->overlay.xsize = voodoo->overlay.size_x; + svga->overlay.ysize = voodoo->overlay.size_y; + svga->overlay.pitch = (banshee->vidDesktopOverlayStride & VID_STRIDE_OVERLAY_MASK) >> VID_STRIDE_OVERLAY_SHIFT; + if (banshee->vidProcCfg & VIDPROCCFG_OVERLAY_TILE) + svga->overlay.pitch *= 128; + if (svga->overlay.xsize <= 0 || svga->overlay.ysize <= 0) + svga->overlay.ena = 0; + if (svga->overlay.ena) + { + pclog("Overlay enabled : start=%i,%i end=%i,%i size=%i,%i pitch=%x\n", + voodoo->overlay.start_x, voodoo->overlay.start_y, + voodoo->overlay.end_x, voodoo->overlay.end_y, + voodoo->overlay.size_x, voodoo->overlay.size_y, + svga->overlay.pitch); + } + + svga->video_res_override = 1; + svga->video_res_x = svga->hdisp; + svga->video_res_y = svga->dispend; + svga->video_bpp = svga->bpp; + } + else + { + pclog("Normal shift out\n"); + svga->bpp = 8; + svga->video_res_override = 0; + } + + if (((svga->miscout >> 2) & 3) == 3) + { + int k = banshee->pllCtrl0 & 3; + int m = (banshee->pllCtrl0 >> 2) & 0x3f; + int n = (banshee->pllCtrl0 >> 8) & 0xff; + double freq = (((double)n + 2) / (((double)m + 2) * (double)(1 << k))) * 14318184.0; + + svga->clock = (cpuclock * (float)(1ull << 32)) / freq; +// svga->clock = cpuclock / freq; + +// pclog("svga->clock = %g %g m=%i k=%i n=%i\n", freq, freq / 1000000.0, m, k, n); + } +} + +static void banshee_ext_out(uint16_t addr, uint8_t val, void *p) +{ +// banshee_t *banshee = (banshee_t *)p; +// svga_t *svga = &banshee->svga; + +// pclog("banshee_ext_out: addr=%04x val=%02x\n", addr, val); + + switch (addr & 0xff) + { + case 0xb0: case 0xb1: case 0xb2: case 0xb3: + case 0xb4: case 0xb5: case 0xb6: case 0xb7: + case 0xb8: case 0xb9: case 0xba: case 0xbb: + case 0xbc: case 0xbd: case 0xbe: case 0xbf: + case 0xc0: case 0xc1: case 0xc2: case 0xc3: + case 0xc4: case 0xc5: case 0xc6: case 0xc7: + case 0xc8: case 0xc9: case 0xca: case 0xcb: + case 0xcc: case 0xcd: case 0xce: case 0xcf: + case 0xd0: case 0xd1: case 0xd2: case 0xd3: + case 0xd4: case 0xd5: case 0xd6: case 0xd7: + case 0xd8: case 0xd9: case 0xda: case 0xdb: + case 0xdc: case 0xdd: case 0xde: case 0xdf: + banshee_out((addr & 0xff)+0x300, val, p); + break; + + default: + fatal("bad banshee_ext_out: addr=%04x val=%02x\n", addr, val); + } +} +static void banshee_ext_outl(uint16_t addr, uint32_t val, void *p) +{ + banshee_t *banshee = (banshee_t *)p; + voodoo_t *voodoo = banshee->voodoo; + svga_t *svga = &banshee->svga; + +// pclog("banshee_ext_outl: addr=%04x val=%08x %04x(%08x):%08x\n", addr, val, CS,cs,cpu_state.pc); + + switch (addr & 0xff) + { + case Init_pciInit0: + banshee->pciInit0 = val; + voodoo->read_time = pci_nonburst_time + pci_burst_time * ((val & 0x100) ? 2 : 1); + voodoo->burst_time = pci_burst_time * ((val & 0x200) ? 1 : 0); + voodoo->write_time = pci_nonburst_time + voodoo->burst_time; + break; + + case Init_lfbMemoryConfig: + banshee->lfbMemoryConfig = val; +// pclog("lfbMemoryConfig=%08x\n", val); + voodoo->tile_base = (val & 0x1fff) << 12; + voodoo->tile_stride = 1024 << ((val >> 13) & 7); + voodoo->tile_stride_shift = 10 + ((val >> 13) & 7); + voodoo->tile_x = ((val >> 16) & 0x7f) * 128; + break; + + case Init_miscInit0: + banshee->miscInit0 = val; + break; + case Init_miscInit1: + banshee->miscInit1 = val; + break; + case Init_dramInit0: + banshee->dramInit0 = val; + break; + case Init_dramInit1: + banshee->dramInit1 = val; + break; + case Init_agpInit0: + banshee->agpInit0 = val; + break; + + case Init_2dCommand: + banshee->command_2d = val; + break; + case Init_2dSrcBaseAddr: + banshee->srcBaseAddr_2d = val; + break; + case Init_vgaInit0: + banshee->vgaInit0 = val; + break; + case Init_vgaInit1: + banshee->vgaInit1 = val; + svga->write_bank = (val & 0x3ff) << 15; + svga->read_bank = ((val >> 10) & 0x3ff) << 15; + break; + + case PLL_pllCtrl0: + banshee->pllCtrl0 = val; + break; + case PLL_pllCtrl1: + banshee->pllCtrl1 = val; + break; + case PLL_pllCtrl2: + banshee->pllCtrl2 = val; + break; + + case DAC_dacMode: + banshee->dacMode = val; + break; + case DAC_dacAddr: + banshee->dacAddr = val & 0x1ff; + break; + case DAC_dacData: + svga->pallook[banshee->dacAddr] = val & 0xffffff; + svga->fullchange = changeframecount; + break; + + case Video_vidProcCfg: + banshee->vidProcCfg = val; +// pclog("vidProcCfg=%08x\n", val); + banshee->overlay_pix_fmt = (val & VIDPROCCFG_OVERLAY_PIX_FORMAT_MASK) >> VIDPROCCFG_OVERLAY_PIX_FORMAT_SHIFT; + svga->hwcursor.ena = val & VIDPROCCFG_HWCURSOR_ENA; + svga->fullchange = changeframecount; + svga_recalctimings(svga); + break; + + case Video_hwCurPatAddr: + banshee->hwCurPatAddr = val; + svga->hwcursor.addr = val & 0xfffff0; + break; + case Video_hwCurLoc: + banshee->hwCurLoc = val; + svga->hwcursor.x = (val & 0x7ff) - 32; + svga->hwcursor.y = ((val >> 16) & 0x7ff) - 64; + if (svga->hwcursor.y < 0) + { + svga->hwcursor.yoff = -svga->hwcursor.y; + svga->hwcursor.y = 0; + } + else + svga->hwcursor.yoff = 0; + svga->hwcursor.xsize = 64; + svga->hwcursor.ysize = 64; +// pclog("hwCurLoc %08x %i\n", val, svga->hwcursor.y); + break; + case Video_hwCurC0: + banshee->hwCurC0 = val; + break; + case Video_hwCurC1: + banshee->hwCurC1 = val; + break; + + case Video_vidScreenSize: + banshee->vidScreenSize = val; + voodoo->h_disp = (val & 0xfff) + 1; + voodoo->v_disp = (val >> 12) & 0xfff; + break; + case Video_vidOverlayStartCoords: + voodoo->overlay.vidOverlayStartCoords = val; + voodoo->overlay.start_x = val & OVERLAY_START_X_MASK; + voodoo->overlay.start_y = (val & OVERLAY_START_Y_MASK) >> OVERLAY_START_Y_SHIFT; + voodoo->overlay.size_x = voodoo->overlay.end_x - voodoo->overlay.start_x; + voodoo->overlay.size_y = voodoo->overlay.end_y - voodoo->overlay.start_y; + svga_recalctimings(svga); + break; + case Video_vidOverlayEndScreenCoords: + voodoo->overlay.vidOverlayEndScreenCoords = val; + voodoo->overlay.end_x = val & OVERLAY_END_X_MASK; + voodoo->overlay.end_y = (val & OVERLAY_END_Y_MASK) >> OVERLAY_END_Y_SHIFT; + voodoo->overlay.size_x = voodoo->overlay.end_x - voodoo->overlay.start_x; + voodoo->overlay.size_y = voodoo->overlay.end_y - voodoo->overlay.start_y; + svga_recalctimings(svga); + break; + case Video_vidOverlayDudx: + voodoo->overlay.vidOverlayDudx = val & VID_DUDX_MASK; +// pclog("vidOverlayDudx=%08x\n", val); + break; + case Video_vidOverlayDudxOffsetSrcWidth: + voodoo->overlay.vidOverlayDudxOffsetSrcWidth = val; + voodoo->overlay.overlay_bytes = (val & OVERLAY_SRC_WIDTH_MASK) >> OVERLAY_SRC_WIDTH_SHIFT; +// pclog("vidOverlayDudxOffsetSrcWidth=%08x\n", val); + break; + case Video_vidOverlayDvdy: + voodoo->overlay.vidOverlayDvdy = val & VID_DVDY_MASK; +// pclog("vidOverlayDvdy=%08x\n", val); + break; + case Video_vidOverlayDvdyOffset: + voodoo->overlay.vidOverlayDvdyOffset = val; + break; + + + case Video_vidDesktopStartAddr: + banshee->vidDesktopStartAddr = val; +// pclog("vidDesktopStartAddr=%08x\n", val); + svga->fullchange = changeframecount; + svga_recalctimings(svga); + break; + case Video_vidDesktopOverlayStride: + banshee->vidDesktopOverlayStride = val; +// pclog("vidDesktopOverlayStride=%08x\n", val); + svga->fullchange = changeframecount; + svga_recalctimings(svga); + break; +// default: +// fatal("bad banshee_ext_outl: addr=%04x val=%08x\n", addr, val); + } +} + +static uint8_t banshee_ext_in(uint16_t addr, void *p) +{ + banshee_t *banshee = (banshee_t *)p; +// svga_t *svga = &banshee->svga; + uint8_t ret = 0xff; + + switch (addr & 0xff) + { + case Init_status: case Init_status+1: case Init_status+2: case Init_status+3: + ret = (banshee_status(banshee) >> ((addr & 3) * 8)) & 0xff; +// pclog("Read status reg! %04x(%08x):%08x\n", CS, cs, cpu_state.pc); + break; + + case 0xb0: case 0xb1: case 0xb2: case 0xb3: + case 0xb4: case 0xb5: case 0xb6: case 0xb7: + case 0xb8: case 0xb9: case 0xba: case 0xbb: + case 0xbc: case 0xbd: case 0xbe: case 0xbf: + case 0xc0: case 0xc1: case 0xc2: case 0xc3: + case 0xc4: case 0xc5: case 0xc6: case 0xc7: + case 0xc8: case 0xc9: case 0xca: case 0xcb: + case 0xcc: case 0xcd: case 0xce: case 0xcf: + case 0xd0: case 0xd1: case 0xd2: case 0xd3: + case 0xd4: case 0xd5: case 0xd6: case 0xd7: + case 0xd8: case 0xd9: case 0xda: case 0xdb: + case 0xdc: case 0xdd: case 0xde: case 0xdf: + ret = banshee_in((addr & 0xff)+0x300, p); + break; + + default: + fatal("bad banshee_ext_in: addr=%04x\n", addr); + break; + } + +// pclog("banshee_ext_in: addr=%04x val=%02x\n", addr, ret); + + return ret; +} + +static uint32_t banshee_status(banshee_t *banshee) +{ + voodoo_t *voodoo = banshee->voodoo; + svga_t *svga = &banshee->svga; + int fifo_entries = FIFO_ENTRIES; + int fifo_size = 0xffff - fifo_entries; + int swap_count = voodoo->swap_count; + int written = voodoo->cmd_written + voodoo->cmd_written_fifo; + int busy = (written - voodoo->cmd_read) || (voodoo->cmdfifo_depth_rd != voodoo->cmdfifo_depth_wr); + uint32_t ret; + + ret = 0; + if (fifo_size < 0x20) + ret |= fifo_size; + else + ret |= 0x1f; + if (fifo_size) + ret |= 0x20; + if (swap_count < 7) + ret |= (swap_count << 28); + else + ret |= (7 << 28); + if (!(svga->cgastat & 8)) + ret |= 0x40; + + if (busy) + ret |= 0x780; /*Busy*/ + + if (voodoo->cmdfifo_depth_rd != voodoo->cmdfifo_depth_wr) + ret |= (1 << 11); + + if (!voodoo->voodoo_busy) + voodoo_wake_fifo_thread(voodoo); + +// pclog("banshee_status: busy %i %i (%i %i) %i %i %i %04x(%08x):%08x %08x\n", busy, written, voodoo->cmd_written, voodoo->cmd_written_fifo, voodoo->cmd_read, voodoo->cmdfifo_depth_rd, voodoo->cmdfifo_depth_wr, CS,cs,cpu_state.pc, ret); + + return ret; +} + +static uint32_t banshee_ext_inl(uint16_t addr, void *p) +{ + banshee_t *banshee = (banshee_t *)p; + voodoo_t *voodoo = banshee->voodoo; + svga_t *svga = &banshee->svga; + uint32_t ret = 0xffffffff; + + cycles -= voodoo->read_time; + + switch (addr & 0xff) + { + case Init_status: + ret = banshee_status(banshee); +// pclog("Read status reg! %04x(%08x):%08x\n", CS, cs, cpu_state.pc); + break; + case Init_lfbMemoryConfig: + ret = banshee->lfbMemoryConfig; + break; + + case Init_miscInit0: + ret = banshee->miscInit0; + break; + case Init_miscInit1: + ret = banshee->miscInit1; + break; + case Init_dramInit0: + ret = banshee->dramInit0; + break; + case Init_dramInit1: + ret = banshee->dramInit1; + break; + case Init_agpInit0: + ret = banshee->agpInit0; + break; + + case Init_vgaInit0: + ret = banshee->vgaInit0; + break; + case Init_vgaInit1: + ret = banshee->vgaInit1; + break; + + case Init_2dCommand: + ret = banshee->command_2d; + break; + case Init_2dSrcBaseAddr: + ret = banshee->srcBaseAddr_2d; + break; + case Init_strapInfo: + ret = 0x00000040; /*8 MB SGRAM, PCI, IRQ enabled, 32kB BIOS*/ + break; + + case PLL_pllCtrl0: + ret = banshee->pllCtrl0; + break; + case PLL_pllCtrl1: + ret = banshee->pllCtrl1; + break; + case PLL_pllCtrl2: + ret = banshee->pllCtrl2; + break; + + case DAC_dacMode: + ret = banshee->dacMode; + break; + case DAC_dacAddr: + ret = banshee->dacAddr; + break; + case DAC_dacData: + ret = svga->pallook[banshee->dacAddr]; + break; + + case Video_vidProcCfg: + ret = banshee->vidProcCfg; + break; + + case Video_hwCurPatAddr: + ret = banshee->hwCurPatAddr; + break; + case Video_hwCurLoc: + ret = banshee->hwCurLoc; + break; + case Video_hwCurC0: + ret = banshee->hwCurC0; + break; + case Video_hwCurC1: + ret = banshee->hwCurC1; + break; + + case Video_vidScreenSize: + ret = banshee->vidScreenSize; + break; + case Video_vidOverlayStartCoords: + ret = voodoo->overlay.vidOverlayStartCoords; + break; + case Video_vidOverlayEndScreenCoords: + ret = voodoo->overlay.vidOverlayEndScreenCoords; + break; + case Video_vidOverlayDudx: + ret = voodoo->overlay.vidOverlayDudx; + break; + case Video_vidOverlayDudxOffsetSrcWidth: + ret = voodoo->overlay.vidOverlayDudxOffsetSrcWidth; + break; + case Video_vidOverlayDvdy: + ret = voodoo->overlay.vidOverlayDvdy; + break; + case Video_vidOverlayDvdyOffset: + ret = voodoo->overlay.vidOverlayDvdyOffset; + break; + + case Video_vidDesktopStartAddr: + ret = banshee->vidDesktopStartAddr; + break; + case Video_vidDesktopOverlayStride: + ret = banshee->vidDesktopOverlayStride; + break; + + default: +// fatal("bad banshee_ext_inl: addr=%04x\n", addr); + break; + } + +// /*if (addr) */pclog("banshee_ext_inl: addr=%04x val=%08x\n", addr, ret); + + return ret; +} + + +static uint32_t banshee_reg_readl(uint32_t addr, void *p); + +static uint8_t banshee_reg_read(uint32_t addr, void *p) +{ +// pclog("banshee_reg_read: addr=%08x\n", addr); + return banshee_reg_readl(addr & ~3, p) >> (8*(addr & 3)); +} + +static uint16_t banshee_reg_readw(uint32_t addr, void *p) +{ +// pclog("banshee_reg_readw: addr=%08x\n", addr); + return banshee_reg_readl(addr & ~3, p) >> (8*(addr & 2)); +} + +static uint32_t banshee_cmd_read(banshee_t *banshee, uint32_t addr) +{ + voodoo_t *voodoo = banshee->voodoo; + uint32_t ret = 0xffffffff; + + switch (addr & 0x1fc) + { + case cmdBaseAddr0: + ret = voodoo->cmdfifo_base >> 12; +// pclog("Read cmdfifo_base %08x\n", ret); + break; + + case cmdRdPtrL0: + ret = voodoo->cmdfifo_rp; +// pclog("Read cmdfifo_rp %08x\n", ret); + break; + + case cmdFifoDepth0: + ret = voodoo->cmdfifo_depth_wr - voodoo->cmdfifo_depth_rd; +// pclog("Read cmdfifo_depth %08x\n", ret); + break; + + case 0x108: + break; + + default: + fatal("Unknown banshee_cmd_read %08x\n", addr); + } + + return ret; +} + +static uint32_t banshee_reg_readl(uint32_t addr, void *p) +{ + banshee_t *banshee = (banshee_t *)p; + voodoo_t *voodoo = banshee->voodoo; + uint32_t ret = 0xffffffff; + + cycles -= voodoo->read_time; + + switch (addr & 0x1f00000) + { + case 0x0000000: /*IO remap*/ + if (!(addr & 0x80000)) + ret = banshee_ext_inl(addr & 0xff, banshee); + else + ret = banshee_cmd_read(banshee, addr); + break; + + case 0x0100000: /*2D registers*/ + voodoo_flush(voodoo); + switch (addr & 0x1fc) + { + case 0x08: + ret = voodoo->banshee_blt.clip0Min; + break; + case 0x0c: + ret = voodoo->banshee_blt.clip0Max; + break; + case 0x10: + ret = voodoo->banshee_blt.dstBaseAddr; + break; + case 0x14: + ret = voodoo->banshee_blt.dstFormat; + break; + case 0x34: + ret = voodoo->banshee_blt.srcBaseAddr; + break; + case 0x38: + ret = voodoo->banshee_blt.commandExtra; + break; + case 0x5c: + ret = voodoo->banshee_blt.srcXY; + break; + case 0x60: + ret = voodoo->banshee_blt.colorBack; + break; + case 0x64: + ret = voodoo->banshee_blt.colorFore; + break; + case 0x68: + ret = voodoo->banshee_blt.dstSize; + break; + case 0x6c: + ret = voodoo->banshee_blt.dstXY; + break; + case 0x70: + ret = voodoo->banshee_blt.command; + break; + default: + pclog("banshee_reg_readl: addr=%08x\n", addr); + } + break; + + case 0x0200000: case 0x0300000: case 0x0400000: case 0x0500000: /*3D registers*/ + switch (addr & 0x3fc) + { + case SST_status: + ret = banshee_status(banshee); + break; + + case SST_intrCtrl: + ret = banshee->intrCtrl & 0x0030003f; + break; + + case SST_fbzColorPath: + voodoo_flush(voodoo); + ret = voodoo->params.fbzColorPath; + break; + case SST_fogMode: + voodoo_flush(voodoo); + ret = voodoo->params.fogMode; + break; + case SST_alphaMode: + voodoo_flush(voodoo); + ret = voodoo->params.alphaMode; + break; + case SST_fbzMode: + voodoo_flush(voodoo); + ret = voodoo->params.fbzMode; + break; + case SST_lfbMode: + voodoo_flush(voodoo); + ret = voodoo->lfbMode; + break; + case SST_clipLeftRight: + voodoo_flush(voodoo); + ret = voodoo->params.clipRight | (voodoo->params.clipLeft << 16); + break; + case SST_clipLowYHighY: + voodoo_flush(voodoo); + ret = voodoo->params.clipHighY | (voodoo->params.clipLowY << 16); + break; + + case SST_clipLeftRight1: + voodoo_flush(voodoo); + ret = voodoo->params.clipRight1 | (voodoo->params.clipLeft1 << 16); + break; + case SST_clipTopBottom1: + voodoo_flush(voodoo); + ret = voodoo->params.clipHighY1 | (voodoo->params.clipLowY1 << 16); + break; + + case SST_stipple: + voodoo_flush(voodoo); + ret = voodoo->params.stipple; + break; + case SST_color0: + voodoo_flush(voodoo); + ret = voodoo->params.color0; + break; + case SST_color1: + voodoo_flush(voodoo); + ret = voodoo->params.color1; + break; + + case SST_fbiPixelsIn: + ret = voodoo->fbiPixelsIn & 0xffffff; + break; + case SST_fbiChromaFail: + ret = voodoo->fbiChromaFail & 0xffffff; + break; + case SST_fbiZFuncFail: + ret = voodoo->fbiZFuncFail & 0xffffff; + break; + case SST_fbiAFuncFail: + ret = voodoo->fbiAFuncFail & 0xffffff; + break; + case SST_fbiPixelsOut: + ret = voodoo->fbiPixelsOut & 0xffffff; + break; + + default: + fatal("banshee_reg_readl: 3D addr=%08x\n", addr); + break; + } + break; + } + +// /*if (addr != 0xe0000000) */pclog("banshee_reg_readl: addr=%08x ret=%08x %04x(%08x):%08x\n", addr, ret, CS,cs,cpu_state.pc); +// if (cpu_state.pc == 0x1000e437) +// output = 3; + return ret; +} + +static void banshee_reg_write(uint32_t addr, uint8_t val, void *p) +{ +// pclog("banshee_reg_writeb: addr=%08x val=%02x\n", addr, val); +} + +static void banshee_reg_writew(uint32_t addr, uint16_t val, void *p) +{ + banshee_t *banshee = (banshee_t *)p; + voodoo_t *voodoo = banshee->voodoo; + + cycles -= voodoo->write_time; + +// pclog("banshee_reg_writew: addr=%08x val=%04x\n", addr, val); + switch (addr & 0x1f00000) + { + case 0x1000000: case 0x1100000: case 0x1200000: case 0x1300000: /*3D LFB*/ + case 0x1400000: case 0x1500000: case 0x1600000: case 0x1700000: + case 0x1800000: case 0x1900000: case 0x1a00000: case 0x1b00000: + case 0x1c00000: case 0x1d00000: case 0x1e00000: case 0x1f00000: + voodoo_queue_command(voodoo, (addr & 0xffffff) | FIFO_WRITEW_FB, val); + break; + } +} + +static void banshee_cmd_write(banshee_t *banshee, uint32_t addr, uint32_t val) +{ + voodoo_t *voodoo = banshee->voodoo; +// pclog("banshee_cmd_write: addr=%03x val=%08x\n", addr & 0x1fc, val); + switch (addr & 0x1fc) + { + case cmdBaseAddr0: + voodoo->cmdfifo_base = (val & 0x3ff) << 12; + voodoo->cmdfifo_end = voodoo->cmdfifo_base + (((voodoo->cmdfifo_size & 0xff) + 1) << 12); +// pclog("cmdfifo_base=%08x cmdfifo_end=%08x %08x\n", voodoo->cmdfifo_base, voodoo->cmdfifo_end, val); + break; + + case cmdBaseSize0: + voodoo->cmdfifo_size = val; + voodoo->cmdfifo_end = voodoo->cmdfifo_base + (((voodoo->cmdfifo_size & 0xff) + 1) << 12); +// pclog("cmdfifo_base=%08x cmdfifo_end=%08x\n", voodoo->cmdfifo_base, voodoo->cmdfifo_end); + break; + +// voodoo->cmdfifo_end = ((val >> 16) & 0x3ff) << 12; +// pclog("CMDFIFO base=%08x end=%08x\n", voodoo->cmdfifo_base, voodoo->cmdfifo_end); +// break; + + case cmdRdPtrL0: + voodoo->cmdfifo_rp = val; + break; + case cmdAMin0: + voodoo->cmdfifo_amin = val; + break; + case cmdAMax0: + voodoo->cmdfifo_amax = val; + break; + case cmdFifoDepth0: + voodoo->cmdfifo_depth_rd = 0; + voodoo->cmdfifo_depth_wr = val & 0xffff; + break; + + default: + pclog("Unknown banshee_cmd_write: addr=%08x val=%08x\n", addr, val); + break; + } + +/* cmdBaseSize0 = 0x24, + cmdBump0 = 0x28, + cmdRdPtrL0 = 0x2c, + cmdRdPtrH0 = 0x30, + cmdAMin0 = 0x34, + cmdAMax0 = 0x3c, + cmdFifoDepth0 = 0x44, + cmdHoleCnt0 = 0x48 + }*/ +} + +static void banshee_reg_writel(uint32_t addr, uint32_t val, void *p) +{ + banshee_t *banshee = (banshee_t *)p; + voodoo_t *voodoo = banshee->voodoo; + + if (addr == voodoo->last_write_addr+4) + cycles -= voodoo->burst_time; + else + cycles -= voodoo->write_time; + voodoo->last_write_addr = addr; + +// pclog("banshee_reg_writel: addr=%08x val=%08x\n", addr, val); + + switch (addr & 0x1f00000) + { + case 0x0000000: /*IO remap*/ + if (!(addr & 0x80000)) + banshee_ext_outl(addr & 0xff, val, banshee); + else + banshee_cmd_write(banshee, addr, val); +// pclog("CMD!!! write %08x %08x\n", addr, val); + break; + + case 0x0100000: /*2D registers*/ + voodoo_queue_command(voodoo, (addr & 0x1fc) | FIFO_WRITEL_2DREG, val); + break; + + case 0x0200000: case 0x0300000: case 0x0400000: case 0x0500000: /*3D registers*/ + switch (addr & 0x3fc) + { + case SST_intrCtrl: + banshee->intrCtrl = val & 0x0030003f; +// pclog("intrCtrl=%08x\n", val); + break; + + case SST_userIntrCMD: + fatal("userIntrCMD write %08x\n", val); + break; + + case SST_swapbufferCMD: + voodoo->cmd_written++; + voodoo_queue_command(voodoo, (addr & 0x3fc) | FIFO_WRITEL_REG, val); + if (!voodoo->voodoo_busy) + voodoo_wake_fifo_threads(voodoo->set, voodoo); +// pclog("SST_swapbufferCMD write: %i %i\n", voodoo->cmd_written, voodoo->cmd_written_fifo); + break; + case SST_triangleCMD: + voodoo->cmd_written++; + voodoo_queue_command(voodoo, (addr & 0x3fc) | FIFO_WRITEL_REG, val); + if (!voodoo->voodoo_busy) + voodoo_wake_fifo_threads(voodoo->set, voodoo); + break; + case SST_ftriangleCMD: + voodoo->cmd_written++; + voodoo_queue_command(voodoo, (addr & 0x3fc) | FIFO_WRITEL_REG, val); + if (!voodoo->voodoo_busy) + voodoo_wake_fifo_threads(voodoo->set, voodoo); + break; + case SST_fastfillCMD: + voodoo->cmd_written++; + voodoo_queue_command(voodoo, (addr & 0x3fc) | FIFO_WRITEL_REG, val); + if (!voodoo->voodoo_busy) + voodoo_wake_fifo_threads(voodoo->set, voodoo); + break; + case SST_nopCMD: + voodoo->cmd_written++; + voodoo_queue_command(voodoo, (addr & 0x3fc) | FIFO_WRITEL_REG, val); + if (!voodoo->voodoo_busy) + voodoo_wake_fifo_threads(voodoo->set, voodoo); + break; + + case SST_swapPending: + voodoo->swap_count++; +// voodoo->cmd_written++; + break; + + default: + voodoo_queue_command(voodoo, (addr & 0x3ffffc) | FIFO_WRITEL_REG, val); + break; + } + break; + + case 0x0600000: case 0x0700000: /*Texture download*/ + voodoo->tex_count++; + voodoo_queue_command(voodoo, (addr & 0x1ffffc) | FIFO_WRITEL_TEX, val); + break; + + case 0x1000000: case 0x1100000: case 0x1200000: case 0x1300000: /*3D LFB*/ + case 0x1400000: case 0x1500000: case 0x1600000: case 0x1700000: + case 0x1800000: case 0x1900000: case 0x1a00000: case 0x1b00000: + case 0x1c00000: case 0x1d00000: case 0x1e00000: case 0x1f00000: + voodoo_queue_command(voodoo, (addr & 0xfffffc) | FIFO_WRITEL_FB, val); + break; + } +} + +static uint8_t banshee_read_linear(uint32_t addr, void *p) +{ + banshee_t *banshee = (banshee_t *)p; + voodoo_t *voodoo = banshee->voodoo; + svga_t *svga = &banshee->svga; + + cycles -= voodoo->read_time; + + addr &= svga->decode_mask; + if (addr >= voodoo->tile_base) + { + int x, y; +// uint32_t old_addr = addr; + + addr -= voodoo->tile_base; + x = addr & (voodoo->tile_stride-1); + y = addr >> voodoo->tile_stride_shift; + + addr = voodoo->tile_base + x + y*voodoo->tile_x; +// pclog(" Tile rb %08x->%08x %i %i\n", old_addr, addr, x, y); + } + if (addr >= svga->vram_max) + return 0xff; + + egareads++; + cycles -= video_timing_read_b; + cycles_lost += video_timing_read_b; + +// pclog("read_linear: addr=%08x val=%02x\n", addr, svga->vram[addr & svga->vram_mask]); + + return svga->vram[addr & svga->vram_mask]; +} + +static uint16_t banshee_read_linear_w(uint32_t addr, void *p) +{ + banshee_t *banshee = (banshee_t *)p; + voodoo_t *voodoo = banshee->voodoo; + svga_t *svga = &banshee->svga; + + cycles -= voodoo->read_time; + + addr &= svga->decode_mask; + if (addr >= voodoo->tile_base) + { + int x, y; +// uint32_t old_addr = addr; + + addr -= voodoo->tile_base; + x = addr & (voodoo->tile_stride-1); + y = addr >> voodoo->tile_stride_shift; + + addr = voodoo->tile_base + x + y*voodoo->tile_x; +// pclog(" Tile rb %08x->%08x %i %i\n", old_addr, addr, x, y); + } + if (addr >= svga->vram_max) + return 0xff; + + egareads++; + cycles -= video_timing_read_w; + cycles_lost += video_timing_read_w; + +// pclog("read_linear: addr=%08x val=%02x\n", addr, svga->vram[addr & svga->vram_mask]); + + return *(uint16_t *)&svga->vram[addr & svga->vram_mask]; +} + +static uint32_t banshee_read_linear_l(uint32_t addr, void *p) +{ + banshee_t *banshee = (banshee_t *)p; + voodoo_t *voodoo = banshee->voodoo; + svga_t *svga = &banshee->svga; + + cycles -= voodoo->read_time; + + addr &= svga->decode_mask; + if (addr >= voodoo->tile_base) + { + int x, y; +// uint32_t old_addr = addr; + + addr -= voodoo->tile_base; + x = addr & (voodoo->tile_stride-1); + y = addr >> voodoo->tile_stride_shift; + + addr = voodoo->tile_base + x + y*voodoo->tile_x; +// pclog(" Tile rb %08x->%08x %i %i\n", old_addr, addr, x, y); + } + if (addr >= svga->vram_max) + return 0xff; + + egareads++; + cycles -= video_timing_read_l; + cycles_lost += video_timing_read_l; + +// pclog("read_linear: addr=%08x val=%02x\n", addr, svga->vram[addr & svga->vram_mask]); + + return *(uint32_t *)&svga->vram[addr & svga->vram_mask]; +} + +static void banshee_write_linear(uint32_t addr, uint8_t val, void *p) +{ + banshee_t *banshee = (banshee_t *)p; + voodoo_t *voodoo = banshee->voodoo; + svga_t *svga = &banshee->svga; + + cycles -= voodoo->write_time; + +// pclog("write_linear: addr=%08x val=%02x\n", addr, val); + addr &= svga->decode_mask; + if (addr >= voodoo->tile_base) + { + int x, y; + uint32_t old_addr = addr; + + addr -= voodoo->tile_base; + x = addr & (voodoo->tile_stride-1); + y = addr >> voodoo->tile_stride_shift; + + addr = voodoo->tile_base + x + y*voodoo->tile_x; +// pclog(" Tile b %08x->%08x %i %i\n", old_addr, addr, x, y); + } + if (addr >= svga->vram_max) + return; + + egawrites++; + + cycles -= video_timing_write_b; + cycles_lost += video_timing_write_b; + + svga->changedvram[addr >> 12] = changeframecount; + svga->vram[addr & svga->vram_mask] = val; +} + +static void banshee_write_linear_w(uint32_t addr, uint16_t val, void *p) +{ + banshee_t *banshee = (banshee_t *)p; + voodoo_t *voodoo = banshee->voodoo; + svga_t *svga = &banshee->svga; + + cycles -= voodoo->write_time; + +// pclog("write_linear: addr=%08x val=%02x\n", addr, val); + addr &= svga->decode_mask; + if (addr >= voodoo->tile_base) + { + int x, y; + uint32_t old_addr = addr; + + addr -= voodoo->tile_base; + x = addr & (voodoo->tile_stride-1); + y = addr >> voodoo->tile_stride_shift; + + addr = voodoo->tile_base + x + y*voodoo->tile_x; +// pclog(" Tile b %08x->%08x %i %i\n", old_addr, addr, x, y); + } + if (addr >= svga->vram_max) + return; + + egawrites++; + + cycles -= video_timing_write_w; + cycles_lost += video_timing_write_w; + + svga->changedvram[addr >> 12] = changeframecount; + *(uint16_t *)&svga->vram[addr & svga->vram_mask] = val; +} + +static void banshee_write_linear_l(uint32_t addr, uint32_t val, void *p) +{ + banshee_t *banshee = (banshee_t *)p; + voodoo_t *voodoo = banshee->voodoo; + svga_t *svga = &banshee->svga; + + if (addr == voodoo->last_write_addr+4) + cycles -= voodoo->burst_time; + else + cycles -= voodoo->write_time; + voodoo->last_write_addr = addr; + +// /*if (val) */pclog("write_linear_l: addr=%08x val=%08x %08x\n", addr, val, voodoo->tile_base); + addr &= svga->decode_mask; + if (addr >= voodoo->tile_base) + { + int x, y; + uint32_t old_addr = addr; + uint32_t addr_off; + uint32_t addr2; + + addr -= voodoo->tile_base; + addr_off = addr; + x = addr & (voodoo->tile_stride-1); + y = addr >> voodoo->tile_stride_shift; + + addr = voodoo->tile_base + x + y*voodoo->tile_x; + addr2 = x + y*voodoo->tile_x; +// pclog(" Tile %08x->%08x->%08x->%08x %i %i stride=%i tile_x=%i\n", old_addr, addr_off, addr2, addr, x, y, voodoo->tile_stride, voodoo->tile_x); + } + + if (addr >= svga->vram_max) + return; + + egawrites += 4; + + cycles -= video_timing_write_l; + cycles_lost += video_timing_write_l; + + svga->changedvram[addr >> 12] = changeframecount; + *(uint32_t *)&svga->vram[addr & svga->vram_mask] = val; + if (addr >= voodoo->cmdfifo_base && addr < voodoo->cmdfifo_end) + { +// pclog("CMDFIFO write %08x %08x %04x:%08x\n", addr, val, CS,cpu_state.pc); + voodoo->cmdfifo_depth_wr++; +// if ((voodoo->cmdfifo_depth_wr - voodoo->cmdfifo_depth_rd) < 20) + voodoo_wake_fifo_thread(voodoo); + } +} + +void banshee_hwcursor_draw(svga_t *svga, int displine) +{ + banshee_t *banshee = (banshee_t *)svga->p; + int x, c; + int x_off; + uint32_t col0 = banshee->hwCurC0; + uint32_t col1 = banshee->hwCurC1; + uint8_t plane0[8], plane1[8]; + + for (c = 0; c < 8; c++) + plane0[c] = svga->vram[svga->hwcursor_latch.addr + c]; + for (c = 0; c < 8; c++) + plane1[c] = svga->vram[svga->hwcursor_latch.addr + c + 8]; + svga->hwcursor_latch.addr += 16; + + x_off = svga->hwcursor_latch.x; + + for (x = 0; x < 64; x += 8) + { + if (x_off > (32-8)) + { + int xx; + + for (xx = 0; xx < 8; xx++) + { + if (!(plane0[x >> 3] & (1 << 7))) + ((uint32_t *)buffer32->line[displine])[x_off + xx] = (plane1[x >> 3] & (1 << 7)) ? col1 : col0; + else if (plane1[x >> 3] & (1 << 7)) + ((uint32_t *)buffer32->line[displine])[x_off + xx] ^= 0xffffff; + + plane0[x >> 3] <<= 1; + plane1[x >> 3] <<= 1; + } + } + + x_off += 8; + } +} + +#define CLAMP(x) do \ + { \ + if ((x) & ~0xff) \ + x = ((x) < 0) ? 0 : 0xff; \ + } \ + while (0) + +#define DECODE_RGB565() \ + do \ + { \ + int c; \ + int wp = 0; \ + \ + for (c = 0; c < voodoo->overlay.overlay_bytes; c += 2) \ + { \ + uint16_t data = *(uint16_t *)src; \ + int r = data & 0x1f; \ + int g = (data >> 5) & 0x3f; \ + int b = data >> 11; \ + \ + banshee->overlay_buffer[wp++] = (r << 3) | (g << 10) | (b << 19); \ + src += 2; \ + } \ + } while (0) + +#define DECODE_YUYV422() \ + do \ + { \ + int c; \ + int wp = 0; \ + \ + for (c = 0; c < voodoo->overlay.overlay_bytes; c += 4) \ + { \ + uint8_t y1, y2; \ + int8_t Cr, Cb; \ + int dR, dG, dB; \ + int r, g, b; \ + \ + y1 = src[0]; \ + Cr = src[1] - 0x80; \ + y2 = src[2]; \ + Cb = src[3] - 0x80; \ + src += 4; \ + \ + dR = (359*Cr) >> 8; \ + dG = (88*Cb + 183*Cr) >> 8; \ + dB = (453*Cb) >> 8; \ + \ + r = y1 + dR; \ + CLAMP(r); \ + g = y1 - dG; \ + CLAMP(g); \ + b = y1 + dB; \ + CLAMP(b); \ + banshee->overlay_buffer[wp++] = r | (g << 8) | (b << 16); \ + \ + r = y2 + dR; \ + CLAMP(r); \ + g = y2 - dG; \ + CLAMP(g); \ + b = y2 + dB; \ + CLAMP(b); \ + banshee->overlay_buffer[wp++] = r | (g << 8) | (b << 16); \ + } \ + } while (0) + +#define DECODE_UYUV422() \ + do \ + { \ + int c; \ + int wp = 0; \ + \ + for (c = 0; c < voodoo->overlay.overlay_bytes; c += 4) \ + { \ + uint8_t y1, y2; \ + int8_t Cr, Cb; \ + int dR, dG, dB; \ + int r, g, b; \ + \ + Cr = src[0] - 0x80; \ + y1 = src[1]; \ + Cb = src[2] - 0x80; \ + y2 = src[3]; \ + src += 4; \ + \ + dR = (359*Cr) >> 8; \ + dG = (88*Cb + 183*Cr) >> 8; \ + dB = (453*Cb) >> 8; \ + \ + r = y1 + dR; \ + CLAMP(r); \ + g = y1 - dG; \ + CLAMP(g); \ + b = y1 + dB; \ + CLAMP(b); \ + banshee->overlay_buffer[wp++] = r | (g << 8) | (b << 16); \ + \ + r = y2 + dR; \ + CLAMP(r); \ + g = y2 - dG; \ + CLAMP(g); \ + b = y2 + dB; \ + CLAMP(b); \ + banshee->overlay_buffer[wp++] = r | (g << 8) | (b << 16); \ + } \ + } while (0) + + +#define OVERLAY_SAMPLE() \ + do \ + { \ + switch (banshee->overlay_pix_fmt) \ + { \ + case 0: \ + break; \ + \ + case OVERLAY_FMT_YUYV422: \ + DECODE_YUYV422(); \ + break; \ + \ + case OVERLAY_FMT_UYVY422: \ + DECODE_UYUV422(); \ + break; \ + \ + case OVERLAY_FMT_565_DITHER: \ + DECODE_RGB565(); \ + break; \ + \ + default: \ + fatal("Unknown overlay pix fmt %i\n", banshee->overlay_pix_fmt); \ + } \ + } while (0) + +static void banshee_overlay_draw(svga_t *svga, int displine) +{ + banshee_t *banshee = (banshee_t *)svga->p; + voodoo_t *voodoo = banshee->voodoo; + uint32_t *p; + int x; + uint32_t src_addr = svga->overlay_latch.addr + svga->overlay_latch.pitch * (voodoo->overlay.src_y >> 20); + uint8_t *src = &svga->vram[src_addr & svga->vram_mask]; + uint32_t src_x = 0; + +// pclog("displine=%i addr=%08x %08x %08x %08x\n", displine, svga->overlay_latch.addr, src_addr, voodoo->overlay.vidOverlayDvdy, *(uint32_t *)src); +// if (src_addr >= 0x800000) +// fatal("overlay out of range!\n"); + p = &((uint32_t *)buffer32->line[displine])[svga->overlay_latch.x + 32]; + + OVERLAY_SAMPLE(); + + if (banshee->vidProcCfg & VIDPROCCFG_H_SCALE_ENABLE) + { + for (x = 0; x < svga->overlay_latch.xsize; x++) + { + p[x] = banshee->overlay_buffer[src_x >> 20]; + + src_x += voodoo->overlay.vidOverlayDudx; + } + } + else + { + for (x = 0; x < svga->overlay_latch.xsize; x++) + p[x] = banshee->overlay_buffer[x]; + } + + if (banshee->vidProcCfg & VIDPROCCFG_V_SCALE_ENABLE) + voodoo->overlay.src_y += voodoo->overlay.vidOverlayDvdy; + else + voodoo->overlay.src_y += (1 << 20); +} + +void banshee_set_overlay_addr(void *p, uint32_t addr) +{ + banshee_t *banshee = (banshee_t *)p; + + banshee->svga.overlay.addr = banshee->voodoo->leftOverlayBuf & 0xfffffff; + banshee->svga.overlay_latch.addr = banshee->voodoo->leftOverlayBuf & 0xfffffff; +} + +static void banshee_vsync_callback(svga_t *svga) +{ + banshee_t *banshee = (banshee_t *)svga->p; + voodoo_t *voodoo = banshee->voodoo; + + voodoo->retrace_count++; + if (voodoo->swap_pending && (voodoo->retrace_count > voodoo->swap_interval)) + { + memset(voodoo->dirty_line, 1, 1024); + voodoo->retrace_count = 0; + banshee_set_overlay_addr(banshee, voodoo->swap_offset); + if (voodoo->swap_count > 0) + voodoo->swap_count--; + voodoo->swap_pending = 0; + thread_set_event(voodoo->wake_fifo_thread); + voodoo->frame_count++; + } + + voodoo->overlay.src_y = 0; +} + +static uint8_t banshee_pci_read(int func, int addr, void *p) +{ + banshee_t *banshee = (banshee_t *)p; +// svga_t *svga = &banshee->svga; + uint8_t ret = 0; + + pclog("Banshee PCI read %08X ", addr); + switch (addr) + { + case 0x00: ret = 0x1a; break; /*3DFX*/ + case 0x01: ret = 0x12; break; + + case 0x02: ret = 0x03; break; + case 0x03: ret = 0x00; break; + + case 0x04: ret = banshee->pci_regs[0x04] & 0x27; break; + + case 0x07: ret = banshee->pci_regs[0x07] & 0x36; break; + + case 0x08: ret = 1; break; /*Revision ID*/ + case 0x09: ret = 0; break; /*Programming interface*/ + + case 0x0a: ret = 0x00; break; /*Supports VGA interface*/ + case 0x0b: ret = 0x03; /*output = 3; */break; + + case 0x0d: ret = banshee->pci_regs[0x0d] & 0xf8; break; + + case 0x10: ret = 0x00; break; /*memBaseAddr0*/ + case 0x11: ret = 0x00; break; + case 0x12: ret = 0x00; break; + case 0x13: ret = banshee->memBaseAddr0 >> 24; break; + + case 0x14: ret = 0x00; break; /*memBaseAddr1*/ + case 0x15: ret = 0x00; break; + case 0x16: ret = 0x00; break; + case 0x17: ret = banshee->memBaseAddr1 >> 24; break; + + case 0x18: ret = 0x01; break; /*ioBaseAddr*/ + case 0x19: ret = banshee->ioBaseAddr >> 8; break; + case 0x1a: ret = 0x00; break; + case 0x1b: ret = 0x00; break; + + case 0x30: ret = banshee->pci_regs[0x30] & 0x01; break; /*BIOS ROM address*/ + case 0x31: ret = 0x00; break; + case 0x32: ret = banshee->pci_regs[0x32]; break; + case 0x33: ret = banshee->pci_regs[0x33]; break; + + case 0x3c: ret = banshee->pci_regs[0x3c]; break; + + case 0x3d: ret = 0x01; break; /*INTA*/ + + case 0x3e: ret = 0x04; break; + case 0x3f: ret = 0xff; break; + + } + pclog("%02X\n", ret); + return ret; +} + +static void banshee_update_mapping(banshee_t *banshee) +{ +} + +static void banshee_pci_write(int func, int addr, uint8_t val, void *p) +{ + banshee_t *banshee = (banshee_t *)p; +// svga_t *svga = &banshee->svga; + + pclog("Banshee write %08X %02X %04X:%08X\n", addr, val, CS, cpu_state.pc); + switch (addr) + { + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x3d: case 0x3e: case 0x3f: + return; + + case PCI_REG_COMMAND: + banshee_update_mapping(banshee); + if (val & PCI_COMMAND_IO) + { + io_removehandler(0x03c0, 0x0020, banshee_in, NULL, NULL, banshee_out, NULL, NULL, banshee); + if (banshee->ioBaseAddr) + io_removehandler(banshee->ioBaseAddr, 0x0100, banshee_ext_in, NULL, banshee_ext_inl, banshee_ext_out, NULL, banshee_ext_outl, banshee); + + io_sethandler(0x03c0, 0x0020, banshee_in, NULL, NULL, banshee_out, NULL, NULL, banshee); + if (banshee->ioBaseAddr) + io_sethandler(banshee->ioBaseAddr, 0x0100, banshee_ext_in, NULL, banshee_ext_inl, banshee_ext_out, NULL, banshee_ext_outl, banshee); + } + else + { + io_removehandler(0x03c0, 0x0020, banshee_in, NULL, NULL, banshee_out, NULL, NULL, banshee); + io_removehandler(banshee->ioBaseAddr, 0x0100, banshee_ext_in, NULL, banshee_ext_inl, banshee_ext_out, NULL, banshee_ext_outl, banshee); + } + banshee->pci_regs[PCI_REG_COMMAND] = val & 0x27; +// s3_virge_updatemapping(virge); + return; + case 0x07: + banshee->pci_regs[0x07] = val & 0x3e; + return; + case 0x0d: + banshee->pci_regs[0x0d] = val & 0xf8; + return; + + case 0x13: + banshee->memBaseAddr0 = (val & 0xfe) << 24; + banshee_updatemapping(banshee); + return; + + case 0x17: + banshee->memBaseAddr1 = (val & 0xfe) << 24; + banshee_updatemapping(banshee); + return; + + case 0x19: + if (banshee->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_IO) + io_removehandler(banshee->ioBaseAddr, 0x0100, banshee_ext_in, NULL, banshee_ext_inl, banshee_ext_out, NULL, banshee_ext_outl, banshee); + banshee->ioBaseAddr = val << 8; + if ((banshee->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_IO) && banshee->ioBaseAddr) + io_sethandler(banshee->ioBaseAddr, 0x0100, banshee_ext_in, NULL, banshee_ext_inl, banshee_ext_out, NULL, banshee_ext_outl, banshee); + pclog("Banshee ioBaseAddr=%08x\n", banshee->ioBaseAddr); +// s3_virge_updatemapping(virge); + return; + + case 0x30: case 0x32: case 0x33: + banshee->pci_regs[addr] = val; + if (banshee->pci_regs[0x30] & 0x01) + { + uint32_t addr = (banshee->pci_regs[0x32] << 16) | (banshee->pci_regs[0x33] << 24); + pclog("Banshee bios_rom enabled at %08x\n", addr); + mem_mapping_set_addr(&banshee->bios_rom.mapping, addr, 0x8000); + mem_mapping_enable(&banshee->bios_rom.mapping); + } + else + { + pclog("Banshee bios_rom disabled\n"); + mem_mapping_disable(&banshee->bios_rom.mapping); + } + return; + case 0x3c: + banshee->pci_regs[0x3c] = val; + return; + } +} + +static device_config_t banshee_config[] = +{ + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "8 MB", + .value = 8 + }, + { + .description = "16 MB", + .value = 16 + }, + { + .description = "" + } + }, + .default_int = 16 + }, + { + .name = "bilinear", + .description = "Bilinear filtering", + .type = CONFIG_BINARY, + .default_int = 1 + }, + { + .name = "render_threads", + .description = "Render threads", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "1", + .value = 1 + }, + { + .description = "2", + .value = 2 + }, + { + .description = "" + } + }, + .default_int = 2 + }, +#ifndef NO_CODEGEN + { + .name = "recompiler", + .description = "Recompiler", + .type = CONFIG_BINARY, + .default_int = 1 + }, +#endif + { + .type = -1 + } +}; + +static void *banshee_init() +{ + int mem_size; + banshee_t *banshee = malloc(sizeof(banshee_t)); + memset(banshee, 0, sizeof(banshee_t)); + + // rom_init(&banshee->bios_rom, "gainward.BIN", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + rom_init(&banshee->bios_rom, "a-trend.VBI", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + mem_size = device_get_config_int("memory"); + svga_init(&banshee->svga, banshee, mem_size << 20, + banshee_recalctimings, + banshee_in, banshee_out, + banshee_hwcursor_draw, + banshee_overlay_draw); + banshee->svga.vsync_callback = banshee_vsync_callback; + + mem_mapping_add(&banshee->linear_mapping, 0, 0, banshee_read_linear, + banshee_read_linear_w, + banshee_read_linear_l, + banshee_write_linear, + banshee_write_linear_w, + banshee_write_linear_l, + NULL, + 0, + &banshee->svga); + mem_mapping_add(&banshee->reg_mapping_low, 0, 0,banshee_reg_read, + banshee_reg_readw, + banshee_reg_readl, + banshee_reg_write, + banshee_reg_writew, + banshee_reg_writel, + NULL, + 0, + banshee); + mem_mapping_add(&banshee->reg_mapping_high, 0,0,banshee_reg_read, + banshee_reg_readw, + banshee_reg_readl, + banshee_reg_write, + banshee_reg_writew, + banshee_reg_writel, + NULL, + 0, + banshee); + +// io_sethandler(0x03c0, 0x0020, banshee_in, NULL, NULL, banshee_out, NULL, NULL, banshee); + + banshee->svga.bpp = 8; + banshee->svga.miscout = 1; + + banshee->dramInit0 = 1 << 27; + if (mem_size == 16) + banshee->dramInit0 |= (1 << 26); /*2xSGRAM = 16 MB*/ +// banshee->dramInit1 = 1 << 30; /*SDRAM*/ + banshee->svga.decode_mask = 0x1ffffff; + + pci_add(banshee_pci_read, banshee_pci_write, banshee); + + banshee->voodoo = voodoo_2d3d_card_init(VOODOO_BANSHEE); + banshee->voodoo->p = banshee; + banshee->voodoo->vram = banshee->svga.vram; + banshee->voodoo->changedvram = banshee->svga.changedvram; + banshee->voodoo->fb_mem = banshee->svga.vram; + banshee->voodoo->fb_mask = banshee->svga.vram_mask; + banshee->voodoo->tex_mem[0] = banshee->svga.vram; + banshee->voodoo->tex_mem_w[0] = (uint16_t *)banshee->svga.vram; + banshee->voodoo->texture_mask = banshee->svga.vram_mask; + + return banshee; +} + +static int banshee_available() +{ + return rom_present("a-trend.VBI"); +} + +static void banshee_close(void *p) +{ + banshee_t *banshee = (banshee_t *)p; + + voodoo_card_close(banshee->voodoo); + svga_close(&banshee->svga); + + free(banshee); +} + +static void banshee_speed_changed(void *p) +{ + banshee_t *banshee = (banshee_t *)p; + + svga_recalctimings(&banshee->svga); +} + +static void banshee_force_redraw(void *p) +{ + banshee_t *banshee = (banshee_t *)p; + + banshee->svga.fullchange = changeframecount; +} + +static uint64_t status_time = 0; + +static void banshee_add_status_info(char *s, int max_len, void *p) +{ + banshee_t *banshee = (banshee_t *)p; + voodoo_t *voodoo = banshee->voodoo; + char temps[512]; + int pixel_count_current[2]; + int pixel_count_total; + int texel_count_current[2]; + int texel_count_total; + int render_time[2]; + uint64_t new_time = timer_read(); + uint64_t status_diff = new_time - status_time; + status_time = new_time; + + svga_add_status_info(s, max_len, &banshee->svga); + + + pixel_count_current[0] = voodoo->pixel_count[0]; + pixel_count_current[1] = voodoo->pixel_count[1]; + texel_count_current[0] = voodoo->texel_count[0]; + texel_count_current[1] = voodoo->texel_count[1]; + render_time[0] = voodoo->render_time[0]; + render_time[1] = voodoo->render_time[1]; + + pixel_count_total = (pixel_count_current[0] + pixel_count_current[1]) - (voodoo->pixel_count_old[0] + voodoo->pixel_count_old[1]); + texel_count_total = (texel_count_current[0] + texel_count_current[1]) - (voodoo->texel_count_old[0] + voodoo->texel_count_old[1]); + sprintf(temps, "%f Mpixels/sec (%f)\n%f Mtexels/sec (%f)\n%f ktris/sec\n%f%% CPU (%f%% real)\n%d frames/sec (%i)\n%f%% CPU (%f%% real)\n"/*%d reads/sec\n%d write/sec\n%d tex/sec\n*/, + (double)pixel_count_total/1000000.0, + ((double)pixel_count_total/1000000.0) / ((double)render_time[0] / status_diff), + (double)texel_count_total/1000000.0, + ((double)texel_count_total/1000000.0) / ((double)render_time[0] / status_diff), + (double)voodoo->tri_count/1000.0, ((double)voodoo->time * 100.0) / timer_freq, ((double)voodoo->time * 100.0) / status_diff, voodoo->frame_count, voodoo_recomp, + ((double)voodoo->render_time[0] * 100.0) / timer_freq, ((double)voodoo->render_time[0] * 100.0) / status_diff); + if (voodoo->render_threads == 2) + { + char temps2[512]; + sprintf(temps2, "%f%% CPU (%f%% real)\n", + ((double)voodoo->render_time[1] * 100.0) / timer_freq, ((double)voodoo->render_time[1] * 100.0) / status_diff); + strncat(temps, temps2, sizeof(temps)-1); + } + + strncat(s, temps, max_len); + strncat(s, "\n", max_len); + + voodoo->pixel_count_old[0] = pixel_count_current[0]; + voodoo->pixel_count_old[1] = pixel_count_current[1]; + voodoo->texel_count_old[0] = texel_count_current[0]; + voodoo->texel_count_old[1] = texel_count_current[1]; + voodoo->tri_count = voodoo->frame_count = 0; + voodoo->rd_count = voodoo->wr_count = voodoo->tex_count = 0; + voodoo->time = 0; + voodoo->render_time[0] = voodoo->render_time[1] = 0; + + voodoo->read_time = pci_nonburst_time + pci_burst_time; + + voodoo_recomp = 0; +} + +device_t atrend_voodoo_banshee_device = +{ + "A-Trend Helios 3D (Voodoo Banshee)", + 0, + banshee_init, + banshee_close, + banshee_available, + banshee_speed_changed, + banshee_force_redraw, + banshee_add_status_info, + banshee_config +}; diff --git a/src/vid_voodoo_banshee.h b/src/vid_voodoo_banshee.h new file mode 100644 index 0000000..9479816 --- /dev/null +++ b/src/vid_voodoo_banshee.h @@ -0,0 +1,3 @@ +extern device_t atrend_voodoo_banshee_device; + +void banshee_set_overlay_addr(void *p, uint32_t addr); diff --git a/src/vid_voodoo_banshee_blitter.c b/src/vid_voodoo_banshee_blitter.c new file mode 100644 index 0000000..032215b --- /dev/null +++ b/src/vid_voodoo_banshee_blitter.c @@ -0,0 +1,1305 @@ +/*Current issues : + - missing screen->screen scaled blits with format conversion + - missing YUV blits + - missing linestyle + - missing wait for vsync + - missing reversible lines + + Notes : + - 16 bpp runs with tiled framebuffer - to aid 3D? + 8 and 32 bpp use linear +*/ +#include +#include +#include "ibm.h" +#include "device.h" +#include "mem.h" +#include "thread.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_voodoo.h" +#include "vid_voodoo_common.h" +#include "vid_voodoo_banshee_blitter.h" + +#define COMMAND_CMD_MASK (0xf) +#define COMMAND_CMD_NOP (0 << 0) +#define COMMAND_CMD_SCREEN_TO_SCREEN_BLT (1 << 0) +#define COMMAND_CMD_SCREEN_TO_SCREEN_STRETCH_BLT (2 << 0) +#define COMMAND_CMD_HOST_TO_SCREEN_BLT (3 << 0) +#define COMMAND_CMD_HOST_TO_SCREEN_STRETCH_BLT (4 << 0) +#define COMMAND_CMD_RECTFILL (5 << 0) +#define COMMAND_CMD_LINE (6 << 0) +#define COMMAND_CMD_POLYLINE (7 << 0) +#define COMMAND_CMD_POLYFILL (8 << 0) +#define COMMAND_INITIATE (1 << 8) +#define COMMAND_PATTERN_MONO (1 << 13) +#define COMMAND_DX (1 << 14) +#define COMMAND_DY (1 << 15) +#define COMMAND_TRANS_MONO (1 << 16) +#define COMMAND_PATOFF_X_MASK (7 << 17) +#define COMMAND_PATOFF_X_SHIFT (17) +#define COMMAND_PATOFF_Y_MASK (7 << 20) +#define COMMAND_PATOFF_Y_SHIFT (20) +#define COMMAND_CLIP_SEL (1 << 23) + +#define CMDEXTRA_SRC_COLORKEY (1 << 0) +#define CMDEXTRA_DST_COLORKEY (1 << 1) +#define CMDEXTRA_FORCE_PAT_ROW0 (1 << 3) + +#define SRC_FORMAT_STRIDE_MASK (0x1fff) +#define SRC_FORMAT_COL_MASK (0xf << 16) +#define SRC_FORMAT_COL_1_BPP (0 << 16) +#define SRC_FORMAT_COL_8_BPP (1 << 16) +#define SRC_FORMAT_COL_16_BPP (3 << 16) +#define SRC_FORMAT_COL_24_BPP (4 << 16) +#define SRC_FORMAT_COL_32_BPP (5 << 16) +#define SRC_FORMAT_COL_YUYV (8 << 16) +#define SRC_FORMAT_COL_UYVY (9 << 16) +#define SRC_FORMAT_BYTE_SWIZZLE (1 << 20) +#define SRC_FORMAT_WORD_SWIZZLE (1 << 21) +#define SRC_FORMAT_PACKING_MASK (3 << 22) +#define SRC_FORMAT_PACKING_STRIDE (0 << 22) +#define SRC_FORMAT_PACKING_BYTE (1 << 22) +#define SRC_FORMAT_PACKING_WORD (2 << 22) +#define SRC_FORMAT_PACKING_DWORD (3 << 22) + +#define DST_FORMAT_STRIDE_MASK (0x1fff) +#define DST_FORMAT_COL_MASK (0xf << 16) +#define DST_FORMAT_COL_8_BPP (1 << 16) +#define DST_FORMAT_COL_16_BPP (3 << 16) +#define DST_FORMAT_COL_24_BPP (4 << 16) +#define DST_FORMAT_COL_32_BPP (5 << 16) + +#define BRES_ERROR_MASK (0xffff) +#define BRES_ERROR_USE (1 << 31) + +enum +{ + COLORKEY_8, + COLORKEY_16, + COLORKEY_32 +}; + +static int colorkey(voodoo_t *voodoo, uint32_t src, int src_notdst, int color_format) +{ + uint32_t min = src_notdst ? voodoo->banshee_blt.srcColorkeyMin : voodoo->banshee_blt.dstColorkeyMin; + uint32_t max = src_notdst ? voodoo->banshee_blt.srcColorkeyMax : voodoo->banshee_blt.dstColorkeyMax; + + if (!(voodoo->banshee_blt.commandExtra & (src_notdst ? CMDEXTRA_SRC_COLORKEY : CMDEXTRA_DST_COLORKEY))) + return 0; + + switch (color_format) + { + case COLORKEY_8: + return ((src & 0xff) >= (min & 0xff)) && ((src & 0xff) <= (max & 0xff)); + + case COLORKEY_16: + { + int r = (src >> 11) & 0x1f, r_min = (min >> 11) & 0x1f, r_max = (max >> 11) & 0x1f; + int g = (src >> 5) & 0x3f, g_min = (min >> 5) & 0x3f, g_max = (max >> 5) & 0x3f; + int b = src & 0x1f, b_min = min & 0x1f, b_max = max & 0x1f; + + return (r >= r_min) && (r <= r_max) && (g >= g_min) && (g <= g_max) && + (b >= b_min) && (b <= b_max); + } + + case COLORKEY_32: + { + int r = (src >> 16) & 0xff, r_min = (min >> 16) & 0xff, r_max = (max >> 16) & 0xff; + int g = (src >> 8) & 0xff, g_min = (min >> 8) & 0xff, g_max = (max >> 8) & 0xff; + int b = src & 0xff, b_min = min & 0xff, b_max = max & 0xff; + + return (r >= r_min) && (r <= r_max) && (g >= g_min) && (g <= g_max) && + (b >= b_min) && (b <= b_max); + } + + default: + return 0; + } +} + +static uint32_t MIX(voodoo_t *voodoo, uint32_t dest, uint32_t src, uint32_t pattern, int colour_format_src, int colour_format_dest) +{ + int rop_nr = 0; + uint32_t result = 0; + uint32_t rop; + + if (colorkey(voodoo, src, 1, colour_format_src)) + rop_nr |= 2; + if (colorkey(voodoo, dest, 0, colour_format_dest)) + rop_nr |= 1; + + rop = voodoo->banshee_blt.rops[rop_nr]; + + if (rop & 0x01) + result |= (~pattern & ~src & ~dest); + if (rop & 0x02) + result |= (~pattern & ~src & dest); + if (rop & 0x04) + result |= (~pattern & src & ~dest); + if (rop & 0x08) + result |= (~pattern & src & dest); + if (rop & 0x10) + result |= ( pattern & ~src & ~dest); + if (rop & 0x20) + result |= ( pattern & ~src & dest); + if (rop & 0x40) + result |= ( pattern & src & ~dest); + if (rop & 0x80) + result |= ( pattern & src & dest); + + return result; +} + +static void PLOT(voodoo_t *voodoo, int x, int y, int pat_x, int pat_y, uint8_t pattern_mask, uint8_t rop, uint32_t src, int src_colorkey) +{ + switch (voodoo->banshee_blt.dstFormat & DST_FORMAT_COL_MASK) + { + case DST_FORMAT_COL_8_BPP: + { + uint32_t addr = (voodoo->banshee_blt.dstBaseAddr + x + y*voodoo->banshee_blt.dst_stride) & voodoo->fb_mask; + uint32_t dest = voodoo->vram[addr]; + uint32_t pattern = (voodoo->banshee_blt.command & COMMAND_PATTERN_MONO) ? + ((pattern_mask & (1 << (7-(pat_x & 7)))) ? voodoo->banshee_blt.colorFore : voodoo->banshee_blt.colorBack) : + voodoo->banshee_blt.colorPattern8[(pat_x & 7) + (pat_y & 7)*8]; + + voodoo->vram[addr] = MIX(voodoo, dest, src, pattern, src_colorkey, COLORKEY_8); + voodoo->changedvram[addr >> 12] = changeframecount; + break; + } + case DST_FORMAT_COL_16_BPP: + { + uint32_t addr = (voodoo->banshee_blt.dstBaseAddr + x*2 + y*voodoo->banshee_blt.dst_stride) & voodoo->fb_mask; + uint32_t dest = *(uint16_t *)&voodoo->vram[addr]; + uint32_t pattern = (voodoo->banshee_blt.command & COMMAND_PATTERN_MONO) ? + ((pattern_mask & (1 << (7-(pat_x & 7)))) ? voodoo->banshee_blt.colorFore : voodoo->banshee_blt.colorBack) : + voodoo->banshee_blt.colorPattern16[(pat_x & 7) + (pat_y & 7)*8]; + + *(uint16_t *)&voodoo->vram[addr] = MIX(voodoo, dest, src, pattern, src_colorkey, COLORKEY_16); + voodoo->changedvram[addr >> 12] = changeframecount; + break; + } + case DST_FORMAT_COL_24_BPP: + { + uint32_t addr = (voodoo->banshee_blt.dstBaseAddr + x*3 + y*voodoo->banshee_blt.dst_stride) & voodoo->fb_mask; + uint32_t dest = *(uint32_t *)&voodoo->vram[addr]; + uint32_t pattern = (voodoo->banshee_blt.command & COMMAND_PATTERN_MONO) ? + ((pattern_mask & (1 << (7-(pat_x & 7)))) ? voodoo->banshee_blt.colorFore : voodoo->banshee_blt.colorBack) : + voodoo->banshee_blt.colorPattern24[(pat_x & 7) + (pat_y & 7)*8]; + + *(uint32_t *)&voodoo->vram[addr] = (MIX(voodoo, dest, src, pattern, src_colorkey, COLORKEY_32) & 0xffffff) | (dest & 0xff000000); + voodoo->changedvram[addr >> 12] = changeframecount; + break; + } + case DST_FORMAT_COL_32_BPP: + { + uint32_t addr = (voodoo->banshee_blt.dstBaseAddr + x*4 + y*voodoo->banshee_blt.dst_stride) & voodoo->fb_mask; + uint32_t dest = *(uint32_t *)&voodoo->vram[addr]; + uint32_t pattern = (voodoo->banshee_blt.command & COMMAND_PATTERN_MONO) ? + ((pattern_mask & (1 << (7-(pat_x & 7)))) ? voodoo->banshee_blt.colorFore : voodoo->banshee_blt.colorBack) : + voodoo->banshee_blt.colorPattern[(pat_x & 7) + (pat_y & 7)*8]; + + *(uint32_t *)&voodoo->vram[addr] = MIX(voodoo, dest, src, pattern, src_colorkey, COLORKEY_32); + voodoo->changedvram[addr >> 12] = changeframecount; + break; + } + } +} + +static void update_src_stride(voodoo_t *voodoo) +{ + int bpp; + + switch (voodoo->banshee_blt.srcFormat & SRC_FORMAT_COL_MASK) + { + case SRC_FORMAT_COL_1_BPP: + bpp = 1; + break; + case SRC_FORMAT_COL_8_BPP: + bpp = 8; + break; + case SRC_FORMAT_COL_16_BPP: + bpp = 16; + break; + case SRC_FORMAT_COL_24_BPP: + bpp = 24; + break; + case SRC_FORMAT_COL_32_BPP: + bpp = 32; + break; + + default: + bpp = 16; + break; + } + + switch (voodoo->banshee_blt.srcFormat & SRC_FORMAT_PACKING_MASK) + { + case SRC_FORMAT_PACKING_STRIDE: + voodoo->banshee_blt.src_stride_src = voodoo->banshee_blt.src_stride; //voodoo->banshee_blt.srcFormat & SRC_FORMAT_STRIDE_MASK; + voodoo->banshee_blt.src_stride_dest = voodoo->banshee_blt.src_stride; //voodoo->banshee_blt.srcFormat & SRC_FORMAT_STRIDE_MASK; + voodoo->banshee_blt.host_data_size_src = (voodoo->banshee_blt.srcSizeX * bpp + (voodoo->banshee_blt.srcX & 3) + 7) >> 3; + voodoo->banshee_blt.host_data_size_dest = (voodoo->banshee_blt.dstSizeX * bpp + (voodoo->banshee_blt.srcX & 3) + 7) >> 3; +// pclog("Stride packing %08x %08x bpp=%i dstSizeX=%i\n", voodoo->banshee_blt.src_stride_dest, voodoo->banshee_blt.host_data_size_dest, bpp, voodoo->banshee_blt.dstSizeX); + break; + + case SRC_FORMAT_PACKING_BYTE: + voodoo->banshee_blt.src_stride_src = (voodoo->banshee_blt.srcSizeX * bpp + 7) >> 3; + voodoo->banshee_blt.src_stride_dest = (voodoo->banshee_blt.dstSizeX * bpp + 7) >> 3; + voodoo->banshee_blt.host_data_size_src = voodoo->banshee_blt.src_stride_src; + voodoo->banshee_blt.host_data_size_dest = voodoo->banshee_blt.src_stride_dest; +// pclog("Byte packing %08x %08x\n", voodoo->banshee_blt.src_stride_dest, voodoo->banshee_blt.host_data_size_dest); + break; + + case SRC_FORMAT_PACKING_WORD: + voodoo->banshee_blt.src_stride_src = ((voodoo->banshee_blt.srcSizeX * bpp + 15) >> 4) * 2; + voodoo->banshee_blt.src_stride_dest = ((voodoo->banshee_blt.dstSizeX * bpp + 15) >> 4) * 2; + voodoo->banshee_blt.host_data_size_src = voodoo->banshee_blt.src_stride_src; + voodoo->banshee_blt.host_data_size_dest = voodoo->banshee_blt.src_stride_dest; +// pclog("Word packing %08x %08x\n", voodoo->banshee_blt.src_stride_dest, voodoo->banshee_blt.host_data_size_dest); + break; + + case SRC_FORMAT_PACKING_DWORD: + voodoo->banshee_blt.src_stride_src = ((voodoo->banshee_blt.srcSizeX * bpp + 31) >> 5) * 4; + voodoo->banshee_blt.src_stride_dest = ((voodoo->banshee_blt.dstSizeX * bpp + 31) >> 5) * 4; + voodoo->banshee_blt.host_data_size_src = voodoo->banshee_blt.src_stride_src; + voodoo->banshee_blt.host_data_size_dest = voodoo->banshee_blt.src_stride_dest; +// pclog("Dword packing %08x %08x\n", voodoo->banshee_blt.src_stride_dest, voodoo->banshee_blt.host_data_size_dest); + break; + } +} + +static void banshee_do_rectfill(voodoo_t *voodoo) +{ + clip_t *clip = &voodoo->banshee_blt.clip[(voodoo->banshee_blt.command & COMMAND_CLIP_SEL) ? 1 : 0]; + int dst_y = voodoo->banshee_blt.dstY; + uint8_t *pattern_mono = (uint8_t *)voodoo->banshee_blt.colorPattern; + int pat_y = (voodoo->banshee_blt.commandExtra & CMDEXTRA_FORCE_PAT_ROW0) ? 0 : (voodoo->banshee_blt.patoff_y + voodoo->banshee_blt.dstY); + int use_pattern_trans = (voodoo->banshee_blt.command & (COMMAND_PATTERN_MONO | COMMAND_TRANS_MONO)) == + (COMMAND_PATTERN_MONO | COMMAND_TRANS_MONO); + uint8_t rop = voodoo->banshee_blt.command >> 24; + +// pclog("banshee_do_rectfill: size=%i,%i dst=%i,%i\n", voodoo->banshee_blt.dstSizeX, voodoo->banshee_blt.dstSizeY, voodoo->banshee_blt.dstX, voodoo->banshee_blt.dstY); +// pclog("clipping: %i,%i -> %i,%i\n", clip->x_min, clip->y_min, clip->x_max, clip->y_max); +// pclog("colorFore=%08x\n", voodoo->banshee_blt.colorFore); + for (voodoo->banshee_blt.cur_y = 0; voodoo->banshee_blt.cur_y < voodoo->banshee_blt.dstSizeY; voodoo->banshee_blt.cur_y++) + { + int dst_x = voodoo->banshee_blt.dstX; + + if (dst_y >= clip->y_min && dst_y < clip->y_max) + { + int pat_x = voodoo->banshee_blt.patoff_x + voodoo->banshee_blt.dstX; + uint8_t pattern_mask = pattern_mono[pat_y & 7]; + + for (voodoo->banshee_blt.cur_x = 0; voodoo->banshee_blt.cur_x < voodoo->banshee_blt.dstSizeX; voodoo->banshee_blt.cur_x++) + { + int pattern_trans = use_pattern_trans ? (pattern_mask & (1 << (7-(pat_x & 7)))) : 1; + + if (dst_x >= clip->x_min && dst_x < clip->x_max && pattern_trans) + PLOT(voodoo, dst_x, dst_y, pat_x, pat_y, pattern_mask, rop, voodoo->banshee_blt.colorFore, COLORKEY_32); + + dst_x += (voodoo->banshee_blt.command & COMMAND_DX) ? -1 : 1; + pat_x += (voodoo->banshee_blt.command & COMMAND_DX) ? -1 : 1; + } + } + dst_y += (voodoo->banshee_blt.command & COMMAND_DY) ? -1 : 1; + if (!(voodoo->banshee_blt.commandExtra & CMDEXTRA_FORCE_PAT_ROW0)) + pat_y += (voodoo->banshee_blt.command & COMMAND_DY) ? -1 : 1; + } +} + + +static void do_screen_to_screen_line(voodoo_t *voodoo, uint8_t *src_p, int use_x_dir, int src_x) +{ + clip_t *clip = &voodoo->banshee_blt.clip[(voodoo->banshee_blt.command & COMMAND_CLIP_SEL) ? 1 : 0]; + int dst_y = voodoo->banshee_blt.dstY; + int pat_y = (voodoo->banshee_blt.commandExtra & CMDEXTRA_FORCE_PAT_ROW0) ? 0 : (voodoo->banshee_blt.patoff_y + voodoo->banshee_blt.dstY); + uint8_t *pattern_mono = (uint8_t *)voodoo->banshee_blt.colorPattern; + int use_pattern_trans = (voodoo->banshee_blt.command & (COMMAND_PATTERN_MONO | COMMAND_TRANS_MONO)) == + (COMMAND_PATTERN_MONO | COMMAND_TRANS_MONO); + uint8_t rop = voodoo->banshee_blt.command >> 24; + int src_colorkey; + + switch (voodoo->banshee_blt.srcFormat & SRC_FORMAT_COL_MASK) + { + case SRC_FORMAT_COL_8_BPP: + src_colorkey = COLORKEY_8; + break; + case SRC_FORMAT_COL_16_BPP: + src_colorkey = COLORKEY_16; + break; + default: + src_colorkey = COLORKEY_32; + break; + } +// pclog("do_screen_to_screen_line: srcFormat=%08x dst=%08x\n", voodoo->banshee_blt.srcFormat, voodoo->banshee_blt.dstFormat); + if ((voodoo->banshee_blt.srcFormat & SRC_FORMAT_COL_MASK) == + (voodoo->banshee_blt.dstFormat & DST_FORMAT_COL_MASK)) + { + /*No conversion required*/ + if (dst_y >= clip->y_min && dst_y < clip->y_max) + { + int dst_x = voodoo->banshee_blt.dstX; + int pat_x = voodoo->banshee_blt.patoff_x + voodoo->banshee_blt.dstX; + uint8_t pattern_mask = pattern_mono[pat_y & 7]; + + for (voodoo->banshee_blt.cur_x = 0; voodoo->banshee_blt.cur_x < voodoo->banshee_blt.dstSizeX; voodoo->banshee_blt.cur_x++) + { + int pattern_trans = use_pattern_trans ? (pattern_mask & (1 << (7-(pat_x & 7)))) : 1; + + if (dst_x >= clip->x_min && dst_x < clip->x_max && pattern_trans) + { + switch (voodoo->banshee_blt.dstFormat & DST_FORMAT_COL_MASK) + { + case DST_FORMAT_COL_8_BPP: + { + uint32_t dst_addr = (voodoo->banshee_blt.dstBaseAddr + dst_x + dst_y*voodoo->banshee_blt.dst_stride) & voodoo->fb_mask; + uint32_t src = src_p[src_x]; + uint32_t dest = voodoo->vram[dst_addr]; + uint32_t pattern = (voodoo->banshee_blt.command & COMMAND_PATTERN_MONO) ? + ((pattern_mask & (1 << (7-(pat_x & 7)))) ? voodoo->banshee_blt.colorFore : voodoo->banshee_blt.colorBack) : + voodoo->banshee_blt.colorPattern8[(pat_x & 7) + (pat_y & 7)*8]; + + voodoo->vram[dst_addr] = MIX(voodoo, dest, src, pattern, COLORKEY_8, COLORKEY_8); + voodoo->changedvram[dst_addr >> 12] = changeframecount; + break; + } + case DST_FORMAT_COL_16_BPP: + { + uint32_t dst_addr = (voodoo->banshee_blt.dstBaseAddr + dst_x*2 + dst_y*voodoo->banshee_blt.dst_stride) & voodoo->fb_mask; + uint32_t src = *(uint16_t *)&src_p[src_x*2]; + uint32_t dest = *(uint16_t *)&voodoo->vram[dst_addr]; + uint32_t pattern = (voodoo->banshee_blt.command & COMMAND_PATTERN_MONO) ? + ((pattern_mask & (1 << (7-(pat_x & 7)))) ? voodoo->banshee_blt.colorFore : voodoo->banshee_blt.colorBack) : + voodoo->banshee_blt.colorPattern16[(pat_x & 7) + (pat_y & 7)*8]; + + *(uint16_t *)&voodoo->vram[dst_addr] = MIX(voodoo, dest, src, pattern, COLORKEY_16, COLORKEY_16); + voodoo->changedvram[dst_addr >> 12] = changeframecount; + break; + } + case DST_FORMAT_COL_24_BPP: + { + uint32_t dst_addr = (voodoo->banshee_blt.dstBaseAddr + dst_x*3 + dst_y*voodoo->banshee_blt.dst_stride) & voodoo->fb_mask; + uint32_t src = *(uint32_t *)&src_p[src_x*3]; + uint32_t dest = *(uint32_t *)&voodoo->vram[dst_addr]; + uint32_t pattern = (voodoo->banshee_blt.command & COMMAND_PATTERN_MONO) ? + ((pattern_mask & (1 << (7-(pat_x & 7)))) ? voodoo->banshee_blt.colorFore : voodoo->banshee_blt.colorBack) : + voodoo->banshee_blt.colorPattern24[(pat_x & 7) + (pat_y & 7)*8]; + + *(uint32_t *)&voodoo->vram[dst_addr] = (MIX(voodoo, dest, src, pattern, COLORKEY_32, COLORKEY_32) & 0xffffff) | (dest & 0xff000000); + voodoo->changedvram[dst_addr >> 12] = changeframecount; + break; + } + case DST_FORMAT_COL_32_BPP: + { + uint32_t dst_addr = (voodoo->banshee_blt.dstBaseAddr + dst_x*4 + dst_y*voodoo->banshee_blt.dst_stride) & voodoo->fb_mask; + uint32_t src = *(uint32_t *)&src_p[src_x*4]; + uint32_t dest = *(uint32_t *)&voodoo->vram[dst_addr]; + uint32_t pattern = (voodoo->banshee_blt.command & COMMAND_PATTERN_MONO) ? + ((pattern_mask & (1 << (7-(pat_x & 7)))) ? voodoo->banshee_blt.colorFore : voodoo->banshee_blt.colorBack) : + voodoo->banshee_blt.colorPattern[(pat_x & 7) + (pat_y & 7)*8]; + + *(uint32_t *)&voodoo->vram[dst_addr] = MIX(voodoo, dest, src, pattern, COLORKEY_32, COLORKEY_32); + voodoo->changedvram[dst_addr >> 12] = changeframecount; + break; + } + } + } + if (use_x_dir) + { + src_x += (voodoo->banshee_blt.command & COMMAND_DX) ? -1 : 1; + dst_x += (voodoo->banshee_blt.command & COMMAND_DX) ? -1 : 1; + pat_x += (voodoo->banshee_blt.command & COMMAND_DX) ? -1 : 1; + } + else + { + src_x++; + dst_x++; + pat_x++; + } + } + } + voodoo->banshee_blt.srcY += (voodoo->banshee_blt.command & COMMAND_DY) ? -1 : 1; + voodoo->banshee_blt.dstY += (voodoo->banshee_blt.command & COMMAND_DY) ? -1 : 1; + } + else + { + /*Conversion required*/ + if (dst_y >= clip->y_min && dst_y < clip->y_max) + { +// int src_x = voodoo->banshee_blt.srcX; + int dst_x = voodoo->banshee_blt.dstX; + int pat_x = voodoo->banshee_blt.patoff_x + voodoo->banshee_blt.dstX; + uint8_t pattern_mask = pattern_mono[pat_y & 7]; + + for (voodoo->banshee_blt.cur_x = 0; voodoo->banshee_blt.cur_x < voodoo->banshee_blt.dstSizeX; voodoo->banshee_blt.cur_x++) + { + int pattern_trans = use_pattern_trans ? (pattern_mask & (1 << (7-(pat_x & 7)))) : 1; + + if (dst_x >= clip->x_min && dst_x < clip->x_max && pattern_trans) + { + uint32_t src_data = 0; + int transparent = 0; + + switch (voodoo->banshee_blt.srcFormat & SRC_FORMAT_COL_MASK) + { + case SRC_FORMAT_COL_1_BPP: + { + uint8_t src_byte = src_p[src_x >> 3]; + src_data = (src_byte & (0x80 >> (src_x & 7))) ? voodoo->banshee_blt.colorFore : voodoo->banshee_blt.colorBack; + if (voodoo->banshee_blt.command & COMMAND_TRANS_MONO) + transparent = !(src_byte & (0x80 >> (src_x & 7))); +// pclog(" 1bpp src_byte=%02x src_x=%i src_data=%x transparent=%i\n", src_byte, src_x, src_data, transparent); + break; + } + case SRC_FORMAT_COL_8_BPP: + { + src_data = src_p[src_x]; + break; + } + case SRC_FORMAT_COL_16_BPP: + { + uint16_t src_16 = *(uint16_t *)&src_p[src_x*2]; + int r = (src_16 >> 11); + int g = (src_16 >> 5) & 0x3f; + int b = src_16 & 0x1f; + + r = (r << 3) | (r >> 2); + g = (g << 2) | (g >> 4); + b = (b << 3) | (b >> 2); + src_data = (r << 16) | (g << 8) | b; + break; + } + case SRC_FORMAT_COL_24_BPP: + { + src_data = *(uint32_t *)&src_p[src_x*3]; + break; + } + case SRC_FORMAT_COL_32_BPP: + { + src_data = *(uint32_t *)&src_p[src_x*4]; + break; + } + + default: + fatal("banshee_do_screen_to_screen_blt: unknown srcFormat %08x\n", voodoo->banshee_blt.srcFormat); + } + + if ((voodoo->banshee_blt.dstFormat & DST_FORMAT_COL_MASK) == DST_FORMAT_COL_16_BPP && + (voodoo->banshee_blt.srcFormat & SRC_FORMAT_COL_MASK) != SRC_FORMAT_COL_1_BPP) + { + int r = src_data >> 16; + int g = (src_data >> 8) & 0xff; + int b = src_data & 0xff; + + src_data = (b >> 3) | ((g >> 2) << 5) | ((r >> 3) << 11); + } + + if (!transparent) + PLOT(voodoo, dst_x, dst_y, pat_x, pat_y, pattern_mask, rop, src_data, src_colorkey); + } + if (use_x_dir) + { + src_x += (voodoo->banshee_blt.command & COMMAND_DX) ? -1 : 1; + dst_x += (voodoo->banshee_blt.command & COMMAND_DX) ? -1 : 1; + pat_x += (voodoo->banshee_blt.command & COMMAND_DX) ? -1 : 1; + } + else + { + src_x++; + dst_x++; + pat_x++; + } + } + } + voodoo->banshee_blt.srcY += (voodoo->banshee_blt.command & COMMAND_DY) ? -1 : 1; + voodoo->banshee_blt.dstY += (voodoo->banshee_blt.command & COMMAND_DY) ? -1 : 1; + } +} + +static void banshee_do_screen_to_screen_blt(voodoo_t *voodoo) +{ +// pclog("screen_to_screen: %08x %08x %08x\n", voodoo->banshee_blt.srcFormat, voodoo->banshee_blt.src_stride, voodoo->banshee_blt.src_stride_dest); +// return; + for (voodoo->banshee_blt.cur_y = 0; voodoo->banshee_blt.cur_y < voodoo->banshee_blt.dstSizeY; voodoo->banshee_blt.cur_y++) + { + uint32_t src_addr = (voodoo->banshee_blt.srcBaseAddr + voodoo->banshee_blt.srcY*/*voodoo->banshee_blt.src_stride*/voodoo->banshee_blt.src_stride_dest) & voodoo->fb_mask; +// if ((voodoo->banshee_blt.srcFormat & SRC_FORMAT_COL_MASK) == SRC_FORMAT_COL_1_BPP) +// pclog(" srcY=%i src_addr=%08x\n", voodoo->banshee_blt.srcY, src_addr); + do_screen_to_screen_line(voodoo, &voodoo->vram[src_addr], 1, voodoo->banshee_blt.srcX); + } +} + +static void banshee_do_host_to_screen_blt(voodoo_t *voodoo, int count, uint32_t data) +{ +// if (voodoo->banshee_blt.dstBaseAddr == 0xee5194) +// pclog("banshee_do_host_to_screen_blt: data=%08x host_data_count=%i src_stride_dest=%i host_data_size_dest=%i\n", data, voodoo->banshee_blt.host_data_count, voodoo->banshee_blt.src_stride_dest, voodoo->banshee_blt.host_data_size_dest); + + if (voodoo->banshee_blt.srcFormat & SRC_FORMAT_BYTE_SWIZZLE) + data = (data >> 24) | ((data >> 8) & 0xff00) | ((data << 8) & 0xff0000) | (data << 24); + if (voodoo->banshee_blt.srcFormat & SRC_FORMAT_WORD_SWIZZLE) + data = (data >> 16) | (data << 16); + + if ((voodoo->banshee_blt.srcFormat & SRC_FORMAT_PACKING_MASK) == SRC_FORMAT_PACKING_STRIDE) + { + int last_byte = (voodoo->banshee_blt.srcX & 3) + voodoo->banshee_blt.host_data_size_dest; + + *(uint32_t *)&voodoo->banshee_blt.host_data[voodoo->banshee_blt.host_data_count] = data; + voodoo->banshee_blt.host_data_count += 4; + if (voodoo->banshee_blt.host_data_count >= last_byte) + { +// pclog(" %i %i srcX=%i srcFormat=%08x\n", voodoo->banshee_blt.cur_y, voodoo->banshee_blt.dstSizeY, voodoo->banshee_blt.srcX); + if (voodoo->banshee_blt.cur_y < voodoo->banshee_blt.dstSizeY) + { + if ((voodoo->banshee_blt.srcFormat & SRC_FORMAT_COL_MASK) == SRC_FORMAT_COL_1_BPP) + do_screen_to_screen_line(voodoo, &voodoo->banshee_blt.host_data[(voodoo->banshee_blt.srcX >> 3) & 3], 0, voodoo->banshee_blt.srcX & 7); + else + do_screen_to_screen_line(voodoo, &voodoo->banshee_blt.host_data[voodoo->banshee_blt.srcX & 3], 0, 0); + voodoo->banshee_blt.cur_y++; + } + + if ((voodoo->banshee_blt.srcFormat & SRC_FORMAT_COL_MASK) == SRC_FORMAT_COL_1_BPP) + voodoo->banshee_blt.srcX += (voodoo->banshee_blt.srcFormat & SRC_FORMAT_STRIDE_MASK) << 3; + else + voodoo->banshee_blt.srcX += (voodoo->banshee_blt.srcFormat & SRC_FORMAT_STRIDE_MASK); + +// pclog(" %i %i %i %i %i\n", (voodoo->banshee_blt.srcX & 3), (last_byte & 3), (voodoo->banshee_blt.srcFormat & SRC_FORMAT_STRIDE_MASK)); +#if 0 + if ((voodoo->banshee_blt.srcX & 3) >= last_byte)// & 3) && (voodoo->banshee_blt.srcFormat & SRC_FORMAT_STRIDE_MASK) < 4) + { + *(uint32_t *)voodoo->banshee_blt.host_data = *(uint32_t *)&voodoo->banshee_blt.host_data[voodoo->banshee_blt.host_data_count-4]; + voodoo->banshee_blt.host_data_count = 4; + } + else + { +#endif + voodoo->banshee_blt.host_data_count = 0; +// } +// last_byte = (voodoo->banshee_blt.srcX & 3) + voodoo->banshee_blt.host_data_size_dest; +// pclog(" host_data_count=%i last_byte=%i srcX=%i\n", voodoo->banshee_blt.host_data_count, last_byte, voodoo->banshee_blt.srcX); + } + } + else + { + *(uint32_t *)&voodoo->banshee_blt.host_data[voodoo->banshee_blt.host_data_count] = data; + voodoo->banshee_blt.host_data_count += 4; + while (voodoo->banshee_blt.host_data_count >= voodoo->banshee_blt.src_stride_dest) + { + voodoo->banshee_blt.host_data_count -= voodoo->banshee_blt.src_stride_dest; + +// pclog(" %i %i\n", voodoo->banshee_blt.cur_y, voodoo->banshee_blt.dstSizeY); + if (voodoo->banshee_blt.cur_y < voodoo->banshee_blt.dstSizeY) + { + do_screen_to_screen_line(voodoo, voodoo->banshee_blt.host_data, 0, 0); + voodoo->banshee_blt.cur_y++; + } + + if (voodoo->banshee_blt.host_data_count) + { +// pclog(" remaining=%i\n", voodoo->banshee_blt.host_data_count); + *(uint32_t *)&voodoo->banshee_blt.host_data[0] = data >> (4-voodoo->banshee_blt.host_data_count)*8; + } + } + } +} + +static void do_screen_to_screen_stretch_line(voodoo_t *voodoo,uint8_t *src_p, int src_x, int *src_y) +{ + clip_t *clip = &voodoo->banshee_blt.clip[(voodoo->banshee_blt.command & COMMAND_CLIP_SEL) ? 1 : 0]; +// int src_y = voodoo->banshee_blt.srcY; + int dst_y = voodoo->banshee_blt.dstY; + int pat_y = (voodoo->banshee_blt.commandExtra & CMDEXTRA_FORCE_PAT_ROW0) ? 0 : (voodoo->banshee_blt.patoff_y + voodoo->banshee_blt.dstY); + uint8_t *pattern_mono = (uint8_t *)voodoo->banshee_blt.colorPattern; + int use_pattern_trans = (voodoo->banshee_blt.command & (COMMAND_PATTERN_MONO | COMMAND_TRANS_MONO)) == + (COMMAND_PATTERN_MONO | COMMAND_TRANS_MONO); + uint32_t *colorPattern = voodoo->banshee_blt.colorPattern; + + //int error_y = voodoo->banshee_blt.dstSizeY / 2; + +/* pclog("banshee_do_screen_to_screen_stretch_blt:\n"); + pclog(" srcXY=%i,%i srcsizeXY=%i,%i\n", voodoo->banshee_blt.srcX, voodoo->banshee_blt.srcY, voodoo->banshee_blt.srcSizeX, voodoo->banshee_blt.srcSizeY); + pclog(" dstXY=%i,%i dstsizeXY=%i,%i\n", voodoo->banshee_blt.dstX, voodoo->banshee_blt.dstY, voodoo->banshee_blt.dstSizeX, voodoo->banshee_blt.dstSizeY);*/ + if (dst_y >= clip->y_min && dst_y < clip->y_max) + { +// int src_x = voodoo->banshee_blt.srcX; + int dst_x = voodoo->banshee_blt.dstX; + int pat_x = voodoo->banshee_blt.patoff_x + voodoo->banshee_blt.dstX; + uint8_t pattern_mask = pattern_mono[pat_y & 7]; + int error_x = voodoo->banshee_blt.dstSizeX / 2; + +// pclog(" Plot dest line %03i : src line %03i\n", dst_y, src_y); + for (voodoo->banshee_blt.cur_x = 0; voodoo->banshee_blt.cur_x < voodoo->banshee_blt.dstSizeX; voodoo->banshee_blt.cur_x++) + { + int pattern_trans = use_pattern_trans ? (pattern_mask & (1 << (7-(pat_x & 7)))) : 1; + + if (dst_x >= clip->x_min && dst_x < clip->x_max && pattern_trans) + { + switch (voodoo->banshee_blt.dstFormat & DST_FORMAT_COL_MASK) + { + case DST_FORMAT_COL_8_BPP: + { + uint32_t dst_addr = (voodoo->banshee_blt.dstBaseAddr + dst_x + dst_y*voodoo->banshee_blt.dst_stride) & voodoo->fb_mask; + uint32_t src = src_p[src_x]; + uint32_t dest = voodoo->vram[dst_addr]; + uint32_t pattern = (voodoo->banshee_blt.command & COMMAND_PATTERN_MONO) ? + ((pattern_mask & (1 << (7-(pat_x & 7)))) ? voodoo->banshee_blt.colorFore : voodoo->banshee_blt.colorBack) : + colorPattern[(pat_x & 7) + (pat_y & 7)*8]; + + voodoo->vram[dst_addr] = MIX(voodoo, dest, src, pattern, COLORKEY_8, COLORKEY_8); +// pclog("%i,%i : sdp=%02x,%02x,%02x res=%02x\n", voodoo->banshee_blt.cur_x, voodoo->banshee_blt.cur_y, src, dest, pattern, voodoo->vram[dst_addr]); + voodoo->changedvram[dst_addr >> 12] = changeframecount; + break; + } + case DST_FORMAT_COL_16_BPP: + { + uint32_t dst_addr = (voodoo->banshee_blt.dstBaseAddr + dst_x*2 + dst_y*voodoo->banshee_blt.dst_stride) & voodoo->fb_mask; + uint32_t src = *(uint16_t *)&src_p[src_x*2]; + uint32_t dest = *(uint16_t *)&voodoo->vram[dst_addr]; + uint32_t pattern = (voodoo->banshee_blt.command & COMMAND_PATTERN_MONO) ? + ((pattern_mask & (1 << (7-(pat_x & 7)))) ? voodoo->banshee_blt.colorFore : voodoo->banshee_blt.colorBack) : + colorPattern[(pat_x & 7) + (pat_y & 7)*8]; + + *(uint16_t *)&voodoo->vram[dst_addr] = MIX(voodoo, dest, src, pattern, COLORKEY_16, COLORKEY_16); +// pclog("%i,%i : sdp=%02x,%02x,%02x res=%02x\n", voodoo->banshee_blt.cur_x, voodoo->banshee_blt.cur_y, src, dest, pattern, *(uint16_t *)&voodoo->vram[dst_addr]); + voodoo->changedvram[dst_addr >> 12] = changeframecount; + break; + } + case DST_FORMAT_COL_24_BPP: + { + uint32_t dst_addr = (voodoo->banshee_blt.dstBaseAddr + dst_x*3 + dst_y*voodoo->banshee_blt.dst_stride) & voodoo->fb_mask; + uint32_t src = *(uint32_t *)&src_p[src_x*3]; + uint32_t dest = *(uint32_t *)&voodoo->vram[dst_addr]; + uint32_t pattern = (voodoo->banshee_blt.command & COMMAND_PATTERN_MONO) ? + ((pattern_mask & (1 << (7-(pat_x & 7)))) ? voodoo->banshee_blt.colorFore : voodoo->banshee_blt.colorBack) : + colorPattern[(pat_x & 7) + (pat_y & 7)*8]; + + *(uint32_t *)&voodoo->vram[dst_addr] = (MIX(voodoo, dest, src, pattern, COLORKEY_32, COLORKEY_32) & 0xffffff) | (*(uint32_t *)&voodoo->vram[dst_addr] & 0xff000000); +// pclog("%i,%i : sdp=%02x,%02x,%02x res=%02x\n", voodoo->banshee_blt.cur_x, voodoo->banshee_blt.cur_y, src, dest, pattern, voodoo->vram[dst_addr]); + voodoo->changedvram[dst_addr >> 12] = changeframecount; + break; + } + case DST_FORMAT_COL_32_BPP: + { + uint32_t dst_addr = (voodoo->banshee_blt.dstBaseAddr + dst_x*4 + dst_y*voodoo->banshee_blt.dst_stride) & voodoo->fb_mask; + uint32_t src = *(uint32_t *)&src_p[src_x*4]; + uint32_t dest = *(uint32_t *)&voodoo->vram[dst_addr]; + uint32_t pattern = (voodoo->banshee_blt.command & COMMAND_PATTERN_MONO) ? + ((pattern_mask & (1 << (7-(pat_x & 7)))) ? voodoo->banshee_blt.colorFore : voodoo->banshee_blt.colorBack) : + colorPattern[(pat_x & 7) + (pat_y & 7)*8]; + + *(uint32_t *)&voodoo->vram[dst_addr] = MIX(voodoo, dest, src, pattern, COLORKEY_32, COLORKEY_32); +// pclog("%i,%i : sdp=%02x,%02x,%02x res=%02x\n", voodoo->banshee_blt.cur_x, voodoo->banshee_blt.cur_y, src, dest, pattern, voodoo->vram[dst_addr]); + voodoo->changedvram[dst_addr >> 12] = changeframecount; + break; + } + } + } + + error_x -= voodoo->banshee_blt.srcSizeX; + while (error_x < 0) + { + error_x += voodoo->banshee_blt.dstSizeX; + src_x++; + } + dst_x++; + pat_x++; + } + } + + voodoo->banshee_blt.bres_error_0 -= voodoo->banshee_blt.srcSizeY; + while (voodoo->banshee_blt.bres_error_0 < 0) + { + voodoo->banshee_blt.bres_error_0 += voodoo->banshee_blt.dstSizeY; + if (src_y) + (*src_y) += (voodoo->banshee_blt.command & COMMAND_DY) ? -1 : 1; + } + voodoo->banshee_blt.dstY += (voodoo->banshee_blt.command & COMMAND_DY) ? -1 : 1; +// pat_y += (voodoo->banshee_blt.command & COMMAND_DY) ? -1 : 1; +} + +static void banshee_do_screen_to_screen_stretch_blt(voodoo_t *voodoo) +{ +// pclog("screen_to_screen: %08x %08x %08x\n", voodoo->banshee_blt.srcFormat, voodoo->banshee_blt.src_stride, voodoo->banshee_blt.src_stride_dest); +// return; + for (voodoo->banshee_blt.cur_y = 0; voodoo->banshee_blt.cur_y < voodoo->banshee_blt.dstSizeY; voodoo->banshee_blt.cur_y++) + { + uint32_t src_addr = (voodoo->banshee_blt.srcBaseAddr + voodoo->banshee_blt.srcY*voodoo->banshee_blt.src_stride_src) & voodoo->fb_mask; + pclog("scale_blit %i %08x %08x\n", voodoo->banshee_blt.cur_y, src_addr, voodoo->banshee_blt.command); +// if ((voodoo->banshee_blt.srcFormat & SRC_FORMAT_COL_MASK) == SRC_FORMAT_COL_1_BPP) +// pclog(" srcY=%i src_addr=%08x\n", voodoo->banshee_blt.srcY, src_addr); + do_screen_to_screen_stretch_line(voodoo, &voodoo->vram[src_addr], voodoo->banshee_blt.srcX, &voodoo->banshee_blt.srcY); + } +} + +static void banshee_do_host_to_screen_stretch_blt(voodoo_t *voodoo, int count, uint32_t data) +{ +// if (voodoo->banshee_blt.dstBaseAddr == 0xee5194) +// pclog("banshee_do_host_to_screen_blt: data=%08x host_data_count=%i src_stride_dest=%i host_data_size_dest=%i\n", data, voodoo->banshee_blt.host_data_count, voodoo->banshee_blt.src_stride_dest, voodoo->banshee_blt.host_data_size_dest); + + if (voodoo->banshee_blt.srcFormat & SRC_FORMAT_BYTE_SWIZZLE) + data = (data >> 24) | ((data >> 8) & 0xff00) | ((data << 8) & 0xff0000) | (data << 24); + if (voodoo->banshee_blt.srcFormat & SRC_FORMAT_WORD_SWIZZLE) + data = (data >> 16) | (data << 16); + + if ((voodoo->banshee_blt.srcFormat & SRC_FORMAT_PACKING_MASK) == SRC_FORMAT_PACKING_STRIDE) + { + int last_byte = (voodoo->banshee_blt.srcX & 3) + voodoo->banshee_blt.host_data_size_src; + + *(uint32_t *)&voodoo->banshee_blt.host_data[voodoo->banshee_blt.host_data_count] = data; + voodoo->banshee_blt.host_data_count += 4; + if (voodoo->banshee_blt.host_data_count >= last_byte) + { +// pclog(" %i %i srcX=%i srcFormat=%08x\n", voodoo->banshee_blt.cur_y, voodoo->banshee_blt.dstSizeY, voodoo->banshee_blt.srcX); + if (voodoo->banshee_blt.cur_y < voodoo->banshee_blt.dstSizeY) + { + if ((voodoo->banshee_blt.srcFormat & SRC_FORMAT_COL_MASK) == SRC_FORMAT_COL_1_BPP) + do_screen_to_screen_stretch_line(voodoo, &voodoo->banshee_blt.host_data[(voodoo->banshee_blt.srcX >> 3) & 3], voodoo->banshee_blt.srcX & 7, NULL); + else + do_screen_to_screen_stretch_line(voodoo, &voodoo->banshee_blt.host_data[voodoo->banshee_blt.srcX & 3], 0, NULL); + voodoo->banshee_blt.cur_y++; + } + + if ((voodoo->banshee_blt.srcFormat & SRC_FORMAT_COL_MASK) == SRC_FORMAT_COL_1_BPP) + voodoo->banshee_blt.srcX += (voodoo->banshee_blt.srcFormat & SRC_FORMAT_STRIDE_MASK) << 3; + else + voodoo->banshee_blt.srcX += (voodoo->banshee_blt.srcFormat & SRC_FORMAT_STRIDE_MASK); + + voodoo->banshee_blt.host_data_count = 0; + } + } + else + { + *(uint32_t *)&voodoo->banshee_blt.host_data[voodoo->banshee_blt.host_data_count] = data; + voodoo->banshee_blt.host_data_count += 4; + while (voodoo->banshee_blt.host_data_count >= voodoo->banshee_blt.src_stride_src) + { + voodoo->banshee_blt.host_data_count -= voodoo->banshee_blt.src_stride_src; + +// pclog(" %i %i\n", voodoo->banshee_blt.cur_y, voodoo->banshee_blt.dstSizeY); + if (voodoo->banshee_blt.cur_y < voodoo->banshee_blt.dstSizeY) + { + do_screen_to_screen_stretch_line(voodoo, voodoo->banshee_blt.host_data, 0, NULL); + voodoo->banshee_blt.cur_y++; + } + + if (voodoo->banshee_blt.host_data_count) + { +// pclog(" remaining=%i\n", voodoo->banshee_blt.host_data_count); + *(uint32_t *)&voodoo->banshee_blt.host_data[0] = data >> (4-voodoo->banshee_blt.host_data_count)*8; + } + } + } +} + +static void banshee_do_line(voodoo_t *voodoo) +{ + clip_t *clip = &voodoo->banshee_blt.clip[(voodoo->banshee_blt.command & COMMAND_CLIP_SEL) ? 1 : 0]; + uint8_t *pattern_mono = (uint8_t *)voodoo->banshee_blt.colorPattern; + int pat_y = (voodoo->banshee_blt.commandExtra & CMDEXTRA_FORCE_PAT_ROW0) ? 0 : (voodoo->banshee_blt.patoff_y + voodoo->banshee_blt.srcY); + int pat_x = voodoo->banshee_blt.patoff_x + voodoo->banshee_blt.srcX; + int use_pattern_trans = (voodoo->banshee_blt.command & (COMMAND_PATTERN_MONO | COMMAND_TRANS_MONO)) == + (COMMAND_PATTERN_MONO | COMMAND_TRANS_MONO); + uint8_t rop = voodoo->banshee_blt.command >> 24; + int dx = ABS(voodoo->banshee_blt.dstX - voodoo->banshee_blt.srcX); + int dy = ABS(voodoo->banshee_blt.dstY - voodoo->banshee_blt.srcY); + int x_inc = (voodoo->banshee_blt.dstX > voodoo->banshee_blt.srcX) ? 1 : -1; + int y_inc = (voodoo->banshee_blt.dstY > voodoo->banshee_blt.srcY) ? 1 : -1; + int x = voodoo->banshee_blt.srcX; + int y = voodoo->banshee_blt.srcY; + int error; + + if (dx > dy) /*X major*/ + { + error = dx/2; + while (x != voodoo->banshee_blt.dstX) + { + uint8_t pattern_mask = pattern_mono[pat_y & 7]; + int pattern_trans = use_pattern_trans ? (pattern_mask & (1 << (7-(pat_x & 7)))) : 1; + + if (y >= clip->y_min && y < clip->y_max && x >= clip->x_min && x < clip->x_max && pattern_trans) + PLOT(voodoo, x, y, pat_x, pat_y, pattern_mask, rop, voodoo->banshee_blt.colorFore, COLORKEY_32); + + error -= dy; + if (error < 0) + { + error += dx; + y += y_inc; + pat_y += y_inc; + } + x += x_inc; + pat_x += x_inc; + } + } + else /*Y major*/ + { + error = dy/2; + while (y != voodoo->banshee_blt.dstY) + { + uint8_t pattern_mask = pattern_mono[pat_y & 7]; + int pattern_trans = use_pattern_trans ? (pattern_mask & (1 << (7-(pat_x & 7)))) : 1; + + if (y >= clip->y_min && y < clip->y_max && x >= clip->x_min && x < clip->x_max && pattern_trans) + PLOT(voodoo, x, y, pat_x, pat_y, pattern_mask, rop, voodoo->banshee_blt.colorFore, COLORKEY_32); + + error -= dx; + if (error < 0) + { + error += dy; + x += x_inc; + pat_x += x_inc; + } + y += y_inc; + pat_y += y_inc; + } + } + + voodoo->banshee_blt.srcXY = (x & 0xffff) | (y << 16); + voodoo->banshee_blt.srcX = x; + voodoo->banshee_blt.srcY = y; +} + +static void banshee_polyfill_start(voodoo_t *voodoo) +{ + voodoo->banshee_blt.lx[0] = voodoo->banshee_blt.srcX; + voodoo->banshee_blt.ly[0] = voodoo->banshee_blt.srcY; + voodoo->banshee_blt.rx[0] = voodoo->banshee_blt.dstX; + voodoo->banshee_blt.ry[0] = voodoo->banshee_blt.dstY; + voodoo->banshee_blt.lx[1] = voodoo->banshee_blt.srcX; + voodoo->banshee_blt.ly[1] = voodoo->banshee_blt.srcY; + voodoo->banshee_blt.rx[1] = voodoo->banshee_blt.dstX; + voodoo->banshee_blt.ry[1] = voodoo->banshee_blt.dstY; + voodoo->banshee_blt.lx_cur = voodoo->banshee_blt.srcX; + voodoo->banshee_blt.rx_cur = voodoo->banshee_blt.dstX; +} + +static void banshee_polyfill_continue(voodoo_t *voodoo, uint32_t data) +{ + clip_t *clip = &voodoo->banshee_blt.clip[(voodoo->banshee_blt.command & COMMAND_CLIP_SEL) ? 1 : 0]; + uint8_t *pattern_mono = (uint8_t *)voodoo->banshee_blt.colorPattern; + int use_pattern_trans = (voodoo->banshee_blt.command & (COMMAND_PATTERN_MONO | COMMAND_TRANS_MONO)) == + (COMMAND_PATTERN_MONO | COMMAND_TRANS_MONO); + uint8_t rop = voodoo->banshee_blt.command >> 24; + int y = MAX(voodoo->banshee_blt.ly[0], voodoo->banshee_blt.ry[0]); + int y_end; + +// pclog("Polyfill : data %08x\n", data); + + /*if r1.y>=l1.y, next vertex is left*/ + if (voodoo->banshee_blt.ry[1] >= voodoo->banshee_blt.ly[1]) + { + voodoo->banshee_blt.lx[1] = ((int32_t)(data << 19)) >> 19; + voodoo->banshee_blt.ly[1] = ((int32_t)(data << 3)) >> 19; + voodoo->banshee_blt.dx[0] = ABS(voodoo->banshee_blt.lx[1] - voodoo->banshee_blt.lx[0]); + voodoo->banshee_blt.dy[0] = ABS(voodoo->banshee_blt.ly[1] - voodoo->banshee_blt.ly[0]); + voodoo->banshee_blt.x_inc[0] = (voodoo->banshee_blt.lx[1] > voodoo->banshee_blt.lx[0]) ? 1 : -1; + voodoo->banshee_blt.error[0] = voodoo->banshee_blt.dy[0] / 2; + } + else + { + voodoo->banshee_blt.rx[1] = ((int32_t)(data << 19)) >> 19; + voodoo->banshee_blt.ry[1] = ((int32_t)(data << 3)) >> 19; + voodoo->banshee_blt.dx[1] = ABS(voodoo->banshee_blt.rx[1] - voodoo->banshee_blt.rx[0]); + voodoo->banshee_blt.dy[1] = ABS(voodoo->banshee_blt.ry[1] - voodoo->banshee_blt.ry[0]); + voodoo->banshee_blt.x_inc[1] = (voodoo->banshee_blt.rx[1] > voodoo->banshee_blt.rx[0]) ? 1 : -1; + voodoo->banshee_blt.error[1] = voodoo->banshee_blt.dy[1] / 2; + } + +/* pclog(" verts now : %03i,%03i %03i,%03i\n", voodoo->banshee_blt.lx[0], voodoo->banshee_blt.ly[0], voodoo->banshee_blt.rx[0], voodoo->banshee_blt.ry[0]); + pclog(" %03i,%03i %03i,%03i\n", voodoo->banshee_blt.lx[1], voodoo->banshee_blt.ly[1], voodoo->banshee_blt.rx[1], voodoo->banshee_blt.ry[1]); + pclog(" left dx=%i dy=%i x_inc=%i error=%i\n", voodoo->banshee_blt.dx[0],voodoo->banshee_blt.dy[0],voodoo->banshee_blt.x_inc[0],voodoo->banshee_blt.error[0]); + pclog(" right dx=%i dy=%i x_inc=%i error=%i\n", voodoo->banshee_blt.dx[1],voodoo->banshee_blt.dy[1],voodoo->banshee_blt.x_inc[1],voodoo->banshee_blt.error[1]);*/ + y_end = MIN(voodoo->banshee_blt.ly[1], voodoo->banshee_blt.ry[1]); +// pclog("Polyfill : draw spans from %i-%i\n", y, y_end); + for (; y < y_end; y++) + { +// pclog(" %i: %i %i\n", y, voodoo->banshee_blt.lx_cur, voodoo->banshee_blt.rx_cur); + /*Draw span from lx_cur to rx_cur*/ + if (y >= clip->y_min && y < clip->y_max) + { + int pat_y = (voodoo->banshee_blt.commandExtra & CMDEXTRA_FORCE_PAT_ROW0) ? 0 : (voodoo->banshee_blt.patoff_y + y); + uint8_t pattern_mask = pattern_mono[pat_y & 7]; + int x; + + for (x = voodoo->banshee_blt.lx_cur; x < voodoo->banshee_blt.rx_cur; x++) + { + int pat_x = voodoo->banshee_blt.patoff_x + x; + int pattern_trans = use_pattern_trans ? (pattern_mask & (1 << (7-(pat_x & 7)))) : 1; + + if (x >= clip->x_min && x < clip->x_max && pattern_trans) + PLOT(voodoo, x, y, pat_x, pat_y, pattern_mask, rop, voodoo->banshee_blt.colorFore, COLORKEY_32); + } + } + + voodoo->banshee_blt.error[0] -= voodoo->banshee_blt.dx[0]; + while (voodoo->banshee_blt.error[0] < 0) + { + voodoo->banshee_blt.error[0] += voodoo->banshee_blt.dy[0]; + voodoo->banshee_blt.lx_cur += voodoo->banshee_blt.x_inc[0]; + } + voodoo->banshee_blt.error[1] -= voodoo->banshee_blt.dx[1]; + while (voodoo->banshee_blt.error[1] < 0) + { + voodoo->banshee_blt.error[1] += voodoo->banshee_blt.dy[1]; + voodoo->banshee_blt.rx_cur += voodoo->banshee_blt.x_inc[1]; + } + } + + if (voodoo->banshee_blt.ry[1] == voodoo->banshee_blt.ly[1]) + { + voodoo->banshee_blt.lx[0] = voodoo->banshee_blt.lx[1]; + voodoo->banshee_blt.ly[0] = voodoo->banshee_blt.ly[1]; + voodoo->banshee_blt.rx[0] = voodoo->banshee_blt.rx[1]; + voodoo->banshee_blt.ry[0] = voodoo->banshee_blt.ry[1]; + } + else if (voodoo->banshee_blt.ry[1] >= voodoo->banshee_blt.ly[1]) + { + voodoo->banshee_blt.lx[0] = voodoo->banshee_blt.lx[1]; + voodoo->banshee_blt.ly[0] = voodoo->banshee_blt.ly[1]; + } + else + { + voodoo->banshee_blt.rx[0] = voodoo->banshee_blt.rx[1]; + voodoo->banshee_blt.ry[0] = voodoo->banshee_blt.ry[1]; + } +} + +static void banshee_do_2d_blit(voodoo_t *voodoo, int count, uint32_t data) +{ + switch (voodoo->banshee_blt.command & COMMAND_CMD_MASK) + { + case COMMAND_CMD_NOP: + break; + + case COMMAND_CMD_SCREEN_TO_SCREEN_BLT: + banshee_do_screen_to_screen_blt(voodoo); + break; + + case COMMAND_CMD_SCREEN_TO_SCREEN_STRETCH_BLT: + banshee_do_screen_to_screen_stretch_blt(voodoo); + break; + + case COMMAND_CMD_HOST_TO_SCREEN_BLT: + banshee_do_host_to_screen_blt(voodoo, count, data); + break; + + case COMMAND_CMD_HOST_TO_SCREEN_STRETCH_BLT: + banshee_do_host_to_screen_stretch_blt(voodoo, count, data); + break; + + case COMMAND_CMD_RECTFILL: + banshee_do_rectfill(voodoo); + break; + + case COMMAND_CMD_POLYLINE: + banshee_do_line(voodoo); + break; + + default: + fatal("banshee_do_2d_blit: unknown command=%08x\n", voodoo->banshee_blt.command); + } +} + +void voodoo_2d_reg_writel(voodoo_t *voodoo, uint32_t addr, uint32_t val) +{ +// /*if ((addr & 0x1fc) != 0x80) */pclog("2D reg write %03x %08x\n", addr & 0x1fc, val); + switch (addr & 0x1fc) + { + case 0x08: + voodoo->banshee_blt.clip0Min = val; + voodoo->banshee_blt.clip[0].x_min = val & 0xfff; + voodoo->banshee_blt.clip[0].y_min = (val >> 16) & 0xfff; + break; + case 0x0c: + voodoo->banshee_blt.clip0Max = val; + voodoo->banshee_blt.clip[0].x_max = val & 0xfff; + voodoo->banshee_blt.clip[0].y_max = (val >> 16) & 0xfff; + break; + case 0x10: + voodoo->banshee_blt.dstBaseAddr = val & 0xffffff; + voodoo->banshee_blt.dstBaseAddr_tiled = val & 0x80000000; + if (voodoo->banshee_blt.dstBaseAddr_tiled) + voodoo->banshee_blt.dst_stride = (voodoo->banshee_blt.dstFormat & DST_FORMAT_STRIDE_MASK) * 128; + else + voodoo->banshee_blt.dst_stride = voodoo->banshee_blt.dstFormat & DST_FORMAT_STRIDE_MASK; +// pclog("dstBaseAddr=%08x\n", val); + break; + case 0x14: + voodoo->banshee_blt.dstFormat = val; + if (voodoo->banshee_blt.dstBaseAddr_tiled) + voodoo->banshee_blt.dst_stride = (voodoo->banshee_blt.dstFormat & DST_FORMAT_STRIDE_MASK) * 128; + else + voodoo->banshee_blt.dst_stride = voodoo->banshee_blt.dstFormat & DST_FORMAT_STRIDE_MASK; +// pclog("dstFormat=%08x\n", val); + break; + + case 0x18: + voodoo->banshee_blt.srcColorkeyMin = val & 0xffffff; + break; + case 0x1c: + voodoo->banshee_blt.srcColorkeyMax = val & 0xffffff; + break; + case 0x20: + voodoo->banshee_blt.dstColorkeyMin = val & 0xffffff; + break; + case 0x24: + voodoo->banshee_blt.dstColorkeyMax = val & 0xffffff; + break; + + case 0x28: + voodoo->banshee_blt.bresError0 = val; + voodoo->banshee_blt.bres_error_0 = val & 0xffff; + break; + case 0x2c: + voodoo->banshee_blt.bresError1 = val; + voodoo->banshee_blt.bres_error_1 = val & 0xffff; + break; + + case 0x30: + voodoo->banshee_blt.rop = val; + voodoo->banshee_blt.rops[1] = val & 0xff; + voodoo->banshee_blt.rops[2] = (val >> 8) & 0xff; + voodoo->banshee_blt.rops[3] = (val >> 16) & 0xff; +// pclog("rop=%08x\n", val); + break; + case 0x34: + voodoo->banshee_blt.srcBaseAddr = val & 0xffffff; + voodoo->banshee_blt.srcBaseAddr_tiled = val & 0x80000000; + if (voodoo->banshee_blt.srcBaseAddr_tiled) + voodoo->banshee_blt.src_stride = (voodoo->banshee_blt.srcFormat & SRC_FORMAT_STRIDE_MASK) * 128; + else + voodoo->banshee_blt.src_stride = voodoo->banshee_blt.srcFormat & SRC_FORMAT_STRIDE_MASK; + update_src_stride(voodoo); +// pclog("srcBaseAddr=%08x\n", val); + break; + case 0x38: + voodoo->banshee_blt.commandExtra = val; +// pclog("commandExtra=%08x\n", val); + break; + case 0x44: + voodoo->banshee_blt.colorPattern[0] = val; +// pclog("colorPattern0=%08x\n", val); + voodoo->banshee_blt.colorPattern24[0] = val & 0xffffff; + voodoo->banshee_blt.colorPattern24[1] = (voodoo->banshee_blt.colorPattern24[1] & 0xffff00) | (val >> 24); + voodoo->banshee_blt.colorPattern16[0] = val & 0xffff; + voodoo->banshee_blt.colorPattern16[1] = (val >> 16) & 0xffff; + voodoo->banshee_blt.colorPattern8[0] = val & 0xff; + voodoo->banshee_blt.colorPattern8[1] = (val >> 8) & 0xff; + voodoo->banshee_blt.colorPattern8[2] = (val >> 16) & 0xff; + voodoo->banshee_blt.colorPattern8[3] = (val >> 24) & 0xff; + break; + case 0x48: + voodoo->banshee_blt.colorPattern[1] = val; +// pclog("colorPattern1=%08x\n", val); + voodoo->banshee_blt.colorPattern24[1] = (voodoo->banshee_blt.colorPattern24[1] & 0xff) | ((val & 0xffff) << 8); + voodoo->banshee_blt.colorPattern24[2] = (voodoo->banshee_blt.colorPattern24[2] & 0xff0000) | (val >> 16); + voodoo->banshee_blt.colorPattern16[2] = val & 0xffff; + voodoo->banshee_blt.colorPattern16[3] = (val >> 16) & 0xffff; + voodoo->banshee_blt.colorPattern8[4] = val & 0xff; + voodoo->banshee_blt.colorPattern8[5] = (val >> 8) & 0xff; + voodoo->banshee_blt.colorPattern8[6] = (val >> 16) & 0xff; + voodoo->banshee_blt.colorPattern8[7] = (val >> 24) & 0xff; + break; + case 0x4c: + voodoo->banshee_blt.clip1Min = val; + voodoo->banshee_blt.clip[1].x_min = val & 0xfff; + voodoo->banshee_blt.clip[1].y_min = (val >> 16) & 0xfff; + break; + case 0x50: + voodoo->banshee_blt.clip1Max = val; + voodoo->banshee_blt.clip[1].x_max = val & 0xfff; + voodoo->banshee_blt.clip[1].y_max = (val >> 16) & 0xfff; + break; + case 0x54: + voodoo->banshee_blt.srcFormat = val; + if (voodoo->banshee_blt.srcBaseAddr_tiled) + voodoo->banshee_blt.src_stride = (voodoo->banshee_blt.srcFormat & SRC_FORMAT_STRIDE_MASK) * 128; + else + voodoo->banshee_blt.src_stride = voodoo->banshee_blt.srcFormat & SRC_FORMAT_STRIDE_MASK; + update_src_stride(voodoo); +// pclog("srcFormat=%08x\n", val); + break; + case 0x58: + voodoo->banshee_blt.srcSize = val; + voodoo->banshee_blt.srcSizeX = voodoo->banshee_blt.srcSize & 0x1fff; + voodoo->banshee_blt.srcSizeY = (voodoo->banshee_blt.srcSize >> 16) & 0x1fff; + update_src_stride(voodoo); +// pclog("srcSize=%08x\n", val); + break; + case 0x5c: + voodoo->banshee_blt.srcXY = val; + voodoo->banshee_blt.srcX = ((int32_t)(val << 19)) >> 19; + voodoo->banshee_blt.srcY = ((int32_t)(val << 3)) >> 19; + update_src_stride(voodoo); +// pclog("srcXY=%08x\n", val); + break; + case 0x60: + voodoo->banshee_blt.colorBack = val; + break; + case 0x64: + voodoo->banshee_blt.colorFore = val; + break; + case 0x68: + voodoo->banshee_blt.dstSize = val; + voodoo->banshee_blt.dstSizeX = voodoo->banshee_blt.dstSize & 0x1fff; + voodoo->banshee_blt.dstSizeY = (voodoo->banshee_blt.dstSize >> 16) & 0x1fff; + update_src_stride(voodoo); +// pclog("dstSize=%08x\n", val); + break; + case 0x6c: + voodoo->banshee_blt.dstXY = val; + voodoo->banshee_blt.dstX = ((int32_t)(val << 19)) >> 19; + voodoo->banshee_blt.dstY = ((int32_t)(val << 3)) >> 19; +// pclog("dstXY=%08x\n", val); + break; + case 0x70: + voodoo->banshee_blt.command = val; + voodoo->banshee_blt.rops[0] = val >> 24; +// pclog("command=%x %08x\n", voodoo->banshee_blt.command & COMMAND_CMD_MASK, val); + voodoo->banshee_blt.patoff_x = (val & COMMAND_PATOFF_X_MASK) >> COMMAND_PATOFF_X_SHIFT; + voodoo->banshee_blt.patoff_y = (val & COMMAND_PATOFF_Y_MASK) >> COMMAND_PATOFF_Y_SHIFT; + voodoo->banshee_blt.cur_x = 0; + voodoo->banshee_blt.cur_y = 0; + voodoo->banshee_blt.srcX = ((int32_t)(voodoo->banshee_blt.srcXY << 19)) >> 19; + voodoo->banshee_blt.srcY = ((int32_t)(voodoo->banshee_blt.srcXY << 3)) >> 19; + voodoo->banshee_blt.old_srcX = voodoo->banshee_blt.srcX; + voodoo->banshee_blt.host_data_remainder = 0; + voodoo->banshee_blt.host_data_count = 0; + switch (voodoo->banshee_blt.command & COMMAND_CMD_MASK) + { +/* case COMMAND_CMD_SCREEN_TO_SCREEN_STRETCH_BLT: + if (voodoo->banshee_blt.bresError0 & BRES_ERROR_USE) + voodoo->banshee_blt.bres_error_0 = (int32_t)(int16_t)(voodoo->banshee_blt.bresError0 & BRES_ERROR_MASK); + else + voodoo->banshee_blt.bres_error_0 = voodoo->banshee_blt.dstSizeY / 2; + if (voodoo->banshee_blt.bresError1 & BRES_ERROR_USE) + voodoo->banshee_blt.bres_error_1 = (int32_t)(int16_t)(voodoo->banshee_blt.bresError1 & BRES_ERROR_MASK); + else + voodoo->banshee_blt.bres_error_1 = voodoo->banshee_blt.dstSizeX / 2; + + if (val & COMMAND_INITIATE) + banshee_do_2d_blit(voodoo, -1, 0); + break;*/ + + case COMMAND_CMD_POLYFILL: + if (val & COMMAND_INITIATE) + { + voodoo->banshee_blt.dstXY = voodoo->banshee_blt.srcXY; + voodoo->banshee_blt.dstX = voodoo->banshee_blt.srcX; + voodoo->banshee_blt.dstY = voodoo->banshee_blt.srcY; + } + banshee_polyfill_start(voodoo); + break; + + default: + if (val & COMMAND_INITIATE) + { + banshee_do_2d_blit(voodoo, -1, 0); + // fatal("Initiate command!\n"); + } + break; + } + break; + + case 0x80: case 0x84: case 0x88: case 0x8c: + case 0x90: case 0x94: case 0x98: case 0x9c: + case 0xa0: case 0xa4: case 0xa8: case 0xac: + case 0xb0: case 0xb4: case 0xb8: case 0xbc: + case 0xc0: case 0xc4: case 0xc8: case 0xcc: + case 0xd0: case 0xd4: case 0xd8: case 0xdc: + case 0xe0: case 0xe4: case 0xe8: case 0xec: + case 0xf0: case 0xf4: case 0xf8: case 0xfc: +// pclog("launch %08x %08x %08x %08x\n", voodoo->banshee_blt.command, voodoo->banshee_blt.commandExtra, voodoo->banshee_blt.srcColorkeyMin, voodoo->banshee_blt.srcColorkeyMax); + switch (voodoo->banshee_blt.command & COMMAND_CMD_MASK) + { + case COMMAND_CMD_SCREEN_TO_SCREEN_BLT: + voodoo->banshee_blt.srcXY = val; + voodoo->banshee_blt.srcX = ((int32_t)(val << 19)) >> 19; + voodoo->banshee_blt.srcY = ((int32_t)(val << 3)) >> 19; + banshee_do_screen_to_screen_blt(voodoo); + break; + + case COMMAND_CMD_HOST_TO_SCREEN_BLT: + banshee_do_2d_blit(voodoo, 32, val); + break; + + case COMMAND_CMD_HOST_TO_SCREEN_STRETCH_BLT: + banshee_do_2d_blit(voodoo, 32, val); + break; + + case COMMAND_CMD_RECTFILL: + voodoo->banshee_blt.dstXY = val; + voodoo->banshee_blt.dstX = ((int32_t)(val << 19)) >> 19; + voodoo->banshee_blt.dstY = ((int32_t)(val << 3)) >> 19; + banshee_do_rectfill(voodoo); + break; + +/* case COMMAND_CMD_LINE: + voodoo->banshee_blt.dstXY = val; + voodoo->banshee_blt.dstX = ((int32_t)(val << 19)) >> 19; + voodoo->banshee_blt.dstY = ((int32_t)(val << 3)) >> 19; + banshee_do_line(voodoo); + break;*/ + + case COMMAND_CMD_POLYLINE: + voodoo->banshee_blt.dstXY = val; + voodoo->banshee_blt.dstX = ((int32_t)(val << 19)) >> 19; + voodoo->banshee_blt.dstY = ((int32_t)(val << 3)) >> 19; + banshee_do_line(voodoo); + break; + + case COMMAND_CMD_POLYFILL: + banshee_polyfill_continue(voodoo, val); + break; + + default: + fatal("launch area write, command=%08x\n", voodoo->banshee_blt.command); + } + break; + + case 0x100: case 0x104: case 0x108: case 0x10c: + case 0x110: case 0x114: case 0x118: case 0x11c: + case 0x120: case 0x124: case 0x128: case 0x12c: + case 0x130: case 0x134: case 0x138: case 0x13c: + case 0x140: case 0x144: case 0x148: case 0x14c: + case 0x150: case 0x154: case 0x158: case 0x15c: + case 0x160: case 0x164: case 0x168: case 0x16c: + case 0x170: case 0x174: case 0x178: case 0x17c: + case 0x180: case 0x184: case 0x188: case 0x18c: + case 0x190: case 0x194: case 0x198: case 0x19c: + case 0x1a0: case 0x1a4: case 0x1a8: case 0x1ac: + case 0x1b0: case 0x1b4: case 0x1b8: case 0x1bc: + case 0x1c0: case 0x1c4: case 0x1c8: case 0x1cc: + case 0x1d0: case 0x1d4: case 0x1d8: case 0x1dc: + case 0x1e0: case 0x1e4: case 0x1e8: case 0x1ec: + case 0x1f0: case 0x1f4: case 0x1f8: case 0x1fc: + voodoo->banshee_blt.colorPattern[(addr >> 2) & 63] = val; + if ((addr & 0x1fc) < 0x1c0) + { + int base_addr = (addr & 0xfc) / 0xc; + uintptr_t src_p = (uintptr_t)&voodoo->banshee_blt.colorPattern[base_addr * 3]; + int col24 = base_addr * 4; + + voodoo->banshee_blt.colorPattern24[col24] = *(uint32_t *)src_p & 0xffffff; + voodoo->banshee_blt.colorPattern24[col24 + 1] = *(uint32_t *)(src_p + 3) & 0xffffff; + voodoo->banshee_blt.colorPattern24[col24 + 2] = *(uint32_t *)(src_p + 6) & 0xffffff; + voodoo->banshee_blt.colorPattern24[col24 + 3] = *(uint32_t *)(src_p + 9) & 0xffffff; + } + if ((addr & 0x1fc) < 0x180) + { + voodoo->banshee_blt.colorPattern16[(addr >> 1) & 62] = val & 0xffff; + voodoo->banshee_blt.colorPattern16[((addr >> 1) & 62) + 1] = (val >> 16) & 0xffff; + } + if ((addr & 0x1fc) < 0x140) + { + voodoo->banshee_blt.colorPattern8[addr & 60] = val & 0xff; + voodoo->banshee_blt.colorPattern8[(addr & 60) + 1] = (val >> 8) & 0xff; + voodoo->banshee_blt.colorPattern8[(addr & 60) + 2] = (val >> 16) & 0xff; + voodoo->banshee_blt.colorPattern8[(addr & 60) + 3] = (val >> 24) & 0xff; + } +// pclog("colorPattern%02x=%08x\n", (addr >> 2) & 63, val); + break; + + default: + fatal("Unknown 2D reg write %03x %08x\n", addr & 0x1fc, val); + } +} diff --git a/src/vid_voodoo_banshee_blitter.h b/src/vid_voodoo_banshee_blitter.h new file mode 100644 index 0000000..cc7a8f2 --- /dev/null +++ b/src/vid_voodoo_banshee_blitter.h @@ -0,0 +1 @@ +void voodoo_2d_reg_writel(voodoo_t *voodoo, uint32_t addr, uint32_t val); diff --git a/src/vid_voodoo_codegen_x86.h b/src/vid_voodoo_codegen_x86.h index 5d14b24..193e1b9 100644 --- a/src/vid_voodoo_codegen_x86.h +++ b/src/vid_voodoo_codegen_x86.h @@ -2175,6 +2175,8 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo // addbyte(0x7e); // addbyte(0x87); // addlong(offsetof(voodoo_state_t, out)); + if (voodoo->type != VOODOO_BANSHEE) /*HACK*/ + { if (params->fogMode & FOG_ENABLE) { if (params->fogMode & FOG_CONSTANT) @@ -2377,6 +2379,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo src_g = CLAMP(src_g); src_b = CLAMP(src_b);*/ } + } if ((params->alphaMode & 1) && (alpha_func != AFUNC_NEVER) && (alpha_func != AFUNC_ALWAYS)) { diff --git a/src/vid_voodoo_common.h b/src/vid_voodoo_common.h index 093fccd..4d3a809 100644 --- a/src/vid_voodoo_common.h +++ b/src/vid_voodoo_common.h @@ -20,8 +20,9 @@ enum { VOODOO_1 = 0, - VOODOO_SB50 = 1, - VOODOO_2 = 2 + VOODOO_SB50, + VOODOO_2, + VOODOO_BANSHEE }; typedef union int_float @@ -62,11 +63,12 @@ typedef union rgba_u enum { - FIFO_INVALID = (0x00 << 24), - FIFO_WRITEL_REG = (0x01 << 24), - FIFO_WRITEW_FB = (0x02 << 24), - FIFO_WRITEL_FB = (0x03 << 24), - FIFO_WRITEL_TEX = (0x04 << 24) + FIFO_INVALID = (0x00 << 24), + FIFO_WRITEL_REG = (0x01 << 24), + FIFO_WRITEW_FB = (0x02 << 24), + FIFO_WRITEL_FB = (0x03 << 24), + FIFO_WRITEL_TEX = (0x04 << 24), + FIFO_WRITEL_2DREG = (0x05 << 24) }; #define PARAM_SIZE 1024 @@ -147,6 +149,7 @@ typedef struct voodoo_params_t int tformat[2]; int clipLeft, clipRight, clipLowY, clipHighY; + int clipLeft1, clipRight1, clipLowY1, clipHighY1; int sign; @@ -177,6 +180,12 @@ typedef struct vert_t float sW1, sS1, sT1; } vert_t; +typedef struct clip_t +{ + int x_min, x_max; + int y_min, y_max; +} clip_t; + typedef struct voodoo_t { mem_mapping_t mapping; @@ -287,7 +296,7 @@ typedef struct voodoo_t voodoo_params_t params_buffer[PARAM_SIZE]; volatile int params_read_idx[2], params_write_idx; - uint32_t cmdfifo_base, cmdfifo_end; + uint32_t cmdfifo_base, cmdfifo_end, cmdfifo_size; int cmdfifo_rp; volatile int cmdfifo_depth_rd, cmdfifo_depth_wr; uint32_t cmdfifo_amin, cmdfifo_amax; @@ -296,6 +305,7 @@ typedef struct voodoo_t vert_t verts[4]; int vertex_num; int num_verticies; + int cull_pingpong; int flush; @@ -332,6 +342,8 @@ typedef struct voodoo_t uint32_t bltCommand; + uint32_t leftOverlayBuf; + struct { int dst_x, dst_y; @@ -341,6 +353,80 @@ typedef struct voodoo_t int dst_stride; } blt; + struct + { + uint32_t bresError0, bresError1; + uint32_t clip0Min, clip0Max; + uint32_t clip1Min, clip1Max; + uint32_t colorBack, colorFore; + uint32_t command, commandExtra; + uint32_t dstBaseAddr; + uint32_t dstFormat; + uint32_t dstSize; + uint32_t dstXY; + uint32_t rop; + uint32_t srcBaseAddr; + uint32_t srcFormat; + uint32_t srcSize; + uint32_t srcXY; + + uint32_t colorPattern[64]; + + int bres_error_0, bres_error_1; + uint32_t colorPattern8[64], colorPattern16[64], colorPattern24[64]; + int cur_x, cur_y; + uint32_t dstBaseAddr_tiled; + uint32_t dstColorkeyMin, dstColorkeyMax; + int dstSizeX, dstSizeY; + int dstX, dstY; + int dst_stride; + int patoff_x, patoff_y; + uint8_t rops[4]; + uint32_t srcBaseAddr_tiled; + uint32_t srcColorkeyMin, srcColorkeyMax; + int srcSizeX, srcSizeY; + int srcX, srcY; + int src_stride; + int old_srcX; + + /*Used for handling packed 24bpp host data*/ + int host_data_remainder; + uint32_t old_host_data; + + /*Polyfill coordinates*/ + int lx[2], rx[2]; + int ly[2], ry[2]; + + /*Polyfill state*/ + int error[2]; + int dx[2], dy[2]; + int x_inc[2]; /*y_inc is always 1 for polyfill*/ + int lx_cur, rx_cur; + + clip_t clip[2]; + + uint8_t host_data[16384]; + int host_data_count; + int host_data_size_src, host_data_size_dest; + int src_stride_src, src_stride_dest; + } banshee_blt; + + struct + { + uint32_t vidOverlayStartCoords; + uint32_t vidOverlayEndScreenCoords; + uint32_t vidOverlayDudx, vidOverlayDudxOffsetSrcWidth; + uint32_t vidOverlayDvdy, vidOverlayDvdyOffset; + //uint32_t vidDesktopOverlayStride; + + int start_x, start_y; + int end_x, end_y; + int size_x, size_y; + int overlay_bytes; + + unsigned int src_y; + } overlay; + rgb_t clutData[33]; int clutData_dirty; rgb_t clutData256[256]; @@ -351,6 +437,9 @@ typedef struct voodoo_t int fb_write_buffer, fb_draw_buffer; int buffer_cutoff; + + uint32_t tile_base, tile_stride; + int tile_stride_shift, tile_x; int read_time, write_time, burst_time; @@ -364,7 +453,7 @@ typedef struct voodoo_t uint16_t purpleline[256][3]; texture_t texture_cache[2][TEX_CACHE_MAX]; - uint8_t texture_present[2][4096]; + uint8_t texture_present[2][16384]; int texture_last_removed; uint32_t palette_checksum[2]; @@ -377,6 +466,11 @@ typedef struct voodoo_t void *codegen_data; struct voodoo_set_t *set; + + + uint8_t *vram, *changedvram; + + void *p; } voodoo_t; typedef struct voodoo_set_t @@ -397,3 +491,5 @@ extern rgba8_t rgb332[0x100], ai44[0x100], rgb565[0x10000], argb1555[0x10000], a void voodoo_recalc(voodoo_t *voodoo); void voodoo_update_ncc(voodoo_t *voodoo, int tmu); +void *voodoo_2d3d_card_init(int type); +void voodoo_card_close(voodoo_t *voodoo); diff --git a/src/vid_voodoo_fifo.c b/src/vid_voodoo_fifo.c index ccf112e..393137e 100644 --- a/src/vid_voodoo_fifo.c +++ b/src/vid_voodoo_fifo.c @@ -8,6 +8,7 @@ #include "vid_svga.h" #include "vid_voodoo.h" #include "vid_voodoo_common.h" +#include "vid_voodoo_banshee_blitter.h" #include "vid_voodoo_fb.h" #include "vid_voodoo_fifo.h" #include "vid_voodoo_reg.h" @@ -205,6 +206,18 @@ void voodoo_fifo_thread(void *param) fifo = &voodoo->fifo[voodoo->fifo_read_idx & FIFO_MASK]; } break; + case FIFO_WRITEL_2DREG: + while ((fifo->addr_type & FIFO_TYPE) == FIFO_WRITEL_2DREG) + { + voodoo_2d_reg_writel(voodoo, fifo->addr_type & FIFO_ADDR, fifo->val); + fifo->addr_type = FIFO_INVALID; + voodoo->fifo_read_idx++; + fifo = &voodoo->fifo[voodoo->fifo_read_idx & FIFO_MASK]; + } + break; + + default: + fatal("Unknown fifo entry %08x\n", fifo->addr_type); } if (FIFO_ENTRIES > 0xe000) @@ -226,7 +239,7 @@ void voodoo_fifo_thread(void *param) int num_verticies; int v_num; -// pclog(" CMDFIFO header %08x at %08x\n", header, voodoo->cmdfifo_rp); +// pclog(" CMDFIFO header %08x at %08x\n", header, voodoo->cmdfifo_rp); switch (header & 7) { @@ -254,17 +267,48 @@ void voodoo_fifo_thread(void *param) while (num--) { uint32_t val = cmdfifo_get(voodoo); - if ((addr & 0x3ff) == SST_triangleCMD || (addr & 0x3ff) == SST_ftriangleCMD || - (addr & 0x3ff) == SST_fastfillCMD || (addr & 0x3ff) == SST_nopCMD) - voodoo->cmd_written_fifo++; + if ((addr & (1 << 13)) && voodoo->type == VOODOO_BANSHEE) + { +// if (voodoo->type != VOODOO_BANSHEE) +// fatal("CMDFIFO1: Not Banshee\n"); +// pclog("CMDFIFO1: write %08x %08x\n", addr, val); + voodoo_2d_reg_writel(voodoo, addr, val); + } + else + { + if ((addr & 0x3ff) == SST_triangleCMD || (addr & 0x3ff) == SST_ftriangleCMD || + (addr & 0x3ff) == SST_fastfillCMD || (addr & 0x3ff) == SST_nopCMD) + voodoo->cmd_written_fifo++; - voodoo_reg_writel(addr, val, voodoo); + if (voodoo->type == VOODOO_BANSHEE && (addr & 0x3ff) == SST_swapbufferCMD) + voodoo->cmd_written_fifo++; + voodoo_reg_writel(addr, val, voodoo); + } if (header & (1 << 15)) addr += 4; } break; + case 2: + if (voodoo->type != VOODOO_BANSHEE) + fatal("CMDFIFO2: Not Banshee\n"); + mask = (header >> 3); + addr = 8; + while (mask) + { + if (mask & 1) + { + uint32_t val = cmdfifo_get(voodoo); + + voodoo_2d_reg_writel(voodoo, addr, val); + } + + addr += 4; + mask >>= 1; + } + break; + case 3: num = (header >> 29) & 7; mask = header;//(header >> 10) & 0xff; @@ -338,11 +382,24 @@ void voodoo_fifo_thread(void *param) if (mask & 1) { uint32_t val = cmdfifo_get(voodoo); - if ((addr & 0x3ff) == SST_triangleCMD || (addr & 0x3ff) == SST_ftriangleCMD || - (addr & 0x3ff) == SST_fastfillCMD || (addr & 0x3ff) == SST_nopCMD) - voodoo->cmd_written_fifo++; - voodoo_reg_writel(addr, val, voodoo); + if ((addr & (1 << 13)) && voodoo->type == VOODOO_BANSHEE) + { + if (voodoo->type != VOODOO_BANSHEE) + fatal("CMDFIFO1: Not Banshee\n"); +// pclog("CMDFIFO1: write %08x %08x\n", addr, val); + voodoo_2d_reg_writel(voodoo, addr, val); + } + else + { + if ((addr & 0x3ff) == SST_triangleCMD || (addr & 0x3ff) == SST_ftriangleCMD || + (addr & 0x3ff) == SST_fastfillCMD || (addr & 0x3ff) == SST_nopCMD) + voodoo->cmd_written_fifo++; + + if (voodoo->type == VOODOO_BANSHEE && (addr & 0x3ff) == SST_swapbufferCMD) + voodoo->cmd_written_fifo++; + voodoo_reg_writel(addr, val, voodoo); + } } addr += 4; @@ -353,13 +410,29 @@ void voodoo_fifo_thread(void *param) break; case 5: - if (header & 0x3fc0000) - fatal("CMDFIFO packet 5 has byte disables set %08x\n", header); +// if (header & 0x3fc00000) +// fatal("CMDFIFO packet 5 has byte disables set %08x\n", header); num = (header >> 3) & 0x7ffff; addr = cmdfifo_get(voodoo) & 0xffffff; + if (!num) + num = 1; // pclog("CMDFIFO5 addr=%08x num=%i\n", addr, num); switch (header >> 30) { + case 0: /*Linear framebuffer (Banshee)*/ + if (voodoo->texture_present[0][(addr & voodoo->texture_mask) >> TEX_DIRTY_SHIFT]) + { +// pclog("texture_present at %08x %i\n", addr, (addr & voodoo->texture_mask) >> TEX_DIRTY_SHIFT); + flush_texture_cache(voodoo, addr & voodoo->texture_mask, 0); + } + while (num--) + { + uint32_t val = cmdfifo_get(voodoo); + if (addr <= voodoo->fb_mask) + *(uint32_t *)&voodoo->fb_mem[addr] = val; + addr += 4; + } + break; case 2: /*Framebuffer*/ while (num--) { @@ -383,7 +456,7 @@ void voodoo_fifo_thread(void *param) break; default: - pclog("Bad CMDFIFO packet %08x %08x\n", header, voodoo->cmdfifo_rp); + fatal("Bad CMDFIFO packet %08x %08x\n", header, voodoo->cmdfifo_rp); } end_time = timer_read(); diff --git a/src/vid_voodoo_reg.c b/src/vid_voodoo_reg.c index 52557f1..fc0626c 100644 --- a/src/vid_voodoo_reg.c +++ b/src/vid_voodoo_reg.c @@ -8,6 +8,7 @@ #include "vid_svga.h" #include "vid_voodoo.h" #include "vid_voodoo_common.h" +#include "vid_voodoo_banshee.h" #include "vid_voodoo_blitter.h" #include "vid_voodoo_dither.h" #include "vid_voodoo_fifo.h" @@ -47,7 +48,38 @@ void voodoo_reg_writel(uint32_t addr, uint32_t val, void *p) switch (addr) { case SST_swapbufferCMD: -// pclog(" start swap buffer command\n"); + if (voodoo->type == VOODOO_BANSHEE) + { +// pclog("swapbufferCMD %08x %08x\n", val, voodoo->leftOverlayBuf); + + voodoo_wait_for_render_thread_idle(voodoo); + if (!(val & 1)) + { + banshee_set_overlay_addr(voodoo->p, voodoo->leftOverlayBuf); + if (voodoo->swap_count > 0) + voodoo->swap_count--; + voodoo->frame_count++; + } + else if (TRIPLE_BUFFER) + { + if (voodoo->swap_pending) + voodoo_wait_for_swap_complete(voodoo); + voodoo->swap_interval = (val >> 1) & 0xff; + voodoo->swap_offset = voodoo->leftOverlayBuf; + voodoo->swap_pending = 1; + } + else + { + voodoo->swap_interval = (val >> 1) & 0xff; + voodoo->swap_offset = voodoo->leftOverlayBuf; + voodoo->swap_pending = 1; + + voodoo_wait_for_swap_complete(voodoo); + } + + voodoo->cmd_read++; + break; + } if (TRIPLE_BUFFER) { @@ -63,7 +95,7 @@ void voodoo_reg_writel(uint32_t addr, uint32_t val, void *p) voodoo->params.swapbufferCMD = val; - pclog("Swap buffer %08x %d %p %i\n", val, voodoo->swap_count, &voodoo->swap_count, (voodoo == voodoo->set->voodoos[1]) ? 1 : 0); +// pclog("Swap buffer %08x %d %p %i\n", val, voodoo->swap_count, &voodoo->swap_count, (voodoo == voodoo->set->voodoos[1]) ? 1 : 0); // voodoo->front_offset = params->front_offset; voodoo_wait_for_render_thread_idle(voodoo); if (!(val & 1)) @@ -503,6 +535,52 @@ void voodoo_reg_writel(uint32_t addr, uint32_t val, void *p) voodoo->params.fogTable[addr+1].dfog = (val >> 16) & 0xff; voodoo->params.fogTable[addr+1].fog = (val >> 24) & 0xff; break; + + case SST_clipLeftRight1: + if (voodoo->type == VOODOO_BANSHEE) + { + voodoo->params.clipRight1 = val & 0xfff; + voodoo->params.clipLeft1 = (val >> 16) & 0xfff; + } + break; + case SST_clipTopBottom1: + if (voodoo->type == VOODOO_BANSHEE) + { + voodoo->params.clipHighY1 = val & 0xfff; + voodoo->params.clipLowY1 = (val >> 16) & 0xfff; + } + break; + + case SST_colBufferAddr: + if (voodoo->type == VOODOO_BANSHEE) + { + voodoo->params.draw_offset = val & 0xfffff0; + voodoo->fb_write_offset = voodoo->params.draw_offset; +// pclog("colorBufferAddr=%06x\n", voodoo->params.draw_offset); + } + break; + case SST_colBufferStride: + if (voodoo->type == VOODOO_BANSHEE) + { + if (val & (1 << 15)) + { + voodoo->row_width = (val & 0x7f) * 128; +// pclog("colBufferStride = %i bytes, tiled\n", voodoo->row_width); + } + else + { + voodoo->row_width = val & 0x3fff; +// pclog("colBufferStride = %i bytes, linear\n", voodoo->row_width); + } + } + break; + case SST_auxBufferAddr: + if (voodoo->type == VOODOO_BANSHEE) + { + voodoo->params.aux_offset = val & 0xfffff0; +// pclog("auxBufferAddr=%06x\n", voodoo->params.aux_offset); + } + break; case SST_clutData: voodoo->clutData[(val >> 24) & 0x3f].b = val & 0xff; @@ -590,6 +668,7 @@ void voodoo_reg_writel(uint32_t addr, uint32_t val, void *p) voodoo->verts[0] = voodoo->verts[3]; voodoo->vertex_num = 1; voodoo->num_verticies = 1; + voodoo->cull_pingpong = 0; break; case SST_sDrawTriCMD: // pclog("sDrawTriCMD %i %i %i\n", voodoo->num_verticies, voodoo->vertex_num, voodoo->sSetupMode & SETUPMODE_STRIP_MODE); @@ -603,6 +682,7 @@ void voodoo_reg_writel(uint32_t addr, uint32_t val, void *p) { // pclog("triangle_setup\n"); voodoo_triangle_setup(voodoo); + voodoo->cull_pingpong = !voodoo->cull_pingpong; voodoo->num_verticies = 2; } @@ -734,48 +814,73 @@ void voodoo_reg_writel(uint32_t addr, uint32_t val, void *p) case SST_texBaseAddr: if (chip & CHIP_TREX0) { - voodoo->params.texBaseAddr[0] = (val & 0x7ffff) << 3; + if (voodoo->type == VOODOO_BANSHEE) + voodoo->params.texBaseAddr[0] = val & 0xfffff0; + else + voodoo->params.texBaseAddr[0] = (val & 0x7ffff) << 3; +// pclog("texBaseAddr = %08x %08x\n", voodoo->params.texBaseAddr[0], val); voodoo_recalc_tex(voodoo, 0); } if (chip & CHIP_TREX1) { - voodoo->params.texBaseAddr[1] = (val & 0x7ffff) << 3; + if (voodoo->type == VOODOO_BANSHEE) + voodoo->params.texBaseAddr[1] = val & 0xfffff0; + else + voodoo->params.texBaseAddr[1] = (val & 0x7ffff) << 3; voodoo_recalc_tex(voodoo, 1); } break; case SST_texBaseAddr1: if (chip & CHIP_TREX0) { - voodoo->params.texBaseAddr1[0] = (val & 0x7ffff) << 3; + if (voodoo->type == VOODOO_BANSHEE) + voodoo->params.texBaseAddr1[0] = val & 0xfffff0; + else + voodoo->params.texBaseAddr1[0] = (val & 0x7ffff) << 3; voodoo_recalc_tex(voodoo, 0); } if (chip & CHIP_TREX1) { - voodoo->params.texBaseAddr1[1] = (val & 0x7ffff) << 3; + if (voodoo->type == VOODOO_BANSHEE) + voodoo->params.texBaseAddr1[1] = val & 0xfffff0; + else + voodoo->params.texBaseAddr1[1] = (val & 0x7ffff) << 3; voodoo_recalc_tex(voodoo, 1); } break; case SST_texBaseAddr2: if (chip & CHIP_TREX0) { - voodoo->params.texBaseAddr2[0] = (val & 0x7ffff) << 3; + if (voodoo->type == VOODOO_BANSHEE) + voodoo->params.texBaseAddr2[0] = val & 0xfffff0; + else + voodoo->params.texBaseAddr2[0] = (val & 0x7ffff) << 3; voodoo_recalc_tex(voodoo, 0); } if (chip & CHIP_TREX1) { - voodoo->params.texBaseAddr2[1] = (val & 0x7ffff) << 3; + if (voodoo->type == VOODOO_BANSHEE) + voodoo->params.texBaseAddr2[1] = val & 0xfffff0; + else + voodoo->params.texBaseAddr2[1] = (val & 0x7ffff) << 3; voodoo_recalc_tex(voodoo, 1); } break; case SST_texBaseAddr38: if (chip & CHIP_TREX0) { - voodoo->params.texBaseAddr38[0] = (val & 0x7ffff) << 3; + if (voodoo->type == VOODOO_BANSHEE) + voodoo->params.texBaseAddr38[0] = val & 0xfffff0; + else + voodoo->params.texBaseAddr38[0] = (val & 0x7ffff) << 3; voodoo_recalc_tex(voodoo, 0); } if (chip & CHIP_TREX1) { - voodoo->params.texBaseAddr38[1] = (val & 0x7ffff) << 3; + if (voodoo->type == VOODOO_BANSHEE) + voodoo->params.texBaseAddr38[1] = val & 0xfffff0; + else + voodoo->params.texBaseAddr38[1] = (val & 0x7ffff) << 3; voodoo_recalc_tex(voodoo, 1); } break; @@ -1136,5 +1241,10 @@ void voodoo_reg_writel(uint32_t addr, uint32_t val, void *p) case SST_userIntrCMD: fatal("userIntrCMD write %08x from FIFO\n", val); break; + + + case SST_leftOverlayBuf: + voodoo->leftOverlayBuf = val; + break; } } diff --git a/src/vid_voodoo_regs.h b/src/vid_voodoo_regs.h index e065a71..f7ab208 100644 --- a/src/vid_voodoo_regs.h +++ b/src/vid_voodoo_regs.h @@ -144,6 +144,14 @@ enum SST_cmdFifoAMax = 0x1f0, SST_cmdFifoDepth = 0x1f4, SST_cmdFifoHoles = 0x1f8, + + SST_colBufferAddr = 0x1ec, /*Banshee*/ + SST_colBufferStride = 0x1f0, /*Banshee*/ + SST_auxBufferAddr = 0x1f4, /*Banshee*/ + SST_auxBufferStride = 0x1f8, /*Banshee*/ + + SST_clipLeftRight1 = 0x200, /*Banshee*/ + SST_clipTopBottom1 = 0x204, /*Banshee*/ SST_fbiInit4 = 0x200, SST_vRetrace = 0x204, @@ -164,7 +172,10 @@ enum SST_fbiInit5 = 0x244, SST_fbiInit6 = 0x248, SST_fbiInit7 = 0x24c, - + + SST_swapPending = 0x24c, /*Banshee*/ + SST_leftOverlayBuf = 0x250, /*Banshee*/ + SST_sSetupMode = 0x260, SST_sVx = 0x264, SST_sVy = 0x268, diff --git a/src/vid_voodoo_render.c b/src/vid_voodoo_render.c index 641e8e2..b348ad5 100644 --- a/src/vid_voodoo_render.c +++ b/src/vid_voodoo_render.c @@ -1266,8 +1266,11 @@ static void voodoo_half_triangle(voodoo_t *voodoo, voodoo_params_t *params, vood if (cca_invert_output) src_a ^= 0xff; - if (params->fogMode & FOG_ENABLE) - APPLY_FOG(src_r, src_g, src_b, state->z, state->ia, state->w); + if (voodoo->type != VOODOO_BANSHEE) /*HACK*/ + { + if (params->fogMode & FOG_ENABLE) + APPLY_FOG(src_r, src_g, src_b, state->z, state->ia, state->w); + } if (params->alphaMode & 1) ALPHA_TEST(src_a); diff --git a/src/vid_voodoo_setup.c b/src/vid_voodoo_setup.c index f3fe076..3572447 100644 --- a/src/vid_voodoo_setup.c +++ b/src/vid_voodoo_setup.c @@ -15,7 +15,6 @@ void voodoo_triangle_setup(voodoo_t *voodoo) float dxAB, dxBC, dyAB, dyBC; float area; int va = 0, vb = 1, vc = 2; - int reverse_cull = 0; vert_t verts[3]; verts[0] = voodoo->verts[0]; @@ -40,7 +39,6 @@ void voodoo_triangle_setup(voodoo_t *voodoo) va = 0; vb = 2; vc = 1; - reverse_cull = 1; } else { @@ -62,7 +60,6 @@ void voodoo_triangle_setup(voodoo_t *voodoo) va = 1; vb = 0; vc = 2; - reverse_cull = 1; } else { @@ -78,10 +75,35 @@ void voodoo_triangle_setup(voodoo_t *voodoo) va = 2; vb = 1; vc = 0; - reverse_cull = 1; } } + dxAB = verts[0].sVx - verts[1].sVx; + dxBC = verts[1].sVx - verts[2].sVx; + dyAB = verts[0].sVy - verts[1].sVy; + dyBC = verts[1].sVy - verts[2].sVy; + + area = dxAB * dyBC - dxBC * dyAB; + + if (area == 0.0) + return; + + if (voodoo->sSetupMode & SETUPMODE_CULLING_ENABLE) + { + int cull_sign = voodoo->sSetupMode & SETUPMODE_CULLING_SIGN; + int sign = (area < 0.0); + + if ((voodoo->sSetupMode & (SETUPMODE_CULLING_ENABLE | SETUPMODE_DISABLE_PINGPONG)) + == SETUPMODE_CULLING_ENABLE && voodoo->cull_pingpong) + cull_sign = !cull_sign; + + if (cull_sign && sign) + return; + if (!cull_sign && !sign) + return; + } + + dxAB = verts[va].sVx - verts[vb].sVx; dxBC = verts[vb].sVx - verts[vc].sVx; dyAB = verts[va].sVy - verts[vb].sVy; @@ -89,36 +111,12 @@ void voodoo_triangle_setup(voodoo_t *voodoo) area = dxAB * dyBC - dxBC * dyAB; - if (area == 0.0) - { - if ((voodoo->sSetupMode & SETUPMODE_CULLING_ENABLE) && - !(voodoo->sSetupMode & SETUPMODE_DISABLE_PINGPONG)) - voodoo->sSetupMode ^= SETUPMODE_CULLING_SIGN; - - return; - } - dxAB /= area; dxBC /= area; dyAB /= area; dyBC /= area; - if (voodoo->sSetupMode & SETUPMODE_CULLING_ENABLE) - { - int cull_sign = voodoo->sSetupMode & SETUPMODE_CULLING_SIGN; - int sign = (area < 0.0); - if (!(voodoo->sSetupMode & SETUPMODE_DISABLE_PINGPONG)) - voodoo->sSetupMode ^= SETUPMODE_CULLING_SIGN; - - if (reverse_cull) - sign = !sign; - - if (cull_sign && sign) - return; - if (!cull_sign && !sign) - return; - } voodoo->params.vertexAx = (int32_t)(int16_t)((int32_t)(verts[va].sVx * 16.0f) & 0xffff); voodoo->params.vertexAy = (int32_t)(int16_t)((int32_t)(verts[va].sVy * 16.0f) & 0xffff); diff --git a/src/vid_voodoo_texture.c b/src/vid_voodoo_texture.c index 69bcbd3..3326f5e 100644 --- a/src/vid_voodoo_texture.c +++ b/src/vid_voodoo_texture.c @@ -157,7 +157,7 @@ void voodoo_use_texture(voodoo_t *voodoo, voodoo_params_t *params, int tmu) return; } } - + /*Texture not found, search for unused texture*/ do { @@ -469,7 +469,7 @@ void voodoo_use_texture(voodoo_t *voodoo, voodoo_params_t *params, int tmu) voodoo->texture_cache[tmu][c].refcount++; } -static void flush_texture_cache(voodoo_t *voodoo, uint32_t dirty_addr, int tmu) +void flush_texture_cache(voodoo_t *voodoo, uint32_t dirty_addr, int tmu) { int wait_for_idle = 0; int c; @@ -531,30 +531,41 @@ void voodoo_tex_writel(uint32_t addr, uint32_t val, void *p) if (tmu && !voodoo->dual_tmus) return; -// pclog("voodoo_tex_writel : %08X %08X %i\n", addr, val, voodoo->params.tformat); - - lod = (addr >> 17) & 0xf; - t = (addr >> 9) & 0xff; - if (voodoo->params.tformat[tmu] & 8) - s = (addr >> 1) & 0xfe; - else + if (voodoo->type != VOODOO_BANSHEE) { - if (voodoo->params.textureMode[tmu] & (1 << 31)) - s = addr & 0xfc; + if (!(voodoo->params.tformat[tmu] & 8) && voodoo->type == VOODOO_BANSHEE) + { + lod = (addr >> 16) & 0xf; + t = (addr >> 8) & 0xff; + } else - s = (addr >> 1) & 0xfc; + { + lod = (addr >> 17) & 0xf; + t = (addr >> 9) & 0xff; + } + if (voodoo->params.tformat[tmu] & 8) + s = (addr >> 1) & 0xfe; + else + { + if ((voodoo->params.textureMode[tmu] & (1 << 31)) || voodoo->type == VOODOO_BANSHEE) + s = addr & 0xfc; + else + s = (addr >> 1) & 0xfc; + } + if (lod > LOD_MAX) + return; + +// if (addr >= 0x200000) +// return; + + if (voodoo->params.tformat[tmu] & 8) + addr = voodoo->params.tex_base[tmu][lod] + s*2 + (t << voodoo->params.tex_shift[tmu][lod])*2; + else + addr = voodoo->params.tex_base[tmu][lod] + s + (t << voodoo->params.tex_shift[tmu][lod]); } - - if (lod > LOD_MAX) - return; - -// if (addr >= 0x200000) -// return; - - if (voodoo->params.tformat[tmu] & 8) - addr = voodoo->params.tex_base[tmu][lod] + s*2 + (t << voodoo->params.tex_shift[tmu][lod])*2; else - addr = voodoo->params.tex_base[tmu][lod] + s + (t << voodoo->params.tex_shift[tmu][lod]); + addr = (addr & 0x1ffffc) + voodoo->params.tex_base[tmu][lod]; + if (voodoo->texture_present[tmu][(addr & voodoo->texture_mask) >> TEX_DIRTY_SHIFT]) { // pclog("texture_present at %08x %i\n", addr, (addr & voodoo->texture_mask) >> TEX_DIRTY_SHIFT); diff --git a/src/vid_voodoo_texture.h b/src/vid_voodoo_texture.h index e744f17..e4c5602 100644 --- a/src/vid_voodoo_texture.h +++ b/src/vid_voodoo_texture.h @@ -16,3 +16,4 @@ static const uint32_t texture_offset[LOD_MAX+3] = void voodoo_recalc_tex(voodoo_t *voodoo, int tmu); void voodoo_use_texture(voodoo_t *voodoo, voodoo_params_t *params, int tmu); void voodoo_tex_writel(uint32_t addr, uint32_t val, void *p); +void flush_texture_cache(voodoo_t *voodoo, uint32_t dirty_addr, int tmu); diff --git a/src/video.c b/src/video.c index 2c81093..0550186 100644 --- a/src/video.c +++ b/src/video.c @@ -50,6 +50,7 @@ #include "vid_wy700.h" #include "vid_t3100e.h" #include "vid_t1000.h" +#include "vid_voodoo_banshee.h" enum { @@ -82,6 +83,7 @@ typedef struct static VIDEO_CARD video_cards[] = { + {"A-Trend Helios 3D (Voodoo Banshee)", "banshee", &atrend_voodoo_banshee_device, GFX_BANSHEE, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 1, 20, 20, 21}}, {"Acumos AVGA2 / Cirrus Logic CL-GD5402", "avga2", &avga2_device, GFX_AVGA2, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 3, 3, 6, 5, 5, 10}}, {"ATI Graphics Pro Turbo (Mach64 GX)", "mach64gx", &mach64gx_device, GFX_MACH64GX, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 1, 20, 20, 21}}, {"ATI Video Xpression (Mach64 VT2)", "mach64vt2", &mach64vt2_device, GFX_MACH64VT2, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 1, 20, 20, 21}},