Some work on the Voodoo Banshee emulation.

- Fixed hardware cursor bottom/right edge display bug.
- Started splitting 2D code in different methods (no functional changes).
- Added hardware cursor to save/restore list.
TODO #1: Implement bitblt engine similar to the Cirrus one.
TODO #2: Voodoo code reorganization: base class with Voodoo core, one subclass
         for Voodoo1/2 and one for Banshee.
This commit is contained in:
Volker Ruppert 2017-10-31 22:58:10 +00:00
parent 78ef782b38
commit 815b8238c7
4 changed files with 156 additions and 51 deletions

View File

@ -564,7 +564,17 @@ void bx_voodoo_c::register_state(void)
if (BX_VOODOO_THIS s.model == VOODOO_BANSHEE) {
bx_list_c *banshee = new bx_list_c(list, "banshee", "Voodoo Banshee State");
new bx_shadow_data_c(banshee, "io", (Bit8u*)v->banshee.io, 256, 1);
new bx_shadow_data_c(banshee, "agp", (Bit8u*)v->banshee.agp, 0x80, 1);
new bx_shadow_data_c(banshee, "crtc", (Bit8u*)v->banshee.crtc, 0x27, 1);
new bx_shadow_data_c(banshee, "blt_reg", (Bit8u*)v->banshee.blt.reg, 0x80, 1);
new bx_shadow_num_c(banshee, "bpp", &v->banshee.bpp);
new bx_shadow_bool_c(banshee, "hwcursor_enabled", &v->banshee.hwcursor.enabled);
new bx_shadow_bool_c(banshee, "hwcursor_mode", &v->banshee.hwcursor.mode);
new bx_shadow_num_c(banshee, "hwcursor_addr", &v->banshee.hwcursor.addr, BASE_HEX);
new bx_shadow_num_c(banshee, "hwcursor_x", &v->banshee.hwcursor.x, BASE_HEX);
new bx_shadow_num_c(banshee, "hwcursor_y", &v->banshee.hwcursor.y, BASE_HEX);
new bx_shadow_num_c(banshee, "hwcursor_color0", &v->banshee.hwcursor.color[0], BASE_HEX);
new bx_shadow_num_c(banshee, "hwcursor_color1", &v->banshee.hwcursor.color[1], BASE_HEX);
// TODO
}
bx_list_c *vdraw = new bx_list_c(list, "vdraw", "Voodoo Draw State");
@ -1452,7 +1462,7 @@ Bit32u bx_voodoo_c::banshee_blt_reg_read(Bit8u reg)
result = register_r(0);
break;
default:
result = v->banshee.blt[reg];
result = v->banshee.blt.reg[reg];
}
BX_DEBUG(("2D read register 0x%03x result = 0x%08x", reg<<2, result));
return result;
@ -1460,67 +1470,43 @@ Bit32u bx_voodoo_c::banshee_blt_reg_read(Bit8u reg)
void bx_voodoo_c::banshee_blt_reg_write(Bit8u reg, Bit32u value)
{
Bit32u start = v->banshee.io[io_vidDesktopStartAddr] & v->fbi.mask;
Bit8u *disp_ptr = &v->fbi.ram[start];
Bit8u *vid_ptr, *vid_ptr2;
Bit32u pitch = v->banshee.io[io_vidDesktopOverlayStride] & 0x7fff;
Bit32u color;
Bit16u x0, y0, x, y, w, h;
BX_DEBUG(("2D write register 0x%03x value = 0x%08x", reg<<2, value));
v->banshee.blt[reg] = value;
v->banshee.blt.reg[reg] = value;
if (reg == blt_intrCtrl) {
BX_ERROR(("intrCtrl register not supported yet"));
} else if (reg == blt_command) {
switch (value & 0x0f) {
v->banshee.blt.cmd = (value & 0x0f);
v->banshee.blt.immed = (value >> 8) & 1;
v->banshee.blt.x_dir = (value >> 14) & 1;
v->banshee.blt.y_dir = (value >> 15) & 1;
v->banshee.blt.rop0 = (value >> 24);
v->banshee.blt.src_x = v->banshee.blt.reg[blt_srcXY] & 0x1fff;
v->banshee.blt.src_y= (v->banshee.blt.reg[blt_srcXY] >> 16) & 0x1fff;
v->banshee.blt.dst_x = v->banshee.blt.reg[blt_dstXY] & 0x1fff;
v->banshee.blt.dst_y= (v->banshee.blt.reg[blt_dstXY] >> 16) & 0x1fff;
v->banshee.blt.dst_w = v->banshee.blt.reg[blt_dstSize] & 0x1fff;
v->banshee.blt.dst_h = (v->banshee.blt.reg[blt_dstSize] >> 16) & 0x1fff;
v->banshee.blt.busy = 1;
switch (v->banshee.blt.cmd) {
case 0: // NOP
break;
case 1:
BX_INFO(("TODO: 2D Screen to screen blt"));
v->banshee.blt.busy = 1;
banshee_blt_screen_to_screen();
break;
case 2:
BX_INFO(("TODO: 2D Screen to screen stretch blt"));
break;
case 3:
BX_INFO(("TODO: 2D Host to screen blt"));
v->banshee.blt.busy = 1;
banshee_blt_host_to_screen();
break;
case 4:
BX_INFO(("TODO: 2D Host to screen stretch blt"));
break;
case 5:
color = v->banshee.blt[blt_colorFore];
x0 = v->banshee.blt[blt_dstXY] & 0x1fff;
y0 = (v->banshee.blt[blt_dstXY] >> 16) & 0x1fff;
w = v->banshee.blt[blt_dstSize] & 0x1fff;
h = (v->banshee.blt[blt_dstSize] >> 16) & 0x1fff;
vid_ptr = disp_ptr + (y0 * pitch + x0);
for (y = y0; y < (y0 + h); y++) {
vid_ptr2 = vid_ptr;
for (x = x0; x < (x0 + w); x++) {
switch (v->banshee.bpp) {
case 8:
*(vid_ptr2++) = (color & 0xff);
break;
case 16:
*(vid_ptr2++) = (color & 0xff);
*(vid_ptr2++) = ((color >> 8) & 0xff);
break;
case 24:
*(vid_ptr2++) = (color & 0xff);
*(vid_ptr2++) = ((color >> 8) & 0xff);
*(vid_ptr2++) = ((color >> 16) & 0xff);
break;
case 32:
*(vid_ptr2++) = (color & 0xff);
*(vid_ptr2++) = ((color >> 8) & 0xff);
*(vid_ptr2++) = ((color >> 16) & 0xff);
*(vid_ptr2++) = ((color >> 24) & 0xff);
break;
}
}
vid_ptr += pitch;
}
theVoodooVga->redraw_area(x0, y0, w, h);
v->banshee.blt.busy = 1;
banshee_blt_rectangle_fill();
break;
case 6:
BX_INFO(("TODO: 2D Line"));
@ -1533,19 +1519,116 @@ void bx_voodoo_c::banshee_blt_reg_write(Bit8u reg, Bit32u value)
break;
case 13:
BX_INFO(("TODO: 2D Write Sgram Mode register"));
break;
return;
case 14:
BX_INFO(("TODO: 2D Write Sgram Mask register"));
break;
return;
case 15:
BX_INFO(("TODO: 2D Write Sgram Color register"));
break;
return;
default:
BX_ERROR(("Unsupported 2D mode"));
}
if (v->banshee.blt.immed) {
banshee_blt_complete();
}
} else if ((reg >= 0x20) && (reg < 0x40)) {
banshee_blt_launch_area_write(value);
} else if ((reg >= 0x40) && (reg < 0x80)) {
BX_DEBUG(("colorPattern write"));
}
}
void bx_voodoo_c::banshee_blt_launch_area_write(Bit32u value)
{
BX_INFO(("launchArea write not handled yet"));
}
void bx_voodoo_c::banshee_blt_complete()
{
Bit32u cmd = v->banshee.blt.reg[blt_command];
bx_bool xinc = (cmd >> 10) & 1;
bx_bool yinc = (cmd >> 11) & 1;
theVoodooVga->redraw_area(v->banshee.blt.dst_x, v->banshee.blt.dst_y,
v->banshee.blt.dst_w, v->banshee.blt.dst_h);
if (xinc) {
if (v->banshee.blt.x_dir) {
v->banshee.blt.dst_x -= v->banshee.blt.dst_w;
} else {
v->banshee.blt.dst_x += v->banshee.blt.dst_w;
}
v->banshee.blt.reg[blt_dstXY] &= ~0xffff;
v->banshee.blt.reg[blt_dstXY] |= v->banshee.blt.dst_x;
}
if (yinc) {
if (v->banshee.blt.y_dir) {
v->banshee.blt.dst_y -= v->banshee.blt.dst_h;
} else {
v->banshee.blt.dst_y += v->banshee.blt.dst_h;
}
v->banshee.blt.reg[blt_dstXY] &= 0xffff;
v->banshee.blt.reg[blt_dstXY] |= (v->banshee.blt.dst_y << 16);
}
}
void bx_voodoo_c::banshee_blt_rectangle_fill()
{
Bit32u start = v->banshee.io[io_vidDesktopStartAddr] & v->fbi.mask;
Bit8u *disp_ptr = &v->fbi.ram[start];
Bit8u *vid_ptr, *vid_ptr2;
Bit32u pitch = v->banshee.io[io_vidDesktopOverlayStride] & 0x7fff;
Bit32u color;
Bit16u x, y, x0, y0, w, h;
BX_DEBUG(("Rectangle fill"));
x0 = v->banshee.blt.dst_x;
y0 = v->banshee.blt.dst_y;
w = v->banshee.blt.dst_w;
h = v->banshee.blt.dst_h;
color = v->banshee.blt.reg[blt_colorFore];
vid_ptr = disp_ptr + y0 * pitch + x0 * (v->banshee.bpp >> 3);
for (y = y0; y < (y0 + h); y++) {
vid_ptr2 = vid_ptr;
for (x = x0; x < (x0 + w); x++) {
switch (v->banshee.bpp) {
case 8:
*(vid_ptr2++) = (color & 0xff);
break;
case 16:
*(vid_ptr2++) = (color & 0xff);
*(vid_ptr2++) = ((color >> 8) & 0xff);
break;
case 24:
*(vid_ptr2++) = (color & 0xff);
*(vid_ptr2++) = ((color >> 8) & 0xff);
*(vid_ptr2++) = ((color >> 16) & 0xff);
break;
case 32:
*(vid_ptr2++) = (color & 0xff);
*(vid_ptr2++) = ((color >> 8) & 0xff);
*(vid_ptr2++) = ((color >> 16) & 0xff);
*(vid_ptr2++) = ((color >> 24) & 0xff);
break;
}
}
vid_ptr += pitch;
}
v->banshee.blt.busy = 0;
}
void bx_voodoo_c::banshee_blt_screen_to_screen()
{
BX_INFO(("TODO: 2D Screen to screen blt (command=0x%08x)", v->banshee.blt.reg[blt_command]));
v->banshee.blt.busy = 0;
}
void bx_voodoo_c::banshee_blt_host_to_screen()
{
BX_INFO(("TODO: 2D Host to screen blt (command=0x%08x)", v->banshee.blt.reg[blt_command]));
v->banshee.blt.busy = 0;
}
#undef LOG_THIS
#define LOG_THIS theVoodooVga->
@ -1726,8 +1809,8 @@ void bx_voodoo_vga_c::banshee_draw_hwcursor(unsigned xc, unsigned yc, bx_svga_ti
ch = h - (v->banshee.hwcursor.y - 63 - yc);
py = 0;
}
tile_ptr += ((h - ch) * info->pitch);
tile_ptr += ((w - cw) * (info->bpp >> 3));
tile_ptr += ((cy - yc) * info->pitch);
tile_ptr += ((cx - xc) * (info->bpp >> 3));
cpat0 = &v->fbi.ram[v->banshee.hwcursor.addr] + (py * 16);
for (y = cy; y < (cy + ch); y++) {
cpat1 = cpat0 + (px >> 3);

View File

@ -74,6 +74,12 @@ public:
Bit32u banshee_blt_reg_read(Bit8u reg);
void banshee_blt_reg_write(Bit8u reg, Bit32u value);
void banshee_blt_launch_area_write(Bit32u value);
void banshee_blt_complete(void);
void banshee_blt_rectangle_fill(void);
void banshee_blt_screen_to_screen(void);
void banshee_blt_host_to_screen(void);
private:
bx_voodoo_t s;

View File

@ -1697,7 +1697,6 @@ struct _banshee_info
{
Bit32u io[0x40]; /* I/O registers */
Bit32u agp[0x80]; /* AGP registers */
Bit32u blt[0x80]; /* 2D registers */
Bit8u crtc[0x27]; /* VGA CRTC registers */
Bit8u bpp;
struct {
@ -1708,6 +1707,21 @@ struct _banshee_info
Bit16u y;
Bit32u color[2];
} hwcursor;
struct {
Bit32u reg[0x80]; /* 2D registers */
Bit8u cmd;
bx_bool immed;
bx_bool busy;
Bit16u src_x;
Bit16u src_y;
Bit16u dst_x;
Bit16u dst_y;
Bit16u dst_w;
Bit16u dst_h;
bx_bool x_dir;
bx_bool y_dir;
Bit8u rop0;
} blt;
};

View File

@ -3048,6 +3048,8 @@ Bit32u register_r(Bit32u offset)
else
{
/* bit 10 is 2D busy */
if (v->banshee.blt.busy)
result |= 1 << 10;
/* bit 11 is cmd FIFO 0 busy */
if (v->fbi.cmdfifo[0].enabled && v->fbi.cmdfifo[0].depth > 0)