video/virge_pci.cpp: fix remapping, allow pcipc with ibm5170_hdd:win98se to boot without hacks in 256 color mode (#10804)

* video/virge_pci.cpp: fix remapping, allow pcipc with ibm5170_hdd:win98se to boot without hacks in 256 color mode

* bus/isa/s3virge.cpp: implement DPna, DSna, DSno, DSPDxax and DSo ROP opcodes

* video/virge_pci.cpp: hookup VGA ports to MMIO, makes HW mouse cursor usable

* bus/isa/s3virge.cpp: fix device_reset inheritance, make s3d to start in idle state

* bus/isa/s3virge.cpp: fix source pitch stride

* bus/isa/s3virge.cpp: make bitblt_colour_step / bitblt_monosrc_step a bit less verbose

* bus/isa/s3virge.cpp: stride follows up what's reading it

* bus/isa/s3virge.cpp: clip against de bit

* video/virge_pci.cpp: update BAR fix to catchup lower address config

* bus/isa/s3virge.cpp: initialize pattern variable in mono mode

* bus/isa/s3virge.cpp: fix mistake with shift << 8 in 8bpp pattern path, fixes Windows tooltips/Windows XP welcome setup screen

* bus/isa/s3virge.cpp: QA notes
This commit is contained in:
Angelo Salese 2023-01-10 14:10:57 +01:00 committed by GitHub
parent 5a29410b26
commit b0c64c29af
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 194 additions and 84 deletions

View File

@ -9,6 +9,19 @@
* - Working on getting VESA video modes working better - 800x600 and higher skip every other line at
* 8-bit depth, but are fine at 15/16-bit depth.
* - S3D is not implemented at all, so no 2D/3D acceleration yet.
*
* TODO:
* - Proper FIFOs;
* - Implement 3d commands;
* - Implement remaining ROP commands;
* - Secondary stream mixing;
* - S3 Scenic Highway i/f (SAA7110 + S3 Scenic/MX2 MPEG-1);
* - DMAs;
* - interrupts;
* - big endian support for non-x86 machines;
* - DDC/I2C i/f, cfr. serial port on MMFF20
* - win98se: doesn't show transparent layer on shut down screen;
*
*/
#include "emu.h"
@ -137,15 +150,23 @@ void s3virgedx_rev1_vga_device::device_start()
void s3virge_vga_device::device_reset()
{
vga_device::device_reset();
s3_vga_device::device_reset();
// Power-on strapping bits. Sampled at reset, but can be modified later.
// These are just assumed defaults.
s3.strapping = 0x000f0912;
// TODO: fix soft reset state
// On Windows 98 shutdown message sometimes leads to an hang the next boot around
s3virge.s3d.state = S3D_STATE_IDLE;
s3virge.s3d.cmd_fifo_current_ptr = 0;
s3virge.s3d.cmd_fifo_slots_free = 16;
s3virge.s3d.busy = false;
//m_draw_timer->adjust(attotime::never);
}
void s3virgedx_vga_device::device_reset()
{
vga_device::device_reset();
s3virge_vga_device::device_reset();
// Power-on strapping bits. Sampled at reset, but can be modified later.
// These are just assumed defaults.
s3.strapping = 0x000f0912;
@ -153,7 +174,7 @@ void s3virgedx_vga_device::device_reset()
void s3virgedx_rev1_vga_device::device_reset()
{
vga_device::device_reset();
s3virgedx_vga_device::device_reset();
// Power-on strapping bits. Sampled at reset, but can be modified later.
// These are based on results from a Diamond Stealth 3D 2000 Pro (Virge/DX based)
// bits 8-15 are still unknown, S3ID doesn't show config register 2 (CR37)
@ -1035,6 +1056,12 @@ uint32_t s3virge_vga_device::GetROP(uint8_t rop, uint32_t src, uint32_t dst, uin
case 0x00: // 0
ret = 0;
break;
case 0x0a: // DPna
ret = (dst & (~pat));
break;
case 0x22: // DSna
ret = (dst & (~src));
break;
case 0x55: // Dn
ret = ~dst;
break;
@ -1049,11 +1076,19 @@ uint32_t s3virge_vga_device::GetROP(uint8_t rop, uint32_t src, uint32_t dst, uin
break;
case 0xb8: // PSDPxax
ret = ((dst ^ pat) & src) ^ pat;
// machine().debug_break();
break;
case 0xbb: // DSno
ret = (dst | (~src));
break;
case 0xcc:
ret = src;
break;
case 0xe2: // DSPDxax
ret = ((pat ^ dst) & src) ^ dst;
break;
case 0xee: // DSo
ret = (dst | src);
break;
case 0xf0:
ret = pat;
break;
@ -1061,7 +1096,7 @@ uint32_t s3virge_vga_device::GetROP(uint8_t rop, uint32_t src, uint32_t dst, uin
ret = 0xffffffff;
break;
default:
popmessage("Unimplemented ROP 0x%02x",rop);
popmessage("bus/isa/s3virge.cpp: Unimplemented ROP 0x%02x",rop);
}
return ret;
@ -1147,12 +1182,17 @@ void s3virge_vga_device::bitblt_colour_step()
// get source and destination addresses
uint32_t src_base = s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_SRC_BASE] & 0x003ffff8;
uint32_t dst_base = s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_DEST_BASE] & 0x003ffff8;
uint8_t pixel_size = (s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x0000001c) >> 2;
uint8_t rop = (s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x01fe0000) >> 17;
const u32 current_command = s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND];
const uint8_t pixel_size = (current_command & 0x0000001c) >> 2;
const uint8_t rop = (current_command & 0x01fe0000) >> 17;
const int align = (current_command & 0x000000c00) >> 10;
//const bool tp = bool(BIT(current_command, 9));
const bool de = bool(BIT(current_command, 5));
uint32_t src = 0;
uint32_t dst = 0;
uint32_t pat = 0;
int align = (s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x000000c00) >> 10;
int x;
bool done = false;
@ -1161,26 +1201,31 @@ void s3virge_vga_device::bitblt_colour_step()
case 0: // 8bpp
for(x=0;x<4;x++)
{
if(s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x80)
if(current_command & 0x80)
src = s3virge.s3d.image_xfer >> (x*8);
else
src = read_pixel8(src_base,s3virge.s3d.bitblt_x_src_current,s3virge.s3d.bitblt_y_src_current);
if(s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x100)
src = read_pixel8(src_base,s3virge.s3d.bitblt_x_src_current,s3virge.s3d.bitblt_y_src_current, src_stride());
if(current_command & 0x100)
{
pat = (s3virge.s3d.bitblt_mono_pattern & (1 << ((s3virge.s3d.bitblt_pat_y*8) + (7-s3virge.s3d.bitblt_pat_x)))
? s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_PAT_FG_CLR] : s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_PAT_BG_CLR]);
}
else
pat = (s3virge.s3d.pattern[(s3virge.s3d.bitblt_pat_y*8) + s3virge.s3d.bitblt_pat_x]) << 8;
dst = read_pixel8(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current);
write_pixel8(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current,GetROP(rop, src, dst, pat) & 0xff);
{
pat = s3virge.s3d.pattern[(s3virge.s3d.bitblt_pat_y * 8) + s3virge.s3d.bitblt_pat_x];
}
dst = read_pixel8(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current, dest_stride());
if (de)
write_pixel8(dst_base, s3virge.s3d.bitblt_x_current, s3virge.s3d.bitblt_y_current, GetROP(rop, src, dst, pat) & 0xff);
done = advance_pixel();
if(done)
{
command_finish();
break;
}
if((s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x80) && s3virge.s3d.bitblt_x_current == s3virge.s3d.bitblt_x_dst)
if((current_command & 0x80) && s3virge.s3d.bitblt_x_current == s3virge.s3d.bitblt_x_dst)
{
if(align == 2) // doubleword aligned, end here
break;
@ -1195,45 +1240,48 @@ void s3virge_vga_device::bitblt_colour_step()
}
break;
case 1: // 16bpp
if(s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x80)
if(current_command & 0x80)
src = s3virge.s3d.image_xfer;
else
src = read_pixel16(src_base,s3virge.s3d.bitblt_x_src_current,s3virge.s3d.bitblt_y_src_current);
dst = read_pixel16(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current);
if(s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x100)
src = read_pixel16(src_base,s3virge.s3d.bitblt_x_src_current,s3virge.s3d.bitblt_y_src_current, src_stride());
dst = read_pixel16(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current, dest_stride());
if(current_command & 0x100)
{
pat = (s3virge.s3d.bitblt_mono_pattern & (1 << ((s3virge.s3d.bitblt_pat_y*8) + (7-s3virge.s3d.bitblt_pat_x)))
? s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_PAT_FG_CLR] : s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_PAT_BG_CLR]);
}
else
pat = s3virge.s3d.pattern[(s3virge.s3d.bitblt_pat_y*16) + (s3virge.s3d.bitblt_pat_x*2)] | (s3virge.s3d.pattern[(s3virge.s3d.bitblt_pat_y*16) + (s3virge.s3d.bitblt_pat_x*2) + 1]) << 8;
write_pixel16(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current,GetROP(rop, src, dst, pat) & 0xffff);
if (de)
write_pixel16(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current,GetROP(rop, src, dst, pat) & 0xffff);
done = advance_pixel();
if(done)
{
command_finish();
break;
}
if((s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x80) && s3virge.s3d.bitblt_x_current == s3virge.s3d.bitblt_x_dst && align == 2)
if((current_command & 0x80) && s3virge.s3d.bitblt_x_current == s3virge.s3d.bitblt_x_dst && align == 2)
break; // if a new line of an image transfer, and is dword aligned, stop here
if(s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x80)
if(current_command & 0x80)
src = s3virge.s3d.image_xfer >> 16;
else
src = read_pixel16(src_base,s3virge.s3d.bitblt_x_src_current,s3virge.s3d.bitblt_y_src_current);
dst = read_pixel16(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current);
if(s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x100)
src = read_pixel16(src_base,s3virge.s3d.bitblt_x_src_current,s3virge.s3d.bitblt_y_src_current, src_stride());
dst = read_pixel16(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current, dest_stride());
if(current_command & 0x100)
{
pat = (s3virge.s3d.bitblt_mono_pattern & (1 << ((s3virge.s3d.bitblt_pat_y*8) + (7-s3virge.s3d.bitblt_pat_x)))
? s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_PAT_FG_CLR] : s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_PAT_BG_CLR]);
}
else
pat = s3virge.s3d.pattern[(s3virge.s3d.bitblt_pat_y*16) + (s3virge.s3d.bitblt_pat_x*2)] | (s3virge.s3d.pattern[(s3virge.s3d.bitblt_pat_y*16) + (s3virge.s3d.bitblt_pat_x*2) + 1]) << 8;
write_pixel16(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current,GetROP(rop, src, dst, pat) & 0xffff);
if (de)
write_pixel16(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current,GetROP(rop, src, dst, pat) & 0xffff);
if(advance_pixel())
command_finish();
break;
case 2: // 24bpp
if(s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x80)
if(current_command & 0x80)
{
src = s3virge.s3d.image_xfer;
for(x=0;x<4;x++)
@ -1243,8 +1291,8 @@ void s3virge_vga_device::bitblt_colour_step()
if(s3virge.s3d.bitblt_pixel_pos > 2)
{
s3virge.s3d.bitblt_pixel_pos = 0;
dst = read_pixel24(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current);
if(s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x100)
dst = read_pixel24(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current, dest_stride());
if(current_command & 0x100)
{
pat = (s3virge.s3d.bitblt_mono_pattern & (1 << ((s3virge.s3d.bitblt_pat_y*8) + (7-s3virge.s3d.bitblt_pat_x)))
? s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_PAT_FG_CLR] : s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_PAT_BG_CLR]);
@ -1252,10 +1300,11 @@ void s3virge_vga_device::bitblt_colour_step()
else
pat = s3virge.s3d.pattern[(s3virge.s3d.bitblt_pat_y*24) + (s3virge.s3d.bitblt_pat_x*3)] | (s3virge.s3d.pattern[(s3virge.s3d.bitblt_pat_y*24) + (s3virge.s3d.bitblt_pat_x*3) + 1]) << 8
| (s3virge.s3d.pattern[(s3virge.s3d.bitblt_pat_y*24) + (s3virge.s3d.bitblt_pat_x*3) + 2]) << 16;
write_pixel24(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current,GetROP(rop, s3virge.s3d.bitblt_current_pixel, dst, pat));
if (de)
write_pixel24(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current,GetROP(rop, s3virge.s3d.bitblt_current_pixel, dst, pat));
s3virge.s3d.bitblt_current_pixel = 0;
done = advance_pixel();
if((s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x80) && s3virge.s3d.bitblt_x_current == s3virge.s3d.bitblt_x_dst)
if((current_command & 0x80) && s3virge.s3d.bitblt_x_current == s3virge.s3d.bitblt_x_dst)
{
if(align == 2) // doubleword aligned, end here
x = 4;
@ -1275,9 +1324,9 @@ void s3virge_vga_device::bitblt_colour_step()
}
else
{
src = read_pixel24(src_base,s3virge.s3d.bitblt_x_src_current,s3virge.s3d.bitblt_y_src_current);
dst = read_pixel24(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current);
if(s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x100)
src = read_pixel24(src_base,s3virge.s3d.bitblt_x_src_current,s3virge.s3d.bitblt_y_src_current, src_stride());
dst = read_pixel24(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current, dest_stride());
if(current_command & 0x100)
{
pat = (s3virge.s3d.bitblt_mono_pattern & (1 << ((s3virge.s3d.bitblt_pat_y*8) + (7-s3virge.s3d.bitblt_pat_x)))
? s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_PAT_FG_CLR] : s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_PAT_BG_CLR]);
@ -1286,7 +1335,8 @@ void s3virge_vga_device::bitblt_colour_step()
pat = s3virge.s3d.pattern[(s3virge.s3d.bitblt_pat_y*24) + (s3virge.s3d.bitblt_pat_x*3)] | (s3virge.s3d.pattern[(s3virge.s3d.bitblt_pat_y*24) + (s3virge.s3d.bitblt_pat_x*3) + 1]) << 8
| (s3virge.s3d.pattern[(s3virge.s3d.bitblt_pat_y*24) + (s3virge.s3d.bitblt_pat_x*3) + 2]) << 16;
}
write_pixel24(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current,GetROP(rop, src, dst, pat));
if (de)
write_pixel24(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current,GetROP(rop, src, dst, pat));
if(advance_pixel())
command_finish();
break;
@ -1300,12 +1350,19 @@ void s3virge_vga_device::bitblt_monosrc_step()
// progress current monochrome source BitBLT operation
uint32_t src_base = s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_SRC_BASE] & 0x003ffff8;
uint32_t dst_base = s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_DEST_BASE] & 0x003ffff8;
uint8_t pixel_size = (s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x0000001c) >> 2;
uint8_t rop = (s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x01fe0000) >> 17;
const u32 current_command = s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND];
const uint8_t pixel_size = (current_command & 0x0000001c) >> 2;
const uint8_t rop = (current_command & 0x01fe0000) >> 17;
//const bool tp = bool(BIT(current_command, 9));
const bool de = bool(BIT(current_command, 5));
const int align = (current_command & 0x000000c00) >> 10;
uint32_t src = 0;
uint32_t dst = 0;
uint32_t pat = 0;
int align = (s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x000000c00) >> 10;
// Windows 98 cares about this being initialized to non-zero for
// greyed back/forward icons in Explorer, system icons and right click disabled Paste command.
uint32_t pat = s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_PAT_FG_CLR];
int x;
bool done = false;
@ -1314,19 +1371,22 @@ void s3virge_vga_device::bitblt_monosrc_step()
case 0: // 8bpp
for(x=31;x>=0;x--)
{
if(s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x80)
if(current_command & 0x80)
src = bitswap<32>(s3virge.s3d.image_xfer,7,6,5,4,3,2,1,0,15,14,13,12,11,10,9,8,23,22,21,20,19,18,17,16,31,30,29,28,27,26,25,24);
else
src = read_pixel8(src_base,s3virge.s3d.bitblt_x_src_current,s3virge.s3d.bitblt_y_src_current);
dst = read_pixel8(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current);
src = read_pixel8(src_base,s3virge.s3d.bitblt_x_src_current,s3virge.s3d.bitblt_y_src_current, src_stride());
dst = read_pixel8(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current, dest_stride());
if(src & (1 << x))
write_pixel8(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current,GetROP(rop, s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_SRC_FG_CLR], dst, pat) & 0xff);
else if(!(s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x200)) // only draw background colour if transparency is not set
write_pixel8(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current,GetROP(rop, s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_SRC_BG_CLR], dst, pat) & 0xff);
if (de)
{
if(src & (1 << x))
write_pixel8(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current,GetROP(rop, s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_SRC_FG_CLR], dst, pat) & 0xff);
else if(!(current_command & 0x200)) // only draw background colour if transparency is not set
write_pixel8(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current,GetROP(rop, s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_SRC_BG_CLR], dst, pat) & 0xff);
}
//printf("Pixel write(%i): X: %i Y: %i SRC: %04x DST: %04x PAT: %04x ROP: %02x\n",x,s3virge.s3d.bitblt_x_current, s3virge.s3d.bitblt_y_current, src, dst, pat, rop);
done = advance_pixel();
if((s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x80) && s3virge.s3d.bitblt_x_current == s3virge.s3d.bitblt_x_dst)
if((current_command & 0x80) && s3virge.s3d.bitblt_x_current == s3virge.s3d.bitblt_x_dst)
{
switch(align)
{
@ -1351,19 +1411,22 @@ void s3virge_vga_device::bitblt_monosrc_step()
case 1: // 16bpp
for(x=31;x>=0;x--)
{
if(s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x80)
if(current_command & 0x80)
src = bitswap<32>(s3virge.s3d.image_xfer,7,6,5,4,3,2,1,0,15,14,13,12,11,10,9,8,23,22,21,20,19,18,17,16,31,30,29,28,27,26,25,24);
else
src = read_pixel16(src_base,s3virge.s3d.bitblt_x_src_current,s3virge.s3d.bitblt_y_src_current);
dst = read_pixel16(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current);
src = read_pixel16(src_base,s3virge.s3d.bitblt_x_src_current,s3virge.s3d.bitblt_y_src_current, src_stride());
dst = read_pixel16(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current, dest_stride());
if(src & (1 << x))
write_pixel16(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current,GetROP(rop, s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_SRC_FG_CLR], dst, pat) & 0xffff);
else if(!(s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x200)) // only draw background colour if transparency is not set
write_pixel16(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current,GetROP(rop, s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_SRC_BG_CLR], dst, pat) & 0xffff);
if (de)
{
if(src & (1 << x))
write_pixel16(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current,GetROP(rop, s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_SRC_FG_CLR], dst, pat) & 0xffff);
else if(!(current_command & 0x200)) // only draw background colour if transparency is not set
write_pixel16(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current,GetROP(rop, s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_SRC_BG_CLR], dst, pat) & 0xffff);
}
//printf("Pixel write(%i): X: %i Y: %i SRC: %04x DST: %04x PAT: %04x ROP: %02x\n",x,s3virge.s3d.bitblt_x_current, s3virge.s3d.bitblt_y_current, src, dst, pat, rop);
done = advance_pixel();
if((s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x80) && s3virge.s3d.bitblt_x_current == s3virge.s3d.bitblt_x_dst)
if((current_command & 0x80) && s3virge.s3d.bitblt_x_current == s3virge.s3d.bitblt_x_dst)
{
switch(align)
{
@ -1388,19 +1451,22 @@ void s3virge_vga_device::bitblt_monosrc_step()
case 2: // 24bpp
for(x=31;x>=0;x--)
{
if(s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x80)
if(current_command & 0x80)
src = bitswap<32>(s3virge.s3d.image_xfer,7,6,5,4,3,2,1,0,15,14,13,12,11,10,9,8,23,22,21,20,19,18,17,16,31,30,29,28,27,26,25,24);
else
src = read_pixel24(src_base,s3virge.s3d.bitblt_x_src_current,s3virge.s3d.bitblt_y_src_current);
dst = read_pixel24(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current);
src = read_pixel24(src_base,s3virge.s3d.bitblt_x_src_current,s3virge.s3d.bitblt_y_src_current, src_stride());
dst = read_pixel24(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current, dest_stride());
if(src & (1 << x))
write_pixel24(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current,GetROP(rop, s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_SRC_FG_CLR], dst, pat));
else if(!(s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x200)) // only draw background colour if transparency is not set
write_pixel24(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current,GetROP(rop, s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_SRC_BG_CLR], dst, pat));
if (de)
{
if(src & (1 << x))
write_pixel24(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current,GetROP(rop, s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_SRC_FG_CLR], dst, pat));
else if(!(current_command & 0x200)) // only draw background colour if transparency is not set
write_pixel24(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current,GetROP(rop, s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_SRC_BG_CLR], dst, pat));
}
//printf("Pixel write(%i): X: %i Y: %i SRC: %04x DST: %04x PAT: %04x ROP: %02x\n",x,s3virge.s3d.bitblt_x_current, s3virge.s3d.bitblt_y_current, src, dst, pat, rop);
done = advance_pixel();
if((s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x80) && s3virge.s3d.bitblt_x_current == s3virge.s3d.bitblt_x_dst)
if((current_command & 0x80) && s3virge.s3d.bitblt_x_current == s3virge.s3d.bitblt_x_dst)
{
switch(align)
{
@ -1491,30 +1557,30 @@ inline void s3virge_vga_device::write_pixel8(uint32_t base, uint16_t x, uint16_t
vga.memory[(base + x + (y*dest_stride())) % vga.svga_intf.vram_size] = val;
}
inline uint32_t s3virge_vga_device::read_pixel32(uint32_t base, uint16_t x, uint16_t y)
inline uint32_t s3virge_vga_device::read_pixel32(uint32_t base, uint16_t x, uint16_t y, u16 stride_select)
{
return (vga.memory[(base + (x*4) + (y*dest_stride())) % vga.svga_intf.vram_size] << 24) |
(vga.memory[(base + 1 + (x*4) + (y*dest_stride())) % vga.svga_intf.vram_size] << 16) |
(vga.memory[(base + 2 + (x*4) + (y*dest_stride())) % vga.svga_intf.vram_size] << 8) |
vga.memory[(base + 3 + (x*4) + (y*dest_stride())) % vga.svga_intf.vram_size];
return (vga.memory[(base + (x * 4) + (y * stride_select)) % vga.svga_intf.vram_size] << 24) |
(vga.memory[(base + 1 + (x * 4) + (y * stride_select)) % vga.svga_intf.vram_size] << 16) |
(vga.memory[(base + 2 + (x * 4) + (y * stride_select)) % vga.svga_intf.vram_size] << 8) |
vga.memory[(base + 3 + (x * 4) + (y * stride_select)) % vga.svga_intf.vram_size];
}
inline uint32_t s3virge_vga_device::read_pixel24(uint32_t base, uint16_t x, uint16_t y)
inline uint32_t s3virge_vga_device::read_pixel24(uint32_t base, uint16_t x, uint16_t y, u16 stride_select)
{
return (vga.memory[(base + (x*3) + (y*dest_stride())) % vga.svga_intf.vram_size]) |
(vga.memory[(base + 1 + (x*3) + (y*dest_stride())) % vga.svga_intf.vram_size] << 8) |
(vga.memory[(base + 2 + (x*3) + (y*dest_stride())) % vga.svga_intf.vram_size] << 16);
return (vga.memory[(base + (x * 3) + (y * stride_select)) % vga.svga_intf.vram_size]) |
(vga.memory[(base + 1 + (x * 3) + (y * stride_select)) % vga.svga_intf.vram_size] << 8) |
(vga.memory[(base + 2 + (x * 3) + (y * stride_select)) % vga.svga_intf.vram_size] << 16);
}
inline uint16_t s3virge_vga_device::read_pixel16(uint32_t base, uint16_t x, uint16_t y)
inline uint16_t s3virge_vga_device::read_pixel16(uint32_t base, uint16_t x, uint16_t y, u16 stride_select)
{
return (vga.memory[(base + (x*2) + (y*dest_stride()) % vga.svga_intf.vram_size)]) |
(vga.memory[(base + 1 + (x*2) + (y*dest_stride())) % vga.svga_intf.vram_size] << 8);
return (vga.memory[(base + (x * 2) + (y * stride_select) % vga.svga_intf.vram_size)]) |
(vga.memory[(base + 1 + (x * 2) + (y * stride_select)) % vga.svga_intf.vram_size] << 8);
}
inline uint8_t s3virge_vga_device::read_pixel8(uint32_t base, uint16_t x, uint16_t y)
inline uint8_t s3virge_vga_device::read_pixel8(uint32_t base, uint16_t x, uint16_t y, u16 stride_select)
{
return vga.memory[(base + x + (y*dest_stride())) % vga.svga_intf.vram_size];
return vga.memory[(base + x + (y * stride_select)) % vga.svga_intf.vram_size];
}
// 2D command register format - A500 (BitBLT), A900 (2D line), AD00 (2D Polygon)
@ -1557,6 +1623,13 @@ void s3virge_vga_device::s3d_sub_control_w(uint32_t data)
LOGMMIO("Sub control = %08x\n", data);
}
/*
* Advanced Function Control Register (MM850C)
* ---- --xx xx-- ---- command fifo status
* ---- ---- ---x ---- LA ENB Linear Addressing Enable (mirror of CR58 bit 4)
* ---- ---- ---- --x- RST DM Reset read DMA
* ---- ---- ---- ---x ENB EHFC Enable enhanced functions (mirror of CR66 bit 0)
*/
uint32_t s3virge_vga_device::s3d_func_ctrl_r()
{
uint32_t ret = 0;

View File

@ -59,6 +59,10 @@ public:
uint32_t get_linear_address_size_full() { return s3virge.linear_address_size_full; }
bool is_linear_address_active() { return s3virge.linear_address_enable; }
bool is_new_mmio_active() { return s3.cr53 & 0x08; }
uint16_t src_stride()
{
return (s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_DEST_SRC_STR] >> 0) & 0xfff8;
}
uint16_t dest_stride()
{
// if((s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x0000001c) == 0x08)
@ -184,10 +188,10 @@ protected:
inline void write_pixel24(uint32_t base, uint16_t x, uint16_t y, uint32_t val);
inline void write_pixel16(uint32_t base, uint16_t x, uint16_t y, uint16_t val);
inline void write_pixel8(uint32_t base, uint16_t x, uint16_t y, uint8_t val);
inline uint32_t read_pixel32(uint32_t base, uint16_t x, uint16_t y);
inline uint32_t read_pixel24(uint32_t base, uint16_t x, uint16_t y);
inline uint16_t read_pixel16(uint32_t base, uint16_t x, uint16_t y);
inline uint8_t read_pixel8(uint32_t base, uint16_t x, uint16_t y);
inline uint32_t read_pixel32(uint32_t base, uint16_t x, uint16_t y, u16 stride_select);
inline uint32_t read_pixel24(uint32_t base, uint16_t x, uint16_t y, u16 stride_select);
inline uint16_t read_pixel16(uint32_t base, uint16_t x, uint16_t y, u16 stride_select);
inline uint8_t read_pixel8(uint32_t base, uint16_t x, uint16_t y, u16 stride_select);
uint32_t GetROP(uint8_t rop, uint32_t src, uint32_t dst, uint32_t pat);
bool advance_pixel();

View File

@ -1,6 +1,7 @@
// license:BSD-3-Clause
// copyright-holders:Barry Rodewald
#include "emu.h"
#include "virge_pci.h"
@ -29,16 +30,28 @@ void virge_pci_device::mmio_map(address_map& map)
// image transfer ports
map(0x1000000,0x1007fff).w(m_vga, FUNC(s3virge_vga_device::image_xfer));
//map(0x1008180,0x10081ff) primary/secondary stream control
//map(0x1008200,0x100821f) memory port controller
//map(0x1008220,0x1008227) DMA control
// MMIO address map
map(0x10083b0,0x10083bf).rw(FUNC(virge_pci_device::vga_3b0_r), FUNC(virge_pci_device::vga_3b0_w));
map(0x10083c0,0x10083df).rw(FUNC(virge_pci_device::vga_3c0_r), FUNC(virge_pci_device::vga_3c0_w));
map(0x10083d0,0x10083df).rw(FUNC(virge_pci_device::vga_3d0_r), FUNC(virge_pci_device::vga_3d0_w));
map(0x1008504,0x1008507).rw(m_vga, FUNC(s3virge_vga_device::s3d_sub_status_r), FUNC(s3virge_vga_device::s3d_sub_control_w));
map(0x100850c,0x100850f).r(m_vga, FUNC(s3virge_vga_device::s3d_func_ctrl_r));
//map(0x1008580,0x100858b) video DMA
//map(0x1008590,0x100859f) command DMA
// S3D engine registers
map(0x100a000,0x100b7ff).rw(m_vga, FUNC(s3virge_vga_device::s3d_register_r), FUNC(s3virge_vga_device::s3d_register_w));
// alternate image transfer ports
map(0x100d000,0x100efff).w(m_vga, FUNC(s3virge_vga_device::image_xfer));
//map(0x100ff00, 0x100ff43) LPB control
}
void virge_pci_device::lfb_map(address_map& map)
@ -95,7 +108,9 @@ uint32_t virge_pci_device::base_address_r()
void virge_pci_device::base_address_w(offs_t offset, uint32_t data)
{
pci_device::address_base_w(offset,data);
downcast<s3virge_vga_device *>(m_vga.target())->set_linear_address(data & 0xffff0000);
// only bits 31-26 are changed here, cfr. page 25-4
const u32 new_address = (data & 0xfc000000) | (base_address_r() & 0x3ffffff);
downcast<s3virge_vga_device *>(m_vga.target())->set_linear_address(new_address);
refresh_linear_window();
}
@ -124,9 +139,16 @@ void virge_pci_device::vga_3b0_w(offs_t offset, uint32_t data, uint32_t mem_mask
if (ACCESSING_BITS_8_15)
{
downcast<s3_vga_device *>(m_vga.target())->port_03b0_w(offset * 4 + 1, data >> 8);
// TODO: make this more transparent
// it shouldn't expose the S3 CRTC regs directly and don't repeat on 0x3d0 I/O below.
if(offset == 1 && downcast<s3virge_vga_device *>(m_vga.target())->get_crtc_port() == 0x3b0)
{
if(m_current_crtc_reg == 0x58)
if (m_current_crtc_reg == 0x53)
{
refresh_linear_window();
remap_cb();
}
else if(m_current_crtc_reg == 0x58)
{
refresh_linear_window();
remap_cb();
@ -197,9 +219,20 @@ void virge_pci_device::vga_3d0_w(offs_t offset, uint32_t data, uint32_t mem_mask
downcast<s3_vga_device *>(m_vga.target())->port_03d0_w(offset * 4 + 1, data >> 8);
if(offset == 1 && downcast<s3virge_vga_device *>(m_vga.target())->get_crtc_port() == 0x3d0)
{
if(m_current_crtc_reg >= 0x58 && m_current_crtc_reg <= 0x5a)
if (m_current_crtc_reg == 0x53)
{
refresh_linear_window();
remap_cb();
}
else if(m_current_crtc_reg == 0x58)
{
refresh_linear_window();
remap_cb();
}
else if(m_current_crtc_reg == 0x59 || m_current_crtc_reg == 0x5a)
{
refresh_linear_window();
remap_cb();
}
}
}