From 47887c3bec0ddff313698ee54356192f80d08341 Mon Sep 17 00:00:00 2001 From: angelosa Date: Wed, 7 Feb 2024 22:46:18 +0100 Subject: [PATCH 01/14] video/s3virge.cpp: initial steps for major structural refactoring --- src/devices/bus/pci/virge_pci.cpp | 45 ++-- src/devices/video/pc_vga.cpp | 2 +- src/devices/video/s3virge.cpp | 328 +++++++++++++++++++----------- src/devices/video/s3virge.h | 16 +- 4 files changed, 252 insertions(+), 139 deletions(-) diff --git a/src/devices/bus/pci/virge_pci.cpp b/src/devices/bus/pci/virge_pci.cpp index 93853ed5cfa04..a992f26d12297 100644 --- a/src/devices/bus/pci/virge_pci.cpp +++ b/src/devices/bus/pci/virge_pci.cpp @@ -31,6 +31,7 @@ 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(0x8000,0x8043) PCI Configuration Space regs //map(0x8180,0x81ff) primary/secondary stream control //map(0x8200,0x821f) memory port controller @@ -39,23 +40,32 @@ 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)); + 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 +162,10 @@ 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; + // medium DEVSELB + status = 0x0200; + remap_cb(); machine().save().register_postload(save_prepost_delegate(FUNC(virge_pci_device::postload), this)); } @@ -174,18 +188,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 e7cfe9d90e7f8..6aded62134408 100644 --- a/src/devices/video/pc_vga.cpp +++ b/src/devices/video/pc_vga.cpp @@ -1099,7 +1099,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 a3d9c0c14e8bb..97e43b4879ceb 100644 --- a/src/devices/video/s3virge.cpp +++ b/src/devices/video/s3virge.cpp @@ -6,7 +6,7 @@ * Implementation of the S3 Virge series of video card * * TODO: - * - Proper FIFOs; + * - Proper FIFOs, remove leaky abstraction; * - Implement 3d commands; * - Implement remaining ROP commands; * - Secondary stream mixing; @@ -31,19 +31,20 @@ //#include +#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 VERBOSE (LOG_REG | LOG_CMD | LOG_MMIO) //#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 CRTC_PORT_ADDR ((vga.miscellaneous_output & 1) ? 0x3d0 : 0x3b0) @@ -152,6 +153,18 @@ void s3virgedx_rev1_vga_device::device_start() s3.id_cr30 = 0xe1; // CR30 } +void s3virge_vga_device::s3d_reset() +{ + s3virge.s3d.state = S3D_STATE_IDLE; + s3virge.s3d.cmd_fifo_current_ptr = 0; + s3virge.s3d.cmd_fifo_slots_free = 16; + s3virge.s3d.busy = false; + // beos 4.x (and presumably Win 3.1) never sets this when using BitBlt, + // expecting 0xf0 ROPs to be 1-filled rather than 0 + s3virge.s3d.bitblt_mono_pattern = (u64)0xffff'ffff'ffff'ffff; + // TODO: the rest of the pipeline, particularly more state reset on dual boot transitions. +} + void s3virge_vga_device::device_reset() { s3_vga_device::device_reset(); @@ -159,13 +172,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() @@ -330,6 +337,23 @@ void s3virge_vga_device::crtc_map(address_map &map) }) ); //map(0x5d, 0x5e).unmapr(); + map(0x66, 0x66).lrw8( + NAME([this] (offs_t offset) { + return s3virge.cr66; + }), + NAME([this] (offs_t offset, u8 data) { + s3virge.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() @@ -458,7 +482,7 @@ void s3virge_vga_device::fb_w(offs_t offset, uint8_t data) 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) @@ -466,9 +490,10 @@ void s3virge_vga_device::add_command(int cmd_type) LOGCMD("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); + memcpy(s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_next_ptr].reg, s3virge.s3d.reg[0], 0x200); 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[s3virge.s3d.cmd_fifo_next_ptr].command = s3virge.s3d.command; + LOGCMD("Added command type %i cmd %08x ptr %u\n",s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_next_ptr].op_type, s3virge.s3d.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; @@ -481,7 +506,7 @@ void s3virge_vga_device::add_command(int cmd_type) 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; + u8 cmd_type = s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].op_type & 0xf; switch(cmd_type) { @@ -517,19 +542,17 @@ void s3virge_vga_device::command_start() 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)) + if(!(s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].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_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(); + break; + default: + LOGCMD(" command detected [%u]\n", cmd_type, s3virge.s3d.cmd_fifo_current_ptr); break; } } @@ -645,8 +668,8 @@ 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 = s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].command & 0x02000000; // X Positive + ypos = s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].command & 0x04000000; // Y Positive if(xpos) { left = s3virge.s3d.bitblt_x_dst; @@ -695,7 +718,7 @@ bool s3virge_vga_device::advance_pixel() 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", + LOGPIXEL("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, @@ -708,7 +731,7 @@ bool s3virge_vga_device::advance_pixel() void s3virge_vga_device::bitblt_step() { - if((s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x40)) + if((s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].command & 0x40)) bitblt_monosrc_step(); else bitblt_colour_step(); @@ -720,13 +743,18 @@ void s3virge_vga_device::bitblt_colour_step() // get source and destination addresses uint32_t src_base = s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_SRC_BASE] & 0x003ffff8; uint32_t dst_base = s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_DEST_BASE] & 0x003ffff8; - - const u32 current_command = s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND]; + const u32 current_command = s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].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 ids = bool(BIT(current_command, 7)); const bool de = bool(BIT(current_command, 5)); + const u8 command_type = current_command >> 27; + + // NOP disables autoexecute (is it supposed to not execute rest of command?) + if (command_type == 0xf) + s3virge.s3d.command &= ~1; uint32_t src = 0; uint32_t dst = 0; @@ -739,23 +767,29 @@ void s3virge_vga_device::bitblt_colour_step() case 0: // 8bpp for(x=0;x<4;x++) { - if(current_command & 0x80) + if(ids) + { src = s3virge.s3d.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) { - 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 = (BIT(s3virge.s3d.bitblt_mono_pattern, (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]; } - dst = read_pixel8(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current, dest_stride()); + dst = read_pixel8(dst_base,s3virge.s3d.bitblt_x_current, s3virge.s3d.bitblt_y_current, dest_stride()); if (de) + { write_pixel8(dst_base, s3virge.s3d.bitblt_x_current, s3virge.s3d.bitblt_y_current, GetROP(rop, src, dst, pat) & 0xff); + } done = advance_pixel(); if(done) @@ -763,7 +797,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) && s3virge.s3d.bitblt_x_current == s3virge.s3d.bitblt_x_dst) { if(align == 2) // doubleword aligned, end here break; @@ -778,15 +812,19 @@ void s3virge_vga_device::bitblt_colour_step() } break; case 1: // 16bpp - if(current_command & 0x80) + if(ids) + { src = s3virge.s3d.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) { 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]); + ? 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; @@ -799,9 +837,9 @@ void s3virge_vga_device::bitblt_colour_step() command_finish(); break; } - if((current_command & 0x80) && s3virge.s3d.bitblt_x_current == s3virge.s3d.bitblt_x_dst && align == 2) + if((ids) && s3virge.s3d.bitblt_x_current == s3virge.s3d.bitblt_x_dst && align == 2) break; // if a new line of an image transfer, and is dword aligned, stop here - if(current_command & 0x80) + if(ids) src = s3virge.s3d.image_xfer >> 16; else src = read_pixel16(src_base,s3virge.s3d.bitblt_x_src_current,s3virge.s3d.bitblt_y_src_current, src_stride()); @@ -809,7 +847,8 @@ void s3virge_vga_device::bitblt_colour_step() if(current_command & 0x100) { pat = (s3virge.s3d.bitblt_mono_pattern & (1 << ((s3virge.s3d.bitblt_pat_y*8) + (7-s3virge.s3d.bitblt_pat_x))) - ? s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_PAT_FG_CLR] : s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_PAT_BG_CLR]); + ? 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; @@ -819,7 +858,7 @@ void s3virge_vga_device::bitblt_colour_step() command_finish(); break; case 2: // 24bpp - if(current_command & 0x80) + if(ids) { src = s3virge.s3d.image_xfer; for(x=0;x<4;x++) @@ -842,7 +881,7 @@ void s3virge_vga_device::bitblt_colour_step() 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((current_command & 0x80) && s3virge.s3d.bitblt_x_current == s3virge.s3d.bitblt_x_dst) + if((ids) && s3virge.s3d.bitblt_x_current == s3virge.s3d.bitblt_x_dst) { if(align == 2) // doubleword aligned, end here x = 4; @@ -889,12 +928,18 @@ void s3virge_vga_device::bitblt_monosrc_step() 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]; + const u32 current_command = s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].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 ids = bool(BIT(current_command, 7)); const bool de = bool(BIT(current_command, 5)); const int align = (current_command & 0x000000c00) >> 10; + const u8 command_type = current_command >> 27; + + // NOP disables autoexecute (is it supposed to not execute rest of command?) + if (command_type == 0xf) + s3virge.s3d.command &= ~1; uint32_t src = 0; uint32_t dst = 0; @@ -909,7 +954,7 @@ void s3virge_vga_device::bitblt_monosrc_step() case 0: // 8bpp for(x=31;x>=0;x--) { - if(current_command & 0x80) + if(ids) 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, src_stride()); @@ -919,12 +964,14 @@ void s3virge_vga_device::bitblt_monosrc_step() { 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 + else if(!tp) + { 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((current_command & 0x80) && s3virge.s3d.bitblt_x_current == s3virge.s3d.bitblt_x_dst) + if((ids) && s3virge.s3d.bitblt_x_current == s3virge.s3d.bitblt_x_dst) { switch(align) { @@ -949,7 +996,7 @@ void s3virge_vga_device::bitblt_monosrc_step() case 1: // 16bpp for(x=31;x>=0;x--) { - if(current_command & 0x80) + if(ids) 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, src_stride()); @@ -959,12 +1006,15 @@ void s3virge_vga_device::bitblt_monosrc_step() { 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 + else if(!tp) + { + // 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((current_command & 0x80) && s3virge.s3d.bitblt_x_current == s3virge.s3d.bitblt_x_dst) + if((ids) && s3virge.s3d.bitblt_x_current == s3virge.s3d.bitblt_x_dst) { switch(align) { @@ -989,7 +1039,7 @@ void s3virge_vga_device::bitblt_monosrc_step() case 2: // 24bpp for(x=31;x>=0;x--) { - if(current_command & 0x80) + if(ids) 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, src_stride()); @@ -999,12 +1049,16 @@ void s3virge_vga_device::bitblt_monosrc_step() { 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 + else if(!tp) + { + // only draw background colour if transparency is not set + // TODO: shouldn't be supported by 24bpp? 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((current_command & 0x80) && s3virge.s3d.bitblt_x_current == s3virge.s3d.bitblt_x_dst) + if((ids) && s3virge.s3d.bitblt_x_current == s3virge.s3d.bitblt_x_dst) { switch(align) { @@ -1059,7 +1113,7 @@ TIMER_CALLBACK_MEMBER(s3virge_vga_device::draw_step_tick) 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(s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].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; @@ -1070,7 +1124,7 @@ inline void s3virge_vga_device::write_pixel32(uint32_t base, uint16_t x, uint16_ 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(s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].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; @@ -1080,7 +1134,7 @@ inline void s3virge_vga_device::write_pixel24(uint32_t base, uint16_t x, uint16_ 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(s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].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; @@ -1089,7 +1143,7 @@ inline void s3virge_vga_device::write_pixel16(uint32_t base, uint16_t x, uint16_ 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(s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].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; @@ -1148,17 +1202,54 @@ uint32_t s3virge_vga_device::s3d_sub_status_r() res |= 0x00002000; // S3d engine is idle //res |= (s3virge.s3d.cmd_fifo_slots_free << 8); - if(s3virge.s3d.cmd_fifo_slots_free == 16) - res |= 0x1f00; + // NOTE: can actually be 24 FIFO depth with specific Scenic Mode (verify if different FIFO altogether) + // & 0x1f00 + res |= std::min(s3virge.s3d.cmd_fifo_slots_free, 16) << 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; + } + if (s3virge.interrupt_enable) + popmessage("s3virge.cpp: IRQ enable warning %08x", s3virge.interrupt_enable); } /* @@ -1176,60 +1267,59 @@ uint32_t s3virge_vga_device::s3d_func_ctrl_r() 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 s3virge.s3d.pattern[offset]; + }), + NAME([this] (offs_t offset, u8 data) { + s3virge.s3d.pattern[offset] = data; + }) + ); + // TODO: remove this trampoline + map(0x0400, 0x05ff).lrw32( + NAME([this] (offs_t offset) { + return s3virge.s3d.reg[0][offset]; + }), + NAME([this] (offs_t offset, u32 data, u32 mem_mask) { + LOGMMIO("MM%04X = %08x\n", (offset*4)+0xa400, data); + COMBINE_DATA(&s3virge.s3d.reg[0][offset]); + }) + ); + map(0x04e8, 0x04ef).lrw32( + NAME([this] (offs_t offset) { + return s3virge.s3d.bitblt_mono_pattern >> (offset * 32); + }), + NAME([this] (offs_t offset, u32 data, u32 mem_mask) { + LOGMMIO("MM%04X = %08x\n", (offset*4)+0xa4e8, data); + if (offset) + s3virge.s3d.bitblt_mono_pattern = ((u64)data << 32) | (s3virge.s3d.bitblt_mono_pattern & 0xffff'ffff); + else + s3virge.s3d.bitblt_mono_pattern = (data & 0xffff'ffff) | (u64)(s3virge.s3d.bitblt_mono_pattern & 0xffff'ffff'0000'0000); + }) + ); + map(0x0500, 0x0503).lrw32( + NAME([this] (offs_t offset) { + return s3virge.s3d.command; + }), + NAME([this] (offs_t offset, u32 data, u32 mem_mask) { + LOGMMIO("MMA500 = %08x\n", data); + COMBINE_DATA(&s3virge.s3d.command); + if(!(BIT(data, 0))) + add_command(0); + }) + ); + map(0x050c, 0x050f).lrw32( + NAME([this] (offs_t offset) { + return s3virge.s3d.reg[0][S3D_REG_RDEST_XY]; + }), + NAME([this] (offs_t offset, u32 data, u32 mem_mask) { + LOGMMIO("MMA50C = %08x\n", data); + COMBINE_DATA(&s3virge.s3d.reg[0][S3D_REG_RDEST_XY]); + if(BIT(s3virge.s3d.command, 0)) // autoexecute enabled + add_command(0); + }) + ); } - diff --git a/src/devices/video/s3virge.h b/src/devices/video/s3virge.h index 812634970cdf6..00fe1282241dc 100644 --- a/src/devices/video/s3virge.h +++ b/src/devices/video/s3virge.h @@ -34,8 +34,7 @@ class s3virge_vga_device : public s3_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) { @@ -123,7 +122,7 @@ class s3virge_vga_device : public s3_vga_device 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_COMMAND = 0x100/4, S3D_REG_RWIDTH_HEIGHT = 0x104/4, S3D_REG_RSRC_XY = 0x108/4, S3D_REG_RDEST_XY = 0x10c/4 @@ -143,15 +142,16 @@ class s3virge_vga_device : public s3_vga_device bool busy; struct { - uint32_t reg[256]; + uint32_t reg[0x200/4]; int op_type; + uint32_t command; } 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]; + uint32_t reg[5][0x200/4]; // BitBLT command state uint16_t bitblt_x_src; @@ -175,7 +175,9 @@ class s3virge_vga_device : public s3_vga_device uint16_t clip_r; uint16_t clip_t; uint16_t clip_b; + uint32_t command; } s3d; + uint8_t cr66; } s3virge; TIMER_CALLBACK_MEMBER(draw_step_tick); @@ -206,9 +208,11 @@ class s3virge_vga_device : public s3_vga_device void poly2d_step(); void line3d_step(); void poly3d_step(); - void add_command(int cmd_type); + void add_command(u8 cmd_type); void command_start(); void command_finish(); + + void s3d_reset(); }; From 67690779555098bc28693167b153117921eb9832 Mon Sep 17 00:00:00 2001 From: angelosa Date: Sat, 24 Feb 2024 21:32:57 +0100 Subject: [PATCH 02/14] video/s3virge: fix ViRGE spelling --- src/devices/video/s3virge.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/devices/video/s3virge.cpp b/src/devices/video/s3virge.cpp index 8b0686b901614..86bb320af0b7d 100644 --- a/src/devices/video/s3virge.cpp +++ b/src/devices/video/s3virge.cpp @@ -3,10 +3,12 @@ /* * 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, remove leaky abstraction; + * - Backport 2d engine to Trio64; * - Implement 3d commands; * - Implement remaining ROP commands; * - Secondary stream mixing; From 489dcb49708400a145d1d2c4429e2b2656d87839 Mon Sep 17 00:00:00 2001 From: angelosa Date: Sat, 24 Feb 2024 23:05:06 +0100 Subject: [PATCH 03/14] pci/virge_pci: fix command_mask --- src/devices/bus/pci/virge_pci.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/devices/bus/pci/virge_pci.cpp b/src/devices/bus/pci/virge_pci.cpp index 53c97562d3ba7..847796bba12ad 100644 --- a/src/devices/bus/pci/virge_pci.cpp +++ b/src/devices/bus/pci/virge_pci.cpp @@ -163,6 +163,8 @@ void virge_pci_device::device_start() set_map_address(0, 0x70000000); command = 0x0000; + // DAC SNP / BME / MEM / I/O + command_mask = 0x27; // medium DEVSELB status = 0x0200; From 0a1e14e9cda054ab0e0b2cc0b6e9c100e6731e21 Mon Sep 17 00:00:00 2001 From: angelosa Date: Tue, 26 Mar 2024 02:46:54 +0100 Subject: [PATCH 04/14] video/s3virge: base conversion to FIFO --- src/devices/video/s3virge.cpp | 337 +++++++++++++++++++++++----------- src/devices/video/s3virge.h | 44 +++-- 2 files changed, 259 insertions(+), 122 deletions(-) diff --git a/src/devices/video/s3virge.cpp b/src/devices/video/s3virge.cpp index 8e7ae53691775..ea6e7e830f4e0 100644 --- a/src/devices/video/s3virge.cpp +++ b/src/devices/video/s3virge.cpp @@ -107,18 +107,19 @@ void s3virge_vga_device::device_start() 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_cmd_timer = timer_alloc(FUNC(s3virge_vga_device::command_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"); +// 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"); // Initialise hardware graphics cursor colours, Windows 95 doesn't touch the registers for some reason for (int x = 0; x < 4; x++) @@ -157,13 +158,15 @@ void s3virgedx_rev1_vga_device::device_start() void s3virge_vga_device::s3d_reset() { + m_bitblt_fifo.clear(); + m_cmd_timer->adjust(attotime::never); + m_draw_timer->adjust(attotime::never); + s3virge.s3d.state = S3D_STATE_IDLE; - s3virge.s3d.cmd_fifo_current_ptr = 0; - s3virge.s3d.cmd_fifo_slots_free = 16; s3virge.s3d.busy = false; // beos 4.x (and presumably Win 3.1) never sets this when using BitBlt, // expecting 0xf0 ROPs to be 1-filled rather than 0 - s3virge.s3d.bitblt_mono_pattern = (u64)0xffff'ffff'ffff'ffff; + m_bitblt_latch.mono_pat = (u64)0xffff'ffff'ffff'ffff; // TODO: the rest of the pipeline, particularly more state reset on dual boot transitions. } @@ -486,75 +489,94 @@ void s3virge_vga_device::fb_w(offs_t offset, uint8_t data) void s3virge_vga_device::add_command(u8 cmd_type) { - // add command to S3D FIFO - if(s3virge.s3d.cmd_fifo_slots_free == 0) - { - LOGCMD("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[0], 0x200); - s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_next_ptr].op_type = cmd_type; - s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_next_ptr].command = s3virge.s3d.command; - LOGCMD("Added command type %i cmd %08x ptr %u\n",s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_next_ptr].op_type, s3virge.s3d.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 + // TODO: handle full FIFO (should discard operation?) + if(m_bitblt_fifo.full()) + throw emu_fatalerror("s3virge: FIFO full"); + m_bitblt_fifo.enqueue(m_bitblt_latch); + + LOGCMD("Added command type %i %08x\n", cmd_type, m_bitblt_latch.cmd_set); + + m_cmd_timer->adjust(attotime::from_usec(1), 0, attotime::from_usec(1)); + +// s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_next_ptr].op_type = cmd_type; +// s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_next_ptr].command = s3virge.s3d.command; +// LOGCMD("Added command type %i cmd %08x ptr %u\n",s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_next_ptr].op_type, s3virge.s3d.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 +// s3virge.s3d.cmd_fifo_slots_free--; } -void s3virge_vga_device::command_start() +TIMER_CALLBACK_MEMBER(s3virge_vga_device::command_timer_cb) { + if (m_bitblt_fifo.empty() || s3virge.s3d.busy) + return; + + bitblt_struct command_struct = m_bitblt_fifo.dequeue(); + // start next command in FIFO - u8 cmd_type = s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].op_type & 0xf; + const u8 cmd_type = 0; //s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].op_type & 0xf; switch(cmd_type) { case OP_2DLINE: - LOGCMD("2D Line command (unsupported) [%u]\n", s3virge.s3d.cmd_fifo_current_ptr); + //LOGCMD("2D Line command (unsupported) [%u]\n", s3virge.s3d.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", s3virge.s3d.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", s3virge.s3d.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", s3virge.s3d.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_src = (command_struct.rsrc_xy & 0x07ff0000) >> 16; + s3virge.s3d.bitblt_y_src = (command_struct.rsrc_xy & 0x000007ff); + s3virge.s3d.bitblt_x_dst = (command_struct.rdest_xy & 0x07ff0000) >> 16; + s3virge.s3d.bitblt_y_dst = (command_struct.rdest_xy & 0x000007ff); + s3virge.s3d.bitblt_width = (command_struct.rwidth_height & 0xffff0000) >> 16; + s3virge.s3d.bitblt_height = (command_struct.rwidth_height & 0x0000ffff); + // TODO: these four goes negative at second transfer of beos 4 (two's complement?) 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].command & 0x00000080)) + s3virge.s3d.clip_r = command_struct.clip_l_r & 0x000007ff; + s3virge.s3d.clip_l = (command_struct.clip_l_r & 0x07ff0000) >> 16; + s3virge.s3d.clip_b = command_struct.clip_t_b & 0x000007ff; + s3virge.s3d.clip_t = (command_struct.clip_t_b & 0x07ff0000) >> 16; + s3virge.s3d.busy = true; + //if(!(BIT(command_struct.cmd_set, 7))) + { 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; - LOGCMD("Started BitBLT command [%u]\n", s3virge.s3d.cmd_fifo_current_ptr); + s3virge.s3d.command = command_struct.cmd_set; + s3virge.s3d.src_base = command_struct.src_base; + s3virge.s3d.dest_base = command_struct.dest_base; + s3virge.s3d.pat_fg_clr = command_struct.pat_fg_clr; + s3virge.s3d.pat_bg_clr = command_struct.pat_bg_clr; + s3virge.s3d.src_fg_clr = command_struct.src_fg_clr; + s3virge.s3d.src_bg_clr = command_struct.src_bg_clr; + s3virge.s3d.dest_src_stride = command_struct.dest_src_str; + LOGCMD("Started BitBLT command [%08x]\n", s3virge.s3d.command); break; default: - LOGCMD(" command detected [%u]\n", cmd_type, s3virge.s3d.cmd_fifo_current_ptr); + LOGCMD(" command detected [%08x]\n", cmd_type, s3virge.s3d.command); break; } } @@ -562,21 +584,18 @@ void s3virge_vga_device::command_start() 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; + s3virge.s3d.busy = false; m_draw_timer->adjust(attotime::never); + if (m_bitblt_fifo.empty()) + m_cmd_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; + //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); + LOGMMIO("Command finished (%u slots free)\n", m_bitblt_fifo.queue_length()); } void s3virge_vga_device::line2d_step() @@ -670,8 +689,8 @@ 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].command & 0x02000000; // X Positive - ypos = s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].command & 0x04000000; // Y Positive + xpos = s3virge.s3d.command & 0x02000000; // X Positive + ypos = s3virge.s3d.command & 0x04000000; // Y Positive if(xpos) { left = s3virge.s3d.bitblt_x_dst; @@ -733,7 +752,7 @@ bool s3virge_vga_device::advance_pixel() void s3virge_vga_device::bitblt_step() { - if((s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].command & 0x40)) + if(BIT(s3virge.s3d.command, 6)) bitblt_monosrc_step(); else bitblt_colour_step(); @@ -743,9 +762,9 @@ 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].command; + uint32_t src_base = s3virge.s3d.src_base & 0x003ffff8; + uint32_t dst_base = s3virge.s3d.dest_base & 0x003ffff8; + const u32 current_command = s3virge.s3d.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; @@ -779,8 +798,8 @@ void s3virge_vga_device::bitblt_colour_step() if(current_command & 0x100) { pat = (BIT(s3virge.s3d.bitblt_mono_pattern, (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]; + ? s3virge.s3d.pat_fg_clr + : s3virge.s3d.pat_bg_clr; } else { @@ -824,9 +843,9 @@ void s3virge_vga_device::bitblt_colour_step() dst = read_pixel16(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current, dest_stride()); if(current_command & 0x100) { - pat = (s3virge.s3d.bitblt_mono_pattern & (1 << ((s3virge.s3d.bitblt_pat_y*8) + (7-s3virge.s3d.bitblt_pat_x))) - ? s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_PAT_FG_CLR] - : s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_PAT_BG_CLR]); + pat = (s3virge.s3d.bitblt_mono_pattern & (1 << ((s3virge.s3d.bitblt_pat_y*8) + (7-s3virge.s3d.bitblt_pat_x)))) + ? s3virge.s3d.pat_fg_clr + : s3virge.s3d.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; @@ -849,8 +868,8 @@ void s3virge_vga_device::bitblt_colour_step() if(current_command & 0x100) { pat = (s3virge.s3d.bitblt_mono_pattern & (1 << ((s3virge.s3d.bitblt_pat_y*8) + (7-s3virge.s3d.bitblt_pat_x))) - ? s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_PAT_FG_CLR] - : s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_PAT_BG_CLR]); + ? s3virge.s3d.pat_fg_clr + : s3virge.s3d.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; @@ -874,7 +893,7 @@ void s3virge_vga_device::bitblt_colour_step() if(current_command & 0x100) { pat = (s3virge.s3d.bitblt_mono_pattern & (1 << ((s3virge.s3d.bitblt_pat_y*8) + (7-s3virge.s3d.bitblt_pat_x))) - ? s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_PAT_FG_CLR] : s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_PAT_BG_CLR]); + ? s3virge.s3d.pat_fg_clr : s3virge.s3d.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 @@ -907,8 +926,8 @@ void s3virge_vga_device::bitblt_colour_step() dst = read_pixel24(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current, dest_stride()); if(current_command & 0x100) { - pat = (s3virge.s3d.bitblt_mono_pattern & (1 << ((s3virge.s3d.bitblt_pat_y*8) + (7-s3virge.s3d.bitblt_pat_x))) - ? s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_PAT_FG_CLR] : s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_PAT_BG_CLR]); + pat = (s3virge.s3d.bitblt_mono_pattern & (1 << ((s3virge.s3d.bitblt_pat_y*8) + (7-s3virge.s3d.bitblt_pat_x)))) + ? s3virge.s3d.pat_fg_clr : s3virge.s3d.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 @@ -927,10 +946,10 @@ void s3virge_vga_device::bitblt_colour_step() 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 = s3virge.s3d.src_base & 0x003ffff8; + uint32_t dst_base = s3virge.s3d.dest_base & 0x003ffff8; - const u32 current_command = s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].command; + const u32 current_command = s3virge.s3d.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)); @@ -941,13 +960,13 @@ void s3virge_vga_device::bitblt_monosrc_step() // NOP disables autoexecute (is it supposed to not execute rest of command?) if (command_type == 0xf) - s3virge.s3d.command &= ~1; + m_bitblt_latch.cmd_set &= ~1; uint32_t src = 0; 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 = s3virge.s3d.pat_fg_clr; int x; bool done = false; @@ -965,10 +984,10 @@ void s3virge_vga_device::bitblt_monosrc_step() 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); + write_pixel8(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current,GetROP(rop, s3virge.s3d.src_fg_clr, dst, pat) & 0xff); else if(!tp) { - 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,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current,GetROP(rop, s3virge.s3d.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); @@ -1007,11 +1026,11 @@ void s3virge_vga_device::bitblt_monosrc_step() 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); + write_pixel16(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current,GetROP(rop, s3virge.s3d.src_fg_clr, dst, pat) & 0xffff); else if(!tp) { // 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,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current,GetROP(rop, s3virge.s3d.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); @@ -1050,12 +1069,12 @@ void s3virge_vga_device::bitblt_monosrc_step() 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)); + write_pixel24(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current,GetROP(rop, s3virge.s3d.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,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,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current,GetROP(rop, s3virge.s3d.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); @@ -1093,7 +1112,7 @@ TIMER_CALLBACK_MEMBER(s3virge_vga_device::draw_step_tick) switch(s3virge.s3d.state) { case S3D_STATE_IDLE: - m_draw_timer->adjust(attotime::zero); + command_finish(); break; case S3D_STATE_2DLINE: line2d_step(); @@ -1115,9 +1134,11 @@ TIMER_CALLBACK_MEMBER(s3virge_vga_device::draw_step_tick) 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].command & 0x00000002) + if(BIT(s3virge.s3d.command, 1)) + { 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; @@ -1126,9 +1147,11 @@ inline void s3virge_vga_device::write_pixel32(uint32_t base, uint16_t x, uint16_ 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].command & 0x00000002) + if(BIT(s3virge.s3d.command, 1)) + { 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; @@ -1136,18 +1159,22 @@ inline void s3virge_vga_device::write_pixel24(uint32_t base, uint16_t x, uint16_ 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].command & 0x00000002) + if(BIT(s3virge.s3d.command, 1)) + { 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; } 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].command & 0x00000002) + if(BIT(s3virge.s3d.command, 1)) + { 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; } @@ -1200,13 +1227,14 @@ uint32_t s3virge_vga_device::s3d_sub_status_r() { uint32_t res = 0x00000000; - if(!s3virge.s3d.busy) + if(s3virge.s3d.busy == false && m_bitblt_fifo.empty()) res |= 0x00002000; // S3d engine is idle //res |= (s3virge.s3d.cmd_fifo_slots_free << 8); // NOTE: can actually be 24 FIFO depth with specific Scenic Mode (verify if different FIFO altogether) // & 0x1f00 - res |= std::min(s3virge.s3d.cmd_fifo_slots_free, 16) << 8; + //res |= std::min(m_bitblt_fifo.queue_length(), 16) << 8; + res |= (15 - m_bitblt_fifo.queue_length()) << 8; return res; } @@ -1265,7 +1293,8 @@ uint32_t s3virge_vga_device::s3d_func_ctrl_r() { uint32_t ret = 0; - ret |= (s3virge.s3d.cmd_fifo_slots_free << 6); +// ret |= (m_bitblt_fifo.queue_length << 6); + ret |= 0xf << 6; return ret; } @@ -1280,47 +1309,137 @@ void s3virge_vga_device::s3d_register_map(address_map &map) s3virge.s3d.pattern[offset] = data; }) ); - // TODO: remove this trampoline - map(0x0400, 0x05ff).lrw32( + map(0x04d4, 0x04d7).lrw32( NAME([this] (offs_t offset) { - return s3virge.s3d.reg[0][offset]; + return m_bitblt_latch.src_base; }), NAME([this] (offs_t offset, u32 data, u32 mem_mask) { - LOGMMIO("MM%04X = %08x\n", (offset*4)+0xa400, data); - COMBINE_DATA(&s3virge.s3d.reg[0][offset]); + LOGMMIO("MMA4D4 (src_base) = %08x & %08x\n", data, mem_mask); + COMBINE_DATA(&m_bitblt_latch.src_base); + }) + ); + map(0x04d8, 0x04db).lrw32( + NAME([this] (offs_t offset) { + return m_bitblt_latch.dest_base; + }), + NAME([this] (offs_t offset, u32 data, u32 mem_mask) { + LOGMMIO("MMA4D8 (dest_base) = %08x & %08x\n", data, mem_mask); + COMBINE_DATA(&m_bitblt_latch.dest_base); + }) + ); + map(0x04dc, 0x04df).lrw32( + NAME([this] (offs_t offset) { + return m_bitblt_latch.clip_l_r; + }), + NAME([this] (offs_t offset, u32 data, u32 mem_mask) { + LOGMMIO("MMA4DC (clip_l_r) = %08x & %08x\n", data, mem_mask); + COMBINE_DATA(&m_bitblt_latch.clip_l_r); + }) + ); + map(0x04e0, 0x04e3).lrw32( + NAME([this] (offs_t offset) { + return m_bitblt_latch.clip_t_b; + }), + NAME([this] (offs_t offset, u32 data, u32 mem_mask) { + LOGMMIO("MMA4E0 (clip_t_b) = %08x & %08x\n", data, mem_mask); + COMBINE_DATA(&m_bitblt_latch.clip_t_b); + }) + ); + map(0x04e4, 0x04e7).lrw32( + NAME([this] (offs_t offset) { + return m_bitblt_latch.dest_src_str; + }), + NAME([this] (offs_t offset, u32 data, u32 mem_mask) { + LOGMMIO("MMA4E4 (dest_src_str) = %08x & %08x\n", data, mem_mask); + COMBINE_DATA(&m_bitblt_latch.dest_src_str); }) ); map(0x04e8, 0x04ef).lrw32( NAME([this] (offs_t offset) { - return s3virge.s3d.bitblt_mono_pattern >> (offset * 32); + return m_bitblt_latch.mono_pat >> (offset * 32); }), NAME([this] (offs_t offset, u32 data, u32 mem_mask) { - LOGMMIO("MM%04X = %08x\n", (offset*4)+0xa4e8, data); + LOGMMIO("MM%04X (mono_pat_%d) = %08x & %08x\n", (offset*4)+0xa4e8, offset, data, mem_mask); if (offset) - s3virge.s3d.bitblt_mono_pattern = ((u64)data << 32) | (s3virge.s3d.bitblt_mono_pattern & 0xffff'ffff); + m_bitblt_latch.mono_pat = ((u64)data << 32) | (m_bitblt_latch.mono_pat & 0xffff'ffff); else - s3virge.s3d.bitblt_mono_pattern = (data & 0xffff'ffff) | (u64)(s3virge.s3d.bitblt_mono_pattern & 0xffff'ffff'0000'0000); + m_bitblt_latch.mono_pat = (data & 0xffff'ffff) | (u64)(m_bitblt_latch.mono_pat & 0xffff'ffff'0000'0000); + }) + ); + map(0x04f0, 0x04f3).lrw32( + NAME([this] (offs_t offset) { + return m_bitblt_latch.pat_bg_clr; + }), + NAME([this] (offs_t offset, u32 data, u32 mem_mask) { + LOGMMIO("MMA4F0 (pat_bg_clr) = %08x & %08x\n", data, mem_mask); + COMBINE_DATA(&m_bitblt_latch.pat_bg_clr); + }) + ); + map(0x04f4, 0x04f7).lrw32( + NAME([this] (offs_t offset) { + return m_bitblt_latch.pat_fg_clr; + }), + NAME([this] (offs_t offset, u32 data, u32 mem_mask) { + LOGMMIO("MMA4F4 (pat_fg_clr) = %08x & %08x\n", data, mem_mask); + COMBINE_DATA(&m_bitblt_latch.pat_fg_clr); + }) + ); + map(0x04f8, 0x04fb).lrw32( + NAME([this] (offs_t offset) { + return m_bitblt_latch.src_bg_clr; + }), + NAME([this] (offs_t offset, u32 data, u32 mem_mask) { + LOGMMIO("MMA4F8 (src_bg_clr) = %08x & %08x\n", data, mem_mask); + COMBINE_DATA(&m_bitblt_latch.src_bg_clr); + }) + ); + map(0x04fc, 0x04ff).lrw32( + NAME([this] (offs_t offset) { + return m_bitblt_latch.src_fg_clr; + }), + NAME([this] (offs_t offset, u32 data, u32 mem_mask) { + LOGMMIO("MMA4FC (src_fg_clr) = %08x & %08x\n", data, mem_mask); + COMBINE_DATA(&m_bitblt_latch.src_fg_clr); }) ); map(0x0500, 0x0503).lrw32( NAME([this] (offs_t offset) { - return s3virge.s3d.command; + return m_bitblt_latch.cmd_set; }), NAME([this] (offs_t offset, u32 data, u32 mem_mask) { - LOGMMIO("MMA500 = %08x\n", data); - COMBINE_DATA(&s3virge.s3d.command); + LOGMMIO("MMA500 (cmd_set) = %08x & %08x\n", data, mem_mask); + COMBINE_DATA(&m_bitblt_latch.cmd_set); if(!(BIT(data, 0))) add_command(0); }) ); + map(0x0504, 0x0507).lrw32( + NAME([this] (offs_t offset) { + return m_bitblt_latch.rwidth_height; + }), + NAME([this] (offs_t offset, u32 data, u32 mem_mask) { + LOGMMIO("MMA504 (rwidth_height) = %08x & %08x\n", data, mem_mask); + COMBINE_DATA(&m_bitblt_latch.rwidth_height); + }) + ); + map(0x0508, 0x050b).lrw32( + NAME([this] (offs_t offset) { + return m_bitblt_latch.rsrc_xy; + }), + NAME([this] (offs_t offset, u32 data, u32 mem_mask) { + LOGMMIO("MMA508 (rsrc_xy) = %08x & %08x\n", data, mem_mask); + COMBINE_DATA(&m_bitblt_latch.rsrc_xy); + }) + ); map(0x050c, 0x050f).lrw32( NAME([this] (offs_t offset) { - return s3virge.s3d.reg[0][S3D_REG_RDEST_XY]; + return m_bitblt_latch.rdest_xy; }), NAME([this] (offs_t offset, u32 data, u32 mem_mask) { - LOGMMIO("MMA50C = %08x\n", data); - COMBINE_DATA(&s3virge.s3d.reg[0][S3D_REG_RDEST_XY]); - if(BIT(s3virge.s3d.command, 0)) // autoexecute enabled + LOGMMIO("MMA50C (rdest_xy) = %08x\n", data); + COMBINE_DATA(&m_bitblt_latch.rdest_xy); + // autoexecute enabled + if(BIT(m_bitblt_latch.cmd_set, 0)) add_command(0); }) ); diff --git a/src/devices/video/s3virge.h b/src/devices/video/s3virge.h index d1288abcc0b90..913e9245c3384 100644 --- a/src/devices/video/s3virge.h +++ b/src/devices/video/s3virge.h @@ -54,7 +54,7 @@ class s3virge_vga_device : public s3trio64_vga_device 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; + return (s3virge.s3d.dest_src_stride >> 0) & 0xfff8; } uint16_t dest_stride() { @@ -66,7 +66,7 @@ class s3virge_vga_device : public s3trio64_vga_device // + ((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; + return (s3virge.s3d.dest_src_stride >> 16) & 0xfff8; } ibm8514a_device* get_8514() { fatalerror("s3virge requested non-existent 8514/A device\n"); return nullptr; } @@ -128,6 +128,26 @@ class s3virge_vga_device : public s3trio64_vga_device S3D_REG_RDEST_XY = 0x10c/4 }; + struct bitblt_struct { + u32 src_base = 0; + u32 dest_base = 0; + u32 clip_l_r = 0; + u32 clip_t_b = 0; + u32 dest_src_str = 0; + u64 mono_pat = 0; + u32 pat_bg_clr = 0; + u32 pat_fg_clr = 0; + u32 src_bg_clr = 0; + u32 src_fg_clr = 0; + u32 cmd_set = 0; + u32 rwidth_height = 0; + u32 rsrc_xy = 0; + u32 rdest_xy = 0; + }; + + util::fifo m_bitblt_fifo; + bitblt_struct m_bitblt_latch; + struct { uint32_t linear_address; @@ -140,18 +160,8 @@ class s3virge_vga_device : public s3trio64_vga_device { int state; bool busy; - struct - { - uint32_t reg[0x200/4]; - int op_type; - uint32_t command; - } 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][0x200/4]; // BitBLT command state uint16_t bitblt_x_src; @@ -176,11 +186,19 @@ class s3virge_vga_device : public s3trio64_vga_device uint16_t clip_t; uint16_t clip_b; uint32_t command; + uint32_t src_base; + uint32_t dest_base; + uint32_t pat_bg_clr; + uint32_t pat_fg_clr; + uint32_t src_bg_clr; + uint32_t src_fg_clr; + uint32_t dest_src_stride; } s3d; uint8_t cr66; } s3virge; TIMER_CALLBACK_MEMBER(draw_step_tick); + TIMER_CALLBACK_MEMBER(command_timer_cb); inline void write_pixel32(uint32_t base, uint16_t x, uint16_t y, uint32_t val); inline void write_pixel24(uint32_t base, uint16_t x, uint16_t y, uint32_t val); @@ -201,6 +219,7 @@ class s3virge_vga_device : public s3trio64_vga_device // has no 8514/A device private: emu_timer* m_draw_timer; + emu_timer* m_cmd_timer; void bitblt_step(); void bitblt_colour_step(); void bitblt_monosrc_step(); @@ -209,7 +228,6 @@ class s3virge_vga_device : public s3trio64_vga_device void line3d_step(); void poly3d_step(); void add_command(u8 cmd_type); - void command_start(); void command_finish(); void s3d_reset(); From 98aa5db3eb13d8ddc3134db29bae6692ddc92104 Mon Sep 17 00:00:00 2001 From: angelosa Date: Tue, 26 Mar 2024 03:12:08 +0100 Subject: [PATCH 05/14] video/s3virge: couple obvious blunders [skip ci] --- src/devices/bus/pci/virge_pci.cpp | 1 + src/devices/video/s3virge.cpp | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/devices/bus/pci/virge_pci.cpp b/src/devices/bus/pci/virge_pci.cpp index 9ff07e24b5177..27dd054e7433f 100644 --- a/src/devices/bus/pci/virge_pci.cpp +++ b/src/devices/bus/pci/virge_pci.cpp @@ -65,6 +65,7 @@ void virge_pci_device::mmio_map(address_map& map) void virge_pci_device::lfb_map(address_map& map) { + // 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)); } diff --git a/src/devices/video/s3virge.cpp b/src/devices/video/s3virge.cpp index ea6e7e830f4e0..5eea6be28c0ae 100644 --- a/src/devices/video/s3virge.cpp +++ b/src/devices/video/s3virge.cpp @@ -496,6 +496,7 @@ void s3virge_vga_device::add_command(u8 cmd_type) LOGCMD("Added command type %i %08x\n", cmd_type, m_bitblt_latch.cmd_set); + // TODO: trigger on idle state only m_cmd_timer->adjust(attotime::from_usec(1), 0, attotime::from_usec(1)); // s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_next_ptr].op_type = cmd_type; @@ -555,14 +556,13 @@ TIMER_CALLBACK_MEMBER(s3virge_vga_device::command_timer_cb) s3virge.s3d.clip_l = (command_struct.clip_l_r & 0x07ff0000) >> 16; s3virge.s3d.clip_b = command_struct.clip_t_b & 0x000007ff; s3virge.s3d.clip_t = (command_struct.clip_t_b & 0x07ff0000) >> 16; - s3virge.s3d.busy = true; - //if(!(BIT(command_struct.cmd_set, 7))) + if(!(BIT(command_struct.cmd_set, 7))) { + s3virge.s3d.busy = true; 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_mono_pattern = command_struct.mono_pat; s3virge.s3d.bitblt_current_pixel = 0; s3virge.s3d.bitblt_pixel_pos = 0; s3virge.s3d.command = command_struct.cmd_set; From 10a78e81030757001e33b6eee6cca101383b734f Mon Sep 17 00:00:00 2001 From: angelosa Date: Wed, 27 Mar 2024 01:20:57 +0100 Subject: [PATCH 06/14] video/s3virge: logging and misc cleanups --- src/devices/video/s3virge.cpp | 77 ++++++++++++++++++++++++----------- src/devices/video/s3virge.h | 19 --------- 2 files changed, 53 insertions(+), 43 deletions(-) diff --git a/src/devices/video/s3virge.cpp b/src/devices/video/s3virge.cpp index 5eea6be28c0ae..daf133c5d03e9 100644 --- a/src/devices/video/s3virge.cpp +++ b/src/devices/video/s3virge.cpp @@ -37,8 +37,9 @@ #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 VERBOSE (LOG_REG | LOG_CMD | LOG_MMIO) +#define VERBOSE (LOG_REG | LOG_CMD | LOG_MMIO | LOG_FIFO) //#define LOG_OUTPUT_STREAM std::cout #include "logmacro.h" @@ -46,7 +47,8 @@ #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 LOGPIXEL(...) LOGMASKED(LOG_PIXEL, __VA_ARGS__) +#define LOGFIFO(...) LOGMASKED(LOG_FIFO, __VA_ARGS__) #define CRTC_PORT_ADDR ((vga.miscellaneous_output & 1) ? 0x3d0 : 0x3b0) @@ -158,10 +160,10 @@ void s3virgedx_rev1_vga_device::device_start() void s3virge_vga_device::s3d_reset() { + LOGFIFO("S3D Reset\n"); m_bitblt_fifo.clear(); m_cmd_timer->adjust(attotime::never); m_draw_timer->adjust(attotime::never); - s3virge.s3d.state = S3D_STATE_IDLE; s3virge.s3d.busy = false; // beos 4.x (and presumably Win 3.1) never sets this when using BitBlt, @@ -490,15 +492,17 @@ void s3virge_vga_device::fb_w(offs_t offset, uint8_t data) void s3virge_vga_device::add_command(u8 cmd_type) { // TODO: handle full FIFO (should discard operation?) - if(m_bitblt_fifo.full()) + if (m_bitblt_fifo.full()) throw emu_fatalerror("s3virge: FIFO full"); + m_bitblt_fifo.enqueue(m_bitblt_latch); - LOGCMD("Added command type %i %08x\n", cmd_type, m_bitblt_latch.cmd_set); + LOGFIFO("Enqueue command type %i %08x (%d free)\n", cmd_type, m_bitblt_latch.cmd_set, 16 - m_bitblt_fifo.queue_length()); // TODO: trigger on idle state only m_cmd_timer->adjust(attotime::from_usec(1), 0, attotime::from_usec(1)); + // s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_next_ptr].op_type = cmd_type; // s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_next_ptr].command = s3virge.s3d.command; // LOGCMD("Added command type %i cmd %08x ptr %u\n",s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_next_ptr].op_type, s3virge.s3d.command, s3virge.s3d.cmd_fifo_next_ptr); @@ -511,10 +515,16 @@ void s3virge_vga_device::add_command(u8 cmd_type) TIMER_CALLBACK_MEMBER(s3virge_vga_device::command_timer_cb) { - if (m_bitblt_fifo.empty() || s3virge.s3d.busy) + // TODO: shouldn't be here + if (m_bitblt_fifo.empty()) + return; + + if (s3virge.s3d.busy) return; - bitblt_struct command_struct = m_bitblt_fifo.dequeue(); + const bitblt_struct command_struct = m_bitblt_fifo.dequeue(); + + LOGFIFO("Dequeue command %08x (%d free)\n", command_struct.cmd_set, 16 - m_bitblt_fifo.queue_length()); // start next command in FIFO const u8 cmd_type = 0; //s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].op_type & 0xf; @@ -584,18 +594,27 @@ TIMER_CALLBACK_MEMBER(s3virge_vga_device::command_timer_cb) void s3virge_vga_device::command_finish() { s3virge.s3d.state = S3D_STATE_IDLE; - s3virge.s3d.busy = false; m_draw_timer->adjust(attotime::never); + + LOGFIFO("Command finished (%u free) ", 16 - m_bitblt_fifo.queue_length()); + s3virge.s3d.busy = false; + if (m_bitblt_fifo.empty()) + { m_cmd_timer->adjust(attotime::never); + LOGFIFO("- timer stop\n"); + } + else + { + //m_cmd_timer->adjust(attotime::from_msec(1)); + LOGFIFO("- timer continue\n"); + } // 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 slots free)\n", m_bitblt_fifo.queue_length()); } void s3virge_vga_device::line2d_step() @@ -769,13 +788,18 @@ void s3virge_vga_device::bitblt_colour_step() 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)); const u8 command_type = current_command >> 27; // NOP disables autoexecute (is it supposed to not execute rest of command?) if (command_type == 0xf) - s3virge.s3d.command &= ~1; + { + m_bitblt_latch.cmd_set &= ~1; + //command_finish(); + //return; + } uint32_t src = 0; uint32_t dst = 0; @@ -795,11 +819,11 @@ void s3virge_vga_device::bitblt_colour_step() } else src = read_pixel8(src_base,s3virge.s3d.bitblt_x_src_current,s3virge.s3d.bitblt_y_src_current, src_stride()); - if(current_command & 0x100) + if(mp) { - pat = (BIT(s3virge.s3d.bitblt_mono_pattern, (s3virge.s3d.bitblt_pat_y*8) + (7-s3virge.s3d.bitblt_pat_x))) - ? s3virge.s3d.pat_fg_clr - : s3virge.s3d.pat_bg_clr; + //pat = (s3virge.s3d.bitblt_mono_pattern & (1 << ((s3virge.s3d.bitblt_pat_y*8) + (7-s3virge.s3d.bitblt_pat_x))) ? s3virge.s3d.pat_fg_clr : s3virge.s3d.pat_bg_clr); + + pat = BIT(s3virge.s3d.bitblt_mono_pattern, (s3virge.s3d.bitblt_pat_y*8) + (7-s3virge.s3d.bitblt_pat_x)) ? s3virge.s3d.pat_fg_clr : s3virge.s3d.pat_bg_clr; } else { @@ -841,7 +865,7 @@ void s3virge_vga_device::bitblt_colour_step() 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) + if(mp) { pat = (s3virge.s3d.bitblt_mono_pattern & (1 << ((s3virge.s3d.bitblt_pat_y*8) + (7-s3virge.s3d.bitblt_pat_x)))) ? s3virge.s3d.pat_fg_clr @@ -865,7 +889,7 @@ void s3virge_vga_device::bitblt_colour_step() 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) + if(mp) { pat = (s3virge.s3d.bitblt_mono_pattern & (1 << ((s3virge.s3d.bitblt_pat_y*8) + (7-s3virge.s3d.bitblt_pat_x))) ? s3virge.s3d.pat_fg_clr @@ -890,7 +914,7 @@ void s3virge_vga_device::bitblt_colour_step() { 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) + if(mp) { pat = (s3virge.s3d.bitblt_mono_pattern & (1 << ((s3virge.s3d.bitblt_pat_y*8) + (7-s3virge.s3d.bitblt_pat_x))) ? s3virge.s3d.pat_fg_clr : s3virge.s3d.pat_bg_clr); @@ -924,7 +948,7 @@ void s3virge_vga_device::bitblt_colour_step() { 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) + if(mp) { pat = (s3virge.s3d.bitblt_mono_pattern & (1 << ((s3virge.s3d.bitblt_pat_y*8) + (7-s3virge.s3d.bitblt_pat_x)))) ? s3virge.s3d.pat_fg_clr : s3virge.s3d.pat_bg_clr; @@ -953,6 +977,7 @@ void s3virge_vga_device::bitblt_monosrc_step() 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 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; @@ -960,7 +985,11 @@ void s3virge_vga_device::bitblt_monosrc_step() // NOP disables autoexecute (is it supposed to not execute rest of command?) if (command_type == 0xf) + { m_bitblt_latch.cmd_set &= ~1; + //command_finish(); + //return; + } uint32_t src = 0; uint32_t dst = 0; @@ -1112,7 +1141,7 @@ TIMER_CALLBACK_MEMBER(s3virge_vga_device::draw_step_tick) switch(s3virge.s3d.state) { case S3D_STATE_IDLE: - command_finish(); + m_draw_timer->adjust(attotime::never); break; case S3D_STATE_2DLINE: line2d_step(); @@ -1222,7 +1251,7 @@ inline uint8_t s3virge_vga_device::read_pixel8(uint32_t base, uint16_t x, uint16 // 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; @@ -1234,7 +1263,7 @@ uint32_t s3virge_vga_device::s3d_sub_status_r() // NOTE: can actually be 24 FIFO depth with specific Scenic Mode (verify if different FIFO altogether) // & 0x1f00 //res |= std::min(m_bitblt_fifo.queue_length(), 16) << 8; - res |= (15 - m_bitblt_fifo.queue_length()) << 8; + res |= (16 - m_bitblt_fifo.queue_length()) << 8; return res; } @@ -1293,7 +1322,7 @@ uint32_t s3virge_vga_device::s3d_func_ctrl_r() { uint32_t ret = 0; -// ret |= (m_bitblt_fifo.queue_length << 6); +// ret |= (s3d_fifo_size << 6); ret |= 0xf << 6; return ret; } @@ -1436,7 +1465,7 @@ void s3virge_vga_device::s3d_register_map(address_map &map) return m_bitblt_latch.rdest_xy; }), NAME([this] (offs_t offset, u32 data, u32 mem_mask) { - LOGMMIO("MMA50C (rdest_xy) = %08x\n", data); + LOGMMIO("MMA50C (rdest_xy) = %08x & mem_mask\n", data, mem_mask); COMBINE_DATA(&m_bitblt_latch.rdest_xy); // autoexecute enabled if(BIT(m_bitblt_latch.cmd_set, 0)) diff --git a/src/devices/video/s3virge.h b/src/devices/video/s3virge.h index 913e9245c3384..5dc9531c09925 100644 --- a/src/devices/video/s3virge.h +++ b/src/devices/video/s3virge.h @@ -109,25 +109,6 @@ 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 bitblt_struct { u32 src_base = 0; u32 dest_base = 0; From f540542357ea1bfbcd5c0ac5b0c2b5cf4107602d Mon Sep 17 00:00:00 2001 From: angelosa Date: Fri, 29 Mar 2024 21:01:22 +0100 Subject: [PATCH 07/14] video/s3virge: WIP FIFO interactions, make command pipeline to be a bare array for now --- src/devices/video/s3virge.cpp | 255 ++++++++++++---------------------- src/devices/video/s3virge.h | 26 ++-- 2 files changed, 98 insertions(+), 183 deletions(-) diff --git a/src/devices/video/s3virge.cpp b/src/devices/video/s3virge.cpp index daf133c5d03e9..c33caa28d1790 100644 --- a/src/devices/video/s3virge.cpp +++ b/src/devices/video/s3virge.cpp @@ -168,7 +168,8 @@ void s3virge_vga_device::s3d_reset() s3virge.s3d.busy = false; // 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.mono_pat = (u64)0xffff'ffff'ffff'ffff; + 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. } @@ -495,12 +496,13 @@ void s3virge_vga_device::add_command(u8 cmd_type) if (m_bitblt_fifo.full()) throw emu_fatalerror("s3virge: FIFO full"); - m_bitblt_fifo.enqueue(m_bitblt_latch); + if (m_bitblt_fifo.empty()) + m_cmd_timer->adjust(attotime::from_nsec(250), 0, attotime::from_nsec(250)); - LOGFIFO("Enqueue command type %i %08x (%d free)\n", cmd_type, m_bitblt_latch.cmd_set, 16 - m_bitblt_fifo.queue_length()); + for (int i = 0; i < 15; i++) + m_bitblt_fifo.enqueue(m_bitblt_latch[i]); - // TODO: trigger on idle state only - m_cmd_timer->adjust(attotime::from_usec(1), 0, attotime::from_usec(1)); + LOGFIFO("Enqueue command type %i %08x (%d free)\n", cmd_type, m_bitblt_latch[11], 16 - m_bitblt_fifo.queue_length() / 15); // s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_next_ptr].op_type = cmd_type; @@ -519,12 +521,19 @@ TIMER_CALLBACK_MEMBER(s3virge_vga_device::command_timer_cb) if (m_bitblt_fifo.empty()) return; - if (s3virge.s3d.busy) + if (s3virge.s3d.xfer_mode) + { + if (!m_xfer_fifo.empty()) + { + s3virge.s3d.busy = true; + s3virge.s3d.image_xfer = m_xfer_fifo.dequeue(); + m_draw_timer->adjust(attotime::from_nsec(250), 1); + } return; + } - const bitblt_struct command_struct = m_bitblt_fifo.dequeue(); - - LOGFIFO("Dequeue command %08x (%d free)\n", command_struct.cmd_set, 16 - m_bitblt_fifo.queue_length()); + if (s3virge.s3d.busy) + return; // start next command in FIFO const u8 cmd_type = 0; //s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].op_type & 0xf; @@ -548,13 +557,38 @@ TIMER_CALLBACK_MEMBER(s3virge_vga_device::command_timer_cb) LOGCMD("3D Tri command (unsupported)\n"); break; case OP_BITBLT: + { + u32 tmp; s3virge.s3d.state = S3D_STATE_BITBLT; - s3virge.s3d.bitblt_x_src = (command_struct.rsrc_xy & 0x07ff0000) >> 16; - s3virge.s3d.bitblt_y_src = (command_struct.rsrc_xy & 0x000007ff); - s3virge.s3d.bitblt_x_dst = (command_struct.rdest_xy & 0x07ff0000) >> 16; - s3virge.s3d.bitblt_y_dst = (command_struct.rdest_xy & 0x000007ff); - s3virge.s3d.bitblt_width = (command_struct.rwidth_height & 0xffff0000) >> 16; - s3virge.s3d.bitblt_height = (command_struct.rwidth_height & 0x0000ffff); + //const bitblt_struct command_struct = m_bitblt_fifo.dequeue(); + s3virge.s3d.src_base = m_bitblt_fifo.dequeue(); + s3virge.s3d.dest_base = m_bitblt_fifo.dequeue(); + tmp = m_bitblt_fifo.dequeue(); + s3virge.s3d.clip_r = tmp & 0x000007ff; + s3virge.s3d.clip_l = (tmp & 0x07ff0000) >> 16; + tmp = m_bitblt_fifo.dequeue(); + s3virge.s3d.clip_b = tmp & 0x000007ff; + s3virge.s3d.clip_t = (tmp & 0x07ff0000) >> 16; + tmp = m_bitblt_fifo.dequeue(); + s3virge.s3d.src_stride = (tmp >> 0) & 0xfff8; + s3virge.s3d.dest_stride = (tmp >> 16) & 0xfff8; + tmp = m_bitblt_fifo.dequeue(); + s3virge.s3d.bitblt_mono_pattern = ((u64)m_bitblt_fifo.dequeue() << 32) | tmp; + s3virge.s3d.pat_bg_clr = m_bitblt_fifo.dequeue(); + s3virge.s3d.pat_fg_clr = m_bitblt_fifo.dequeue(); + s3virge.s3d.src_bg_clr = m_bitblt_fifo.dequeue(); + s3virge.s3d.src_fg_clr = m_bitblt_fifo.dequeue(); + s3virge.s3d.command = m_bitblt_fifo.dequeue(); + tmp = m_bitblt_fifo.dequeue(); + s3virge.s3d.bitblt_width = (tmp & 0xffff0000) >> 16; + s3virge.s3d.bitblt_height = (tmp & 0x0000ffff); + tmp = m_bitblt_fifo.dequeue(); + s3virge.s3d.bitblt_x_src = (tmp & 0x07ff0000) >> 16; + s3virge.s3d.bitblt_y_src = (tmp & 0x000007ff); + tmp = m_bitblt_fifo.dequeue(); + s3virge.s3d.bitblt_x_dst = (tmp & 0x07ff0000) >> 16; + s3virge.s3d.bitblt_y_dst = (tmp & 0x000007ff); + // TODO: these four goes negative at second transfer of beos 4 (two's complement?) s3virge.s3d.bitblt_x_current = s3virge.s3d.bitblt_x_dst; s3virge.s3d.bitblt_x_src_current = s3virge.s3d.bitblt_x_src; @@ -562,29 +596,24 @@ TIMER_CALLBACK_MEMBER(s3virge_vga_device::command_timer_cb) 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 = command_struct.clip_l_r & 0x000007ff; - s3virge.s3d.clip_l = (command_struct.clip_l_r & 0x07ff0000) >> 16; - s3virge.s3d.clip_b = command_struct.clip_t_b & 0x000007ff; - s3virge.s3d.clip_t = (command_struct.clip_t_b & 0x07ff0000) >> 16; - if(!(BIT(command_struct.cmd_set, 7))) - { - s3virge.s3d.busy = true; - m_draw_timer->adjust(attotime::from_nsec(250),0,attotime::from_nsec(250)); - } s3virge.s3d.bitblt_step_count = 0; - s3virge.s3d.bitblt_mono_pattern = command_struct.mono_pat; s3virge.s3d.bitblt_current_pixel = 0; s3virge.s3d.bitblt_pixel_pos = 0; - s3virge.s3d.command = command_struct.cmd_set; - s3virge.s3d.src_base = command_struct.src_base; - s3virge.s3d.dest_base = command_struct.dest_base; - s3virge.s3d.pat_fg_clr = command_struct.pat_fg_clr; - s3virge.s3d.pat_bg_clr = command_struct.pat_bg_clr; - s3virge.s3d.src_fg_clr = command_struct.src_fg_clr; - s3virge.s3d.src_bg_clr = command_struct.src_bg_clr; - s3virge.s3d.dest_src_stride = command_struct.dest_src_str; + + if(!(BIT(s3virge.s3d.command, 7))) + { + s3virge.s3d.busy = true; + s3virge.s3d.xfer_mode = false; + m_draw_timer->adjust(attotime::from_nsec(250), 0, attotime::from_nsec(250)); + } + else + s3virge.s3d.xfer_mode = true; + + LOGFIFO("Dequeue command %08x (%d free)\n", s3virge.s3d.command, 16 - (m_bitblt_fifo.queue_length() / 15)); + LOGCMD("Started BitBLT command [%08x]\n", s3virge.s3d.command); break; + } default: LOGCMD(" command detected [%08x]\n", cmd_type, s3virge.s3d.command); break; @@ -593,19 +622,22 @@ TIMER_CALLBACK_MEMBER(s3virge_vga_device::command_timer_cb) void s3virge_vga_device::command_finish() { - s3virge.s3d.state = S3D_STATE_IDLE; m_draw_timer->adjust(attotime::never); - LOGFIFO("Command finished (%u free) ", 16 - m_bitblt_fifo.queue_length()); + LOGFIFO("Command finished (%u free) ", 16 - (m_bitblt_fifo.queue_length() / 15)); s3virge.s3d.busy = false; + s3virge.s3d.xfer_mode = false; if (m_bitblt_fifo.empty()) { + s3virge.s3d.state = S3D_STATE_IDLE; + m_draw_timer->adjust(attotime::never); m_cmd_timer->adjust(attotime::never); LOGFIFO("- timer stop\n"); } else { + s3virge.s3d.state = S3D_STATE_BITBLT; //m_cmd_timer->adjust(attotime::from_msec(1)); LOGFIFO("- timer continue\n"); } @@ -796,9 +828,9 @@ void s3virge_vga_device::bitblt_colour_step() // NOP disables autoexecute (is it supposed to not execute rest of command?) if (command_type == 0xf) { - m_bitblt_latch.cmd_set &= ~1; - //command_finish(); - //return; + m_bitblt_latch[11] &= ~1; + command_finish(); + return; } uint32_t src = 0; @@ -986,9 +1018,9 @@ void s3virge_vga_device::bitblt_monosrc_step() // NOP disables autoexecute (is it supposed to not execute rest of command?) if (command_type == 0xf) { - m_bitblt_latch.cmd_set &= ~1; - //command_finish(); - //return; + m_bitblt_latch[11] &= ~1; + command_finish(); + return; } uint32_t src = 0; @@ -1157,6 +1189,8 @@ TIMER_CALLBACK_MEMBER(s3virge_vga_device::draw_step_tick) break; case S3D_STATE_BITBLT: bitblt_step(); + if (param == 1) + s3virge.s3d.busy = false; break; } } @@ -1256,14 +1290,15 @@ uint32_t s3virge_vga_device::s3d_sub_status_r() { uint32_t res = 0x00000000; - if(s3virge.s3d.busy == false && m_bitblt_fifo.empty()) + // HACK: this is entirely wrong, TBD log the status interactions + if(s3virge.s3d.busy == true || m_bitblt_fifo.empty() || m_xfer_fifo.empty()) res |= 0x00002000; // S3d engine is idle //res |= (s3virge.s3d.cmd_fifo_slots_free << 8); // NOTE: can actually be 24 FIFO depth with specific Scenic Mode (verify if different FIFO altogether) // & 0x1f00 //res |= std::min(m_bitblt_fifo.queue_length(), 16) << 8; - res |= (16 - m_bitblt_fifo.queue_length()) << 8; + res |= (16 - (m_bitblt_fifo.queue_length() / 15)) << 8; return res; } @@ -1338,137 +1373,17 @@ void s3virge_vga_device::s3d_register_map(address_map &map) s3virge.s3d.pattern[offset] = data; }) ); - map(0x04d4, 0x04d7).lrw32( - NAME([this] (offs_t offset) { - return m_bitblt_latch.src_base; - }), - NAME([this] (offs_t offset, u32 data, u32 mem_mask) { - LOGMMIO("MMA4D4 (src_base) = %08x & %08x\n", data, mem_mask); - COMBINE_DATA(&m_bitblt_latch.src_base); - }) - ); - map(0x04d8, 0x04db).lrw32( - NAME([this] (offs_t offset) { - return m_bitblt_latch.dest_base; - }), - NAME([this] (offs_t offset, u32 data, u32 mem_mask) { - LOGMMIO("MMA4D8 (dest_base) = %08x & %08x\n", data, mem_mask); - COMBINE_DATA(&m_bitblt_latch.dest_base); - }) - ); - map(0x04dc, 0x04df).lrw32( + map(0x04d4, 0x050f).lrw32( NAME([this] (offs_t offset) { - return m_bitblt_latch.clip_l_r; + return m_bitblt_latch[offset]; }), NAME([this] (offs_t offset, u32 data, u32 mem_mask) { - LOGMMIO("MMA4DC (clip_l_r) = %08x & %08x\n", data, mem_mask); - COMBINE_DATA(&m_bitblt_latch.clip_l_r); - }) - ); - map(0x04e0, 0x04e3).lrw32( - NAME([this] (offs_t offset) { - return m_bitblt_latch.clip_t_b; - }), - NAME([this] (offs_t offset, u32 data, u32 mem_mask) { - LOGMMIO("MMA4E0 (clip_t_b) = %08x & %08x\n", data, mem_mask); - COMBINE_DATA(&m_bitblt_latch.clip_t_b); - }) - ); - map(0x04e4, 0x04e7).lrw32( - NAME([this] (offs_t offset) { - return m_bitblt_latch.dest_src_str; - }), - NAME([this] (offs_t offset, u32 data, u32 mem_mask) { - LOGMMIO("MMA4E4 (dest_src_str) = %08x & %08x\n", data, mem_mask); - COMBINE_DATA(&m_bitblt_latch.dest_src_str); - }) - ); - map(0x04e8, 0x04ef).lrw32( - NAME([this] (offs_t offset) { - return m_bitblt_latch.mono_pat >> (offset * 32); - }), - NAME([this] (offs_t offset, u32 data, u32 mem_mask) { - LOGMMIO("MM%04X (mono_pat_%d) = %08x & %08x\n", (offset*4)+0xa4e8, offset, data, mem_mask); - if (offset) - m_bitblt_latch.mono_pat = ((u64)data << 32) | (m_bitblt_latch.mono_pat & 0xffff'ffff); - else - m_bitblt_latch.mono_pat = (data & 0xffff'ffff) | (u64)(m_bitblt_latch.mono_pat & 0xffff'ffff'0000'0000); - }) - ); - map(0x04f0, 0x04f3).lrw32( - NAME([this] (offs_t offset) { - return m_bitblt_latch.pat_bg_clr; - }), - NAME([this] (offs_t offset, u32 data, u32 mem_mask) { - LOGMMIO("MMA4F0 (pat_bg_clr) = %08x & %08x\n", data, mem_mask); - COMBINE_DATA(&m_bitblt_latch.pat_bg_clr); - }) - ); - map(0x04f4, 0x04f7).lrw32( - NAME([this] (offs_t offset) { - return m_bitblt_latch.pat_fg_clr; - }), - NAME([this] (offs_t offset, u32 data, u32 mem_mask) { - LOGMMIO("MMA4F4 (pat_fg_clr) = %08x & %08x\n", data, mem_mask); - COMBINE_DATA(&m_bitblt_latch.pat_fg_clr); - }) - ); - map(0x04f8, 0x04fb).lrw32( - NAME([this] (offs_t offset) { - return m_bitblt_latch.src_bg_clr; - }), - NAME([this] (offs_t offset, u32 data, u32 mem_mask) { - LOGMMIO("MMA4F8 (src_bg_clr) = %08x & %08x\n", data, mem_mask); - COMBINE_DATA(&m_bitblt_latch.src_bg_clr); - }) - ); - map(0x04fc, 0x04ff).lrw32( - NAME([this] (offs_t offset) { - return m_bitblt_latch.src_fg_clr; - }), - NAME([this] (offs_t offset, u32 data, u32 mem_mask) { - LOGMMIO("MMA4FC (src_fg_clr) = %08x & %08x\n", data, mem_mask); - COMBINE_DATA(&m_bitblt_latch.src_fg_clr); - }) - ); - map(0x0500, 0x0503).lrw32( - NAME([this] (offs_t offset) { - return m_bitblt_latch.cmd_set; - }), - NAME([this] (offs_t offset, u32 data, u32 mem_mask) { - LOGMMIO("MMA500 (cmd_set) = %08x & %08x\n", data, mem_mask); - COMBINE_DATA(&m_bitblt_latch.cmd_set); - if(!(BIT(data, 0))) + 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); - }) - ); - map(0x0504, 0x0507).lrw32( - NAME([this] (offs_t offset) { - return m_bitblt_latch.rwidth_height; - }), - NAME([this] (offs_t offset, u32 data, u32 mem_mask) { - LOGMMIO("MMA504 (rwidth_height) = %08x & %08x\n", data, mem_mask); - COMBINE_DATA(&m_bitblt_latch.rwidth_height); - }) - ); - map(0x0508, 0x050b).lrw32( - NAME([this] (offs_t offset) { - return m_bitblt_latch.rsrc_xy; - }), - NAME([this] (offs_t offset, u32 data, u32 mem_mask) { - LOGMMIO("MMA508 (rsrc_xy) = %08x & %08x\n", data, mem_mask); - COMBINE_DATA(&m_bitblt_latch.rsrc_xy); - }) - ); - map(0x050c, 0x050f).lrw32( - NAME([this] (offs_t offset) { - return m_bitblt_latch.rdest_xy; - }), - NAME([this] (offs_t offset, u32 data, u32 mem_mask) { - LOGMMIO("MMA50C (rdest_xy) = %08x & mem_mask\n", data, mem_mask); - COMBINE_DATA(&m_bitblt_latch.rdest_xy); - // autoexecute enabled - if(BIT(m_bitblt_latch.cmd_set, 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 5dc9531c09925..11286aab5dc85 100644 --- a/src/devices/video/s3virge.h +++ b/src/devices/video/s3virge.h @@ -36,14 +36,10 @@ class s3virge_vga_device : public s3trio64_vga_device void s3d_register_map(address_map &map); - void image_xfer(uint32_t data) + 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(); - } + m_xfer_fifo.enqueue(data); + machine().scheduler().synchronize(); } uint32_t get_linear_address() { return s3virge.linear_address; } @@ -54,7 +50,7 @@ class s3virge_vga_device : public s3trio64_vga_device bool is_new_mmio_active() { return s3.cr53 & 0x08; } uint16_t src_stride() { - return (s3virge.s3d.dest_src_stride >> 0) & 0xfff8; + return s3virge.s3d.src_stride; } uint16_t dest_stride() { @@ -66,7 +62,7 @@ class s3virge_vga_device : public s3trio64_vga_device // + ((s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_DEST_SRC_STR] >> 16) & 0xfff8); // } // else - return (s3virge.s3d.dest_src_stride >> 16) & 0xfff8; + return s3virge.s3d.dest_stride; } ibm8514a_device* get_8514() { fatalerror("s3virge requested non-existent 8514/A device\n"); return nullptr; } @@ -126,8 +122,10 @@ class s3virge_vga_device : public s3trio64_vga_device u32 rdest_xy = 0; }; - util::fifo m_bitblt_fifo; - bitblt_struct m_bitblt_latch; +// util::fifo m_bitblt_fifo; + util::fifo m_bitblt_fifo; + util::fifo m_xfer_fifo; + u32 m_bitblt_latch[15]{}; struct { @@ -140,7 +138,8 @@ class s3virge_vga_device : public s3trio64_vga_device struct { int state; - bool busy; + bool busy = false; + bool xfer_mode = false; uint8_t pattern[0xc0]; @@ -173,7 +172,8 @@ class s3virge_vga_device : public s3trio64_vga_device uint32_t pat_fg_clr; uint32_t src_bg_clr; uint32_t src_fg_clr; - uint32_t dest_src_stride; + uint16_t dest_stride; + uint16_t src_stride; } s3d; uint8_t cr66; } s3virge; From f39e73cf37e94d95c2c8336a8404fb4b0ebab263 Mon Sep 17 00:00:00 2001 From: angelosa Date: Fri, 29 Mar 2024 21:17:34 +0100 Subject: [PATCH 08/14] video/s3virge: refine a bit FIFO status --- src/devices/video/s3virge.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/devices/video/s3virge.cpp b/src/devices/video/s3virge.cpp index c33caa28d1790..bc430430e9146 100644 --- a/src/devices/video/s3virge.cpp +++ b/src/devices/video/s3virge.cpp @@ -517,10 +517,6 @@ void s3virge_vga_device::add_command(u8 cmd_type) TIMER_CALLBACK_MEMBER(s3virge_vga_device::command_timer_cb) { - // TODO: shouldn't be here - if (m_bitblt_fifo.empty()) - return; - if (s3virge.s3d.xfer_mode) { if (!m_xfer_fifo.empty()) @@ -532,6 +528,9 @@ TIMER_CALLBACK_MEMBER(s3virge_vga_device::command_timer_cb) return; } + if (m_bitblt_fifo.empty()) + return; + if (s3virge.s3d.busy) return; @@ -1189,7 +1188,7 @@ TIMER_CALLBACK_MEMBER(s3virge_vga_device::draw_step_tick) break; case S3D_STATE_BITBLT: bitblt_step(); - if (param == 1) + if (param == 1 && m_xfer_fifo.empty()) s3virge.s3d.busy = false; break; } @@ -1290,14 +1289,14 @@ uint32_t s3virge_vga_device::s3d_sub_status_r() { uint32_t res = 0x00000000; - // HACK: this is entirely wrong, TBD log the status interactions - if(s3virge.s3d.busy == true || m_bitblt_fifo.empty() || m_xfer_fifo.empty()) + if(s3virge.s3d.busy == false && m_bitblt_fifo.empty()) res |= 0x00002000; // S3d engine is idle //res |= (s3virge.s3d.cmd_fifo_slots_free << 8); // NOTE: can actually be 24 FIFO depth with specific Scenic Mode (verify if 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; From 5b3cd4735f0cd0d7b6c80bd0b3e647f79deacf5d Mon Sep 17 00:00:00 2001 From: angelosa Date: Sat, 30 Mar 2024 21:35:35 +0100 Subject: [PATCH 09/14] video/s3virge: merge draw & command timers in one, simplify state logic, workaround GFX corruption issue --- src/devices/video/s3virge.cpp | 208 ++++++++++++++-------------------- src/devices/video/s3virge.h | 36 ++---- 2 files changed, 97 insertions(+), 147 deletions(-) diff --git a/src/devices/video/s3virge.cpp b/src/devices/video/s3virge.cpp index bc430430e9146..28b439132b829 100644 --- a/src/devices/video/s3virge.cpp +++ b/src/devices/video/s3virge.cpp @@ -108,8 +108,7 @@ 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_cmd_timer = timer_alloc(FUNC(s3virge_vga_device::command_timer_cb), this); + m_op_timer = timer_alloc(FUNC(s3virge_vga_device::op_timer_cb), this); memset(&s3, 0, sizeof(s3)); memset(&s3virge, 0, sizeof(s3virge)); @@ -117,11 +116,11 @@ void s3virge_vga_device::device_start() s3virge.linear_address_size_full = 0x10000; 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"); +// 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"); // Initialise hardware graphics cursor colours, Windows 95 doesn't touch the registers for some reason for (int x = 0; x < 4; x++) @@ -162,10 +161,9 @@ void s3virge_vga_device::s3d_reset() { LOGFIFO("S3D Reset\n"); m_bitblt_fifo.clear(); - m_cmd_timer->adjust(attotime::never); - m_draw_timer->adjust(attotime::never); - s3virge.s3d.state = S3D_STATE_IDLE; - s3virge.s3d.busy = 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; @@ -496,48 +494,57 @@ void s3virge_vga_device::add_command(u8 cmd_type) if (m_bitblt_fifo.full()) throw emu_fatalerror("s3virge: FIFO full"); - if (m_bitblt_fifo.empty()) - m_cmd_timer->adjust(attotime::from_nsec(250), 0, attotime::from_nsec(250)); - for (int i = 0; i < 15; i++) m_bitblt_fifo.enqueue(m_bitblt_latch[i]); - LOGFIFO("Enqueue command type %i %08x (%d free)\n", cmd_type, m_bitblt_latch[11], 16 - m_bitblt_fifo.queue_length() / 15); - + if (m_s3d_state == S3D_STATE_IDLE) + { + m_op_timer->adjust(attotime::from_nsec(250), 0, attotime::from_nsec(250)); + m_s3d_state = S3D_STATE_COMMAND_RX; + } -// s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_next_ptr].op_type = cmd_type; -// s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_next_ptr].command = s3virge.s3d.command; -// LOGCMD("Added command type %i cmd %08x ptr %u\n",s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_next_ptr].op_type, s3virge.s3d.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 -// s3virge.s3d.cmd_fifo_slots_free--; + LOGFIFO("Enqueue command type %i %08x (%d free)\n", cmd_type, m_bitblt_latch[11], 16 - m_bitblt_fifo.queue_length() / 15); } -TIMER_CALLBACK_MEMBER(s3virge_vga_device::command_timer_cb) +TIMER_CALLBACK_MEMBER(s3virge_vga_device::op_timer_cb) { - if (s3virge.s3d.xfer_mode) + switch (m_s3d_state) { - if (!m_xfer_fifo.empty()) - { - s3virge.s3d.busy = true; - s3virge.s3d.image_xfer = m_xfer_fifo.dequeue(); - m_draw_timer->adjust(attotime::from_nsec(250), 1); - } - return; + case S3D_STATE_IDLE: + return; + case S3D_STATE_COMMAND_RX: + // start next command in FIFO + //const u8 cmd_type = 0; //s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].op_type & 0xf; + assert(!m_bitblt_fifo.empty()); + command_dequeue(OP_BITBLT); + break; + case S3D_STATE_BITBLT: + if (s3virge.s3d.xfer_mode == true) + { + if (m_xfer_fifo.empty()) + return; + s3virge.s3d.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; } +} - if (m_bitblt_fifo.empty()) - return; - - if (s3virge.s3d.busy) - return; - - // start next command in FIFO - const u8 cmd_type = 0; //s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].op_type & 0xf; - - 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); @@ -558,7 +565,6 @@ TIMER_CALLBACK_MEMBER(s3virge_vga_device::command_timer_cb) case OP_BITBLT: { u32 tmp; - s3virge.s3d.state = S3D_STATE_BITBLT; //const bitblt_struct command_struct = m_bitblt_fifo.dequeue(); s3virge.s3d.src_base = m_bitblt_fifo.dequeue(); s3virge.s3d.dest_base = m_bitblt_fifo.dequeue(); @@ -599,53 +605,41 @@ TIMER_CALLBACK_MEMBER(s3virge_vga_device::command_timer_cb) s3virge.s3d.bitblt_current_pixel = 0; s3virge.s3d.bitblt_pixel_pos = 0; - if(!(BIT(s3virge.s3d.command, 7))) - { - s3virge.s3d.busy = true; - s3virge.s3d.xfer_mode = false; - m_draw_timer->adjust(attotime::from_nsec(250), 0, attotime::from_nsec(250)); - } - else - s3virge.s3d.xfer_mode = true; + s3virge.s3d.xfer_mode = bool(BIT(s3virge.s3d.command, 7)); + m_s3d_state = S3D_STATE_BITBLT; - LOGFIFO("Dequeue command %08x (%d free)\n", s3virge.s3d.command, 16 - (m_bitblt_fifo.queue_length() / 15)); + LOGFIFO("Dequeued command %08x (%d free)\n", s3virge.s3d.command, 16 - (m_bitblt_fifo.queue_length() / 15)); LOGCMD("Started BitBLT command [%08x]\n", s3virge.s3d.command); break; } default: - LOGCMD(" command detected [%08x]\n", cmd_type, s3virge.s3d.command); + LOGCMD(" command detected [%08x]\n", op_type, s3virge.s3d.command); break; } } void s3virge_vga_device::command_finish() { - m_draw_timer->adjust(attotime::never); - LOGFIFO("Command finished (%u free) ", 16 - (m_bitblt_fifo.queue_length() / 15)); - s3virge.s3d.busy = false; - s3virge.s3d.xfer_mode = false; if (m_bitblt_fifo.empty()) { - s3virge.s3d.state = S3D_STATE_IDLE; - m_draw_timer->adjust(attotime::never); - m_cmd_timer->adjust(attotime::never); - LOGFIFO("- timer stop\n"); + m_s3d_state = S3D_STATE_IDLE; + m_op_timer->adjust(attotime::never); + LOGFIFO("- state idle\n"); } else { - s3virge.s3d.state = S3D_STATE_BITBLT; - //m_cmd_timer->adjust(attotime::from_msec(1)); - LOGFIFO("- timer continue\n"); + m_s3d_state = S3D_STATE_COMMAND_RX; + const auto xfer_fifo = m_xfer_fifo.queue_length(); + // NOTE: without flushing xfer FIFO GFXs will go awry in win98se + // i.e. when calling shutdown menu + 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(); } - - // check if there is another command in the FIFO - //if(s3virge.s3d.cmd_fifo_slots_free < 16) - // command_start(); - //else - // s3virge.s3d.busy = false; } void s3virge_vga_device::line2d_step() @@ -800,6 +794,24 @@ bool s3virge_vga_device::advance_pixel() 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(BIT(s3virge.s3d.command, 6)) @@ -1166,34 +1178,6 @@ void s3virge_vga_device::bitblt_monosrc_step() s3virge.s3d.bitblt_step_count++; } -TIMER_CALLBACK_MEMBER(s3virge_vga_device::draw_step_tick) -{ - // TODO: S3D state timing - switch(s3virge.s3d.state) - { - case S3D_STATE_IDLE: - m_draw_timer->adjust(attotime::never); - 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(); - if (param == 1 && m_xfer_fifo.empty()) - s3virge.s3d.busy = false; - break; - } -} - inline void s3virge_vga_device::write_pixel32(uint32_t base, uint16_t x, uint16_t y, uint32_t val) { if(BIT(s3virge.s3d.command, 1)) @@ -1266,34 +1250,16 @@ 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 == false && m_bitblt_fifo.empty()) - res |= 0x00002000; // S3d engine is idle + res |= (m_s3d_state == S3D_STATE_IDLE) << 13; //res |= (s3virge.s3d.cmd_fifo_slots_free << 8); - // NOTE: can actually be 24 FIFO depth with specific Scenic Mode (verify if different FIFO altogether) + // 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 @@ -1356,7 +1322,7 @@ uint32_t s3virge_vga_device::s3d_func_ctrl_r() { uint32_t ret = 0; -// ret |= (s3d_fifo_size << 6); +// ret |= (s3d_fifo_size << 6); ret |= 0xf << 6; return ret; } diff --git a/src/devices/video/s3virge.h b/src/devices/video/s3virge.h index 11286aab5dc85..0b464733c7c60 100644 --- a/src/devices/video/s3virge.h +++ b/src/devices/video/s3virge.h @@ -39,7 +39,7 @@ class s3virge_vga_device : public s3trio64_vga_device void image_xfer(offs_t offset, uint32_t data, uint32_t mem_mask) { m_xfer_fifo.enqueue(data); - machine().scheduler().synchronize(); + //machine().scheduler().synchronize(); } uint32_t get_linear_address() { return s3virge.linear_address; } @@ -95,9 +95,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, @@ -105,27 +106,12 @@ class s3virge_vga_device : public s3trio64_vga_device S3D_STATE_3DPOLY }; - struct bitblt_struct { - u32 src_base = 0; - u32 dest_base = 0; - u32 clip_l_r = 0; - u32 clip_t_b = 0; - u32 dest_src_str = 0; - u64 mono_pat = 0; - u32 pat_bg_clr = 0; - u32 pat_fg_clr = 0; - u32 src_bg_clr = 0; - u32 src_fg_clr = 0; - u32 cmd_set = 0; - u32 rwidth_height = 0; - u32 rsrc_xy = 0; - u32 rdest_xy = 0; - }; - -// util::fifo m_bitblt_fifo; +// util::fifo m_bitblt_fifo; + // TODO: sketchy, command pipeline size is unclear util::fifo m_bitblt_fifo; util::fifo m_xfer_fifo; u32 m_bitblt_latch[15]{}; + s3d_state_t m_s3d_state = S3D_STATE_IDLE; struct { @@ -137,8 +123,6 @@ class s3virge_vga_device : public s3trio64_vga_device struct { - int state; - bool busy = false; bool xfer_mode = false; uint8_t pattern[0xc0]; @@ -178,8 +162,7 @@ class s3virge_vga_device : public s3trio64_vga_device uint8_t cr66; } s3virge; - TIMER_CALLBACK_MEMBER(draw_step_tick); - TIMER_CALLBACK_MEMBER(command_timer_cb); + TIMER_CALLBACK_MEMBER(op_timer_cb); inline void write_pixel32(uint32_t base, uint16_t x, uint16_t y, uint32_t val); inline void write_pixel24(uint32_t base, uint16_t x, uint16_t y, uint32_t val); @@ -199,8 +182,7 @@ class s3virge_vga_device : public s3trio64_vga_device // has no 8514/A device private: - emu_timer* m_draw_timer; - emu_timer* m_cmd_timer; + emu_timer *m_op_timer; void bitblt_step(); void bitblt_colour_step(); void bitblt_monosrc_step(); @@ -209,6 +191,8 @@ class s3virge_vga_device : public s3trio64_vga_device void line3d_step(); void poly3d_step(); void add_command(u8 cmd_type); + void command_enqueue(u8 op_type); + void command_dequeue(u8 op_type); void command_finish(); void s3d_reset(); From 32052757d22c1e4fee745d8eec6205d298759824 Mon Sep 17 00:00:00 2001 From: angelosa Date: Sun, 31 Mar 2024 17:45:30 +0200 Subject: [PATCH 10/14] video/s3virge: move NOP logic in dequeue fn --- src/devices/video/s3virge.cpp | 56 +++++++++++++++++++++-------------- src/devices/video/s3virge.h | 3 ++ 2 files changed, 36 insertions(+), 23 deletions(-) diff --git a/src/devices/video/s3virge.cpp b/src/devices/video/s3virge.cpp index 28b439132b829..71b2bdc84fd65 100644 --- a/src/devices/video/s3virge.cpp +++ b/src/devices/video/s3virge.cpp @@ -161,6 +161,8 @@ void s3virge_vga_device::s3d_reset() { LOGFIFO("S3D Reset\n"); m_bitblt_fifo.clear(); + m_xfer_fifo.clear(); + s3virge.s3d.xfer_mode = false; m_op_timer->adjust(attotime::never); m_s3d_state = S3D_STATE_IDLE; @@ -605,12 +607,34 @@ void s3virge_vga_device::command_dequeue(u8 op_type) s3virge.s3d.bitblt_current_pixel = 0; s3virge.s3d.bitblt_pixel_pos = 0; - s3virge.s3d.xfer_mode = bool(BIT(s3virge.s3d.command, 7)); + LOGFIFO("Dequeued command %08x (%d free)\n", s3virge.s3d.command, 16 - (m_bitblt_fifo.queue_length() / 15)); + + const u32 current_command = s3virge.s3d.command; + + s3virge.s3d.xfer_mode = bool(BIT(current_command, 7)); m_s3d_state = S3D_STATE_BITBLT; - LOGFIFO("Dequeued command %08x (%d free)\n", s3virge.s3d.command, 16 - (m_bitblt_fifo.queue_length() / 15)); + 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; + s3virge.s3d.xfer_mode = false; + command_finish(); + return; + } + else + { + LOGCMD("Started BitBLT command [%08x type=%02x xfer_mode=%d]\n" + , s3virge.s3d.command + , command_type + , s3virge.s3d.xfer_mode + ); + } - LOGCMD("Started BitBLT command [%08x]\n", s3virge.s3d.command); break; } default: @@ -633,8 +657,9 @@ void s3virge_vga_device::command_finish() { m_s3d_state = S3D_STATE_COMMAND_RX; const auto xfer_fifo = m_xfer_fifo.queue_length(); - // NOTE: without flushing xfer FIFO GFXs will go awry in win98se - // i.e. when calling shutdown menu + // 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"); @@ -834,15 +859,6 @@ void s3virge_vga_device::bitblt_colour_step() 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 u8 command_type = current_command >> 27; - - // NOP disables autoexecute (is it supposed to not execute rest of command?) - if (command_type == 0xf) - { - m_bitblt_latch[11] &= ~1; - command_finish(); - return; - } uint32_t src = 0; uint32_t dst = 0; @@ -1024,15 +1040,6 @@ void s3virge_vga_device::bitblt_monosrc_step() const bool ids = bool(BIT(current_command, 7)); const bool de = bool(BIT(current_command, 5)); const int align = (current_command & 0x000000c00) >> 10; - const u8 command_type = current_command >> 27; - - // NOP disables autoexecute (is it supposed to not execute rest of command?) - if (command_type == 0xf) - { - m_bitblt_latch[11] &= ~1; - command_finish(); - return; - } uint32_t src = 0; uint32_t dst = 0; @@ -1255,7 +1262,10 @@ uint32_t s3virge_vga_device::s3d_sub_status_r() { uint32_t res = 0x00000000; + // check for idle res |= (m_s3d_state == S3D_STATE_IDLE) << 13; + //if (m_s3d_state == S3D_STATE_BITBLT && s3virge.s3d.xfer_mode == true && m_xfer_fifo.empty()) + // res |= 1 << 13; //res |= (s3virge.s3d.cmd_fifo_slots_free << 8); // NOTE: can actually be 24 FIFO depth with specific Scenic Mode diff --git a/src/devices/video/s3virge.h b/src/devices/video/s3virge.h index 0b464733c7c60..6f1b5129cee9b 100644 --- a/src/devices/video/s3virge.h +++ b/src/devices/video/s3virge.h @@ -38,6 +38,9 @@ class s3virge_vga_device : public s3trio64_vga_device void image_xfer(offs_t offset, uint32_t data, uint32_t mem_mask) { + 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(); } From 69d0dfb12107d0e56b8065fa41cad6e96acf76c9 Mon Sep 17 00:00:00 2001 From: angelosa Date: Thu, 4 Apr 2024 03:59:14 +0200 Subject: [PATCH 11/14] video/s3virge: add primary streams stride override, fix Ubuntu flavor gfxs --- src/devices/bus/pci/virge_pci.cpp | 2 +- src/devices/video/s3virge.cpp | 82 +++++++++++++++++++++++-------- src/devices/video/s3virge.h | 8 +++ 3 files changed, 71 insertions(+), 21 deletions(-) diff --git a/src/devices/bus/pci/virge_pci.cpp b/src/devices/bus/pci/virge_pci.cpp index 27dd054e7433f..26fde9cb6c979 100644 --- a/src/devices/bus/pci/virge_pci.cpp +++ b/src/devices/bus/pci/virge_pci.cpp @@ -32,7 +32,7 @@ void virge_pci_device::mmio_map(address_map& map) map(0x0000,0x7fff).w(m_vga, FUNC(s3virge_vga_device::image_xfer)); //map(0x8000,0x8043) PCI Configuration Space regs - //map(0x8180,0x81ff) primary/secondary stream control + map(0x8180,0x81ff).m(m_vga, FUNC(s3virge_vga_device::streams_control_map)); //map(0x8200,0x821f) memory port controller //map(0x8220,0x8227) DMA control diff --git a/src/devices/video/s3virge.cpp b/src/devices/video/s3virge.cpp index 71b2bdc84fd65..f41d311f97c91 100644 --- a/src/devices/video/s3virge.cpp +++ b/src/devices/video/s3virge.cpp @@ -33,22 +33,24 @@ //#include -#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 VERBOSE (LOG_REG | LOG_CMD | LOG_MMIO | LOG_FIFO) +#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 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 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) @@ -160,6 +162,8 @@ void s3virgedx_rev1_vga_device::device_start() 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(); s3virge.s3d.xfer_mode = false; @@ -200,12 +204,46 @@ 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; + if (s3.ext_misc_ctrl_2 & 0xc) + return m_streams.primary_stride; + // TODO: SDD expects offset x8 with streams disabled return s3trio64_vga_device::offset(); } @@ -391,7 +429,7 @@ void s3virge_vga_device::s3_define_video_mode() 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)); + default: popmessage("video/s3virge.cpp: video mode not implemented %02x\n",((s3.ext_misc_ctrl_2) >> 4)); } } else @@ -573,6 +611,7 @@ void s3virge_vga_device::command_dequeue(u8 op_type) tmp = m_bitblt_fifo.dequeue(); s3virge.s3d.clip_r = tmp & 0x000007ff; s3virge.s3d.clip_l = (tmp & 0x07ff0000) >> 16; + // $a4e0 tmp = m_bitblt_fifo.dequeue(); s3virge.s3d.clip_b = tmp & 0x000007ff; s3virge.s3d.clip_t = (tmp & 0x07ff0000) >> 16; @@ -581,13 +620,15 @@ void s3virge_vga_device::command_dequeue(u8 op_type) s3virge.s3d.dest_stride = (tmp >> 16) & 0xfff8; tmp = m_bitblt_fifo.dequeue(); s3virge.s3d.bitblt_mono_pattern = ((u64)m_bitblt_fifo.dequeue() << 32) | tmp; + // $a4f0 s3virge.s3d.pat_bg_clr = m_bitblt_fifo.dequeue(); s3virge.s3d.pat_fg_clr = m_bitblt_fifo.dequeue(); s3virge.s3d.src_bg_clr = m_bitblt_fifo.dequeue(); s3virge.s3d.src_fg_clr = m_bitblt_fifo.dequeue(); + // $a500 s3virge.s3d.command = m_bitblt_fifo.dequeue(); tmp = m_bitblt_fifo.dequeue(); - s3virge.s3d.bitblt_width = (tmp & 0xffff0000) >> 16; + s3virge.s3d.bitblt_width = ((tmp & 0xffff0000) >> 16) + 1; s3virge.s3d.bitblt_height = (tmp & 0x0000ffff); tmp = m_bitblt_fifo.dequeue(); s3virge.s3d.bitblt_x_src = (tmp & 0x07ff0000) >> 16; @@ -763,14 +804,15 @@ bool s3virge_vga_device::advance_pixel() if(xpos) { left = s3virge.s3d.bitblt_x_dst; - right = s3virge.s3d.bitblt_x_dst + s3virge.s3d.bitblt_width + 1; + right = s3virge.s3d.bitblt_x_dst + s3virge.s3d.bitblt_width; 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; + // FIXME: beos 4 dominos demo + left = s3virge.s3d.bitblt_x_dst - s3virge.s3d.bitblt_width; right = s3virge.s3d.bitblt_x_dst; s3virge.s3d.bitblt_x_current--; s3virge.s3d.bitblt_x_src_current--; diff --git a/src/devices/video/s3virge.h b/src/devices/video/s3virge.h index 6f1b5129cee9b..2c308c5e612ad 100644 --- a/src/devices/video/s3virge.h +++ b/src/devices/video/s3virge.h @@ -36,6 +36,8 @@ class s3virge_vga_device : public s3trio64_vga_device void s3d_register_map(address_map &map); + void streams_control_map(address_map &map); + void image_xfer(offs_t offset, uint32_t data, uint32_t mem_mask) { if (mem_mask != 0xffff'ffff) @@ -109,6 +111,12 @@ class s3virge_vga_device : public s3trio64_vga_device S3D_STATE_3DPOLY }; + struct { + u8 psidf = 0; + u8 pshfc = 0; + u16 primary_stride = 0; + } m_streams; + // util::fifo m_bitblt_fifo; // TODO: sketchy, command pipeline size is unclear util::fifo m_bitblt_fifo; From bfd0363d145a9995ce4b9f5e1d02ac30980f2be8 Mon Sep 17 00:00:00 2001 From: angelosa Date: Sun, 7 Apr 2024 03:35:52 +0200 Subject: [PATCH 12/14] video/s3virge: RAMDAC runs in unpacked mode if streams processor disabled --- src/devices/video/s3virge.cpp | 38 +++++++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/src/devices/video/s3virge.cpp b/src/devices/video/s3virge.cpp index f41d311f97c91..8898cec023311 100644 --- a/src/devices/video/s3virge.cpp +++ b/src/devices/video/s3virge.cpp @@ -220,13 +220,13 @@ void s3virge_vga_device::streams_control_map(address_map &map) 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(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); @@ -243,8 +243,11 @@ uint16_t s3virge_vga_device::offset() { if (s3.ext_misc_ctrl_2 & 0xc) return m_streams.primary_stride; - // TODO: SDD expects offset x8 with streams disabled - return s3trio64_vga_device::offset(); + + // 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) @@ -423,12 +426,24 @@ 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; + 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)); } } @@ -438,6 +453,7 @@ 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; @@ -1307,7 +1323,7 @@ uint32_t s3virge_vga_device::s3d_sub_status_r() // check for idle res |= (m_s3d_state == S3D_STATE_IDLE) << 13; //if (m_s3d_state == S3D_STATE_BITBLT && s3virge.s3d.xfer_mode == true && m_xfer_fifo.empty()) - // res |= 1 << 13; + // res |= 1 << 13; //res |= (s3virge.s3d.cmd_fifo_slots_free << 8); // NOTE: can actually be 24 FIFO depth with specific Scenic Mode From 4d29c802009a083897f22435e328419764052d90 Mon Sep 17 00:00:00 2001 From: angelosa Date: Sun, 14 Apr 2024 00:09:48 +0200 Subject: [PATCH 13/14] video/s3virge: flatten s3dvirge.s3d down to one struct (m_bitblt), get rid of src_stride and dest_stride fns, update QA --- src/devices/video/s3virge.cpp | 474 +++++++++++++++++----------------- src/devices/video/s3virge.h | 122 ++++----- 2 files changed, 287 insertions(+), 309 deletions(-) diff --git a/src/devices/video/s3virge.cpp b/src/devices/video/s3virge.cpp index 8898cec023311..f6c98153c0a0d 100644 --- a/src/devices/video/s3virge.cpp +++ b/src/devices/video/s3virge.cpp @@ -7,10 +7,11 @@ * ViRGE = Video and Rendering Graphics Engine * * TODO: - * - Proper FIFOs, remove leaky abstraction; + * - Complete FIFO details, fix remaining stalls (win2k); * - Backport 2d engine to Trio64; - * - Implement 3d commands; + * - 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; @@ -18,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 * */ @@ -113,16 +116,15 @@ void s3virge_vga_device::device_start() 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; + m_linear_address = 0x70000000; + m_linear_address_size_full = 0x10000; - 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"); + 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++) @@ -166,7 +168,7 @@ void s3virge_vga_device::s3d_reset() m_streams.pshfc = 0; m_bitblt_fifo.clear(); m_xfer_fifo.clear(); - s3virge.s3d.xfer_mode = false; + m_bitblt.xfer_mode = false; m_op_timer->adjust(attotime::never); m_s3d_state = S3D_STATE_IDLE; @@ -175,6 +177,7 @@ void s3virge_vga_device::s3d_reset() 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() @@ -297,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); @@ -340,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); } @@ -356,30 +359,30 @@ 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); } @@ -388,10 +391,10 @@ void s3virge_vga_device::crtc_map(address_map &map) //map(0x5d, 0x5e).unmapr(); map(0x66, 0x66).lrw8( NAME([this] (offs_t offset) { - return s3virge.cr66; + return m_cr66; }), NAME([this] (offs_t offset, u8 data) { - s3virge.cr66 = data; + m_cr66 = data; LOGREG("CR66: write %02x\n", data); // bit 0: ENBL ENH Enable Enhanced Functions if (BIT(data, 1)) @@ -457,6 +460,8 @@ void s3virge_vga_device::s3_define_video_mode() } 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()); } @@ -533,14 +538,14 @@ 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; } @@ -570,16 +575,16 @@ TIMER_CALLBACK_MEMBER(s3virge_vga_device::op_timer_cb) return; case S3D_STATE_COMMAND_RX: // start next command in FIFO - //const u8 cmd_type = 0; //s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].op_type & 0xf; + //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 (s3virge.s3d.xfer_mode == true) + if (m_bitblt.xfer_mode == true) { if (m_xfer_fifo.empty()) return; - s3virge.s3d.image_xfer = m_xfer_fifo.dequeue(); + m_bitblt.image_xfer = m_xfer_fifo.dequeue(); } bitblt_step(); break; @@ -603,72 +608,72 @@ 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: { u32 tmp; //const bitblt_struct command_struct = m_bitblt_fifo.dequeue(); - s3virge.s3d.src_base = m_bitblt_fifo.dequeue(); - s3virge.s3d.dest_base = 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(); - s3virge.s3d.clip_r = tmp & 0x000007ff; - s3virge.s3d.clip_l = (tmp & 0x07ff0000) >> 16; + m_bitblt.clip_r = tmp & 0x000007ff; + m_bitblt.clip_l = (tmp & 0x07ff0000) >> 16; // $a4e0 tmp = m_bitblt_fifo.dequeue(); - s3virge.s3d.clip_b = tmp & 0x000007ff; - s3virge.s3d.clip_t = (tmp & 0x07ff0000) >> 16; + m_bitblt.clip_b = tmp & 0x000007ff; + m_bitblt.clip_t = (tmp & 0x07ff0000) >> 16; tmp = m_bitblt_fifo.dequeue(); - s3virge.s3d.src_stride = (tmp >> 0) & 0xfff8; - s3virge.s3d.dest_stride = (tmp >> 16) & 0xfff8; + m_bitblt.src_stride = (tmp >> 0) & 0xfff8; + m_bitblt.dest_stride = (tmp >> 16) & 0xfff8; tmp = m_bitblt_fifo.dequeue(); - s3virge.s3d.bitblt_mono_pattern = ((u64)m_bitblt_fifo.dequeue() << 32) | tmp; + m_bitblt.mono_pattern = ((u64)m_bitblt_fifo.dequeue() << 32) | tmp; // $a4f0 - s3virge.s3d.pat_bg_clr = m_bitblt_fifo.dequeue(); - s3virge.s3d.pat_fg_clr = m_bitblt_fifo.dequeue(); - s3virge.s3d.src_bg_clr = m_bitblt_fifo.dequeue(); - s3virge.s3d.src_fg_clr = m_bitblt_fifo.dequeue(); + 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 - s3virge.s3d.command = m_bitblt_fifo.dequeue(); + m_bitblt.command = m_bitblt_fifo.dequeue(); tmp = m_bitblt_fifo.dequeue(); - s3virge.s3d.bitblt_width = ((tmp & 0xffff0000) >> 16) + 1; - s3virge.s3d.bitblt_height = (tmp & 0x0000ffff); + m_bitblt.width = ((tmp & 0xffff0000) >> 16) + 1; + m_bitblt.height = (tmp & 0x0000ffff); tmp = m_bitblt_fifo.dequeue(); - s3virge.s3d.bitblt_x_src = (tmp & 0x07ff0000) >> 16; - s3virge.s3d.bitblt_y_src = (tmp & 0x000007ff); + m_bitblt.x_src = (tmp & 0x07ff0000) >> 16; + m_bitblt.y_src = (tmp & 0x000007ff); tmp = m_bitblt_fifo.dequeue(); - s3virge.s3d.bitblt_x_dst = (tmp & 0x07ff0000) >> 16; - s3virge.s3d.bitblt_y_dst = (tmp & 0x000007ff); + 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?) - 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.bitblt_step_count = 0; - s3virge.s3d.bitblt_current_pixel = 0; - s3virge.s3d.bitblt_pixel_pos = 0; + 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", s3virge.s3d.command, 16 - (m_bitblt_fifo.queue_length() / 15)); + LOGFIFO("Dequeued command %08x (%d free)\n", m_bitblt.command, 16 - (m_bitblt_fifo.queue_length() / 15)); - const u32 current_command = s3virge.s3d.command; + const u32 current_command = m_bitblt.command; - s3virge.s3d.xfer_mode = bool(BIT(current_command, 7)); + m_bitblt.xfer_mode = bool(BIT(current_command, 7)); m_s3d_state = S3D_STATE_BITBLT; const u8 command_type = BIT(current_command, 27, 4); @@ -679,23 +684,23 @@ void s3virge_vga_device::command_dequeue(u8 op_type) { LOGCMD("BitBLT NOP encountered\n"); m_bitblt_latch[11] &= ~1; - s3virge.s3d.xfer_mode = false; + m_bitblt.xfer_mode = false; command_finish(); return; } else { LOGCMD("Started BitBLT command [%08x type=%02x xfer_mode=%d]\n" - , s3virge.s3d.command + , m_bitblt.command , command_type - , s3virge.s3d.xfer_mode + , m_bitblt.xfer_mode ); } break; } default: - LOGCMD(" command detected [%08x]\n", op_type, s3virge.s3d.command); + LOGCMD(" command detected [%08x]\n", op_type, m_bitblt.command); break; } } @@ -815,63 +820,63 @@ bool s3virge_vga_device::advance_pixel() bool xpos, ypos; int16_t top, left, right, bottom; // advance src/dst and pattern location - xpos = s3virge.s3d.command & 0x02000000; // X Positive - ypos = s3virge.s3d.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; - 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 { // FIXME: beos 4 dominos demo - left = s3virge.s3d.bitblt_x_dst - s3virge.s3d.bitblt_width; - right = s3virge.s3d.bitblt_x_dst; - s3virge.s3d.bitblt_x_current--; - s3virge.s3d.bitblt_x_src_current--; - s3virge.s3d.bitblt_pat_x--; + 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; + 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", - 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.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; @@ -897,7 +902,7 @@ bool s3virge_vga_device::advance_pixel() void s3virge_vga_device::bitblt_step() { - if(BIT(s3virge.s3d.command, 6)) + if(BIT(m_bitblt.command, 6)) bitblt_monosrc_step(); else bitblt_colour_step(); @@ -907,9 +912,9 @@ void s3virge_vga_device::bitblt_colour_step() { // progress current BitBLT operation // get source and destination addresses - uint32_t src_base = s3virge.s3d.src_base & 0x003ffff8; - uint32_t dst_base = s3virge.s3d.dest_base & 0x003ffff8; - const u32 current_command = s3virge.s3d.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; @@ -931,26 +936,26 @@ void s3virge_vga_device::bitblt_colour_step() { if(ids) { - src = s3virge.s3d.image_xfer >> (x*8); + 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()); + 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.pat_fg_clr : s3virge.s3d.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(s3virge.s3d.bitblt_mono_pattern, (s3virge.s3d.bitblt_pat_y*8) + (7-s3virge.s3d.bitblt_pat_x)) ? s3virge.s3d.pat_fg_clr : s3virge.s3d.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(); @@ -959,7 +964,7 @@ void s3virge_vga_device::bitblt_colour_step() command_finish(); break; } - if((ids) && 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; @@ -976,74 +981,74 @@ void s3virge_vga_device::bitblt_colour_step() case 1: // 16bpp if(ids) { - src = s3virge.s3d.image_xfer; + 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()); + 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.pat_fg_clr - : s3virge.s3d.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((ids) && 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(ids) - src = s3virge.s3d.image_xfer >> 16; + 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()); + 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.pat_fg_clr - : s3virge.s3d.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(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()); + 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.pat_fg_clr : s3virge.s3d.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((ids) && 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; @@ -1063,34 +1068,36 @@ 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()); + 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.pat_fg_clr : s3virge.s3d.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.src_base & 0x003ffff8; - uint32_t dst_base = s3virge.s3d.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.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)); @@ -1103,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.pat_fg_clr; + uint32_t pat = m_bitblt.pat_fg_clr; int x; bool done = false; @@ -1113,23 +1120,23 @@ void s3virge_vga_device::bitblt_monosrc_step() for(x=31;x>=0;x--) { if(ids) - 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); + 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.src_fg_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,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current,GetROP(rop, s3virge.s3d.src_bg_clr, dst, pat) & 0xff); + 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((ids) && s3virge.s3d.bitblt_x_current == s3virge.s3d.bitblt_x_dst) + if((ids) && m_bitblt.x_current == m_bitblt.x_dst) { switch(align) { @@ -1155,24 +1162,24 @@ void s3virge_vga_device::bitblt_monosrc_step() for(x=31;x>=0;x--) { if(ids) - 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); + 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.src_fg_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,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current,GetROP(rop, s3virge.s3d.src_bg_clr, dst, pat) & 0xffff); + 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((ids) && s3virge.s3d.bitblt_x_current == s3virge.s3d.bitblt_x_dst) + if((ids) && m_bitblt.x_current == m_bitblt.x_dst) { switch(align) { @@ -1198,25 +1205,25 @@ void s3virge_vga_device::bitblt_monosrc_step() for(x=31;x>=0;x--) { if(ids) - 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); + 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.src_fg_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,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current,GetROP(rop, s3virge.s3d.src_bg_clr, dst, pat)); + 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((ids) && s3virge.s3d.bitblt_x_current == s3virge.s3d.bitblt_x_dst) + if((ids) && m_bitblt.x_current == m_bitblt.x_dst) { switch(align) { @@ -1240,61 +1247,47 @@ void s3virge_vga_device::bitblt_monosrc_step() break; } - s3virge.s3d.bitblt_step_count++; + m_bitblt.step_count++; } -inline void s3virge_vga_device::write_pixel32(uint32_t base, uint16_t x, uint16_t y, uint32_t val) +inline void s3virge_vga_device::write_pixel24(uint32_t base, uint16_t x, uint16_t y, uint32_t val) { - if(BIT(s3virge.s3d.command, 1)) + if(BIT(m_bitblt.command, 1)) { - 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(BIT(s3virge.s3d.command, 1)) + for (int i = 0; i < 3; i ++) { - if(x < s3virge.s3d.clip_l || x > s3virge.s3d.clip_r || y < s3virge.s3d.clip_t || y > s3virge.s3d.clip_b) - return; + const u8 data = (val >> (8 * i)) & 0xff; + vga.memory[(base + i + (x * 3) + (y * m_bitblt.dest_stride)) % vga.svga_intf.vram_size] = data; } - 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; } inline void s3virge_vga_device::write_pixel16(uint32_t base, uint16_t x, uint16_t y, uint16_t val) { - if(BIT(s3virge.s3d.command, 1)) + if(BIT(m_bitblt.command, 1)) { - 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*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(BIT(s3virge.s3d.command, 1)) + if(BIT(m_bitblt.command, 1)) { - 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 + (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) @@ -1322,10 +1315,10 @@ uint32_t s3virge_vga_device::s3d_sub_status_r() // check for idle res |= (m_s3d_state == S3D_STATE_IDLE) << 13; - //if (m_s3d_state == S3D_STATE_BITBLT && s3virge.s3d.xfer_mode == true && m_xfer_fifo.empty()) + //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); + //res |= (m_bitblt.cmd_fifo_slots_free << 8); // NOTE: can actually be 24 FIFO depth with specific Scenic Mode // (looks different FIFO altogether) // & 0x1f00 @@ -1360,7 +1353,6 @@ uint32_t s3virge_vga_device::s3d_sub_status_r() */ void s3virge_vga_device::s3d_sub_control_w(uint32_t data) { - s3virge.interrupt_enable = data & 0x00003f80; LOGMMIO("Sub control = %08x\n", data); const u8 s3d_rst = (data >> 14) & 3; switch(s3d_rst) @@ -1375,8 +1367,10 @@ void s3virge_vga_device::s3d_sub_control_w(uint32_t data) LOG("S3D RST state set\n"); break; } - if (s3virge.interrupt_enable) - popmessage("s3virge.cpp: IRQ enable warning %08x", s3virge.interrupt_enable); + + m_interrupt_enable = data & 0x00003f80; + if (m_interrupt_enable) + popmessage("s3virge.cpp: IRQ enable warning %08x", m_interrupt_enable); } /* @@ -1400,10 +1394,10 @@ void s3virge_vga_device::s3d_register_map(address_map &map) { map(0x0100, 0x01bf).lrw8( NAME([this] (offs_t offset) { - return s3virge.s3d.pattern[offset]; + return m_bitblt.pattern[offset]; }), NAME([this] (offs_t offset, u8 data) { - s3virge.s3d.pattern[offset] = data; + m_bitblt.pattern[offset] = data; }) ); map(0x04d4, 0x050f).lrw32( diff --git a/src/devices/video/s3virge.h b/src/devices/video/s3virge.h index 2c308c5e612ad..0a38446ae7118 100644 --- a/src/devices/video/s3virge.h +++ b/src/devices/video/s3virge.h @@ -47,28 +47,12 @@ class s3virge_vga_device : public s3trio64_vga_device //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.src_stride; - } - 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.dest_stride; - } ibm8514a_device* get_8514() { fatalerror("s3virge requested non-existent 8514/A device\n"); return nullptr; } @@ -117,69 +101,69 @@ class s3virge_vga_device : public s3trio64_vga_device 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 - { - bool xfer_mode = false; - - uint8_t pattern[0xc0]; - - // 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; - uint32_t command; - uint32_t src_base; - uint32_t dest_base; - uint32_t pat_bg_clr; - uint32_t pat_fg_clr; - uint32_t src_bg_clr; - uint32_t src_fg_clr; - uint16_t dest_stride; - uint16_t src_stride; - } s3d; - uint8_t cr66; - } s3virge; + 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_pixel32(uint32_t base, uint16_t x, uint16_t y, uint32_t val); 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); From 76d914c2533d1d0153fc2774ede7c3427643878c Mon Sep 17 00:00:00 2001 From: angelosa Date: Mon, 15 Apr 2024 21:20:52 +0200 Subject: [PATCH 14/14] video/s3virge: fix 8514/A comment position --- src/devices/video/s3virge.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/devices/video/s3virge.h b/src/devices/video/s3virge.h index 0a38446ae7118..8592fd80db3e2 100644 --- a/src/devices/video/s3virge.h +++ b/src/devices/video/s3virge.h @@ -54,6 +54,8 @@ class s3virge_vga_device : public s3trio64_vga_device bool is_linear_address_active() { return m_linear_address_enable; } bool is_new_mmio_active() { return s3.cr53 & 0x08; } + // 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: @@ -175,7 +177,6 @@ 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_op_timer; void bitblt_step();