#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_ddc.h" #include "vid_svga.h" #include "vid_svga_render.h" #include "vid_voodoo_banshee.h" #include "vid_voodoo_common.h" #include "vid_voodoo_display.h" #include "vid_voodoo_fifo.h" #include "vid_voodoo_regs.h" #include "vid_voodoo_render.h" #include "x86.h" #ifdef CLAMP #undef CLAMP #endif static uint8_t vb_filter_v1_rb[256][256]; static uint8_t vb_filter_v1_g [256][256]; static uint8_t vb_filter_bx_rb[256][256]; static uint8_t vb_filter_bx_g [256][256]; enum { TYPE_BANSHEE = 0, TYPE_V3_2000, TYPE_V3_3000 }; 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; uint32_t vidSerialParallelPort; int overlay_pix_fmt; uint32_t hwCurPatAddr, hwCurLoc, hwCurC0, hwCurC1; uint32_t intrCtrl; uint32_t overlay_buffer[2][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; uint32_t desktop_addr; int desktop_y; uint32_t desktop_stride_tiled; int type; int vblank_irq; } 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_maxRgbDelta = 0x58, Video_hwCurPatAddr = 0x60, Video_hwCurLoc = 0x64, Video_hwCurC0 = 0x68, Video_hwCurC1 = 0x6c, Video_vidSerialParallelPort = 0x78, 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_VIDPROC_ENABLE (1 << 0) #define VIDPROCCFG_CURSOR_MODE (1 << 1) #define VIDPROCCFG_INTERLACE (1 << 3) #define VIDPROCCFG_HALF_MODE (1 << 4) #define VIDPROCCFG_OVERLAY_ENABLE (1 << 8) #define VIDPROCCFG_OVERLAY_CLUT_BYPASS (1 << 11) #define VIDPROCCFG_OVERLAY_CLUT_SEL (1 << 13) #define VIDPROCCFG_H_SCALE_ENABLE (1 << 14) #define VIDPROCCFG_V_SCALE_ENABLE (1 << 15) #define VIDPROCCFG_FILTER_MODE_MASK (3 << 16) #define VIDPROCCFG_FILTER_MODE_POINT (0 << 16) #define VIDPROCCFG_FILTER_MODE_DITHER_2X2 (1 << 16) #define VIDPROCCFG_FILTER_MODE_DITHER_4X4 (2 << 16) #define VIDPROCCFG_FILTER_MODE_BILINEAR (3 << 16) #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_565 (1) #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 #define VIDSERIAL_DDC_DCK_W (1 << 19) #define VIDSERIAL_DDC_DDA_W (1 << 20) #define VIDSERIAL_DDC_DCK_R (1 << 21) #define VIDSERIAL_DDC_DDA_R (1 << 22) #define VIDSERIAL_I2C_SCK_W (1 << 24) #define VIDSERIAL_I2C_SDA_W (1 << 25) #define VIDSERIAL_I2C_SCK_R (1 << 26) #define VIDSERIAL_I2C_SDA_R (1 << 27) #define MISCINIT0_Y_ORIGIN_SWAP_SHIFT (18) #define MISCINIT0_Y_ORIGIN_SWAP_MASK (0xfff << MISCINIT0_Y_ORIGIN_SWAP_SHIFT) static int banshee_vga_vsync_enabled(banshee_t *banshee) { if (!(banshee->svga.crtc[0x11] & 0x20) && (banshee->svga.crtc[0x11] & 0x10) && ((banshee->pciInit0 >> 18) & 1) != 0) return 1; return 0; } static void banshee_update_irqs(banshee_t *banshee) { if (banshee->vblank_irq > 0 && banshee_vga_vsync_enabled(banshee)) { pci_set_irq(NULL, PCI_INTA); } else { pci_clear_irq(NULL, PCI_INTA); } } static void banshee_vblank_start(svga_t* svga) { banshee_t *banshee = (banshee_t*)svga->p; if (banshee->vblank_irq >= 0) { banshee->vblank_irq = 1; banshee_update_irqs(banshee); } } 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 == 0x11) { if (!(val & 0x10)) { if (banshee->vblank_irq > 0) banshee->vblank_irq = -1; } else if (banshee->vblank_irq < 0) { banshee->vblank_irq = 0; } banshee_update_irqs(banshee); if ((val & ~0x30) == (old & ~0x30)) old = val; } if (svga->crtcreg < 0xe || svga->crtcreg > 0x11 || (svga->crtcreg == 0x11 && old != val)) { 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; if (banshee->vblank_irq > 0) temp |= 0x80; 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_disablex(&svga->mapping); mem_mapping_disablex(&banshee->linear_mapping); mem_mapping_disablex(&banshee->reg_mapping_low); mem_mapping_disablex(&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_addrx(&svga->mapping, 0xa0000, 0x20000); svga->banked_mask = 0xffff; break; case 0x4: /*64k at A0000*/ mem_mapping_set_addrx(&svga->mapping, 0xa0000, 0x10000); svga->banked_mask = 0xffff; break; case 0x8: /*32k at B0000*/ mem_mapping_set_addrx(&svga->mapping, 0xb0000, 0x08000); svga->banked_mask = 0x7fff; break; case 0xC: /*32k at B8000*/ mem_mapping_set_addrx(&svga->mapping, 0xb8000, 0x08000); svga->banked_mask = 0x7fff; break; } pclog("Linear framebuffer %08X ", banshee->memBaseAddr1); mem_mapping_set_addrx(&banshee->linear_mapping, banshee->memBaseAddr1, 32 << 20); pclog("registers %08X\n", banshee->memBaseAddr0); mem_mapping_set_addrx(&banshee->reg_mapping_low, banshee->memBaseAddr0, 8 << 20); mem_mapping_set_addrx(&banshee->reg_mapping_high, banshee->memBaseAddr0 + 0xc00000, 20 << 20); } static void banshee_render_16bpp_tiled(svga_t *svga) { banshee_t *banshee = (banshee_t *)svga->p; int x; int offset = 32; uint32_t *p = &((uint32_t *)buffer32->line[svga->displine])[offset]; uint32_t addr; int drawn = 0; if (banshee->vidProcCfg & VIDPROCCFG_HALF_MODE) addr = banshee->desktop_addr + ((banshee->desktop_y >> 1) & 31) * 128 + ((banshee->desktop_y >> 6) * banshee->desktop_stride_tiled); else addr = banshee->desktop_addr + (banshee->desktop_y & 31) * 128 + ((banshee->desktop_y >> 5) * banshee->desktop_stride_tiled); for (x = 0; x <= svga->hdisp; x += 64) { if (svga->hwcursor_on || svga->overlay_on) svga->changedvram[addr >> 12] = 2; if (svga->changedvram[addr >> 12] || svga->fullchange) { uint16_t *vram_p = (uint16_t *)&svga->vram[addr & svga->vram_display_mask]; int xx; for (xx = 0; xx < 64; xx++) *p++ = video_16to32[*vram_p++]; drawn = 1; } else p += 64; addr += 128*32; } if (drawn) { if (svga->firstline_draw == 2000) svga->firstline_draw = svga->displine; svga->lastline_draw = svga->displine; } banshee->desktop_y++; } 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); svga->interlace = 0; // if (banshee->vgaInit0 & VGAINIT0_EXTENDED_SHIFT_OUT) if (banshee->vidProcCfg & VIDPROCCFG_VIDPROC_ENABLE) { // this is some VGA-only feature? G-REX driver sets it and still expects normal 640x480 display. svga->lowres = 0; 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 = (banshee->vidProcCfg & VIDPROCCFG_DESKTOP_TILE) ? banshee_render_16bpp_tiled : 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; #ifndef RELEASE_BUILD default: fatal("Unknown pixel format %08x\n", banshee->vgaInit0); #endif } svga->rowcount = 0; if (!(banshee->vidProcCfg & VIDPROCCFG_DESKTOP_TILE) && (banshee->vidProcCfg & VIDPROCCFG_HALF_MODE)) svga->linedbl = 1; else svga->linedbl = 0; 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; banshee->desktop_stride_tiled = (banshee->vidDesktopOverlayStride & 0x3fff) * 128 * 32; // 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; } if (banshee->vidProcCfg & VIDPROCCFG_INTERLACE) { svga->interlace = 1; } 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*32; 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);*/ if (!voodoo->overlay.start_x && !voodoo->overlay.start_y && svga->hdisp == voodoo->overlay.size_x && svga->dispend == voodoo->overlay.size_y) { /*Overlay is full screen, so don't bother rendering the desktop behind it*/ svga->render = svga_render_null; svga->bpp = 0; } } 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; } svga->fb_only = (banshee->vidProcCfg & VIDPROCCFG_VIDPROC_ENABLE); svga->horizontal_linedbl = svga->dispend * 9 / 10 >= svga->hdisp; 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: pclog("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; voodoo->tile_x_real = ((val >> 16) & 0x7f) * 128*32; break; case Init_miscInit0: banshee->miscInit0 = val; extern void gfxboard_voodoo_lfb_endianswap(int); gfxboard_voodoo_lfb_endianswap(val >> 30); 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_maxRgbDelta: banshee->voodoo->scrfilterThreshold = val; if (val > 0x00) banshee->voodoo->scrfilterEnabled = 1; else banshee->voodoo->scrfilterEnabled = 0; voodoo_threshold_check(banshee->voodoo); //pclog("Banshee Filter: %06x\n", val); break; case Video_hwCurPatAddr: banshee->hwCurPatAddr = val; svga->hwcursor.addr = (val & 0xfffff0) + (svga->hwcursor.yoff * 16); 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.addr = (banshee->hwCurPatAddr & 0xfffff0) + (svga->hwcursor.yoff * 16); 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_vidSerialParallelPort: banshee->vidSerialParallelPort = val; // pclog("vidSerialParallelPort: write %08x %08x %04x(%08x):%08x\n", val, val & (VIDSERIAL_DDC_DCK_W | VIDSERIAL_DDC_DDA_W), CS,cs,cpu_state.pc); //ddc_i2c_change((val & VIDSERIAL_DDC_DCK_W) ? 1 : 0, (val & VIDSERIAL_DDC_DDA_W) ? 1 : 0); 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) + 1; voodoo->overlay.size_y = (voodoo->overlay.end_y - voodoo->overlay.start_y) + 1; 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 & 0xffffff; // 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: pclog("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) || voodoo->render_voodoo_busy[0] || voodoo->render_voodoo_busy[1] || voodoo->render_voodoo_busy[2] || voodoo->render_voodoo_busy[3] || voodoo->voodoo_busy; uint32_t ret; ret = 0; if (fifo_entries < 0x20) ret |= 0x1f - fifo_entries; else ret |= 0x1f; if (fifo_entries) 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_pciInit0: ret = banshee->pciInit0; 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_vidSerialParallelPort: ret = banshee->vidSerialParallelPort & ~(VIDSERIAL_DDC_DCK_R | VIDSERIAL_DDC_DDA_R); if ((banshee->vidSerialParallelPort & VIDSERIAL_DDC_DCK_W) && 0) //ddc_read_clock()) ret |= VIDSERIAL_DDC_DCK_R; if ((banshee->vidSerialParallelPort & VIDSERIAL_DDC_DDA_W) && 0) //ddc_read_data()) ret |= VIDSERIAL_DDC_DDA_R; ret = ret & ~(VIDSERIAL_I2C_SCK_R | VIDSERIAL_I2C_SDA_R); if (banshee->vidSerialParallelPort & VIDSERIAL_I2C_SCK_W) ret |= VIDSERIAL_I2C_SCK_R; if (banshee->vidSerialParallelPort & VIDSERIAL_I2C_SDA_W) ret |= VIDSERIAL_I2C_SDA_R; // pclog("vidSerialParallelPort: read %08x %08x %04x(%08x):%08x\n", ret, ret & (VIDSERIAL_DDC_DCK_R | VIDSERIAL_DDC_DDA_R), CS,cs,cpu_state.pc); 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; } // miscInit0 register swizzle static uint32_t registerswizzle(uint32_t data, uint32_t addr, int addrtype, banshee_t *banshee) { // swizzling enabled if miscInit0 swizzle bit(s) set and: // 2D register address space and address bit 19 set // 3D register address space and address bit 20 set if ((!addrtype && (addr & 0x00080000)) || (addrtype && (addr & 0x00100000))) { if (banshee->miscInit0 & 4) data = (data >> 24) | ((data >> 8) & 0xff00) | ((data << 8) & 0xff0000) | (data << 24); if (banshee->miscInit0 & 8) data = (data >> 16) | (data << 16); } return data; } 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; #ifndef RELEASE_BUILD default: fatal("Unknown banshee_cmd_read %08x\n", addr); #endif } 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 SST_status: ret = banshee_status(banshee); break; case SST_intrCtrl: ret = banshee->intrCtrl & 0x0030003f; break; 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); } ret = registerswizzle(ret, addr, 0, banshee); 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: ret = voodoo->params.clipRight | (voodoo->params.clipLeft << 16); break; case SST_clipLowYHighY: ret = voodoo->params.clipHighY | (voodoo->params.clipLowY << 16); break; case SST_clipLeftRight1: ret = voodoo->params.clipRight1 | (voodoo->params.clipLeft1 << 16); break; case SST_clipTopBottom1: 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: pclog("banshee_reg_readl: 3D addr=%08x\n", addr); break; } ret = registerswizzle(ret, addr, 1, banshee); 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 & 0xfff) << 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); voodoo->cmdfifo_enabled = val & 0x100; if (!voodoo->cmdfifo_enabled) voodoo->cmdfifo_in_sub = 0; /*Not sure exactly when this should be reset*/ // 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*/ val = registerswizzle(val, addr, 0, banshee); if ((addr & 0x3fc) == SST_intrCtrl) { banshee->intrCtrl = val & 0x0030003f; } else { voodoo_queue_command(voodoo, (addr & 0x1fc) | FIFO_WRITEL_2DREG, val); } break; case 0x0200000: case 0x0300000: case 0x0400000: case 0x0500000: /*3D registers*/ val = registerswizzle(val, addr, 1, banshee); switch (addr & 0x3fc) { case SST_intrCtrl: banshee->intrCtrl = val & 0x0030003f; // pclog("intrCtrl=%08x\n", val); break; case SST_userIntrCMD: #ifndef RELEASE_BUILD fatal("userIntrCMD write %08x\n", val); #endif 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: thread_lock_mutex(voodoo->swap_mutex); voodoo->swap_count++; thread_unlock_mutex(voodoo->swap_mutex); // 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; #if 0 cycles -= voodoo->read_time; cycles_lost += voodoo->read_time; #endif addr &= svga->decode_mask; if (addr >= voodoo->tile_base) { int x, y; addr -= voodoo->tile_base; x = addr & (voodoo->tile_stride-1); y = addr >> voodoo->tile_stride_shift; addr = voodoo->tile_base + (x & 127) + ((x >> 7) * 128*32) + ((y & 31) * 128) + (y >> 5)*voodoo->tile_x_real; // pclog(" Tile rb %08x->%08x %i %i\n", old_addr, addr, x, y); } if (addr >= svga->vram_max) return 0xff; #if 0 egareads++; cycles -= video_timing_read_b; cycles_lost += video_timing_read_b; #endif // 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; if (addr & 1) return banshee_read_linear(addr, p) | (banshee_read_linear(addr+1, p) << 8); #if 0 cycles -= voodoo->read_time; cycles_lost += voodoo->read_time; #endif addr &= svga->decode_mask; if (addr >= voodoo->tile_base) { int x, y; addr -= voodoo->tile_base; x = addr & (voodoo->tile_stride-1); y = addr >> voodoo->tile_stride_shift; addr = voodoo->tile_base + (x & 127) + ((x >> 7) * 128*32) + ((y & 31) * 128) + (y >> 5)*voodoo->tile_x_real; // pclog(" Tile rb %08x->%08x %i %i\n", old_addr, addr, x, y); } if (addr >= svga->vram_max) return 0xff; #if 0 egareads++; cycles -= video_timing_read_w; cycles_lost += video_timing_read_w; #endif // 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; if (addr & 3) return banshee_read_linear_w(addr, p) | (banshee_read_linear_w(addr+2, p) << 16); #if 0 cycles -= voodoo->read_time; cycles_lost += voodoo->read_time; #endif addr &= svga->decode_mask; if (addr >= voodoo->tile_base) { int x, y; addr -= voodoo->tile_base; x = addr & (voodoo->tile_stride-1); y = addr >> voodoo->tile_stride_shift; addr = voodoo->tile_base + (x & 127) + ((x >> 7) * 128*32) + ((y & 31) * 128) + (y >> 5)*voodoo->tile_x_real; // pclog(" Tile rb %08x->%08x %i %i\n", old_addr, addr, x, y); } if (addr >= svga->vram_max) return 0xff; #if 0 egareads++; cycles -= video_timing_read_l; cycles_lost += video_timing_read_l; #endif // 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; #if 0 cycles -= voodoo->write_time; cycles_lost += voodoo->write_time; #endif // pclog("write_linear: addr=%08x val=%02x\n", addr, val); addr &= svga->decode_mask; if (addr >= voodoo->tile_base) { int x, y; addr -= voodoo->tile_base; x = addr & (voodoo->tile_stride-1); y = addr >> voodoo->tile_stride_shift; addr = voodoo->tile_base + (x & 127) + ((x >> 7) * 128*32) + ((y & 31) * 128) + (y >> 5)*voodoo->tile_x_real; // pclog(" Tile b %08x->%08x %i %i\n", old_addr, addr, x, y); } if (addr >= svga->vram_max) return; #if 0 egawrites++; cycles -= video_timing_write_b; cycles_lost += video_timing_write_b; #endif 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; if (addr & 1) { banshee_write_linear(addr, val, p); banshee_write_linear(addr + 1, val >> 8, p); return; } #if 0 cycles -= voodoo->write_time; cycles_lost += voodoo->write_time; #endif // pclog("write_linear: addr=%08x val=%02x\n", addr, val); addr &= svga->decode_mask; if (addr >= voodoo->tile_base) { int x, y; addr -= voodoo->tile_base; x = addr & (voodoo->tile_stride-1); y = addr >> voodoo->tile_stride_shift; addr = voodoo->tile_base + (x & 127) + ((x >> 7) * 128*32) + ((y & 31) * 128) + (y >> 5)*voodoo->tile_x_real; // pclog(" Tile b %08x->%08x %i %i\n", old_addr, addr, x, y); } if (addr >= svga->vram_max) return; #if 0 egawrites++; cycles -= video_timing_write_w; cycles_lost += video_timing_write_w; #endif 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; int timing; if (addr & 3) { banshee_write_linear_w(addr, val, p); banshee_write_linear_w(addr + 2, val >> 16, p); return; } #if 0 if (addr == voodoo->last_write_addr+4) timing = voodoo->burst_time; else timing = voodoo->write_time; cycles -= timing; cycles_lost += timing; #endif 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; addr -= voodoo->tile_base; x = addr & (voodoo->tile_stride-1); y = addr >> voodoo->tile_stride_shift; addr = voodoo->tile_base + (x & 127) + ((x >> 7) * 128*32) + ((y & 31) * 128) + (y >> 5)*voodoo->tile_x_real; // pclog(" Tile %08x->%08x->%08x->%08x %i %i tile_x=%i\n", old_addr, addr_off, addr2, addr, x, y, voodoo->tile_x_real); } if (addr >= svga->vram_max) return; #if 0 egawrites += 4; cycles -= video_timing_write_l; cycles_lost += video_timing_write_l; #endif svga->changedvram[addr >> 12] = changeframecount; *(uint32_t *)&svga->vram[addr & svga->vram_mask] = val; if (voodoo->cmdfifo_enabled && addr >= voodoo->cmdfifo_base && addr < voodoo->cmdfifo_end) { // pclog("CMDFIFO write %08x %08x old amin=%08x amax=%08x hlcnt=%i depth_wr=%i rp=%08x\n", addr, val, voodoo->cmdfifo_amin, voodoo->cmdfifo_amax, voodoo->cmdfifo_holecount, voodoo->cmdfifo_depth_wr, voodoo->cmdfifo_rp); if (addr == voodoo->cmdfifo_base && !voodoo->cmdfifo_holecount) { // if (voodoo->cmdfifo_holecount) // fatal("CMDFIFO reset pointers while outstanding holes\n"); /*Reset pointers*/ voodoo->cmdfifo_amin = voodoo->cmdfifo_base; voodoo->cmdfifo_amax = voodoo->cmdfifo_base; voodoo->cmdfifo_depth_wr++; voodoo_wake_fifo_thread(voodoo); } else if (voodoo->cmdfifo_holecount) { // if ((addr <= voodoo->cmdfifo_amin && voodoo->cmdfifo_amin != -4) || addr >= voodoo->cmdfifo_amax) // fatal("CMDFIFO holecount write outside of amin/amax - amin=%08x amax=%08x holecount=%i\n", voodoo->cmdfifo_amin, voodoo->cmdfifo_amax, voodoo->cmdfifo_holecount); // pclog("holecount %i\n", voodoo->cmdfifo_holecount); voodoo->cmdfifo_holecount--; if (!voodoo->cmdfifo_holecount) { /*Filled in holes, resume normal operation*/ voodoo->cmdfifo_depth_wr += ((voodoo->cmdfifo_amax - voodoo->cmdfifo_amin) >> 2); voodoo->cmdfifo_amin = voodoo->cmdfifo_amax; voodoo_wake_fifo_thread(voodoo); // pclog("hole filled! amin=%08x amax=%08x added %i words\n", voodoo->cmdfifo_amin, voodoo->cmdfifo_amax, words_to_add); } } else if (addr == voodoo->cmdfifo_amax+4) { /*In-order write*/ voodoo->cmdfifo_amin = addr; voodoo->cmdfifo_amax = addr; voodoo->cmdfifo_depth_wr++; voodoo_wake_fifo_thread(voodoo); } else { /*Out-of-order write*/ if (addr < voodoo->cmdfifo_amin) { /*Reset back to start. Note that write is still out of order!*/ voodoo->cmdfifo_amin = voodoo->cmdfifo_base-4; } // else if (addr < voodoo->cmdfifo_amax) // fatal("Out-of-order write really out of order\n"); voodoo->cmdfifo_amax = addr; voodoo->cmdfifo_holecount = ((voodoo->cmdfifo_amax - voodoo->cmdfifo_amin) >> 2) - 1; // pclog("CMDFIFO out of order: amin=%08x amax=%08x holecount=%i\n", voodoo->cmdfifo_amin, voodoo->cmdfifo_amax, voodoo->cmdfifo_holecount); } } } 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; x_off <<= svga->horizontal_linedbl; if (banshee->vidProcCfg & VIDPROCCFG_CURSOR_MODE) { /*X11 mode*/ 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; plane0[x >> 3] <<= 1; plane1[x >> 3] <<= 1; } } x_off += 8; } } else { /*Windows mode*/ 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(buf) \ 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; \ \ if (banshee->vidProcCfg & VIDPROCCFG_OVERLAY_CLUT_BYPASS) \ buf[wp++] = (r << 3) | (g << 10) | (b << 19); \ else \ buf[wp++] = (clut[r << 3] & 0x0000ff) | \ (clut[g << 2] & 0x00ff00) | \ (clut[b << 3] & 0xff0000); \ src += 2; \ } \ } while (0) #define DECODE_RGB565_TILED(buf) \ do \ { \ int c; \ int wp = 0; \ uint32_t base_addr = (buf == banshee->overlay_buffer[1]) ? src_addr2 : src_addr; \ \ for (c = 0; c < voodoo->overlay.overlay_bytes; c += 2) \ { \ uint16_t data = *(uint16_t *)&svga->vram[(base_addr + (c & 127) + (c >> 7)*128*32) & svga->vram_mask]; \ int r = data & 0x1f; \ int g = (data >> 5) & 0x3f; \ int b = data >> 11; \ \ if (banshee->vidProcCfg & VIDPROCCFG_OVERLAY_CLUT_BYPASS) \ buf[wp++] = (r << 3) | (g << 10) | (b << 19); \ else \ buf[wp++] = (clut[r << 3] & 0x0000ff) | \ (clut[g << 2] & 0x00ff00) | \ (clut[b << 3] & 0xff0000); \ } \ } while (0) #define DECODE_YUYV422(buf) \ 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); \ buf[wp++] = r | (g << 8) | (b << 16); \ \ r = y2 + dR; \ CLAMP(r); \ g = y2 - dG; \ CLAMP(g); \ b = y2 + dB; \ CLAMP(b); \ buf[wp++] = r | (g << 8) | (b << 16); \ } \ } while (0) #define DECODE_UYUV422(buf) \ 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); \ buf[wp++] = r | (g << 8) | (b << 16); \ \ r = y2 + dR; \ CLAMP(r); \ g = y2 - dG; \ CLAMP(g); \ b = y2 + dB; \ CLAMP(b); \ buf[wp++] = r | (g << 8) | (b << 16); \ } \ } while (0) #define OVERLAY_SAMPLE(buf) \ do \ { \ switch (banshee->overlay_pix_fmt) \ { \ case 0: \ break; \ \ case OVERLAY_FMT_YUYV422: \ DECODE_YUYV422(buf); \ break; \ \ case OVERLAY_FMT_UYVY422: \ DECODE_UYUV422(buf); \ break; \ \ case OVERLAY_FMT_565: \ case OVERLAY_FMT_565_DITHER: \ if (banshee->vidProcCfg & VIDPROCCFG_OVERLAY_TILE) \ DECODE_RGB565_TILED(buf); \ else \ DECODE_RGB565(buf); \ break; \ } \ } while (0) /* generate both filters for the static table here */ void voodoo_generate_vb_filters(voodoo_t *voodoo, int fcr, int fcg) { int g, h; float difference, diffg; float thiscol, thiscolg; float clr, clg = 0; float hack = 1.0f; // pre-clamping fcr *= hack; fcg *= hack; /* box prefilter */ for (g=0;g<256;g++) // pixel 1 - our target pixel we want to bleed into { for (h=0;h<256;h++) // pixel 2 - our main pixel { float avg; float avgdiff; difference = (float)(g - h); avg = g; avgdiff = avg - h; avgdiff = avgdiff * 0.75f; if (avgdiff < 0) avgdiff *= -1; if (difference < 0) difference *= -1; thiscol = thiscolg = g; if (h > g) { clr = clg = avgdiff; if (clr>fcr) clr=fcr; if (clg>fcg) clg=fcg; thiscol = g; thiscolg = g; if (thiscol>g+fcr) thiscol=g+fcr; if (thiscolg>g+fcg) thiscolg=g+fcg; if (thiscol>g+difference) thiscol=g+difference; if (thiscolg>g+difference) thiscolg=g+difference; // hmm this might not be working out.. int ugh = g - h; if (ugh < fcr) thiscol = h; if (ugh < fcg) thiscolg = h; } if (difference > fcr) thiscol = g; if (difference > fcg) thiscolg = g; // clamp if (thiscol < 0) thiscol = 0; if (thiscolg < 0) thiscolg = 0; if (thiscol > 255) thiscol = 255; if (thiscolg > 255) thiscolg = 255; vb_filter_bx_rb[g][h] = (thiscol); vb_filter_bx_g [g][h] = (thiscolg); } float lined = g + 4; if (lined > 255) lined = 255; voodoo->purpleline[g][0] = lined; voodoo->purpleline[g][2] = lined; lined = g + 0; if (lined > 255) lined = 255; voodoo->purpleline[g][1] = lined; } /* 4x1 and 2x2 filter */ //fcr *= 5; //fcg *= 6; for (g=0;g<256;g++) // pixel 1 { for (h=0;h<256;h++) // pixel 2 { difference = (float)(h - g); diffg = difference; thiscol = thiscolg = g; if (difference > fcr) difference = fcr; if (difference < -fcr) difference = -fcr; if (diffg > fcg) diffg = fcg; if (diffg < -fcg) diffg = -fcg; if ((difference < fcr) || (-difference > -fcr)) thiscol = g + (difference / 2); if ((diffg < fcg) || (-diffg > -fcg)) thiscolg = g + (diffg / 2); if (thiscol < 0) thiscol = 0; if (thiscol > 255) thiscol = 255; if (thiscolg < 0) thiscolg = 0; if (thiscolg > 255) thiscolg = 255; vb_filter_v1_rb[g][h] = thiscol; vb_filter_v1_g [g][h] = thiscolg; } } } 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; int y = voodoo->overlay.src_y >> 20; uint32_t src_addr = svga->overlay_latch.addr + ((banshee->vidProcCfg & VIDPROCCFG_OVERLAY_TILE) ? ((y & 31) * 128 + (y >> 5) * svga->overlay_latch.pitch) : y * svga->overlay_latch.pitch); uint32_t src_addr2 = svga->overlay_latch.addr + ((banshee->vidProcCfg & VIDPROCCFG_OVERLAY_TILE) ? (((y + 1) & 31) * 128 + ((y + 1) >> 5) * svga->overlay_latch.pitch) : (y + 1) * svga->overlay_latch.pitch); uint8_t *src = &svga->vram[src_addr & svga->vram_mask]; uint32_t src_x = 0; unsigned int y_coeff = (voodoo->overlay.src_y & 0xfffff) >> 4; int skip_filtering; uint32_t *clut = &svga->pallook[(banshee->vidProcCfg & VIDPROCCFG_OVERLAY_CLUT_SEL) ? 256 : 0]; if (svga->render == svga_render_null && !svga->changedvram[src_addr >> 12] && !svga->changedvram[src_addr2 >> 12] && !svga->fullchange && ((voodoo->overlay.src_y >> 20) < 2048 && !voodoo->dirty_line[voodoo->overlay.src_y >> 20]) && !(banshee->vidProcCfg & VIDPROCCFG_V_SCALE_ENABLE)) { voodoo->overlay.src_y += (1 << 20); return; } if ((voodoo->overlay.src_y >> 20) < 2048) voodoo->dirty_line[voodoo->overlay.src_y >> 20] = 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]; if (banshee->voodoo->scrfilter && banshee->voodoo->scrfilterEnabled) skip_filtering = ((banshee->vidProcCfg & VIDPROCCFG_FILTER_MODE_MASK) != VIDPROCCFG_FILTER_MODE_BILINEAR && !(banshee->vidProcCfg & VIDPROCCFG_H_SCALE_ENABLE) && !(banshee->vidProcCfg & VIDPROCCFG_FILTER_MODE_DITHER_4X4) && !(banshee->vidProcCfg & VIDPROCCFG_FILTER_MODE_DITHER_2X2)); else skip_filtering = ((banshee->vidProcCfg & VIDPROCCFG_FILTER_MODE_MASK) != VIDPROCCFG_FILTER_MODE_BILINEAR && !(banshee->vidProcCfg & VIDPROCCFG_H_SCALE_ENABLE)); if (skip_filtering) { /*No scaling or filtering required, just write straight to output buffer*/ OVERLAY_SAMPLE(p); } else { OVERLAY_SAMPLE(banshee->overlay_buffer[0]); switch (banshee->vidProcCfg & VIDPROCCFG_FILTER_MODE_MASK) { case VIDPROCCFG_FILTER_MODE_BILINEAR: src = &svga->vram[src_addr2 & svga->vram_mask]; OVERLAY_SAMPLE(banshee->overlay_buffer[1]); if (banshee->vidProcCfg & VIDPROCCFG_H_SCALE_ENABLE) { for (x = 0; x < svga->overlay_latch.xsize; x++) { unsigned int x_coeff = (src_x & 0xfffff) >> 4; unsigned int coeffs[4] = { ((0x10000 - x_coeff) * (0x10000 - y_coeff)) >> 16, ( x_coeff * (0x10000 - y_coeff)) >> 16, ((0x10000 - x_coeff) * y_coeff) >> 16, ( x_coeff * y_coeff) >> 16 }; uint32_t samp0 = banshee->overlay_buffer[0][src_x >> 20]; uint32_t samp1 = banshee->overlay_buffer[0][(src_x >> 20) + 1]; uint32_t samp2 = banshee->overlay_buffer[1][src_x >> 20]; uint32_t samp3 = banshee->overlay_buffer[1][(src_x >> 20) + 1]; int r = (((samp0 >> 16) & 0xff) * coeffs[0] + ((samp1 >> 16) & 0xff) * coeffs[1] + ((samp2 >> 16) & 0xff) * coeffs[2] + ((samp3 >> 16) & 0xff) * coeffs[3]) >> 16; int g = (((samp0 >> 8) & 0xff) * coeffs[0] + ((samp1 >> 8) & 0xff) * coeffs[1] + ((samp2 >> 8) & 0xff) * coeffs[2] + ((samp3 >> 8) & 0xff) * coeffs[3]) >> 16; int b = ((samp0 & 0xff) * coeffs[0] + (samp1 & 0xff) * coeffs[1] + (samp2 & 0xff) * coeffs[2] + (samp3 & 0xff) * coeffs[3]) >> 16; p[x] = (r << 16) | (g << 8) | b; src_x += voodoo->overlay.vidOverlayDudx; } } else { for (x = 0; x < svga->overlay_latch.xsize; x++) { uint32_t samp0 = banshee->overlay_buffer[0][src_x >> 20]; uint32_t samp1 = banshee->overlay_buffer[1][src_x >> 20]; int r = (((samp0 >> 16) & 0xff) * (0x10000 - y_coeff) + ((samp1 >> 16) & 0xff) * y_coeff) >> 16; int g = (((samp0 >> 8) & 0xff) * (0x10000 - y_coeff) + ((samp1 >> 8) & 0xff) * y_coeff) >> 16; int b = ((samp0 & 0xff) * (0x10000 - y_coeff) + (samp1 & 0xff) * y_coeff) >> 16; p[x] = (r << 16) | (g << 8) | b; } } break; case VIDPROCCFG_FILTER_MODE_DITHER_4X4: if (banshee->voodoo->scrfilter && banshee->voodoo->scrfilterEnabled) { //uint8_t fil[(svga->overlay_latch.xsize) * 3]; //uint8_t fil3[(svga->overlay_latch.xsize) * 3]; uint8_t fil[4096 * 3]; uint8_t fil3[4096 * 3]; if (banshee->vidProcCfg & VIDPROCCFG_H_SCALE_ENABLE) /* leilei HACK - don't know of real 4x1 hscaled behavior yet, double for now */ { for (x=0; xoverlay_latch.xsize;x++) { fil[x*3] = ((banshee->overlay_buffer[0][src_x >> 20])); fil[x*3+1] = ((banshee->overlay_buffer[0][src_x >> 20] >> 8)); fil[x*3+2] = ((banshee->overlay_buffer[0][src_x >> 20] >> 16)); fil3[x*3+0] = fil[x*3+0]; fil3[x*3+1] = fil[x*3+1]; fil3[x*3+2] = fil[x*3+2]; src_x += voodoo->overlay.vidOverlayDudx; } } else { for (x=0; xoverlay_latch.xsize;x++) { fil[x*3] = ((banshee->overlay_buffer[0][x])); fil[x*3+1] = ((banshee->overlay_buffer[0][x] >> 8)); fil[x*3+2] = ((banshee->overlay_buffer[0][x] >> 16)); fil3[x*3+0] = fil[x*3+0]; fil3[x*3+1] = fil[x*3+1]; fil3[x*3+2] = fil[x*3+2]; } } if (y % 2 == 0) { for (x=0; xoverlay_latch.xsize;x++) { fil[x*3] = banshee->voodoo->purpleline[fil[x*3+0]][0]; fil[x*3+1] = banshee->voodoo->purpleline[fil[x*3+1]][1]; fil[x*3+2] = banshee->voodoo->purpleline[fil[x*3+2]][2]; } } for (x=1; xoverlay_latch.xsize;x++) { fil3[(x)*3] = vb_filter_v1_rb [fil[x*3]] [fil[(x-1) *3]]; fil3[(x)*3+1] = vb_filter_v1_g [fil[x*3+1]][fil[(x-1) *3+1]]; fil3[(x)*3+2] = vb_filter_v1_rb [fil[x*3+2]] [fil[(x-1) *3+2]]; } for (x=1; xoverlay_latch.xsize;x++) { fil[(x)*3] = vb_filter_v1_rb [fil[x*3]] [fil3[(x-1) *3]]; fil[(x)*3+1] = vb_filter_v1_g [fil[x*3+1]][fil3[(x-1) *3+1]]; fil[(x)*3+2] = vb_filter_v1_rb [fil[x*3+2]] [fil3[(x-1) *3+2]]; } for (x=1; xoverlay_latch.xsize;x++) { fil3[(x)*3] = vb_filter_v1_rb [fil[x*3]] [fil[(x-1) *3]]; fil3[(x)*3+1] = vb_filter_v1_g [fil[x*3+1]][fil[(x-1) *3+1]]; fil3[(x)*3+2] = vb_filter_v1_rb [fil[x*3+2]] [fil[(x-1) *3+2]]; } for (x=0; xoverlay_latch.xsize;x++) { fil[(x)*3] = vb_filter_v1_rb [fil[x*3]] [fil3[(x+1) *3]]; fil[(x)*3+1] = vb_filter_v1_g [fil[x*3+1]][fil3[(x+1) *3+1]]; fil[(x)*3+2] = vb_filter_v1_rb [fil[x*3+2]] [fil3[(x+1) *3+2]]; p[x] = (fil[x*3+2] << 16) | (fil[x*3+1] << 8) | fil[x*3]; } } else /* filter disabled by emulator option */ { if (banshee->vidProcCfg & VIDPROCCFG_H_SCALE_ENABLE) { for (x = 0; x < svga->overlay_latch.xsize; x++) { p[x] = banshee->overlay_buffer[0][src_x >> 20]; src_x += voodoo->overlay.vidOverlayDudx; } } else { for (x = 0; x < svga->overlay_latch.xsize; x++) p[x] = banshee->overlay_buffer[0][x]; } } break; case VIDPROCCFG_FILTER_MODE_DITHER_2X2: if (banshee->voodoo->scrfilter && banshee->voodoo->scrfilterEnabled) { //uint8_t fil[(svga->overlay_latch.xsize) * 3]; //uint8_t soak[(svga->overlay_latch.xsize) * 3]; //uint8_t soak2[(svga->overlay_latch.xsize) * 3]; //uint8_t samp1[(svga->overlay_latch.xsize) * 3]; //uint8_t samp2[(svga->overlay_latch.xsize) * 3]; //uint8_t samp3[(svga->overlay_latch.xsize) * 3]; //uint8_t samp4[(svga->overlay_latch.xsize) * 3]; uint8_t fil[4096 * 3]; uint8_t soak[4096 * 3]; uint8_t soak2[4096 * 3]; uint8_t samp1[4096 * 3]; uint8_t samp2[4096 * 3]; uint8_t samp3[4096 * 3]; uint8_t samp4[4096 * 3]; src = &svga->vram[src_addr2 & svga->vram_mask]; OVERLAY_SAMPLE(banshee->overlay_buffer[1]); for (x=0; xoverlay_latch.xsize;x++) { samp1[x*3] = ((banshee->overlay_buffer[0][x])); samp1[x*3+1] = ((banshee->overlay_buffer[0][x] >> 8)); samp1[x*3+2] = ((banshee->overlay_buffer[0][x] >> 16)); samp2[x*3+0] = ((banshee->overlay_buffer[0][x+1])); samp2[x*3+1] = ((banshee->overlay_buffer[0][x+1] >> 8)); samp2[x*3+2] = ((banshee->overlay_buffer[0][x+1] >> 16)); samp3[x*3+0] = ((banshee->overlay_buffer[1][x])); samp3[x*3+1] = ((banshee->overlay_buffer[1][x] >> 8)); samp3[x*3+2] = ((banshee->overlay_buffer[1][x] >> 16)); samp4[x*3+0] = ((banshee->overlay_buffer[1][x+1])); samp4[x*3+1] = ((banshee->overlay_buffer[1][x+1] >> 8)); samp4[x*3+2] = ((banshee->overlay_buffer[1][x+1] >> 16)); /* sample two lines */ soak[x*3+0] = vb_filter_bx_rb [samp1[x*3+0]] [samp2[x*3+0]]; soak[x*3+1] = vb_filter_bx_g [samp1[x*3+1]] [samp2[x*3+1]]; soak[x*3+2] = vb_filter_bx_rb [samp1[x*3+2]] [samp2[x*3+2]]; soak2[x*3+0] = vb_filter_bx_rb[samp3[x*3+0]] [samp4[x*3+0]]; soak2[x*3+1] = vb_filter_bx_g [samp3[x*3+1]] [samp4[x*3+1]]; soak2[x*3+2] = vb_filter_bx_rb[samp3[x*3+2]] [samp4[x*3+2]]; /* then pour it on the rest */ fil[x*3+0] = vb_filter_v1_rb[soak[x*3+0]] [soak2[x*3+0]]; fil[x*3+1] = vb_filter_v1_g [soak[x*3+1]] [soak2[x*3+1]]; fil[x*3+2] = vb_filter_v1_rb[soak[x*3+2]] [soak2[x*3+2]]; } if (banshee->vidProcCfg & VIDPROCCFG_H_SCALE_ENABLE) /* 2x2 on a scaled low res */ { for (x=0; xoverlay_latch.xsize;x++) { p[x] = (fil[(src_x >> 20)*3+2] << 16) | (fil[(src_x >> 20)*3+1] << 8) | fil[(src_x >> 20)*3]; src_x += voodoo->overlay.vidOverlayDudx; } } else { for (x=0; xoverlay_latch.xsize;x++) { p[x] = (fil[x*3+2] << 16) | (fil[x*3+1] << 8) | fil[x*3]; } } } else /* filter disabled by emulator option */ { if (banshee->vidProcCfg & VIDPROCCFG_H_SCALE_ENABLE) { for (x = 0; x < svga->overlay_latch.xsize; x++) { p[x] = banshee->overlay_buffer[0][src_x >> 20]; src_x += voodoo->overlay.vidOverlayDudx; } } else { for (x = 0; x < svga->overlay_latch.xsize; x++) p[x] = banshee->overlay_buffer[0][x]; } } break; case VIDPROCCFG_FILTER_MODE_POINT: default: if (banshee->vidProcCfg & VIDPROCCFG_H_SCALE_ENABLE) { for (x = 0; x < svga->overlay_latch.xsize; x++) { p[x] = banshee->overlay_buffer[0][src_x >> 20]; src_x += voodoo->overlay.vidOverlayDudx; } } else { for (x = 0; x < svga->overlay_latch.xsize; x++) p[x] = banshee->overlay_buffer[0][x]; } break; } } 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; voodoo_t *voodoo = banshee->voodoo; banshee->svga.overlay.addr = banshee->voodoo->leftOverlayBuf & 0xfffffff; banshee->svga.overlay_latch.addr = banshee->voodoo->leftOverlayBuf & 0xfffffff; memset(voodoo->dirty_line, 1, sizeof(voodoo->dirty_line)); } static void banshee_vsync_callback(svga_t *svga) { banshee_t *banshee = (banshee_t *)svga->p; voodoo_t *voodoo = banshee->voodoo; voodoo->retrace_count++; thread_lock_mutex(voodoo->swap_mutex); if (voodoo->swap_pending && (voodoo->retrace_count > voodoo->swap_interval)) { if (voodoo->swap_count > 0) voodoo->swap_count--; voodoo->swap_pending = 0; thread_unlock_mutex(voodoo->swap_mutex); memset(voodoo->dirty_line, 1, sizeof(voodoo->dirty_line)); voodoo->retrace_count = 0; banshee_set_overlay_addr(banshee, voodoo->swap_offset); thread_set_event(voodoo->wake_fifo_thread); voodoo->frame_count++; } else thread_unlock_mutex(voodoo->swap_mutex); voodoo->overlay.src_y = 0; banshee->desktop_addr = banshee->vidDesktopStartAddr; banshee->desktop_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; if (func) return 0xff; // pclog("Banshee PCI read %08X ", addr); switch (addr) { case 0x00: ret = 0x1a; break; /*3DFX*/ case 0x01: ret = 0x12; break; case 0x02: ret = (banshee->type == TYPE_BANSHEE) ? 0x03 : 0x05; 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 = (banshee->type == TYPE_BANSHEE) ? 3 : 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 = banshee->ioBaseAddr >> 16; break; case 0x1b: ret = banshee->ioBaseAddr >> 24; break; /*Subsystem vendor ID*/ case 0x2c: ret = banshee->pci_regs[0x2c]; break; case 0x2d: ret = banshee->pci_regs[0x2d]; break; case 0x2e: ret = banshee->pci_regs[0x2e]; break; case 0x2f: ret = banshee->pci_regs[0x2f]; 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_pci_write(int func, int addr, uint8_t val, void *p) { banshee_t *banshee = (banshee_t *)p; // svga_t *svga = &banshee->svga; uint32_t basemask = 0xfe; if (func) return; // 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: if (val & PCI_COMMAND_IO) { io_removehandlerx(0x03c0, 0x0020, banshee_in, NULL, NULL, banshee_out, NULL, NULL, banshee); if (banshee->ioBaseAddr) io_removehandlerx(banshee->ioBaseAddr, 0x0100, banshee_ext_in, NULL, banshee_ext_inl, banshee_ext_out, NULL, banshee_ext_outl, banshee); io_sethandlerx(0x03c0, 0x0020, banshee_in, NULL, NULL, banshee_out, NULL, NULL, banshee); if (banshee->ioBaseAddr) io_sethandlerx(banshee->ioBaseAddr, 0x0100, banshee_ext_in, NULL, banshee_ext_inl, banshee_ext_out, NULL, banshee_ext_outl, banshee); } else { io_removehandlerx(0x03c0, 0x0020, banshee_in, NULL, NULL, banshee_out, NULL, NULL, banshee); io_removehandlerx(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; banshee_updatemapping(banshee); return; case 0x07: banshee->pci_regs[0x07] = val & 0x3e; return; case 0x0d: banshee->pci_regs[0x0d] = val & 0xf8; return; case 0x13: banshee->memBaseAddr0 = (val & basemask) << 24; banshee_updatemapping(banshee); return; case 0x17: banshee->memBaseAddr1 = (val & basemask) << 24; banshee_updatemapping(banshee); return; case 0x1a: banshee->ioBaseAddr &= 0xff00ffff; banshee->ioBaseAddr |= val << 16; break; case 0x1b: banshee->ioBaseAddr &= 0x00ffffff; banshee->ioBaseAddr |= val << 24; break; case 0x19: if (banshee->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_IO) io_removehandlerx(banshee->ioBaseAddr, 0x0100, banshee_ext_in, NULL, banshee_ext_inl, banshee_ext_out, NULL, banshee_ext_outl, banshee); banshee->ioBaseAddr &= 0xffff00ff; banshee->ioBaseAddr |= val << 8; if ((banshee->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_IO) && banshee->ioBaseAddr) io_sethandlerx(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_addrx(&banshee->bios_rom.mapping, addr, 0x10000); mem_mapping_enablex(&banshee->bios_rom.mapping); } else { pclog("Banshee bios_rom disabled\n"); mem_mapping_disablex(&banshee->bios_rom.mapping); } return; case 0x3c: banshee->pci_regs[0x3c] = val; return; } } static device_config_t banshee_sgram_config[] = { { .name = "memory", .description = "Memory size", .type = CONFIG_SELECTION, .default_int = 16, .selection = { { .description = "8 MB", .value = 8 }, { .description = "16 MB", .value = 16 }, { .description = "" } } }, { .name = "bilinear", .description = "Bilinear filtering", .type = CONFIG_BINARY, .default_int = 1 }, { .name = "dithersub", .description = "Dither subtraction", .type = CONFIG_BINARY, .default_int = 1 }, { .name = "dacfilter", .description = "Screen Filter", .type = CONFIG_BINARY, .default_int = 0 }, { .name = "render_threads", .description = "Render threads", .type = CONFIG_SELECTION, .default_int = 2, .selection = { { .description = "1", .value = 1 }, { .description = "2", .value = 2 }, { .description = "4", .value = 4 }, { .description = "" } } }, #ifndef NO_CODEGEN { .name = "recompiler", .description = "Recompiler", .type = CONFIG_BINARY, .default_int = 1 }, #endif { .type = -1 } }; static device_config_t banshee_sdram_config[] = { { .name = "bilinear", .description = "Bilinear filtering", .type = CONFIG_BINARY, .default_int = 1 }, { .name = "dithersub", .description = "Dither subtraction", .type = CONFIG_BINARY, .default_int = 1 }, { .name = "dacfilter", .description = "Screen Filter", .type = CONFIG_BINARY, .default_int = 0 }, { .name = "render_threads", .description = "Render threads", .type = CONFIG_SELECTION, .default_int = 2, .selection = { { .description = "1", .value = 1 }, { .description = "2", .value = 2 }, { .description = "4", .value = 4 }, { .description = "" } }, }, #ifndef NO_CODEGEN { .name = "recompiler", .description = "Recompiler", .type = CONFIG_BINARY, .default_int = 1 }, #endif { .type = -1 } }; void voodoo_update_vram(void *p) { banshee_t *banshee = (banshee_t*)p; banshee->voodoo->vram = banshee->svga.vram; banshee->voodoo->fb_mem = banshee->svga.vram; banshee->voodoo->tex_mem[0] = banshee->svga.vram; banshee->voodoo->tex_mem_w[0] = (uint16_t*)banshee->svga.vram; banshee->voodoo->tex_mem[1] = banshee->svga.vram; banshee->voodoo->tex_mem_w[1] = (uint16_t*)banshee->svga.vram; } static void *banshee_init_common(char *fn, int has_sgram, int type, int voodoo_type) { int mem_size; banshee_t *banshee = (banshee_t*)malloc(sizeof(banshee_t)); memset(banshee, 0, sizeof(banshee_t)); banshee->type = type; banshee->intrCtrl = 0x80000000; rom_init(&banshee->bios_rom, fn, 0xc0000, 0x10000, 0xffff, 0, MEM_MAPPING_EXTERNAL); mem_mapping_disablex(&banshee->bios_rom.mapping); if (has_sgram) mem_size = device_get_config_int("memory"); else mem_size = 16; /*SDRAM Banshee only supports 16 MB*/ 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_addx(&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, MEM_MAPPING_EXTERNAL, &banshee->svga); mem_mapping_addx(&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, MEM_MAPPING_EXTERNAL, banshee); mem_mapping_addx(&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, MEM_MAPPING_EXTERNAL, banshee); // io_sethandlerx(0x03c0, 0x0020, banshee_in, NULL, NULL, banshee_out, NULL, NULL, banshee); banshee->svga.bpp = 8; banshee->svga.miscout = 1; banshee->dramInit0 = 1 << 27; if (has_sgram && mem_size == 16) banshee->dramInit0 |= (1 << 26); /*2xSGRAM = 16 MB*/ if (!has_sgram) banshee->dramInit1 = 1 << 30; /*SDRAM*/ banshee->svga.decode_mask = 0x1ffffff; pci_add(banshee_pci_read, banshee_pci_write, banshee); banshee->voodoo = (voodoo_t*)voodoo_2d3d_card_init(voodoo_type); 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->tex_mem[1] = banshee->svga.vram; banshee->voodoo->tex_mem_w[1] = (uint16_t *)banshee->svga.vram; banshee->voodoo->texture_mask = banshee->svga.vram_mask; voodoo_generate_filter_v1(banshee->voodoo); banshee->vidSerialParallelPort = VIDSERIAL_DDC_DCK_W | VIDSERIAL_DDC_DDA_W; //ddc_init(); switch (type) { case TYPE_BANSHEE: if (has_sgram) { banshee->pci_regs[0x2c] = 0x1a; banshee->pci_regs[0x2d] = 0x12; banshee->pci_regs[0x2e] = 0x04; banshee->pci_regs[0x2f] = 0x00; } else { banshee->pci_regs[0x2c] = 0x02; banshee->pci_regs[0x2d] = 0x11; banshee->pci_regs[0x2e] = 0x17; banshee->pci_regs[0x2f] = 0x10; } break; case TYPE_V3_2000: banshee->pci_regs[0x2c] = 0x1a; banshee->pci_regs[0x2d] = 0x12; banshee->pci_regs[0x2e] = 0x30; banshee->pci_regs[0x2f] = 0x00; break; case TYPE_V3_3000: banshee->pci_regs[0x2c] = 0x1a; banshee->pci_regs[0x2d] = 0x12; banshee->pci_regs[0x2e] = 0x3a; banshee->pci_regs[0x2f] = 0x00; break; } banshee->svga.vblank_start = banshee_vblank_start; return banshee; } static void *banshee_init() { return banshee_init_common("pci_sg.rom", 1, TYPE_BANSHEE, VOODOO_BANSHEE); } static void *creative_banshee_init() { return banshee_init_common("blasterpci.rom", 0, TYPE_BANSHEE, VOODOO_BANSHEE); } static void *v3_2000_init() { return banshee_init_common("voodoo3_2000/2k11sd.rom", 0, TYPE_V3_2000, VOODOO_3); } static void *v3_3000_init() { return banshee_init_common("voodoo3_3000/3k12sd.rom", 0, TYPE_V3_3000, VOODOO_3); } static int banshee_available() { return rom_present("pci_sg.rom"); } static int creative_banshee_available() { return rom_present("blasterpci.rom"); } static int v3_2000_available() { return rom_present("voodoo3_2000/2k11sd.rom"); } static int v3_3000_available() { return rom_present("voodoo3_3000/3k12sd.rom"); } 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[4]; int pixel_count_total; int texel_count_current[4]; int texel_count_total; int render_time[4]; uint64_t new_time = timer_read(); uint64_t status_diff = new_time - status_time; int c; status_time = new_time; svga_add_status_info(s, max_len, &banshee->svga); for (c = 0; c < 4; c++) { pixel_count_current[c] = voodoo->pixel_count[c]; texel_count_current[c] = voodoo->texel_count[c]; render_time[c] = voodoo->render_time[c]; } pixel_count_total = (pixel_count_current[0] + pixel_count_current[1] + pixel_count_current[2] + pixel_count_current[3]) - (voodoo->pixel_count_old[0] + voodoo->pixel_count_old[1] + voodoo->pixel_count_old[2] + voodoo->pixel_count_old[3]); texel_count_total = (texel_count_current[0] + texel_count_current[1] + texel_count_current[2] + texel_count_current[3]) - (voodoo->texel_count_old[0] + voodoo->texel_count_old[1] + voodoo->texel_count_old[2] + voodoo->texel_count_old[3]); 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); } if (voodoo->render_threads == 4) { char temps2[512]; sprintf(temps2, "%f%% CPU (%f%% real)\n%f%% CPU (%f%% real)\n", ((double)voodoo->render_time[2] * 100.0) / timer_freq, ((double)voodoo->render_time[2] * 100.0) / status_diff, ((double)voodoo->render_time[3] * 100.0) / timer_freq, ((double)voodoo->render_time[3] * 100.0) / status_diff); strncat(temps, temps2, sizeof(temps)-1); } strncat(s, temps, max_len); strncat(s, "Overlay mode: ", max_len); /* leilei debug additions */ if ((banshee->vidProcCfg & VIDPROCCFG_FILTER_MODE_MASK) == VIDPROCCFG_FILTER_MODE_DITHER_2X2) strncat(s, "2x2 box filter\n", max_len); if ((banshee->vidProcCfg & VIDPROCCFG_FILTER_MODE_MASK) == VIDPROCCFG_FILTER_MODE_DITHER_4X4) strncat(s, "4x1 tap filter\n", max_len); if ((banshee->vidProcCfg & VIDPROCCFG_FILTER_MODE_MASK) == VIDPROCCFG_FILTER_MODE_POINT) strncat(s, "Nearest neighbor\n", max_len); if ((banshee->vidProcCfg & VIDPROCCFG_FILTER_MODE_MASK) == VIDPROCCFG_FILTER_MODE_BILINEAR) strncat(s, "Bilinear filtered\n", max_len); if ((banshee->vidProcCfg & VIDPROCCFG_H_SCALE_ENABLE)) strncat(s, "H scaled \n", max_len); if ((banshee->vidProcCfg & VIDPROCCFG_V_SCALE_ENABLE)) strncat(s, "V scaled \n", max_len); if ((banshee->vidProcCfg & VIDPROCCFG_2X_MODE)) strncat(s, "2X mode\n", max_len); strncat(s, "\n", max_len); for (c = 0; c < 4; c++) { voodoo->pixel_count_old[c] = pixel_count_current[c]; voodoo->texel_count_old[c] = texel_count_current[c]; voodoo->render_time[c] = 0; } voodoo->tri_count = voodoo->frame_count = 0; voodoo->rd_count = voodoo->wr_count = voodoo->tex_count = 0; voodoo->time = 0; voodoo->read_time = pci_nonburst_time + pci_burst_time; voodoo_recomp = 0; } device_t voodoo_banshee_device = { "Voodoo Banshee PCI (reference)", DEVICE_PCI, banshee_init, banshee_close, banshee_available, banshee_speed_changed, banshee_force_redraw, banshee_add_status_info, banshee_sgram_config }; device_t creative_voodoo_banshee_device = { "Creative Labs 3D Blaster Banshee PCI", DEVICE_PCI, creative_banshee_init, banshee_close, creative_banshee_available, banshee_speed_changed, banshee_force_redraw, banshee_add_status_info, banshee_sdram_config }; device_t voodoo_3_2000_device = { "Voodoo 3 2000 PCI", DEVICE_PCI, v3_2000_init, banshee_close, v3_2000_available, banshee_speed_changed, banshee_force_redraw, banshee_add_status_info, banshee_sdram_config }; device_t voodoo_3_3000_device = { "Voodoo 3 3000 PCI", DEVICE_PCI, v3_3000_init, banshee_close, v3_3000_available, banshee_speed_changed, banshee_force_redraw, banshee_add_status_info, banshee_sdram_config };