diff --git a/src/devices/bus/pci/virge_pci.cpp b/src/devices/bus/pci/virge_pci.cpp index ae3d7b5666265..26fde9cb6c979 100644 --- a/src/devices/bus/pci/virge_pci.cpp +++ b/src/devices/bus/pci/virge_pci.cpp @@ -31,7 +31,8 @@ void virge_pci_device::mmio_map(address_map& map) // image transfer ports map(0x0000,0x7fff).w(m_vga, FUNC(s3virge_vga_device::image_xfer)); - //map(0x8180,0x81ff) primary/secondary stream control + //map(0x8000,0x8043) PCI Configuration Space regs + map(0x8180,0x81ff).m(m_vga, FUNC(s3virge_vga_device::streams_control_map)); //map(0x8200,0x821f) memory port controller //map(0x8220,0x8227) DMA control @@ -39,23 +40,33 @@ void virge_pci_device::mmio_map(address_map& map) // MMIO address map map(0x83b0,0x83df).m(m_vga, FUNC(s3virge_vga_device::io_map)); map(0x8504,0x8507).rw(m_vga, FUNC(s3virge_vga_device::s3d_sub_status_r), FUNC(s3virge_vga_device::s3d_sub_control_w)); + // TODO: writeable map(0x850c,0x850f).r(m_vga, FUNC(s3virge_vga_device::s3d_func_ctrl_r)); //map(0x8580,0x858b) video DMA //map(0x8590,0x859f) command DMA // S3D engine registers - map(0xa000,0xb7ff).rw(m_vga, FUNC(s3virge_vga_device::s3d_register_r), FUNC(s3virge_vga_device::s3d_register_w)); + map(0xa000,0xb7ff).m(m_vga, FUNC(s3virge_vga_device::s3d_register_map)); // alternate image transfer ports map(0xd000,0xefff).w(m_vga, FUNC(s3virge_vga_device::image_xfer)); - //map(0xff00, 0xff43) LPB control + //map(0xff00, 0xff5f) LPB Local Peripheral Bus control + //map(0xff1c, 0xff1f) LPB GIP/GOP General Input/Output Port (for OEM implementations) + //map(0xff20, 0xff23) Serial Port Register (DDC/I2C, pins 205-206, aliased at I/O ports $e2 or $e8) + //map(0xff24, 0xff27) LPB Video Input Window Size + //map(0xff28, 0xff2b) LPB Video Data Offsets + //map(0xff2c, 0xff2f) LPB Horizontal Decimation Control Register + //map(0xff30, 0xff33) LPB Vertical Decimation Control Register + //map(0xff34, 0xff37) LPB Line Stride + //map(0xff40, 0xff5f) LPB Output FIFO Register } void virge_pci_device::lfb_map(address_map& map) { - map(0x0, 0x00ffffff).rw(m_vga, FUNC(s3virge_vga_device::fb_r), FUNC(s3virge_vga_device::fb_w)); + // NOTE: upper mirror is i/f for BE hosts. + map(0x0, 0x00ffffff).mirror(0x02000000).rw(m_vga, FUNC(s3virge_vga_device::fb_r), FUNC(s3virge_vga_device::fb_w)); } void virge_pci_device::config_map(address_map &map) @@ -152,6 +163,12 @@ void virge_pci_device::device_start() add_map(64 * 1024 * 1024, M_MEM | M_DISABLED, FUNC(virge_pci_device::lfb_map)); set_map_address(0, 0x70000000); + command = 0x0000; + // DAC SNP / BME / MEM / I/O + command_mask = 0x27; + // medium DEVSELB + status = 0x0200; + remap_cb(); machine().save().register_postload(save_prepost_delegate(FUNC(virge_pci_device::postload), this)); } @@ -174,18 +191,23 @@ void virgedx_pci_device::device_start() void virge_pci_device::map_extra(uint64_t memory_window_start, uint64_t memory_window_end, uint64_t memory_offset, address_space *memory_space, uint64_t io_window_start, uint64_t io_window_end, uint64_t io_offset, address_space *io_space) { - memory_space->install_readwrite_handler(0xa0000, 0xbffff, read8sm_delegate(*this, FUNC(virge_pci_device::vram_r)), write8sm_delegate(*this, FUNC(virge_pci_device::vram_w))); - - io_space->install_device(0x03b0, 0x03df, *this, &virge_pci_device::legacy_io_map); - - // NOTE: this looks unrelated to the linear addressing - // xubuntu 6.10 and BeOS 3.x definitely wants it this way. - if(downcast(m_vga.target())->is_new_mmio_active()) + if (BIT(command, 1)) { - const u32 get_bar_address = get_vga_linear_address() | 0x01000000; - - memory_space->install_device(get_bar_address, get_bar_address | 0xffff, *this, &virge_pci_device::mmio_map); + memory_space->install_readwrite_handler(0xa0000, 0xbffff, read8sm_delegate(*this, FUNC(virge_pci_device::vram_r)), write8sm_delegate(*this, FUNC(virge_pci_device::vram_w))); + // NOTE: this looks unrelated to the linear addressing + // xubuntu 6.10 and BeOS 3.x definitely wants it this way. + if(downcast(m_vga.target())->is_new_mmio_active()) + { + u32 get_bar_address = get_vga_linear_address() | 0x01000000; + memory_space->install_device(get_bar_address, get_bar_address | 0xffff, *this, &virge_pci_device::mmio_map); + + get_bar_address |= 0x02000000; + memory_space->install_device(get_bar_address, get_bar_address | 0xffff, *this, &virge_pci_device::mmio_map); + } } + + if (BIT(command, 0)) + io_space->install_device(0x03b0, 0x03df, *this, &virge_pci_device::legacy_io_map); } void virge_pci_device::device_add_mconfig(machine_config &config) diff --git a/src/devices/video/pc_vga.cpp b/src/devices/video/pc_vga.cpp index 1780997b3ca00..04a4e2730d31f 100644 --- a/src/devices/video/pc_vga.cpp +++ b/src/devices/video/pc_vga.cpp @@ -1161,7 +1161,7 @@ void vga_device::sequencer_map(address_map &map) vga.sequencer.char_sel.A = (((data & 0xc) >> 2)<<1) | ((data & 0x20) >> 5); vga.sequencer.char_sel.B = (((data & 0x3) >> 0)<<1) | ((data & 0x10) >> 4); if(data) - popmessage("Char SEL checker, contact MAMEdev (%02x %02x)\n",vga.sequencer.char_sel.A,vga.sequencer.char_sel.B); + popmessage("Char SEL checker (%02x %02x)\n",vga.sequencer.char_sel.A,vga.sequencer.char_sel.B); }) ); // Sequencer Memory Mode Register diff --git a/src/devices/video/s3virge.cpp b/src/devices/video/s3virge.cpp index 63492746a5fb5..f6c98153c0a0d 100644 --- a/src/devices/video/s3virge.cpp +++ b/src/devices/video/s3virge.cpp @@ -3,12 +3,15 @@ /* * s3virge.cpp * - * Implementation of the S3 Virge series of video card + * Implementation of the S3 ViRGE series of video card + * ViRGE = Video and Rendering Graphics Engine * * TODO: - * - Proper FIFOs; - * - Implement 3d commands; + * - Complete FIFO details, fix remaining stalls (win2k); + * - Backport 2d engine to Trio64; + * - Implement 3d commands, cfr. s3dsdk demos; * - Implement remaining ROP commands; + * - Primary stream details, namely FIFO thresholds and start address override (any DirectX 5 2D game) * - Secondary stream mixing; * - S3 Scenic Highway i/f (SAA7110 + S3 Scenic/MX2 MPEG-1); * - DMAs; @@ -16,11 +19,13 @@ * - big endian support for non-x86 machines; * - DDC/I2C i/f, cfr. serial port on MMFF20; * - Fix PLL calculation for 1k+ width VESA modes (tends to either be too fast or too slow); - * - Fix interlace mode line compare downstream (1600x1200 res); - * - xubuntu: black screen after booting into GNOME, - * tries to setup linear address with new MMIO disabled, - * kernel driver has DDC checks around that ... - * - win98se: doesn't show transparent layer on shut down screen; + * - 1600x1200x4 needs line compare fix in downstream pc_vga (cuts too early); + * - 1280x1024x16 draws 256 H and stupid high refresh rate; + * + * Notes: + * - Most Windows s3dsdk demos starts in software render (at least with win98se base S3 drivers, + * cfr. cube.exe), work around by reselecting File -> Direct3D HAL or flip the + * Maximize/Restore Down window button * */ @@ -31,19 +36,24 @@ //#include -#define VERBOSE (LOG_REG | LOG_CMD | LOG_MMIO) +#define LOG_REG (1U << 1) +#define LOG_CMD (1U << 2) +#define LOG_MMIO (1U << 3) +#define LOG_PIXEL (1U << 4) // log pixel writes (verbose) +#define LOG_FIFO (1U << 5) +#define LOG_STREAMS (1U << 6) + +#define VERBOSE (LOG_REG | LOG_CMD | LOG_MMIO | LOG_FIFO | LOG_STREAMS) //#define LOG_OUTPUT_STREAM std::cout #include "logmacro.h" -#define LOG_REG (1U << 1) -#define LOG_CMD (1U << 2) -#define LOG_MMIO (1U << 3) - -#define LOGREG(...) LOGMASKED(LOG_REG, __VA_ARGS__) -#define LOGCMD(...) LOGMASKED(LOG_CMD, __VA_ARGS__) -#define LOGMMIO(...) LOGMASKED(LOG_MMIO, __VA_ARGS__) - +#define LOGREG(...) LOGMASKED(LOG_REG, __VA_ARGS__) +#define LOGCMD(...) LOGMASKED(LOG_CMD, __VA_ARGS__) +#define LOGMMIO(...) LOGMASKED(LOG_MMIO, __VA_ARGS__) +#define LOGPIXEL(...) LOGMASKED(LOG_PIXEL, __VA_ARGS__) +#define LOGFIFO(...) LOGMASKED(LOG_FIFO, __VA_ARGS__) +#define LOGSTREAMS(...) LOGMASKED(LOG_STREAMS, __VA_ARGS__) #define CRTC_PORT_ADDR ((vga.miscellaneous_output & 1) ? 0x3d0 : 0x3b0) @@ -103,19 +113,18 @@ void s3virge_vga_device::device_start() save_item(vga.attribute.data,"Attribute Registers"); m_vblank_timer = timer_alloc(FUNC(s3virge_vga_device::vblank_timer_cb), this); - m_draw_timer = timer_alloc(FUNC(s3virge_vga_device::draw_step_tick), this); + m_op_timer = timer_alloc(FUNC(s3virge_vga_device::op_timer_cb), this); memset(&s3, 0, sizeof(s3)); - memset(&s3virge, 0, sizeof(s3virge)); - s3virge.linear_address = 0x70000000; - s3virge.linear_address_size_full = 0x10000; - s3virge.s3d.cmd_fifo_slots_free = 16; - save_item(s3virge.s3d.pattern,"S3D Pattern Data"); - save_item(s3virge.s3d.reg[0],"S3D Registers: BitBLT"); - save_item(s3virge.s3d.reg[1],"S3D Registers: 2D Line"); - save_item(s3virge.s3d.reg[2],"S3D Registers: 2D Polygon"); - save_item(s3virge.s3d.reg[3],"S3D Registers: 3D Line"); - save_item(s3virge.s3d.reg[4],"S3D Registers: 3D Triangle"); + m_linear_address = 0x70000000; + m_linear_address_size_full = 0x10000; + + save_item(m_bitblt.pattern,"S3D Pattern Data"); +// save_item(m_bitblt.reg[0],"S3D Registers: BitBLT"); +// save_item(m_bitblt.reg[1],"S3D Registers: 2D Line"); +// save_item(m_bitblt.reg[2],"S3D Registers: 2D Polygon"); +// save_item(m_bitblt.reg[3],"S3D Registers: 3D Line"); +// save_item(m_bitblt.reg[4],"S3D Registers: 3D Triangle"); // Initialise hardware graphics cursor colours, Windows 95 doesn't touch the registers for some reason for (int x = 0; x < 4; x++) @@ -152,6 +161,25 @@ void s3virgedx_rev1_vga_device::device_start() s3.id_cr30 = 0xe1; // CR30 } +void s3virge_vga_device::s3d_reset() +{ + LOGFIFO("S3D Reset\n"); + m_streams.psidf = 0; + m_streams.pshfc = 0; + m_bitblt_fifo.clear(); + m_xfer_fifo.clear(); + m_bitblt.xfer_mode = false; + m_op_timer->adjust(attotime::never); + + m_s3d_state = S3D_STATE_IDLE; + // beos 4.x (and presumably Win 3.1) never sets this when using BitBlt, + // expecting 0xf0 ROPs to be 1-filled rather than 0 + m_bitblt_latch[5] = 0xffff'ffff; + m_bitblt_latch[6] = 0xffff'ffff; + // TODO: the rest of the pipeline, particularly more state reset on dual boot transitions. + // Notice that some stuff may really need real HW checks, namely streams processor or irq enable +} + void s3virge_vga_device::device_reset() { s3trio64_vga_device::device_reset(); @@ -159,13 +187,7 @@ void s3virge_vga_device::device_reset() // These are just assumed defaults. s3.strapping = 0x000f0912; - // TODO: fix soft reset state - // On Windows 98 shutdown message sometimes leads to an hang the next boot around - s3virge.s3d.state = S3D_STATE_IDLE; - s3virge.s3d.cmd_fifo_current_ptr = 0; - s3virge.s3d.cmd_fifo_slots_free = 16; - s3virge.s3d.busy = false; - //m_draw_timer->adjust(attotime::never); + s3d_reset(); } void s3virgedx_vga_device::device_reset() @@ -185,13 +207,50 @@ void s3virgedx_rev1_vga_device::device_reset() s3.strapping = 0x0aff0912; } +// base 0x8180 +void s3virge_vga_device::streams_control_map(address_map &map) +{ + map(0x0000, 0x0003).lrw32( + NAME([this] (offs_t offset) { + return (m_streams.psidf << 24) | (m_streams.pshfc << 28); + }), + NAME([this] (offs_t offset, u32 data, u32 mem_mask) { + if (ACCESSING_BITS_24_31) + { + m_streams.psidf = (data >> 24) & 7; + m_streams.pshfc = (data >> 28) & 7; + } + LOGSTREAMS("MM8180 (Primary Stream Control) %08x & %08x\n", data, mem_mask); + }) + ); +// map(0x0004, 0x0007) Color/Chroma Key Control (MM8184) +// map(0x0010, 0x0013) Secondary Stream Control (MM8190) +// map(0x0014, 0x0017) Chroma Key Upper Bound (MM8194) +// map(0x0018, 0x001b) Secondary Stream Stretch/Filter Constants (MM8198) +// map(0x0020, 0x0023) Blend Control (MM81A0) +// map(0x0040, 0x0043) Primary Stream Frame Buffer Address 0 (MM81C0) +// map(0x0044, 0x0047) Primary Stream Frame Buffer Address 1 (MM81C4) + map(0x0048, 0x004b).lrw32( + NAME([this] (offs_t offset) { + return (m_streams.primary_stride); + }), + NAME([this] (offs_t offset, u32 data, u32 mem_mask) { + COMBINE_DATA(&m_streams.primary_stride); + m_streams.primary_stride &= 0xfff; + LOGSTREAMS("MM81C8 (Primary Stream Stride) %08x & %08x\n", data, mem_mask); + }) + ); +} + uint16_t s3virge_vga_device::offset() { - // win98se expects 24bpp packed mode with x6 boundaries - // this breaks SDD, which detects these VESA modes as 32bpp. - if(svga.rgb24_en) - return vga.crtc.offset * 6; - return s3trio64_vga_device::offset(); + if (s3.ext_misc_ctrl_2 & 0xc) + return m_streams.primary_stride; + + // NOTE: same as Vision968 + if (s3.memory_config & 0x08) + return vga.crtc.offset << 3; + return vga_device::offset(); } void s3virge_vga_device::crtc_map(address_map &map) @@ -241,42 +300,42 @@ void s3virge_vga_device::crtc_map(address_map &map) LOGREG("CR53: write %02x\n", data); // FIXME: this is just to make PCI to catch up for the side effect of relocating MMIO. // TODO: Big Endian at bits 2-1 - m_linear_config_changed_cb(s3virge.linear_address_enable); + m_linear_config_changed_cb(m_linear_address_enable); }) ); map(0x58, 0x58).lrw8( NAME([this] (offs_t offset) { - u8 res = s3virge.linear_address_size & 0x03; - res |= s3virge.linear_address_enable ? 0x10 : 0x00; + u8 res = m_linear_address_size & 0x03; + res |= m_linear_address_enable ? 0x10 : 0x00; return res; }), NAME([this] (offs_t offset, u8 data) { - const uint8_t old_size = s3virge.linear_address_size; - const bool old_enable = s3virge.linear_address_enable; - const bool size_changed = old_size != s3virge.linear_address_size; + const uint8_t old_size = m_linear_address_size; + const bool old_enable = m_linear_address_enable; + const bool size_changed = old_size != m_linear_address_size; - s3virge.linear_address_size = data & 0x03; - s3virge.linear_address_enable = data & 0x10; + m_linear_address_size = data & 0x03; + m_linear_address_enable = data & 0x10; switch(data & 0x03) { case LAW_64K: - s3virge.linear_address_size_full = 0x10000; + m_linear_address_size_full = 0x10000; break; case LAW_1MB: - s3virge.linear_address_size_full = 0x100000; + m_linear_address_size_full = 0x100000; break; case LAW_2MB: - s3virge.linear_address_size_full = 0x200000; + m_linear_address_size_full = 0x200000; break; case LAW_4MB: - s3virge.linear_address_size_full = 0x400000; + m_linear_address_size_full = 0x400000; break; } - if ((s3virge.linear_address_enable != old_enable) || size_changed) + if ((m_linear_address_enable != old_enable) || size_changed) { - m_linear_config_changed_cb(s3virge.linear_address_enable); + m_linear_config_changed_cb(m_linear_address_enable); } LOGREG("CR58: write %02x\n", data); @@ -284,14 +343,14 @@ void s3virge_vga_device::crtc_map(address_map &map) ); map(0x59, 0x59).lrw8( NAME([this] (offs_t offset) { - return (s3virge.linear_address & 0xff000000) >> 24; + return (m_linear_address & 0xff000000) >> 24; }), NAME([this] (offs_t offset, u8 data) { - const uint32_t old_address = s3virge.linear_address; - s3virge.linear_address = (s3virge.linear_address & 0x00ff0000) | (data << 24); - LOGREG("Linear framebuffer address = %08x\n",s3virge.linear_address); + const uint32_t old_address = m_linear_address; + m_linear_address = (m_linear_address & 0x00ff0000) | (data << 24); + LOGREG("Linear framebuffer address = %08x\n",m_linear_address); - if (old_address != s3virge.linear_address && s3virge.linear_address_enable) + if (old_address != m_linear_address && m_linear_address_enable) { m_linear_config_changed_cb(1); } @@ -300,36 +359,53 @@ void s3virge_vga_device::crtc_map(address_map &map) map(0x5a, 0x5a).lrw8( NAME([this] (offs_t offset) { u8 res = 0; - switch(s3virge.linear_address_size & 0x03) + switch(m_linear_address_size & 0x03) { case 0: // 64kB default: - res = (s3virge.linear_address & 0x00ff0000) >> 16; + res = (m_linear_address & 0x00ff0000) >> 16; break; case 1: // 1MB - res = (s3virge.linear_address & 0x00f00000) >> 16; + res = (m_linear_address & 0x00f00000) >> 16; break; case 2: // 2MB - res = (s3virge.linear_address & 0x00e00000) >> 16; + res = (m_linear_address & 0x00e00000) >> 16; break; case 3: // 4MB - res = (s3virge.linear_address & 0x00c00000) >> 16; + res = (m_linear_address & 0x00c00000) >> 16; break; } return res; }), NAME([this] (offs_t offset, u8 data) { - const uint32_t old_address = s3virge.linear_address; - s3virge.linear_address = (s3virge.linear_address & 0xff000000) | (data << 16); - LOGREG("Linear framebuffer address = %08x\n",s3virge.linear_address); + const uint32_t old_address = m_linear_address; + m_linear_address = (m_linear_address & 0xff000000) | (data << 16); + LOGREG("Linear framebuffer address = %08x\n",m_linear_address); - if (old_address != s3virge.linear_address && s3virge.linear_address_enable) + if (old_address != m_linear_address && m_linear_address_enable) { m_linear_config_changed_cb(1); } }) ); //map(0x5d, 0x5e).unmapr(); + map(0x66, 0x66).lrw8( + NAME([this] (offs_t offset) { + return m_cr66; + }), + NAME([this] (offs_t offset, u8 data) { + m_cr66 = data; + LOGREG("CR66: write %02x\n", data); + // bit 0: ENBL ENH Enable Enhanced Functions + if (BIT(data, 1)) + s3d_reset(); + // bit 6: TOFF PADT - Tri-State Off Pixel Address bus + // TODO: bit 7 enables, bit 3 will disconnect from the PCI bus if FIFO under/overflow happens + // This is enabled by win98se already during startup. + //if (data & 0x88) + // popmessage("s3virge.cpp: PCI disconnect enabled warning"); + }) + ); } void s3virge_vga_device::s3_define_video_mode() @@ -353,13 +429,25 @@ void s3virge_vga_device::s3_define_video_mode() svga.rgb15_en = 0; svga.rgb16_en = 0; svga.rgb24_en = 0; + svga.rgb32_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.rgb24_en = 1; divisor = 1; break; - default: fatalerror("TODO: s3 video mode not implemented %02x\n",((s3.ext_misc_ctrl_2) >> 4)); + case 0x0d: + { + // if streams disabled run RAMDAC in unpacked mode + // NOTE: it matches original Vision968 behaviour + // - SDD and Tiny Core Linux relies on this + if (s3.ext_misc_ctrl_2 & 0xc) + svga.rgb24_en = 1; + else + svga.rgb32_en = 1; + divisor = 1; + break; + } + default: popmessage("video/s3virge.cpp: video mode not implemented %02x\n",((s3.ext_misc_ctrl_2) >> 4)); } } else @@ -368,9 +456,12 @@ void s3virge_vga_device::s3_define_video_mode() svga.rgb15_en = 0; svga.rgb16_en = 0; svga.rgb24_en = 0; + svga.rgb32_en = 0; } if(s3.cr43 & 0x80) // Horizontal clock doubling (technically, doubles horizontal CRT parameters) divisor *= 2; + + //popmessage("%02x %02x %d", s3.cr43, s3.sr15, divisor); recompute_params_clock(divisor, xtal.value()); } @@ -447,111 +538,195 @@ void s3virge_vga_device::mem_w(offs_t offset, uint8_t data) uint8_t s3virge_vga_device::fb_r(offs_t offset) { - if(offset < s3virge.linear_address_size_full) + if(offset < m_linear_address_size_full) return vga.memory[offset % vga.svga_intf.vram_size]; return 0xff; } void s3virge_vga_device::fb_w(offs_t offset, uint8_t data) { - if(offset < s3virge.linear_address_size_full) + if(offset < m_linear_address_size_full) vga.memory[offset % vga.svga_intf.vram_size] = data; } -void s3virge_vga_device::add_command(int cmd_type) +void s3virge_vga_device::add_command(u8 cmd_type) { - // add command to S3D FIFO - if(s3virge.s3d.cmd_fifo_slots_free == 0) + // TODO: handle full FIFO (should discard operation?) + if (m_bitblt_fifo.full()) + throw emu_fatalerror("s3virge: FIFO full"); + + for (int i = 0; i < 15; i++) + m_bitblt_fifo.enqueue(m_bitblt_latch[i]); + + if (m_s3d_state == S3D_STATE_IDLE) { - LOGCMD("Attempt to add command when all command slots are full\n"); - return; + m_op_timer->adjust(attotime::from_nsec(250), 0, attotime::from_nsec(250)); + m_s3d_state = S3D_STATE_COMMAND_RX; } - 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; - LOGCMD("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 + + LOGFIFO("Enqueue command type %i %08x (%d free)\n", cmd_type, m_bitblt_latch[11], 16 - m_bitblt_fifo.queue_length() / 15); } -void s3virge_vga_device::command_start() +TIMER_CALLBACK_MEMBER(s3virge_vga_device::op_timer_cb) { - // start next command in FIFO - int cmd_type = s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].op_type; + switch (m_s3d_state) + { + case S3D_STATE_IDLE: + return; + case S3D_STATE_COMMAND_RX: + // start next command in FIFO + //const u8 cmd_type = 0; //m_bitblt.cmd_fifo[m_bitblt.cmd_fifo_current_ptr].op_type & 0xf; + assert(!m_bitblt_fifo.empty()); + command_dequeue(OP_BITBLT); + break; + case S3D_STATE_BITBLT: + if (m_bitblt.xfer_mode == true) + { + if (m_xfer_fifo.empty()) + return; + m_bitblt.image_xfer = m_xfer_fifo.dequeue(); + } + bitblt_step(); + break; + case S3D_STATE_2DLINE: + line2d_step(); + break; + case S3D_STATE_2DPOLY: + poly2d_step(); + break; + case S3D_STATE_3DLINE: + line3d_step(); + break; + case S3D_STATE_3DPOLY: + poly3d_step(); + break; + } +} - switch(cmd_type) +void s3virge_vga_device::command_dequeue(u8 op_type) +{ + switch(op_type) { case OP_2DLINE: - LOGCMD("2D Line command (unsupported) [%u]\n", s3virge.s3d.cmd_fifo_current_ptr); + //LOGCMD("2D Line command (unsupported) [%u]\n", m_bitblt.cmd_fifo_current_ptr); + LOGCMD("2D Line command (unsupported)\n"); break; case OP_2DPOLY: - LOGCMD("2D Poly command (unsupported) [%u]\n", s3virge.s3d.cmd_fifo_current_ptr); + //LOGCMD("2D Poly command (unsupported) [%u]\n", m_bitblt.cmd_fifo_current_ptr); + LOGCMD("2D Poly command (unsupported)\n"); break; case OP_3DLINE: - LOGCMD("3D Line command (unsupported) [%u]\n", s3virge.s3d.cmd_fifo_current_ptr); + //LOGCMD("3D Line command (unsupported) [%u]\n", m_bitblt.cmd_fifo_current_ptr); + LOGCMD("3D Poly command (unsupported)\n"); break; case OP_3DTRI: - LOGCMD("3D Tri command (unsupported) [%u]\n", s3virge.s3d.cmd_fifo_current_ptr); + //LOGCMD("3D Tri command (unsupported) [%u]\n", m_bitblt.cmd_fifo_current_ptr); + LOGCMD("3D Tri command (unsupported)\n"); break; 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); - // TODO: these four goes negative at second transfer of beos 4 - 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; - // FIXME: win31 & beos 4.x never sets this. - // Latter definitely relies on what's set in PAT_FG_CLR for background pen being set (???) - s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_PAT_BG_CLR] = 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] = 0xffffffff; - LOGCMD("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(); + { + u32 tmp; + //const bitblt_struct command_struct = m_bitblt_fifo.dequeue(); + m_bitblt.src_base = m_bitblt_fifo.dequeue(); + m_bitblt.dest_base = m_bitblt_fifo.dequeue(); + tmp = m_bitblt_fifo.dequeue(); + m_bitblt.clip_r = tmp & 0x000007ff; + m_bitblt.clip_l = (tmp & 0x07ff0000) >> 16; + // $a4e0 + tmp = m_bitblt_fifo.dequeue(); + m_bitblt.clip_b = tmp & 0x000007ff; + m_bitblt.clip_t = (tmp & 0x07ff0000) >> 16; + tmp = m_bitblt_fifo.dequeue(); + m_bitblt.src_stride = (tmp >> 0) & 0xfff8; + m_bitblt.dest_stride = (tmp >> 16) & 0xfff8; + tmp = m_bitblt_fifo.dequeue(); + m_bitblt.mono_pattern = ((u64)m_bitblt_fifo.dequeue() << 32) | tmp; + // $a4f0 + m_bitblt.pat_bg_clr = m_bitblt_fifo.dequeue(); + m_bitblt.pat_fg_clr = m_bitblt_fifo.dequeue(); + m_bitblt.src_bg_clr = m_bitblt_fifo.dequeue(); + m_bitblt.src_fg_clr = m_bitblt_fifo.dequeue(); + // $a500 + m_bitblt.command = m_bitblt_fifo.dequeue(); + tmp = m_bitblt_fifo.dequeue(); + m_bitblt.width = ((tmp & 0xffff0000) >> 16) + 1; + m_bitblt.height = (tmp & 0x0000ffff); + tmp = m_bitblt_fifo.dequeue(); + m_bitblt.x_src = (tmp & 0x07ff0000) >> 16; + m_bitblt.y_src = (tmp & 0x000007ff); + tmp = m_bitblt_fifo.dequeue(); + m_bitblt.x_dst = (tmp & 0x07ff0000) >> 16; + m_bitblt.y_dst = (tmp & 0x000007ff); + + // TODO: these four goes negative at second transfer of beos 4 (two's complement?) + m_bitblt.x_current = m_bitblt.x_dst; + m_bitblt.x_src_current = m_bitblt.x_src; + m_bitblt.y_current = m_bitblt.y_dst; + m_bitblt.y_src_current = m_bitblt.y_src; + m_bitblt.pat_x = m_bitblt.x_current % 8; + m_bitblt.pat_y = m_bitblt.y_current % 8; + m_bitblt.step_count = 0; + m_bitblt.current_pixel = 0; + m_bitblt.pixel_pos = 0; + + LOGFIFO("Dequeued command %08x (%d free)\n", m_bitblt.command, 16 - (m_bitblt_fifo.queue_length() / 15)); + + const u32 current_command = m_bitblt.command; + + m_bitblt.xfer_mode = bool(BIT(current_command, 7)); + m_s3d_state = S3D_STATE_BITBLT; + + const u8 command_type = BIT(current_command, 27, 4); + + // NOP disables autoexecute without executing a command + // win2k relies on this at explorer startup + if (command_type == 0xf) + { + LOGCMD("BitBLT NOP encountered\n"); + m_bitblt_latch[11] &= ~1; + m_bitblt.xfer_mode = false; + command_finish(); + return; + } + else + { + LOGCMD("Started BitBLT command [%08x type=%02x xfer_mode=%d]\n" + , m_bitblt.command + , command_type + , m_bitblt.xfer_mode + ); + } + + break; + } + default: + LOGCMD(" command detected [%08x]\n", op_type, m_bitblt.command); 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; + LOGFIFO("Command finished (%u free) ", 16 - (m_bitblt_fifo.queue_length() / 15)); - LOGMMIO("Command finished [%u] (%u slots free)\n",s3virge.s3d.cmd_fifo_current_ptr,s3virge.s3d.cmd_fifo_slots_free); + if (m_bitblt_fifo.empty()) + { + m_s3d_state = S3D_STATE_IDLE; + m_op_timer->adjust(attotime::never); + LOGFIFO("- state idle\n"); + } + else + { + m_s3d_state = S3D_STATE_COMMAND_RX; + const auto xfer_fifo = m_xfer_fifo.queue_length(); + // FIXME: without flushing xfer FIFO GFXs will go awry in win98se (i.e. when calling shutdown menu) + // root cause of this is also causing hangs in win2k when bringing up explorer window, + // possibly a command is misbehaving in size. + if (xfer_fifo) + LOGFIFO("Warning: non-empty xfer FIFO at command end (%lld)\n", xfer_fifo); + LOGFIFO("- state new command\n"); + m_xfer_fifo.clear(); + } } void s3virge_vga_device::line2d_step() @@ -645,70 +820,89 @@ 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 + xpos = m_bitblt.command & 0x02000000; // X Positive + ypos = m_bitblt.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++; + left = m_bitblt.x_dst; + right = m_bitblt.x_dst + m_bitblt.width; + m_bitblt.x_current++; + m_bitblt.x_src_current++; + m_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--; + // FIXME: beos 4 dominos demo + left = m_bitblt.x_dst - m_bitblt.width; + right = m_bitblt.x_dst; + m_bitblt.x_current--; + m_bitblt.x_src_current--; + m_bitblt.pat_x--; // machine().debug_break(); } if(ypos) { - top = s3virge.s3d.bitblt_y_dst; - bottom = s3virge.s3d.bitblt_y_dst + s3virge.s3d.bitblt_height; + top = m_bitblt.y_dst; + bottom = m_bitblt.y_dst + m_bitblt.height; } else { - top = s3virge.s3d.bitblt_y_dst - s3virge.s3d.bitblt_height; - bottom = s3virge.s3d.bitblt_y_dst; + top = m_bitblt.y_dst - m_bitblt.height; + bottom = m_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)) + if(m_bitblt.pat_x < 0 || m_bitblt.pat_x >= 8) + m_bitblt.pat_x = m_bitblt.x_current % 8; + if((m_bitblt.x_current >= right) || (m_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; + m_bitblt.x_current = m_bitblt.x_dst; + m_bitblt.x_src_current = m_bitblt.x_src; if(ypos) { - s3virge.s3d.bitblt_y_current++; - s3virge.s3d.bitblt_y_src_current++; - s3virge.s3d.bitblt_pat_y++; + m_bitblt.y_current++; + m_bitblt.y_src_current++; + m_bitblt.pat_y++; } else { - s3virge.s3d.bitblt_y_current--; - s3virge.s3d.bitblt_y_src_current--; - s3virge.s3d.bitblt_pat_y--; + m_bitblt.y_current--; + m_bitblt.y_src_current--; + m_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; - logerror("SRC: %i,%i DST: %i,%i PAT: %i,%i Bounds: %i,%i,%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, + m_bitblt.pat_x = m_bitblt.x_current % 8; + if(m_bitblt.pat_y >= 8 || m_bitblt.pat_y < 0) + m_bitblt.pat_y = m_bitblt.y_current % 8; + LOGPIXEL("SRC: %i,%i DST: %i,%i PAT: %i,%i Bounds: %i,%i,%i,%i\n", + m_bitblt.x_src_current,m_bitblt.y_src_current, + m_bitblt.x_current,m_bitblt.y_current, + m_bitblt.pat_x,m_bitblt.pat_y, left,right,top,bottom); - if((s3virge.s3d.bitblt_y_current >= bottom) || (s3virge.s3d.bitblt_y_current <= top)) + if((m_bitblt.y_current >= bottom) || (m_bitblt.y_current <= top)) return true; } return false; } +// 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 +// bits 2-4 - Destination colour format - (0 = 8bpp palettised, 1 = 16bpp RGB1555 or RGB565, 2 = 24bpp RGB888 +// bit 5 - Draw enable - if reset, doesn't draw anything, but is still executed +// bit 6 - Image source Mono transfer, if set source is mono, otherwise source is the same pixel depth as the destination +// bit 7 - Image data source - 0 = source is in video memory, 1 = source is from the image transfer port (CPU / system memory) +// bit 8 - Mono pattern - if set, pattern data is mono, otherwise pattern data is the same pixel depth as the destination +// Cleared to 0 if using an ROP with a colour source Must be set to 1 if doing a rectangle fill operation +// bit 9 - Transparency - if set, does not update if a background colour is selected. Effectively only if bit 7 is set, Typically used for text display. +// bits 10-11 - Image transfer alignment - Data for an image transfer is byte (0), word (1), or doubleword (2) aligned. All image transfers are doubleword in size. +// bits 12-13 - First doubleword offset - (Image transfers) - start with the given byte (+1) in a doubleword for an image transfer +// bits 17-24 - MS Windows Raster Operation +// bit 25 - X Positive - if set, BitBLT is performed from left to right, otherwise, from right to left +// bit 26 - Y Positive - if set, BitBLT is performed from top to bottom, otherwise from bottom to top +// bits 27-30 - 2D Command - 0000 = BitBLT, 0010 = Rectangle Fill, 0011 = Line Draw, 0101 = Polygon Fill, 1111 = NOP (Turns off autoexecute without executing a command) +// bit 31 - 2D / 3D Select + void s3virge_vga_device::bitblt_step() { - if((s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x40)) + if(BIT(m_bitblt.command, 6)) bitblt_monosrc_step(); else bitblt_colour_step(); @@ -718,14 +912,15 @@ 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; - - const u32 current_command = s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND]; + uint32_t src_base = m_bitblt.src_base & 0x003ffff8; + uint32_t dst_base = m_bitblt.dest_base & 0x003ffff8; + const u32 current_command = m_bitblt.command; const uint8_t pixel_size = (current_command & 0x0000001c) >> 2; const uint8_t rop = (current_command & 0x01fe0000) >> 17; const int align = (current_command & 0x000000c00) >> 10; //const bool tp = bool(BIT(current_command, 9)); + const bool mp = bool(BIT(current_command, 8)); + const bool ids = bool(BIT(current_command, 7)); const bool de = bool(BIT(current_command, 5)); uint32_t src = 0; @@ -739,23 +934,29 @@ void s3virge_vga_device::bitblt_colour_step() case 0: // 8bpp for(x=0;x<4;x++) { - if(current_command & 0x80) - src = s3virge.s3d.image_xfer >> (x*8); + if(ids) + { + src = m_bitblt.image_xfer >> (x*8); + src &= 0xff; + } else - src = read_pixel8(src_base,s3virge.s3d.bitblt_x_src_current,s3virge.s3d.bitblt_y_src_current, src_stride()); - if(current_command & 0x100) + src = read_pixel8(src_base, m_bitblt.x_src_current, m_bitblt.y_src_current, m_bitblt.src_stride); + if(mp) { - 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]); + //pat = (m_bitblt.mono_pattern & (1 << ((m_bitblt.pat_y*8) + (7-m_bitblt.pat_x))) ? m_bitblt.pat_fg_clr : m_bitblt.pat_bg_clr); + + pat = BIT(m_bitblt.mono_pattern, (m_bitblt.pat_y*8) + (7-m_bitblt.pat_x)) ? m_bitblt.pat_fg_clr : m_bitblt.pat_bg_clr; } else { - pat = s3virge.s3d.pattern[(s3virge.s3d.bitblt_pat_y * 8) + s3virge.s3d.bitblt_pat_x]; + pat = m_bitblt.pattern[(m_bitblt.pat_y * 8) + m_bitblt.pat_x]; } - dst = read_pixel8(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current, dest_stride()); + dst = read_pixel8(dst_base, m_bitblt.x_current, m_bitblt.y_current, m_bitblt.dest_stride); if (de) - write_pixel8(dst_base, s3virge.s3d.bitblt_x_current, s3virge.s3d.bitblt_y_current, GetROP(rop, src, dst, pat) & 0xff); + { + write_pixel8(dst_base, m_bitblt.x_current, m_bitblt.y_current, GetROP(rop, src, dst, pat) & 0xff); + } done = advance_pixel(); if(done) @@ -763,7 +964,7 @@ void s3virge_vga_device::bitblt_colour_step() command_finish(); break; } - if((current_command & 0x80) && s3virge.s3d.bitblt_x_current == s3virge.s3d.bitblt_x_dst) + if((ids) && m_bitblt.x_current == m_bitblt.x_dst) { if(align == 2) // doubleword aligned, end here break; @@ -778,71 +979,76 @@ void s3virge_vga_device::bitblt_colour_step() } break; case 1: // 16bpp - if(current_command & 0x80) - src = s3virge.s3d.image_xfer; + if(ids) + { + src = m_bitblt.image_xfer; + src &= 0xffff; + } else - src = read_pixel16(src_base,s3virge.s3d.bitblt_x_src_current,s3virge.s3d.bitblt_y_src_current, src_stride()); - dst = read_pixel16(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current, dest_stride()); - if(current_command & 0x100) + src = read_pixel16(src_base, m_bitblt.x_src_current, m_bitblt.y_src_current, m_bitblt.src_stride); + dst = read_pixel16(dst_base, m_bitblt.x_current, m_bitblt.y_current, m_bitblt.dest_stride); + if(mp) { - 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]); + pat = (m_bitblt.mono_pattern & (1 << ((m_bitblt.pat_y*8) + (7-m_bitblt.pat_x)))) + ? m_bitblt.pat_fg_clr + : m_bitblt.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; + pat = m_bitblt.pattern[(m_bitblt.pat_y*16) + (m_bitblt.pat_x*2)] | (m_bitblt.pattern[(m_bitblt.pat_y*16) + (m_bitblt.pat_x*2) + 1]) << 8; if (de) - write_pixel16(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current,GetROP(rop, src, dst, pat) & 0xffff); + write_pixel16(dst_base, m_bitblt.x_current, m_bitblt.y_current, GetROP(rop, src, dst, pat) & 0xffff); done = advance_pixel(); if(done) { command_finish(); break; } - if((current_command & 0x80) && s3virge.s3d.bitblt_x_current == s3virge.s3d.bitblt_x_dst && align == 2) + if((ids) && m_bitblt.x_current == m_bitblt.x_dst && align == 2) break; // if a new line of an image transfer, and is dword aligned, stop here - if(current_command & 0x80) - src = s3virge.s3d.image_xfer >> 16; + if(ids) + src = m_bitblt.image_xfer >> 16; else - src = read_pixel16(src_base,s3virge.s3d.bitblt_x_src_current,s3virge.s3d.bitblt_y_src_current, src_stride()); - dst = read_pixel16(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current, dest_stride()); - if(current_command & 0x100) + src = read_pixel16(src_base, m_bitblt.x_src_current, m_bitblt.y_src_current, m_bitblt.src_stride); + dst = read_pixel16(dst_base, m_bitblt.x_current, m_bitblt.y_current, m_bitblt.dest_stride); + if(mp) { - 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]); + pat = (m_bitblt.mono_pattern & (1 << ((m_bitblt.pat_y*8) + (7-m_bitblt.pat_x))) + ? m_bitblt.pat_fg_clr + : m_bitblt.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; + pat = m_bitblt.pattern[(m_bitblt.pat_y*16) + (m_bitblt.pat_x*2)] | (m_bitblt.pattern[(m_bitblt.pat_y*16) + (m_bitblt.pat_x*2) + 1]) << 8; if (de) - write_pixel16(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current,GetROP(rop, src, dst, pat) & 0xffff); + write_pixel16(dst_base, m_bitblt.x_current, m_bitblt.y_current, GetROP(rop, src, dst, pat) & 0xffff); if(advance_pixel()) command_finish(); break; case 2: // 24bpp - if(current_command & 0x80) + if(ids) { - src = s3virge.s3d.image_xfer; + src = m_bitblt.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) + m_bitblt.current_pixel |= ((m_bitblt.image_xfer >> (x*8)) & 0xff) << m_bitblt.pixel_pos*8; + m_bitblt.pixel_pos++; + if(m_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, dest_stride()); - if(current_command & 0x100) + m_bitblt.pixel_pos = 0; + dst = read_pixel24(dst_base, m_bitblt.x_current, m_bitblt.y_current, m_bitblt.dest_stride); + if(mp) { - 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]); + pat = (m_bitblt.mono_pattern & (1 << ((m_bitblt.pat_y*8) + (7-m_bitblt.pat_x))) + ? m_bitblt.pat_fg_clr : m_bitblt.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; + pat = m_bitblt.pattern[(m_bitblt.pat_y*24) + (m_bitblt.pat_x*3)] | (m_bitblt.pattern[(m_bitblt.pat_y*24) + (m_bitblt.pat_x*3) + 1]) << 8 + | (m_bitblt.pattern[(m_bitblt.pat_y*24) + (m_bitblt.pat_x*3) + 2]) << 16; if (de) - write_pixel24(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current,GetROP(rop, s3virge.s3d.bitblt_current_pixel, dst, pat)); - s3virge.s3d.bitblt_current_pixel = 0; + write_pixel24(dst_base, m_bitblt.x_current, m_bitblt.y_current, GetROP(rop, m_bitblt.current_pixel, dst, pat)); + m_bitblt.current_pixel = 0; done = advance_pixel(); - if((current_command & 0x80) && s3virge.s3d.bitblt_x_current == s3virge.s3d.bitblt_x_dst) + if((ids) && m_bitblt.x_current == m_bitblt.x_dst) { if(align == 2) // doubleword aligned, end here x = 4; @@ -862,37 +1068,41 @@ void s3virge_vga_device::bitblt_colour_step() } else { - src = read_pixel24(src_base,s3virge.s3d.bitblt_x_src_current,s3virge.s3d.bitblt_y_src_current, src_stride()); - dst = read_pixel24(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current, dest_stride()); - if(current_command & 0x100) + src = read_pixel24(src_base, m_bitblt.x_src_current, m_bitblt.y_src_current, m_bitblt.src_stride); + dst = read_pixel24(dst_base, m_bitblt.x_current, m_bitblt.y_current, m_bitblt.dest_stride); + if(mp) { - 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]); + pat = (m_bitblt.mono_pattern & (1 << ((m_bitblt.pat_y*8) + (7-m_bitblt.pat_x)))) + ? m_bitblt.pat_fg_clr : m_bitblt.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; + pat = m_bitblt.pattern[(m_bitblt.pat_y*24) + (m_bitblt.pat_x*3)] | (m_bitblt.pattern[(m_bitblt.pat_y*24) + (m_bitblt.pat_x*3) + 1]) << 8 + | (m_bitblt.pattern[(m_bitblt.pat_y*24) + (m_bitblt.pat_x*3) + 2]) << 16; } if (de) - write_pixel24(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current,GetROP(rop, src, dst, pat)); + write_pixel24(dst_base, m_bitblt.x_current, m_bitblt.y_current, + + GetROP(rop, src, dst, pat)); if(advance_pixel()) command_finish(); break; } - s3virge.s3d.bitblt_step_count++; + m_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; + uint32_t src_base = m_bitblt.src_base & 0x003ffff8; + uint32_t dst_base = m_bitblt.dest_base & 0x003ffff8; - const u32 current_command = s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND]; + const u32 current_command = m_bitblt.command; const uint8_t pixel_size = (current_command & 0x0000001c) >> 2; const uint8_t rop = (current_command & 0x01fe0000) >> 17; - //const bool tp = bool(BIT(current_command, 9)); + const bool tp = bool(BIT(current_command, 9)); + //const bool mp = bool(BIT(current_command, 8)); + const bool ids = bool(BIT(current_command, 7)); const bool de = bool(BIT(current_command, 5)); const int align = (current_command & 0x000000c00) >> 10; @@ -900,7 +1110,7 @@ void s3virge_vga_device::bitblt_monosrc_step() uint32_t dst = 0; // Windows 98 cares about this being initialized to non-zero for // greyed back/forward icons in Explorer, system icons and right click disabled Paste command. - uint32_t pat = s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_PAT_FG_CLR]; + uint32_t pat = m_bitblt.pat_fg_clr; int x; bool done = false; @@ -909,22 +1119,24 @@ void s3virge_vga_device::bitblt_monosrc_step() case 0: // 8bpp for(x=31;x>=0;x--) { - if(current_command & 0x80) - src = bitswap<32>(s3virge.s3d.image_xfer,7,6,5,4,3,2,1,0,15,14,13,12,11,10,9,8,23,22,21,20,19,18,17,16,31,30,29,28,27,26,25,24); + if(ids) + src = bitswap<32>(m_bitblt.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, src_stride()); - dst = read_pixel8(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current, dest_stride()); + src = read_pixel8(src_base,m_bitblt.x_src_current,m_bitblt.y_src_current, m_bitblt.src_stride); + dst = read_pixel8(dst_base,m_bitblt.x_current,m_bitblt.y_current, m_bitblt.dest_stride); if (de) { if(src & (1 << x)) - write_pixel8(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current,GetROP(rop, s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_SRC_FG_CLR], dst, pat) & 0xff); - else if(!(current_command & 0x200)) // only draw background colour if transparency is not set - write_pixel8(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current,GetROP(rop, s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_SRC_BG_CLR], dst, pat) & 0xff); + write_pixel8(dst_base,m_bitblt.x_current,m_bitblt.y_current,GetROP(rop, m_bitblt.src_fg_clr, dst, pat) & 0xff); + else if(!tp) + { + write_pixel8(dst_base,m_bitblt.x_current,m_bitblt.y_current,GetROP(rop, m_bitblt.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); + //printf("Pixel write(%i): X: %i Y: %i SRC: %04x DST: %04x PAT: %04x ROP: %02x\n",x,m_bitblt.x_current, m_bitblt.y_current, src, dst, pat, rop); done = advance_pixel(); - if((current_command & 0x80) && s3virge.s3d.bitblt_x_current == s3virge.s3d.bitblt_x_dst) + if((ids) && m_bitblt.x_current == m_bitblt.x_dst) { switch(align) { @@ -949,22 +1161,25 @@ void s3virge_vga_device::bitblt_monosrc_step() case 1: // 16bpp for(x=31;x>=0;x--) { - if(current_command & 0x80) - src = bitswap<32>(s3virge.s3d.image_xfer,7,6,5,4,3,2,1,0,15,14,13,12,11,10,9,8,23,22,21,20,19,18,17,16,31,30,29,28,27,26,25,24); + if(ids) + src = bitswap<32>(m_bitblt.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, src_stride()); - dst = read_pixel16(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current, dest_stride()); + src = read_pixel16(src_base,m_bitblt.x_src_current,m_bitblt.y_src_current, m_bitblt.src_stride); + dst = read_pixel16(dst_base,m_bitblt.x_current,m_bitblt.y_current, m_bitblt.dest_stride); if (de) { if(src & (1 << x)) - write_pixel16(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current,GetROP(rop, s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_SRC_FG_CLR], dst, pat) & 0xffff); - else if(!(current_command & 0x200)) // only draw background colour if transparency is not set - write_pixel16(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current,GetROP(rop, s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_SRC_BG_CLR], dst, pat) & 0xffff); + write_pixel16(dst_base,m_bitblt.x_current,m_bitblt.y_current,GetROP(rop, m_bitblt.src_fg_clr, dst, pat) & 0xffff); + else if(!tp) + { + // only draw background colour if transparency is not set + write_pixel16(dst_base,m_bitblt.x_current,m_bitblt.y_current,GetROP(rop, m_bitblt.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); + //printf("Pixel write(%i): X: %i Y: %i SRC: %04x DST: %04x PAT: %04x ROP: %02x\n",x,m_bitblt.x_current, m_bitblt.y_current, src, dst, pat, rop); done = advance_pixel(); - if((current_command & 0x80) && s3virge.s3d.bitblt_x_current == s3virge.s3d.bitblt_x_dst) + if((ids) && m_bitblt.x_current == m_bitblt.x_dst) { switch(align) { @@ -989,22 +1204,26 @@ void s3virge_vga_device::bitblt_monosrc_step() case 2: // 24bpp for(x=31;x>=0;x--) { - if(current_command & 0x80) - src = bitswap<32>(s3virge.s3d.image_xfer,7,6,5,4,3,2,1,0,15,14,13,12,11,10,9,8,23,22,21,20,19,18,17,16,31,30,29,28,27,26,25,24); + if(ids) + src = bitswap<32>(m_bitblt.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, src_stride()); - dst = read_pixel24(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current, dest_stride()); + src = read_pixel24(src_base,m_bitblt.x_src_current,m_bitblt.y_src_current, m_bitblt.src_stride); + dst = read_pixel24(dst_base,m_bitblt.x_current,m_bitblt.y_current, m_bitblt.dest_stride); if (de) { if(src & (1 << x)) - write_pixel24(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current,GetROP(rop, s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_SRC_FG_CLR], dst, pat)); - else if(!(current_command & 0x200)) // only draw background colour if transparency is not set - write_pixel24(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current,GetROP(rop, s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_SRC_BG_CLR], dst, pat)); + write_pixel24(dst_base,m_bitblt.x_current,m_bitblt.y_current,GetROP(rop, m_bitblt.src_fg_clr, dst, pat)); + else if(!tp) + { + // only draw background colour if transparency is not set + // TODO: shouldn't be supported by 24bpp? + write_pixel24(dst_base,m_bitblt.x_current,m_bitblt.y_current,GetROP(rop, m_bitblt.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); + //printf("Pixel write(%i): X: %i Y: %i SRC: %04x DST: %04x PAT: %04x ROP: %02x\n",x,m_bitblt.x_current, m_bitblt.y_current, src, dst, pat, rop); done = advance_pixel(); - if((current_command & 0x80) && s3virge.s3d.bitblt_x_current == s3virge.s3d.bitblt_x_dst) + if((ids) && m_bitblt.x_current == m_bitblt.x_dst) { switch(align) { @@ -1028,79 +1247,47 @@ void s3virge_vga_device::bitblt_monosrc_step() break; } - s3virge.s3d.bitblt_step_count++; + m_bitblt.step_count++; } -TIMER_CALLBACK_MEMBER(s3virge_vga_device::draw_step_tick) +inline void s3virge_vga_device::write_pixel24(uint32_t base, uint16_t x, uint16_t y, uint32_t val) { - // TODO: S3D state timing - switch(s3virge.s3d.state) + if(BIT(m_bitblt.command, 1)) { - case S3D_STATE_IDLE: - m_draw_timer->adjust(attotime::zero); - break; - case S3D_STATE_2DLINE: - line2d_step(); - break; - case S3D_STATE_2DPOLY: - poly2d_step(); - break; - case S3D_STATE_3DLINE: - line3d_step(); - break; - case S3D_STATE_3DPOLY: - poly3d_step(); - break; - case S3D_STATE_BITBLT: - bitblt_step(); - break; - } -} - -inline void s3virge_vga_device::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) + if(x < m_bitblt.clip_l || x > m_bitblt.clip_r || y < m_bitblt.clip_t || y > m_bitblt.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; -} + } -inline void s3virge_vga_device::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; + for (int i = 0; i < 3; i ++) + { + const u8 data = (val >> (8 * i)) & 0xff; + vga.memory[(base + i + (x * 3) + (y * m_bitblt.dest_stride)) % vga.svga_intf.vram_size] = data; + } } inline void s3virge_vga_device::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) + if(BIT(m_bitblt.command, 1)) + { + if(x < m_bitblt.clip_l || x > m_bitblt.clip_r || y < m_bitblt.clip_t || y > m_bitblt.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; + } + + for (int i = 0; i < 2; i ++) + { + const u8 data = (val >> (8 * i)) & 0xff; + vga.memory[(base + i + (x * 2) + (y * m_bitblt.dest_stride)) % vga.svga_intf.vram_size] = data; + } } inline void s3virge_vga_device::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) + if(BIT(m_bitblt.command, 1)) + { + if(x < m_bitblt.clip_l || x > m_bitblt.clip_r || y < m_bitblt.clip_t || y > m_bitblt.clip_b) return; - vga.memory[(base + x + (y*dest_stride())) % vga.svga_intf.vram_size] = val; -} - -inline uint32_t s3virge_vga_device::read_pixel32(uint32_t base, uint16_t x, uint16_t y, u16 stride_select) -{ - return (vga.memory[(base + (x * 4) + (y * stride_select)) % vga.svga_intf.vram_size] << 24) | - (vga.memory[(base + 1 + (x * 4) + (y * stride_select)) % vga.svga_intf.vram_size] << 16) | - (vga.memory[(base + 2 + (x * 4) + (y * stride_select)) % vga.svga_intf.vram_size] << 8) | - vga.memory[(base + 3 + (x * 4) + (y * stride_select)) % vga.svga_intf.vram_size]; + } + vga.memory[(base + x + (y * m_bitblt.dest_stride)) % vga.svga_intf.vram_size] = val; } inline uint32_t s3virge_vga_device::read_pixel24(uint32_t base, uint16_t x, uint16_t y, u16 stride_select) @@ -1121,44 +1308,69 @@ inline uint8_t s3virge_vga_device::read_pixel8(uint32_t base, uint16_t x, uint16 return vga.memory[(base + x + (y * stride_select)) % vga.svga_intf.vram_size]; } -// 2D command register format - A500 (BitBLT), A900 (2D line), AD00 (2D Polygon) -// bit 0 - Autoexecute, if set command is executed when the highest relevant register is written to (A50C / A97C / AD7C) -// bit 1 - Enable hardware clipping -// bits 2-4 - Destination colour format - (0 = 8bpp palettised, 1 = 16bpp RGB1555 or RGB565, 2 = 24bpp RGB888 -// bit 5 - Draw enable - if reset, doesn't draw anything, but is still executed -// bit 6 - Image source Mono transfer, if set source is mono, otherwise source is the same pixel depth as the destination -// bit 7 - Image data source - 0 = source is in video memory, 1 = source is from the image transfer port (CPU / system memory) -// bit 8 - Mono pattern - if set, pattern data is mono, otherwise pattern data is the same pixel depth as the destination -// Cleared to 0 if using an ROP with a colour source Must be set to 1 if doing a rectangle fill operation -// bit 9 - Transparency - if set, does not update if a background colour is selected. Effectively only if bit 7 is set, Typically used for text display. -// bits 10-11 - Image transfer alignment - Data for an image transfer is byte (0), word (1), or doubleword (2) aligned. All image transfers are doubleword in size. -// bits 12-13 - First doubleword offset - (Image transfers) - start with the given byte (+1) in a doubleword for an image transfer -// bits 17-24 - MS Windows Raster Operation -// bit 25 - X Positive - if set, BitBLT is performed from left to right, otherwise, from right to left -// bit 26 - Y Positive - if set, BitBLT is performed from top to bottom, otherwise from bottom to top -// bits 27-30 - 2D Command - 0000 = BitBLT, 0010 = Rectangle Fill, 0011 = Line Draw, 0101 = Polygon Fill, 1111 = NOP (Turns off autoexecute without executing a command) -// bit 31 - 2D / 3D Select - - +// MM8504 uint32_t s3virge_vga_device::s3d_sub_status_r() { uint32_t res = 0x00000000; - if(!s3virge.s3d.busy) - res |= 0x00002000; // S3d engine is idle + // check for idle + res |= (m_s3d_state == S3D_STATE_IDLE) << 13; + //if (m_s3d_state == S3D_STATE_BITBLT && m_bitblt.xfer_mode == true && m_xfer_fifo.empty()) + // res |= 1 << 13; - //res |= (s3virge.s3d.cmd_fifo_slots_free << 8); - if(s3virge.s3d.cmd_fifo_slots_free == 16) - res |= 0x1f00; + //res |= (m_bitblt.cmd_fifo_slots_free << 8); + // NOTE: can actually be 24 FIFO depth with specific Scenic Mode + // (looks different FIFO altogether) + // & 0x1f00 + //res |= std::min(m_bitblt_fifo.queue_length(), 16) << 8; + // TODO: this likely listens for xfer FIFO, not command + res |= (16 - (m_bitblt_fifo.queue_length() / 15)) << 8; return res; } +/* + * xx-- ---- ---- ---- S3d Engine Software Reset + * 00-- ---- ---- ---- |- No change + * 01-- ---- ---- ---- |- S3d Engine enabled + * 10-- ---- ---- ---- |- Reset (alias of CR66 bit 1 = 1) + * 11-- ---- ---- ---- |- + * --x- ---- ---- ---- 3DF ENB S3d FIFO Empty IRQ Enable + * ---x ---- ---- ---- CDD ENB Command DMA Done IRQ Enable + * ---- x--- ---- ---- FIFO ENB EMP Command FIFO Empty IRQ Enable + * ---- -x-- ---- ---- FIFO ENB OVF Command FIFO Overflow IRQ Enable + * ---- --x- ---- ---- 3DD ENB S3d Engine Done IRQ Enable + * ---- ---x ---- ---- VSY ENB Vertical Sync IRQ Enable + * ---- ---- x--- ---- HDD ENB Host DMA Done IRQ Enable + * + * ---- ---- -1-- ---- 3DF CLR S3d FIFO Empty IRQ Acknowledge + * ---- ---- --1- ---- CDD CLR Command DMA Done IRQ Acknowledge + * ---- ---- ---1 ---- HDD CLR Host DMA Done IRQ Acknowledge + * ---- ---- ---- 1--- FIFO CLE Command FIFO Empty IRQ Acknowledge + * ---- ---- ---- -1-- FIFO CLO Command FIFO Overflow IRQ Acknowledge + * ---- ---- ---- --1- 3DD CLR S3d Engine DOne IRQ Acknowledge + * ---- ---- ---- ---1 VSY CLR Vertical Sync IRQ Acknowledge + */ void s3virge_vga_device::s3d_sub_control_w(uint32_t data) { - s3virge.interrupt_enable = data & 0x00003f80; - // TODO: bits 14-15==10 - reset engine LOGMMIO("Sub control = %08x\n", data); + const u8 s3d_rst = (data >> 14) & 3; + switch(s3d_rst) + { + // NOP + case 0: break; + // TODO: case 1 S3d Engine enabled + case 2: s3d_reset(); break; + default: + case 3: + // happens in BeOS 4.0 already, alias for a reset? + LOG("S3D RST state set\n"); + break; + } + + m_interrupt_enable = data & 0x00003f80; + if (m_interrupt_enable) + popmessage("s3virge.cpp: IRQ enable warning %08x", m_interrupt_enable); } /* @@ -1172,64 +1384,34 @@ uint32_t s3virge_vga_device::s3d_func_ctrl_r() { uint32_t ret = 0; - ret |= (s3virge.s3d.cmd_fifo_slots_free << 6); +// ret |= (s3d_fifo_size << 6); + ret |= 0xf << 6; return ret; } -uint32_t s3virge_vga_device::s3d_register_r(offs_t offset) +// base 0xa000 +void s3virge_vga_device::s3d_register_map(address_map &map) { - uint32_t res = 0; - 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; -} - -void s3virge_vga_device::s3d_register_w(offs_t offset, uint32_t data) -{ - 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 0x500/4: - if(!(data & 0x00000001)) - add_command(op_type); - break; - case 0x50c/4: - if(s3virge.s3d.reg[op_type][S3D_REG_COMMAND] & 0x00000001) // autoexecute enabled - add_command(op_type); - break; - } + map(0x0100, 0x01bf).lrw8( + NAME([this] (offs_t offset) { + return m_bitblt.pattern[offset]; + }), + NAME([this] (offs_t offset, u8 data) { + m_bitblt.pattern[offset] = data; + }) + ); + map(0x04d4, 0x050f).lrw32( + NAME([this] (offs_t offset) { + return m_bitblt_latch[offset]; + }), + NAME([this] (offs_t offset, u32 data, u32 mem_mask) { + const u32 native_offset = (offset * 4) + 0xa4d4; + LOGMMIO("MM%04X = %08x & %08x\n", native_offset, data, mem_mask); + COMBINE_DATA(&m_bitblt_latch[offset]); + if (native_offset == 0xa500 && !(BIT(data, 0))) + add_command(0); + if (native_offset == 0xa50c && BIT(m_bitblt_latch[11], 0)) + add_command(0); + }) + ); } - diff --git a/src/devices/video/s3virge.h b/src/devices/video/s3virge.h index d99b14446f573..8592fd80db3e2 100644 --- a/src/devices/video/s3virge.h +++ b/src/devices/video/s3virge.h @@ -34,42 +34,28 @@ class s3virge_vga_device : public s3trio64_vga_device uint32_t s3d_func_ctrl_r(); // void s3d_func_ctrl_w(offs_t offset, uint32_t data, u32 mem_mask = ~0); - uint32_t s3d_register_r(offs_t offset); - void s3d_register_w(offs_t offset, uint32_t data); + void s3d_register_map(address_map &map); - void image_xfer(uint32_t data) + void streams_control_map(address_map &map); + + void image_xfer(offs_t offset, uint32_t data, uint32_t mem_mask) { -// 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(); - } + if (mem_mask != 0xffff'ffff) + logerror("Warning: image_xfer access with non-32 parallelism %08x & %08x\n", data, mem_mask); + + m_xfer_fifo.enqueue(data); + //machine().scheduler().synchronize(); } - 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; } - uint32_t get_linear_address_size_full() { return s3virge.linear_address_size_full; } - bool is_linear_address_active() { return s3virge.linear_address_enable; } + uint32_t get_linear_address() { return m_linear_address; } + void set_linear_address(uint32_t addr) { m_linear_address = addr; } + uint8_t get_linear_address_size() { return m_linear_address_size; } + uint32_t get_linear_address_size_full() { return m_linear_address_size_full; } + bool is_linear_address_active() { return m_linear_address_enable; } bool is_new_mmio_active() { return s3.cr53 & 0x08; } - uint16_t src_stride() - { - return (s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_DEST_SRC_STR] >> 0) & 0xfff8; - } - uint16_t dest_stride() - { -// if((s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x0000001c) == 0x08) -// { -// 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; - } + // has no 8514/A device + // FIXME: should map this dependency in machine_config ibm8514a_device* get_8514() { fatalerror("s3virge requested non-existent 8514/A device\n"); return nullptr; } protected: @@ -100,9 +86,10 @@ class s3virge_vga_device : public s3trio64_vga_device OP_3DTRI }; - enum + enum s3d_state_t { S3D_STATE_IDLE = 0, + S3D_STATE_COMMAND_RX, S3D_STATE_BITBLT, S3D_STATE_2DLINE, S3D_STATE_2DPOLY, @@ -110,81 +97,75 @@ class s3virge_vga_device : public s3trio64_vga_device 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 { + u8 psidf = 0; + u8 pshfc = 0; + u16 primary_stride = 0; + } m_streams; + + u32 m_interrupt_enable = 0; + + bool m_linear_address_enable = false; + u32 m_linear_address = 0; + u8 m_linear_address_size = 0; + u32 m_linear_address_size_full = 0; + + u8 m_cr66 = 0; + +// util::fifo m_bitblt_fifo; + // TODO: sketchy, command pipeline size is unclear + util::fifo m_bitblt_fifo; + util::fifo m_xfer_fifo; + // TODO: sketchy type, verify implications of using a struct class with util::fifo + // (may be required if we want to glue in a "execute command" insert flag) + u32 m_bitblt_latch[15]{}; + s3d_state_t m_s3d_state = S3D_STATE_IDLE; struct { - uint32_t linear_address; - uint8_t linear_address_size; - uint32_t linear_address_size_full; - bool linear_address_enable; - uint32_t interrupt_enable; - - struct - { - 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; - - TIMER_CALLBACK_MEMBER(draw_step_tick); - - inline void write_pixel32(uint32_t base, uint16_t x, uint16_t y, uint32_t val); + bool xfer_mode = false; + + u8 pattern[0xc0]{}; + + u16 x_src = 0; + u16 y_src = 0; + u16 x_dst = 0; + u16 y_dst = 0; + s16 x_current = 0; + s16 y_current = 0; + s16 x_src_current = 0; + s16 y_src_current = 0; + s8 pat_x = 0; + s8 pat_y = 0; + u16 height = 0; + u16 width = 0; + u32 step_count = 0; + u64 mono_pattern = 0; + u32 current_pixel = 0; + // current position in a pixel (for packed 24bpp colour image transfers) + u32 pixel_pos = 0; + // source data via image transfer ports + u32 image_xfer = 0; + u16 clip_l = 0; + u16 clip_r = 0; + u16 clip_t = 0; + u16 clip_b = 0; + u32 command = 0; + u32 src_base = 0; + u32 dest_base = 0; + u32 pat_bg_clr = 0; + u32 pat_fg_clr = 0; + u32 src_bg_clr = 0; + u32 src_fg_clr = 0; + u16 dest_stride = 0; + u16 src_stride = 0; + } m_bitblt; + + TIMER_CALLBACK_MEMBER(op_timer_cb); + inline void write_pixel24(uint32_t base, uint16_t x, uint16_t y, uint32_t val); inline void write_pixel16(uint32_t base, uint16_t x, uint16_t y, uint16_t val); inline void write_pixel8(uint32_t base, uint16_t x, uint16_t y, uint8_t val); - inline uint32_t read_pixel32(uint32_t base, uint16_t x, uint16_t y, u16 stride_select); inline uint32_t read_pixel24(uint32_t base, uint16_t x, uint16_t y, u16 stride_select); inline uint16_t read_pixel16(uint32_t base, uint16_t x, uint16_t y, u16 stride_select); inline uint8_t read_pixel8(uint32_t base, uint16_t x, uint16_t y, u16 stride_select); @@ -196,9 +177,8 @@ class s3virge_vga_device : public s3trio64_vga_device virtual void s3_define_video_mode(void) override; - // has no 8514/A device private: - emu_timer* m_draw_timer; + emu_timer *m_op_timer; void bitblt_step(); void bitblt_colour_step(); void bitblt_monosrc_step(); @@ -206,9 +186,12 @@ class s3virge_vga_device : public s3trio64_vga_device void poly2d_step(); void line3d_step(); void poly3d_step(); - void add_command(int cmd_type); - void command_start(); + void add_command(u8 cmd_type); + void command_enqueue(u8 op_type); + void command_dequeue(u8 op_type); void command_finish(); + + void s3d_reset(); };