s3virge: get started on BitBLT support, gets Windows 3.1 usable with Virge drivers. [Barry Rodewald]

This commit is contained in:
mahlemiut 2020-01-15 21:13:43 +13:00
parent 2c32f6d68a
commit 599453f6c2
3 changed files with 741 additions and 96 deletions

View File

@ -85,10 +85,19 @@ void s3virge_vga_device::device_start()
save_pointer(vga.attribute.data,"Attribute Registers", 0x15);
m_vblank_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(vga_device::vblank_timer_cb),this));
m_draw_timer = timer_alloc(TIMER_DRAW_STEP);
memset(&s3, 0, sizeof(s3));
memset(&s3virge, 0, sizeof(s3virge));
s3virge.linear_address = 0x70000000;
s3virge.s3d.cmd_fifo_slots_free = 16;
save_pointer(s3virge.s3d.pattern,"S3D Pattern Data", 0xc0);
save_pointer(s3virge.s3d.reg[0],"S3D Registers: BitBLT",0x100);
save_pointer(s3virge.s3d.reg[1],"S3D Registers: 2D Line",0x100);
save_pointer(s3virge.s3d.reg[2],"S3D Registers: 2D Polygon",0x100);
save_pointer(s3virge.s3d.reg[3],"S3D Registers: 3D Line",0x100);
save_pointer(s3virge.s3d.reg[4],"S3D Registers: 3D Triangle",0x100);
// Initialise hardware graphics cursor colours, Windows 95 doesn't touch the registers for some reason
for(x=0;x<4;x++)
{
@ -149,6 +158,13 @@ void s3virgedx_rev1_vga_device::device_reset()
s3.strapping = 0x0aff0912;
}
uint16_t s3virge_vga_device::offset()
{
if(svga.rgb24_en)
return vga.crtc.offset * 6; // special handling for 24bpp packed mode
return s3_vga_device::offset();
}
uint8_t s3virge_vga_device::s3_crtc_reg_read(uint8_t index)
{
uint8_t res;
@ -315,13 +331,13 @@ void s3virge_vga_device::s3_define_video_mode()
svga.rgb8_en = 0;
svga.rgb15_en = 0;
svga.rgb16_en = 0;
svga.rgb32_en = 0;
svga.rgb24_en = 0;
switch((s3.ext_misc_ctrl_2) >> 4)
{
case 0x01: svga.rgb8_en = 1; break;
case 0x03: svga.rgb15_en = 1; divisor = 2; break;
case 0x05: svga.rgb16_en = 1; divisor = 2; break;
case 0x0d: svga.rgb32_en = 1; divisor = 1; break;
case 0x0d: svga.rgb24_en = 1; divisor = 1; break;
default: fatalerror("TODO: s3 video mode not implemented %02x\n",((s3.ext_misc_ctrl_2) >> 4));
}
}
@ -330,9 +346,9 @@ void s3virge_vga_device::s3_define_video_mode()
svga.rgb8_en = (s3.cr3a & 0x10) >> 4;
svga.rgb15_en = 0;
svga.rgb16_en = 0;
svga.rgb32_en = 0;
svga.rgb24_en = 0;
}
if(s3.cr43 & 0x80) // Horizontal clock doubling (techincally, doubles horizontal CRT parameters)
if(s3.cr43 & 0x80) // Horizontal clock doubling (technically, doubles horizontal CRT parameters)
divisor *= 2;
recompute_params_clock(divisor, xtal.value());
}
@ -394,10 +410,10 @@ void s3virge_vga_device::s3_crtc_reg_write(uint8_t index, uint8_t data)
case 0x43:
s3.cr43 = data; // bit 2 = bit 8 of offset register, but only if bits 4-5 of CR51 are 00h.
if((s3.cr51 & 0x30) == 0)
{
vga.crtc.offset = (vga.crtc.offset & 0x00ff) | ((data & 0x04) << 6);
s3_define_video_mode();
}
else
vga.crtc.offset = (vga.crtc.offset & 0x00ff) | ((s3.cr51 & 0x30) << 4);
s3_define_video_mode();
break;
/*
3d4h index 45h (R/W): CR45 Hardware Graphics Cursor Mode
@ -502,11 +518,13 @@ bit 0-9 (911,924) HCS_STADR. Hardware Graphics Cursor Storage Start Address
(801/5,928) For Hi/True color modes use the Horizontal Stretch bits
(3d4h index 45h bits 2 and 3).
*/
case 0x4c:
case 0x4c:
s3.cursor_start_addr = (s3.cursor_start_addr & 0x00ff) | (data << 8);
LOGREG("HW Cursor Address: %08x\n",s3.cursor_start_addr);
break;
case 0x4d:
s3.cursor_start_addr = (s3.cursor_start_addr & 0xff00) | data;
LOGREG("HW Cursor Address: %08x\n",s3.cursor_start_addr);
break;
/*
3d4h index 4Eh (R/W): CR4E HGC Pattern Disp Start X-Pixel Position
@ -782,7 +800,7 @@ WRITE8_MEMBER(s3virge_vga_device::port_03d0_w)
READ8_MEMBER(s3virge_vga_device::mem_r)
{
if (svga.rgb8_en || svga.rgb15_en || svga.rgb16_en || svga.rgb32_en)
if (svga.rgb8_en || svga.rgb15_en || svga.rgb16_en || svga.rgb24_en || svga.rgb32_en)
{
uint8_t data;
if(offset & 0x10000)
@ -864,6 +882,497 @@ WRITE8_MEMBER(s3virge_vga_device::fb_w)
vga.memory[offset % vga.svga_intf.vram_size] = data;
}
void s3virge_vga_device::add_command(int cmd_type)
{
// add command to S3D FIFO
if(s3virge.s3d.cmd_fifo_slots_free == 0)
{
LOGMMIO("Attempt to add command when all command slots are full\n");
return;
}
memcpy(s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_next_ptr].reg,s3virge.s3d.reg[cmd_type],256*4);
s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_next_ptr].op_type = cmd_type;
LOGMMIO("Added command type %i cmd %08x ptr %u\n",s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_next_ptr].op_type,s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_next_ptr].reg[S3D_REG_COMMAND],s3virge.s3d.cmd_fifo_next_ptr);
s3virge.s3d.cmd_fifo_next_ptr++;
if(s3virge.s3d.cmd_fifo_next_ptr >= 16)
s3virge.s3d.cmd_fifo_next_ptr = 0;
if(s3virge.s3d.cmd_fifo_slots_free == 16) // if all slots are free, start command now
command_start();
s3virge.s3d.cmd_fifo_slots_free--;
// TODO: handle full FIFO
}
void s3virge_vga_device::command_start()
{
// start next command in FIFO
int cmd_type = s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].op_type;
switch(cmd_type)
{
case OP_BITBLT:
s3virge.s3d.state = S3D_STATE_BITBLT;
s3virge.s3d.busy = true;
s3virge.s3d.bitblt_x_src = (s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_RSRC_XY] & 0x07ff0000) >> 16;
s3virge.s3d.bitblt_y_src = (s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_RSRC_XY] & 0x000007ff);
s3virge.s3d.bitblt_x_dst = (s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_RDEST_XY] & 0x07ff0000) >> 16;
s3virge.s3d.bitblt_y_dst = (s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_RDEST_XY] & 0x000007ff);
s3virge.s3d.bitblt_width = (s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_RWIDTH_HEIGHT] & 0xffff0000) >> 16;
s3virge.s3d.bitblt_height = (s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_RWIDTH_HEIGHT] & 0x0000ffff);
s3virge.s3d.bitblt_x_current = s3virge.s3d.bitblt_x_dst;
s3virge.s3d.bitblt_x_src_current = s3virge.s3d.bitblt_x_src;
s3virge.s3d.bitblt_y_current = s3virge.s3d.bitblt_y_dst;
s3virge.s3d.bitblt_y_src_current = s3virge.s3d.bitblt_y_src;
s3virge.s3d.bitblt_pat_x = s3virge.s3d.bitblt_x_current % 8;
s3virge.s3d.bitblt_pat_y = s3virge.s3d.bitblt_y_current % 8;
s3virge.s3d.clip_r = s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_CLIP_L_R] & 0x000007ff;
s3virge.s3d.clip_l = (s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_CLIP_L_R] & 0x07ff0000) >> 16;
s3virge.s3d.clip_b = s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_CLIP_T_B] & 0x000007ff;
s3virge.s3d.clip_t = (s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_CLIP_T_B] & 0x07ff0000) >> 16;
if(!(s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x00000080))
m_draw_timer->adjust(attotime::from_nsec(250),0,attotime::from_nsec(250));
s3virge.s3d.bitblt_step_count = 0;
s3virge.s3d.bitblt_mono_pattern =
s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_MONO_PAT_0] | (uint64_t)(s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_MONO_PAT_1]) << 32;
s3virge.s3d.bitblt_current_pixel = 0;
s3virge.s3d.bitblt_pixel_pos = 0;
s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_PAT_BG_CLR] = 0xffffffff; // win31 never sets this?
LOGMMIO("Started BitBLT command [%u]\n", s3virge.s3d.cmd_fifo_current_ptr);
//if(((s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x01fe0000) >> 17) == 0xf0) machine().debug_break();
break;
}
}
void s3virge_vga_device::command_finish()
{
s3virge.s3d.state = S3D_STATE_IDLE;
s3virge.s3d.cmd_fifo_current_ptr++;
if(s3virge.s3d.cmd_fifo_current_ptr >= 16)
s3virge.s3d.cmd_fifo_current_ptr = 0;
s3virge.s3d.cmd_fifo_slots_free++;
if(s3virge.s3d.cmd_fifo_slots_free > 16)
s3virge.s3d.cmd_fifo_slots_free = 16;
m_draw_timer->adjust(attotime::never);
// check if there is another command in the FIFO
if(s3virge.s3d.cmd_fifo_slots_free < 16)
command_start();
else
s3virge.s3d.busy = false;
LOGMMIO("Command finished [%u] (%u slots free)\n",s3virge.s3d.cmd_fifo_current_ptr,s3virge.s3d.cmd_fifo_slots_free);
}
uint32_t s3virge_vga_device::GetROP(uint8_t rop, uint32_t src, uint32_t dst, uint32_t pat)
{
uint32_t ret = 0;
switch(rop)
{
case 0x00: // 0
ret = 0;
break;
case 0x55: // Dn
ret = ~dst;
break;
case 0x5a: // DPx
ret = dst ^ pat;
break;
case 0x66: // DSx
ret = dst ^ src;
break;
case 0x88: // DSa
ret = dst & src;
break;
case 0xb8: // PSDPxax
ret = ((dst ^ pat) & src) ^ pat;
// machine().debug_break();
break;
case 0xcc:
ret = src;
break;
case 0xf0:
ret = pat;
break;
case 0xff: // 1
ret = 0xffffffff;
break;
default:
popmessage("Unimplemented ROP 0x%02x",rop);
}
return ret;
}
bool s3virge_vga_device::advance_pixel()
{
bool xpos, ypos;
int16_t top, left, right, bottom;
// advance src/dst and pattern location
xpos = s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x02000000; // X Positive
ypos = s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x04000000; // Y Positive
if(xpos)
{
left = s3virge.s3d.bitblt_x_dst;
right = s3virge.s3d.bitblt_x_dst + s3virge.s3d.bitblt_width + 1;
s3virge.s3d.bitblt_x_current++;
s3virge.s3d.bitblt_x_src_current++;
s3virge.s3d.bitblt_pat_x++;
}
else
{
left = s3virge.s3d.bitblt_x_dst - s3virge.s3d.bitblt_width - 1;
right = s3virge.s3d.bitblt_x_dst;
s3virge.s3d.bitblt_x_current--;
s3virge.s3d.bitblt_x_src_current--;
s3virge.s3d.bitblt_pat_x--;
// logerror("SRC: %i,%i DST: %i,%i PAT: %i,%i\n",
// s3virge.s3d.bitblt_x_src_current,s3virge.s3d.bitblt_y_src_current,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current,s3virge.s3d.bitblt_pat_x,s3virge.s3d.bitblt_pat_y);
// machine().debug_break();
}
if(ypos)
{
top = s3virge.s3d.bitblt_y_dst;
bottom = s3virge.s3d.bitblt_y_dst + s3virge.s3d.bitblt_height;
}
else
{
top = s3virge.s3d.bitblt_y_dst - s3virge.s3d.bitblt_height;
bottom = s3virge.s3d.bitblt_y_dst;
}
if(s3virge.s3d.bitblt_pat_x < 0 || s3virge.s3d.bitblt_pat_x >= 8)
s3virge.s3d.bitblt_pat_x = s3virge.s3d.bitblt_x_current % 8;
if((s3virge.s3d.bitblt_x_current >= right) || (s3virge.s3d.bitblt_x_current <= left))
{
s3virge.s3d.bitblt_x_current = s3virge.s3d.bitblt_x_dst;
s3virge.s3d.bitblt_x_src_current = s3virge.s3d.bitblt_x_src;
if(ypos)
{
s3virge.s3d.bitblt_y_current++;
s3virge.s3d.bitblt_y_src_current++;
s3virge.s3d.bitblt_pat_y++;
}
else
{
s3virge.s3d.bitblt_y_current--;
s3virge.s3d.bitblt_y_src_current--;
s3virge.s3d.bitblt_pat_y--;
}
s3virge.s3d.bitblt_pat_x = s3virge.s3d.bitblt_x_current % 8;
if(s3virge.s3d.bitblt_pat_y >= 8 || s3virge.s3d.bitblt_pat_y < 0)
s3virge.s3d.bitblt_pat_y = s3virge.s3d.bitblt_y_current % 8;
if((s3virge.s3d.bitblt_y_current >= bottom) || (s3virge.s3d.bitblt_y_current <= top))
return true;
}
return false;
}
void s3virge_vga_device::bitblt_step()
{
if((s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x40))
bitblt_monosrc_step();
else
bitblt_colour_step();
}
void s3virge_vga_device::bitblt_colour_step()
{
// progress current BitBLT operation
// 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;
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;
switch(pixel_size)
{
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)
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)
{
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);
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(align == 2) // doubleword aligned, end here
break;
if(align == 1) // word aligned, move to next word
{
if(x < 2)
x = 2;
else
break;
}
}
}
if(done)
command_finish();
break;
case 1: // 16bpp
if(s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_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)
{
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);
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 && align == 2)
{
if(done)
command_finish();
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)
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)
{
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(advance_pixel())
command_finish();
break;
case 2: // 24bpp
if(s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x80)
{
src = s3virge.s3d.image_xfer;
for(x=0;x<4;x++)
{
s3virge.s3d.bitblt_current_pixel |= ((s3virge.s3d.image_xfer >> (x*8)) & 0xff) << s3virge.s3d.bitblt_pixel_pos*8;
s3virge.s3d.bitblt_pixel_pos++;
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)
{
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*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));
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(align == 2) // doubleword aligned, end here
x = 4;
if(align == 1) // word aligned, move to next word
{
if(x < 2)
x = 2;
else
x = 4;
}
}
if(done)
command_finish();
}
}
break;
}
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)
{
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*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(advance_pixel())
command_finish();
break;
}
s3virge.s3d.bitblt_step_count++;
}
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;
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;
switch(pixel_size)
{
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)
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);
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);
//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)
{
switch(align)
{
case 0:
x &= ~7;
break;
case 1:
x &= ~15;
break;
case 2:
x = -1;
break;
}
if(done)
{
command_finish();
break;
}
}
}
break;
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)
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);
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);
//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)
{
switch(align)
{
case 0:
x &= ~7;
break;
case 1:
x &= ~15;
break;
case 2:
x = -1;
break;
}
if(done)
{
command_finish();
break;
}
}
}
break;
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)
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);
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));
//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)
{
switch(align)
{
case 0:
x &= ~7;
break;
case 1:
x &= ~15;
break;
case 2:
x = -1;
break;
}
if(done)
{
command_finish();
break;
}
}
}
break;
}
s3virge.s3d.bitblt_step_count++;
}
void s3virge_vga_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
{
// TODO: S3D state timing
if(id == TIMER_DRAW_STEP)
{
switch(s3virge.s3d.state)
{
case S3D_STATE_IDLE:
m_draw_timer->adjust(attotime::zero);
break;
case S3D_STATE_BITBLT:
bitblt_step();
break;
}
}
}
// 2D command register format - A500 (BitBLT), A900 (2D line), AD00 (2D Polygon)
// bit 0 - Autoexecute, if set command is executed when the highest relevant register is written to (A50C / A97C / AD7C)
// bit 1 - Enable hardware clipping
@ -885,7 +1394,16 @@ WRITE8_MEMBER(s3virge_vga_device::fb_w)
READ32_MEMBER(s3virge_vga_device::s3d_sub_status_r)
{
return 0x00003000; // S3D engine idle, all FIFO slots free
uint32_t res = 0x00000000;
if(!s3virge.s3d.busy)
res |= 0x00002000; // S3d engine is idle
//res |= (s3virge.s3d.cmd_fifo_slots_free << 8);
if(s3virge.s3d.cmd_fifo_slots_free == 16)
res |= 0x1f00;
return res;
}
WRITE32_MEMBER(s3virge_vga_device::s3d_sub_control_w)
@ -895,99 +1413,68 @@ WRITE32_MEMBER(s3virge_vga_device::s3d_sub_control_w)
LOGMMIO("Sub control = %08x\n", data);
}
READ32_MEMBER(s3virge_vga_device::s3d_func_ctrl_r)
{
uint32_t ret = 0;
ret |= (s3virge.s3d.cmd_fifo_slots_free << 6);
return ret;
}
READ32_MEMBER(s3virge_vga_device::s3d_register_r)
{
uint32_t res = 0;
int op_type = (((offset*4) & 0x0f00) / 4) - 1;
int op_type = (((offset*4) & 0x1c00) >> 10) - 1;
switch(offset)
{
case 0x4d4/4:
case 0x8d4/4:
case 0xcd4/4:
res = s3virge.s3d.src_base[op_type];
break;
case 0xad8/4:
case 0x8d8/4:
case 0xcd8/4:
res = s3virge.s3d.dest_base[op_type];
break;
case 0x500/4:
case 0x900/4:
case 0xd00/4:
res = s3virge.s3d.command[op_type];
break;
case 0x504/4:
res = s3virge.s3d.rect_height[op_type];
res |= (s3virge.s3d.rect_width[op_type] << 16);
break;
case 0x508/4:
res = s3virge.s3d.source_y[op_type];
res |= (s3virge.s3d.source_x[op_type] << 16);
break;
case 0x50c/4:
res = s3virge.s3d.dest_y[op_type];
res |= (s3virge.s3d.dest_x[op_type] << 16);
break;
default:
res = 0xffffffff;
LOGMMIO("MMIO unknown/unused register read MM%04X\n", (offset*4)+0xa000);
}
// unused registers
if(offset < 0x100/4)
return 0;
if(offset >= 0x1c0/4 && offset < 0x400/4)
return 0;
// handle BitBLT pattern registers
if((offset >= 0x100/4) && (offset < 0x1c0/4))
return s3virge.s3d.pattern[offset - (0x100/4)];
res = s3virge.s3d.reg[op_type][((offset*4) & 0x03ff) / 4];
LOGMMIO("MM%04X returning %08x\n", (offset*4)+0xa000, res);
return res;
}
WRITE32_MEMBER(s3virge_vga_device::s3d_register_w)
{
int op_type = (((offset*4) & 0x0f00) / 4) - 1;
int op_type = (((offset*4) & 0x1c00) >> 10) - 1;
// unused registers
if(offset < 0x100/4)
return;
if(offset >= 0x1c0/4 && offset < 0x400/4)
return;
// handle BitBLT pattern registers
if((offset >= 0x100/4) && (offset < 0x1c0/4))
{
//COMBINE_DATA(&s3virge.s3d.pattern[(offset*4) - (0x100/4)]);
s3virge.s3d.pattern[((offset - 0x100/4)*4)+3] = (data & 0xff000000) >> 24;
s3virge.s3d.pattern[((offset - 0x100/4)*4)+2] = (data & 0x00ff0000) >> 16;
s3virge.s3d.pattern[((offset - 0x100/4)*4)+1] = (data & 0x0000ff00) >> 8;
s3virge.s3d.pattern[((offset - 0x100/4)*4)] = (data & 0x000000ff);
return;
}
s3virge.s3d.reg[op_type][((offset*4) & 0x03ff) / 4] = data;
LOGMMIO("MM%04X = %08x\n", (offset*4)+0xa000, data);
switch(offset)
{
case 0x4d4/4:
case 0x8d4/4:
case 0xcd4/4:
s3virge.s3d.src_base[op_type] = data;
LOGMMIO("MM%04X: Source Base = %08x\n", (offset*4)+0xa000, data);
break;
case 0xad8/4:
case 0x8d8/4:
case 0xcd8/4:
s3virge.s3d.dest_base[op_type] = data;
LOGMMIO("MM%04X: Destination base address = %08x\n", (offset*4)+0xa000, data);
break;
case 0x500/4:
s3virge.s3d.command[OP_BITBLT] = data;
// TODO:if bit 0 is reset, then execute now
LOGMMIO("MM%04X: Command [BitBLT/FilledRect] = %08x\n", (offset*4)+0xa000, data);
break;
case 0x900/4:
s3virge.s3d.command[OP_2DLINE] = data;
// TODO:if bit 0 is reset, then execute now
LOGMMIO("MM%04X: Command [2D Line] = %08x\n", (offset*4)+0xa000, data);
break;
case 0xd00/4:
s3virge.s3d.command[OP_2DPOLY] = data;
// TODO:if bit 0 is reset, then execute now
LOGMMIO("MM%04X: Command [2D Polygon] = %08x\n", (offset*4)+0xa000, data);
break;
case 0x504/4:
s3virge.s3d.rect_height[OP_BITBLT] = data & 0x000003ff;
s3virge.s3d.rect_width[OP_BITBLT] = (data & 0x03ff0000) >> 16;
LOGMMIO("MM%04X: Rectangle Width/Height = %08x (%ix%i)\n", (offset*4)+0xa000, data, s3virge.s3d.rect_width[OP_BITBLT], s3virge.s3d.rect_height[OP_BITBLT]);
break;
case 0x508/4:
s3virge.s3d.source_y[OP_BITBLT] = data & 0x000003ff;
s3virge.s3d.source_x[OP_BITBLT] = (data & 0x03ff0000) >> 16;
LOGMMIO("MM%04X: Rectangle Source X/Y = %08x (%i, %i)\n",(offset*4)+0xa000, data, s3virge.s3d.source_x[OP_BITBLT], s3virge.s3d.source_y[OP_BITBLT]);
if(!(data & 0x00000001))
add_command(op_type);
break;
case 0x50c/4:
s3virge.s3d.dest_y[OP_BITBLT] = data & 0x000003ff;
s3virge.s3d.dest_x[OP_BITBLT] = (data & 0x03ff0000) >> 16;
// TODO:if previous command has bit 0 set, then execute here
LOGMMIO("MM%04X: Rectangle Destination X/Y = %08x (%i, %i)\n", (offset*4)+0xa000, data, s3virge.s3d.dest_x[OP_BITBLT], s3virge.s3d.dest_y[OP_BITBLT]);
if(s3virge.s3d.reg[op_type][S3D_REG_COMMAND] & 0x00000001) // autoexecute enabled
add_command(op_type);
break;
default:
LOGMMIO("MMIO unknown/unused register write MM%04X = %08x\n", (offset*4)+0xa000, data);
}
}

View File

@ -35,26 +35,56 @@ public:
DECLARE_WRITE8_MEMBER(fb_w);
DECLARE_READ32_MEMBER(s3d_sub_status_r);
DECLARE_WRITE32_MEMBER(s3d_sub_control_w);
DECLARE_READ32_MEMBER(s3d_func_ctrl_r);
DECLARE_READ32_MEMBER(s3d_register_r);
DECLARE_WRITE32_MEMBER(s3d_register_w);
DECLARE_WRITE32_MEMBER(image_xfer)
{
// if(s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x00000080)
{
// logerror("IMG Xfer:(%u):%08x X:%u(%u) Y:%u(%u)\n",s3virge.s3d.bitblt_step_count,data,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_width,s3virge.s3d.bitblt_y_current,s3virge.s3d.bitblt_height);
s3virge.s3d.image_xfer = data;
bitblt_step();
}
}
uint16_t get_crtc_port() { return (vga.miscellaneous_output&1)?0x3d0:0x3b0; }
uint32_t get_linear_address() { return s3virge.linear_address; }
void set_linear_address(uint32_t addr) { s3virge.linear_address = addr; }
uint8_t get_linear_address_size() { return s3virge.linear_address_size; }
bool is_linear_address_active() { return s3virge.linear_address_enable; }
bool is_new_mmio_active() { return s3.cr53 & 0x08; }
uint16_t dest_stride()
{
// if((s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x0000001c) == 0x08)
// {
// popmessage("Stride=%08x",(((s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_DEST_SRC_STR] >> 16) & 0xfff8) / 3)
// + ((s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_DEST_SRC_STR] >> 16) & 0xfff8));
// return (((s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_DEST_SRC_STR] >> 16) & 0xfff8) / 3)
// + ((s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_DEST_SRC_STR] >> 16) & 0xfff8);
// }
// else
return (s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_DEST_SRC_STR] >> 16) & 0xfff8;
}
ibm8514a_device* get_8514() { fatalerror("s3virge requested non-existent 8514/A device\n"); return nullptr; }
enum
{
TIMER_DRAW_STEP = 10
};
protected:
s3virge_vga_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
// device-level overrides
virtual void device_start() override;
virtual void device_reset() override;
virtual uint16_t offset() override;
enum
{
LAW_64K = 0,
@ -63,6 +93,7 @@ protected:
LAW_4MB
};
// register groups
enum
{
OP_BITBLT = 0,
@ -72,6 +103,35 @@ protected:
OP_3DTRI
};
enum
{
S3D_STATE_IDLE = 0,
S3D_STATE_BITBLT,
S3D_STATE_2DLINE,
S3D_STATE_2DPOLY,
S3D_STATE_3DLINE,
S3D_STATE_3DPOLY
};
enum
{
S3D_REG_SRC_BASE = 0xd4/4,
S3D_REG_DEST_BASE = 0xd8/4,
S3D_REG_CLIP_L_R = 0xdc/4,
S3D_REG_CLIP_T_B = 0xe0/4,
S3D_REG_DEST_SRC_STR = 0xe4/4,
S3D_REG_MONO_PAT_0 = 0xe8/4,
S3D_REG_MONO_PAT_1 = 0xec/4,
S3D_REG_PAT_BG_CLR = 0xf0/4,
S3D_REG_PAT_FG_CLR = 0xf4/4,
S3D_REG_SRC_BG_CLR = 0xf8/4,
S3D_REG_SRC_FG_CLR = 0xfc/4,
S3D_REG_COMMAND = 0x100/4,
S3D_REG_RWIDTH_HEIGHT = 0x104/4,
S3D_REG_RSRC_XY = 0x108/4,
S3D_REG_RDEST_XY = 0x10c/4
};
struct
{
uint32_t linear_address;
@ -82,19 +142,109 @@ protected:
struct
{
uint32_t src_base[5];
uint32_t dest_base[5];
uint32_t command[5];
uint16_t source_x[5];
uint16_t source_y[5];
uint16_t dest_x[5];
uint16_t dest_y[5];
uint16_t rect_width[5];
uint16_t rect_height[5];
int state;
bool busy;
struct
{
uint32_t reg[256];
int op_type;
} cmd_fifo[16];
int cmd_fifo_next_ptr; // command added here in FIFO
int cmd_fifo_current_ptr; // command currently being processed in FIFO
int cmd_fifo_slots_free;
uint8_t pattern[0xc0];
uint32_t reg[5][256];
// BitBLT command state
uint16_t bitblt_x_src;
uint16_t bitblt_y_src;
uint16_t bitblt_x_dst;
uint16_t bitblt_y_dst;
int16_t bitblt_x_current;
int16_t bitblt_y_current;
int16_t bitblt_x_src_current;
int16_t bitblt_y_src_current;
int8_t bitblt_pat_x;
int8_t bitblt_pat_y;
uint16_t bitblt_height;
uint16_t bitblt_width;
uint32_t bitblt_step_count;
uint64_t bitblt_mono_pattern;
uint32_t bitblt_current_pixel;
uint32_t bitblt_pixel_pos; // current position in a pixel (for packed 24bpp colour image transfers)
uint32_t image_xfer; // source data via image transfer ports
uint16_t clip_l;
uint16_t clip_r;
uint16_t clip_t;
uint16_t clip_b;
} s3d;
} s3virge;
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
void write_pixel32(uint32_t base, uint16_t x, uint16_t y, uint32_t val)
{
if(s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x00000002)
if(x < s3virge.s3d.clip_l || x > s3virge.s3d.clip_r || y < s3virge.s3d.clip_t || y > s3virge.s3d.clip_b)
return;
vga.memory[(base + (x*4) + (y*dest_stride())) % vga.svga_intf.vram_size] = val & 0xff;
vga.memory[(base + 1 + (x*4) + (y*dest_stride())) % vga.svga_intf.vram_size] = (val >> 8) & 0xff;
vga.memory[(base + 2 + (x*4) + (y*dest_stride())) % vga.svga_intf.vram_size] = (val >> 16) & 0xff;
vga.memory[(base + 3 + (x*4) + (y*dest_stride())) % vga.svga_intf.vram_size] = (val >> 24) & 0xff;
}
void write_pixel24(uint32_t base, uint16_t x, uint16_t y, uint32_t val)
{
if(s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x00000002)
if(x < s3virge.s3d.clip_l || x > s3virge.s3d.clip_r || y < s3virge.s3d.clip_t || y > s3virge.s3d.clip_b)
return;
vga.memory[(base + (x*3) + (y*dest_stride())) % vga.svga_intf.vram_size] = val & 0xff;
vga.memory[(base + 1 + (x*3) + (y*dest_stride())) % vga.svga_intf.vram_size] = (val >> 8) & 0xff;
vga.memory[(base + 2 + (x*3) + (y*dest_stride())) % vga.svga_intf.vram_size] = (val >> 16) & 0xff;
}
void write_pixel16(uint32_t base, uint16_t x, uint16_t y, uint16_t val)
{
if(s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x00000002)
if(x < s3virge.s3d.clip_l || x > s3virge.s3d.clip_r || y < s3virge.s3d.clip_t || y > s3virge.s3d.clip_b)
return;
vga.memory[(base + (x*2) + (y*dest_stride())) % vga.svga_intf.vram_size] = val & 0xff;
vga.memory[(base + 1 + (x*2) + (y*dest_stride())) % vga.svga_intf.vram_size] = (val >> 8) & 0xff;
}
void write_pixel8(uint32_t base, uint16_t x, uint16_t y, uint8_t val)
{
if(s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x00000002)
if(x < s3virge.s3d.clip_l || x > s3virge.s3d.clip_r || y < s3virge.s3d.clip_t || y > s3virge.s3d.clip_b)
return;
vga.memory[(base + x + (y*dest_stride())) % vga.svga_intf.vram_size] = val;
}
uint32_t read_pixel32(uint32_t base, uint16_t x, uint16_t y)
{
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];
}
uint32_t read_pixel24(uint32_t base, uint16_t x, uint16_t y)
{
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);
}
uint16_t read_pixel16(uint32_t base, uint16_t x, uint16_t y)
{
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);
}
uint8_t read_pixel8(uint32_t base, uint16_t x, uint16_t y)
{
return vga.memory[(base + x + (y*dest_stride())) % vga.svga_intf.vram_size];
}
uint32_t GetROP(uint8_t rop, uint32_t src, uint32_t dst, uint32_t pat);
bool advance_pixel();
private:
emu_timer* m_draw_timer;
void bitblt_step();
void bitblt_colour_step();
void bitblt_monosrc_step();
void add_command(int cmd_type);
void command_start();
void command_finish();
virtual uint8_t s3_crtc_reg_read(uint8_t index);
virtual void s3_define_video_mode(void);
virtual void s3_crtc_reg_write(uint8_t index, uint8_t data);

View File

@ -26,11 +26,19 @@ virgedx_pci_device::virgedx_pci_device(const machine_config &mconfig, const char
void virge_pci_device::mmio_map(address_map& map)
{
// image transfer ports
map(0x1000000,0x1007fff).w(m_vga, FUNC(s3virge_vga_device::image_xfer));
// MMIO address map
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));
// 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));
}
void virge_pci_device::lfb_map(address_map& map)