mirror of
https://github.com/holub/mame
synced 2025-06-01 18:41:47 +03:00
s3virge: get started on BitBLT support, gets Windows 3.1 usable with Virge drivers. [Barry Rodewald]
This commit is contained in:
parent
2c32f6d68a
commit
599453f6c2
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user