From 599453f6c2aaa9e9b3fab13bf254854cbc1b206b Mon Sep 17 00:00:00 2001 From: mahlemiut Date: Wed, 15 Jan 2020 21:13:43 +1300 Subject: s3virge: get started on BitBLT support, gets Windows 3.1 usable with Virge drivers. [Barry Rodewald] --- src/devices/bus/isa/s3virge.cpp | 663 ++++++++++++++++++++++++++++++++++------ src/devices/bus/isa/s3virge.h | 170 ++++++++++- src/devices/video/virge_pci.cpp | 8 + 3 files changed, 743 insertions(+), 98 deletions(-) diff --git a/src/devices/bus/isa/s3virge.cpp b/src/devices/bus/isa/s3virge.cpp index 959e9a2e79f..2d2343c58e1 100644 --- a/src/devices/bus/isa/s3virge.cpp +++ b/src/devices/bus/isa/s3virge.cpp @@ -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; - - 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); - } - + int op_type = (((offset*4) & 0x1c00) >> 10) - 1; + + // 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); } } diff --git a/src/devices/bus/isa/s3virge.h b/src/devices/bus/isa/s3virge.h index daa7607ef0c..9b9716b88f2 100644 --- a/src/devices/bus/isa/s3virge.h +++ b/src/devices/bus/isa/s3virge.h @@ -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); diff --git a/src/devices/video/virge_pci.cpp b/src/devices/video/virge_pci.cpp index c3d55f4cc62..6bebe26bc88 100644 --- a/src/devices/video/virge_pci.cpp +++ b/src/devices/video/virge_pci.cpp @@ -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) -- cgit v1.2.3