diff options
| author | 2026-02-26 19:46:24 +0100 | |
|---|---|---|
| committer | 2026-02-26 22:04:13 +0100 | |
| commit | 35ddefa8f160a39b8237c92b39c245d1f3d68773 (patch) | |
| tree | ea0fe6d70954ea92c62d632b9bb3ed42668756b4 | |
| parent | d7abdb1cfd8c5300340e1261cf3fc2de4c78a752 (diff) | |
bus/pci/sis6326.cpp: initial BitBlt implementation
| -rw-r--r-- | src/devices/bus/pci/sis6326.cpp | 378 | ||||
| -rw-r--r-- | src/devices/bus/pci/sis6326.h | 34 | ||||
| -rw-r--r-- | src/devices/video/pc_vga_matrox.cpp | 12 | ||||
| -rw-r--r-- | src/devices/video/pc_vga_sis.cpp | 16 | ||||
| -rw-r--r-- | src/devices/video/pc_vga_sis.h | 10 |
5 files changed, 434 insertions, 16 deletions
diff --git a/src/devices/bus/pci/sis6326.cpp b/src/devices/bus/pci/sis6326.cpp index 966c25f7844..6bb7dc70ec3 100644 --- a/src/devices/bus/pci/sis6326.cpp +++ b/src/devices/bus/pci/sis6326.cpp @@ -14,6 +14,7 @@ SiS 6326 #define VERBOSE (LOG_GENERAL | LOG_WARN | LOG_AGP) //#define LOG_OUTPUT_FUNC osd_printf_info + #include "logmacro.h" #define LOGWARN(...) LOGMASKED(LOG_WARN, __VA_ARGS__) @@ -113,11 +114,108 @@ void sis6326_pci_device::vram_aperture_map(address_map &map) void sis6326_pci_device::mmio_map(address_map &map) { + map(0x8280, 0x8283).lw32( + NAME([this] (offs_t offset, u32 data, u32 mem_mask) { + COMBINE_DATA(&m_src_start_addr); + m_src_start_addr &= 0x3f'ffff; + }) + ); + // TODO: bit 31 is read only for Enhanced Color Expansion busy bit + map(0x8284, 0x8287).lw32( + NAME([this] (offs_t offset, u32 data, u32 mem_mask) { + COMBINE_DATA(&m_dst_start_addr); + m_dst_start_addr &= 0x3f'ffff; + if (ACCESSING_BITS_24_31) + m_draw_sel = data >> 24; + }) + ); + map(0x8288, 0x8289).lw16( + NAME([this] (offs_t offset, u16 data, u16 mem_mask) { + COMBINE_DATA(&m_src_pitch); + m_src_pitch &= 0x7ff; + }) + ); + map(0x828a, 0x828b).lw16( + NAME([this] (offs_t offset, u16 data, u16 mem_mask) { + COMBINE_DATA(&m_dst_pitch); + m_dst_pitch &= 0x7ff; + }) + ); + map(0x828c, 0x828d).lw16( + NAME([this] (offs_t offset, u16 data, u16 mem_mask) { + COMBINE_DATA(&m_rect_width); + m_rect_width &= 0x7ff; + m_rect_width ++; + }) + ); + map(0x828e, 0x828f).lw16( + NAME([this] (offs_t offset, u16 data, u16 mem_mask) { + COMBINE_DATA(&m_rect_height); + m_rect_height &= 0x7ff; + m_rect_height ++; + }) + ); + map(0x8290, 0x8293).lw32( + NAME([this] (offs_t offset, u32 data, u32 mem_mask) { + COMBINE_DATA(&m_fg_color); + m_fg_color &= 0xff'ffff; + if (ACCESSING_BITS_24_31) + m_fg_rop = data >> 24; + }) + ); + map(0x8294, 0x8297).lw32( + NAME([this] (offs_t offset, u32 data, u32 mem_mask) { + COMBINE_DATA(&m_bg_color); + m_bg_color &= 0xff'ffff; + if (ACCESSING_BITS_24_31) + m_bg_rop = data >> 24; + }) + ); + map(0x8298, 0x829f).lw8(NAME([this] (offs_t offset, u8 data) { m_mask[offset] = data; })); + map(0x82a0, 0x82a1).lw16( + NAME([this] (offs_t offset, u16 data, u16 mem_mask) { + COMBINE_DATA(&m_clip_left); + m_clip_left &= 0x7ff; + }) + ); + map(0x82a2, 0x82a3).lw16( + NAME([this] (offs_t offset, u16 data, u16 mem_mask) { + COMBINE_DATA(&m_clip_top); + m_clip_top &= 0x7ff; + }) + ); + map(0x82a4, 0x82a5).lw16( + NAME([this] (offs_t offset, u16 data, u16 mem_mask) { + COMBINE_DATA(&m_clip_right); + m_clip_right &= 0x7ff; + }) + ); + map(0x82a6, 0x82a7).lw16( + NAME([this] (offs_t offset, u16 data, u16 mem_mask) { + COMBINE_DATA(&m_clip_bottom); + m_clip_bottom &= 0x7ff; + }) + ); + // HACK: fake Turbo Queue so to not lockup windows - map(0x82a8, 0x82ab).lr32(NAME([] () { return 0x8000'0100; })); + map(0x82a8, 0x82a9).lr16( + NAME([] (offs_t offset) { return 0x0100; }) + ); + map(0x82aa, 0x82ab).lrw16( + NAME([] (offs_t offset) { return 0x8000; }), + NAME([this] (offs_t offset, u16 data, u16 mem_mask) { + COMBINE_DATA(&m_draw_command); + if (mem_mask == 0xffff) + trigger_2d_command(); + }) + ); + + map(0x82ac, 0x82eb).lw8(NAME([this] (offs_t offset, u8 data) { + m_pattern_data[offset] = data; + })); map(0x8378, 0x837f).w(m_vga, FUNC(sis6326_vga_device::cursor_mmio_w)); - // Same deal, 3D Engine Status + // HACK: Same deal for 3D Engine Status map(0x89fc, 0x89ff).lr32(NAME([] () { return (0x3ff << 16) | 3; })); } @@ -163,6 +261,282 @@ void sis6326_pci_device::map_extra(uint64_t memory_window_start, uint64_t memory } /* + * 2d drawing + */ + +const sis6326_pci_device::get_src_func sis6326_pci_device::get_src_table[4] = +{ + &sis6326_pci_device::get_src_bgcol, + &sis6326_pci_device::get_src_fgcol, + &sis6326_pci_device::get_src_mem, + &sis6326_pci_device::get_src_cpu +}; + + +u8 sis6326_pci_device::get_src_bgcol(u32 offset_base, u32 x) +{ + return m_bg_color; +} + +u8 sis6326_pci_device::get_src_fgcol(u32 offset_base, u32 x) +{ + return m_fg_color; +} + +u8 sis6326_pci_device::get_src_mem(u32 offset_base, u32 x) +{ + return m_vga->read_memory(offset_base + x); +} + +// TODO: no idea about this yet +u8 sis6326_pci_device::get_src_cpu(u32 offset_base, u32 x) +{ + return x & 1 ? 0x55 : 0xaa; +} + +const sis6326_pci_device::get_pat_func sis6326_pci_device::get_pat_table[4] = +{ + &sis6326_pci_device::get_pat_bgcol, + &sis6326_pci_device::get_pat_fgcol, + &sis6326_pci_device::get_pat_regs, + &sis6326_pci_device::get_pat_ddraw +}; + +u8 sis6326_pci_device::get_pat_bgcol(u32 y, u32 x) +{ + return m_bg_color; +} + +u8 sis6326_pci_device::get_pat_fgcol(u32 y, u32 x) +{ + return m_fg_color; +} + +// TODO: not yet sure about how this works either +// testable in win98se shutdown options +u8 sis6326_pci_device::get_pat_regs(u32 y, u32 x) +{ + return m_pattern_data[x & 3]; +} + +// TODO: this is special, uses regs in a different way +u8 sis6326_pci_device::get_pat_ddraw(u32 y, u32 x) +{ + return x & 1 ? 0x55 : 0xaa; +} + +// TODO: copied from s3virge, really needs moving in a common interface +// https://learn.microsoft.com/en-us/windows/win32/gdi/ternary-raster-operations +uint32_t sis6326_pci_device::GetROP(uint8_t rop, uint32_t src, uint32_t dst, uint32_t pat) +{ + uint32_t ret = 0; + + switch(rop) + { + case 0x00: // 0 + ret = 0; + break; + case 0x0a: // DPna + ret = (dst & (~pat)); + break; + case 0x22: // DSna + ret = (dst & (~src)); + break; + case 0x33: // Sn + ret = ~src; + break; + case 0x55: // Dn + ret = ~dst; + break; + case 0x5a: // DPx + ret = dst ^ pat; + break; + case 0x66: // DSx + ret = dst ^ src; + break; + case 0x88: // DSa + ret = dst & src; + break; + case 0xaa: // D + ret = dst; + break; + case 0xb8: // PSDPxax + ret = ((dst ^ pat) & src) ^ pat; + break; + case 0xbb: // DSno + ret = (dst | (~src)); + break; + case 0xca: // DPSDxax (moneynet install screen, no effective change?) + ret = ((src ^ dst) & pat) ^ dst; + break; + case 0xcc: + ret = src; + break; + case 0xe2: // DSPDxax + ret = ((pat ^ dst) & src) ^ dst; + break; + case 0xee: // DSo + ret = (dst | src); + break; + case 0xf0: + ret = pat; + break; + case 0xff: // 1 + ret = 0xffffffff; + break; + default: + popmessage("bus/pci/sis6326.cpp: Unimplemented ROP 0x%02x",rop); + } + + return ret; +} + + +void sis6326_pci_device::trigger_2d_command() +{ + const u8 src_select = m_draw_command & 3; + const u8 pat_select = (m_draw_command >> 2) & 3; + const s8 x_dir = BIT(m_draw_command, 4) ? 1 : -1; + const s8 y_dir = BIT(m_draw_command, 5) ? 1 : -1; + const bool clip_enable = !!BIT(m_draw_command, 6); + const bool clip_external = !!BIT(m_draw_command, 7); + const u8 cmd_type = (m_draw_command >> 8) & 3; + const std::string src_types[] = { "bgcol", "fgcol", "memory", "CPU" }; + // NOTE: pat type 3 may really select Direct Draw mode + const std::string pat_types[] = { "bgcol", "fgcol", "pattern", "<reserved>" }; + LOG("Command: %04x: SRC %s, PAT %s, XY: %d|%d, clip: %d%d\n" + , m_draw_command, src_types[src_select], pat_types[pat_select] + , x_dir, y_dir, clip_enable, clip_external + ); + if (clip_enable) + { + LOG("cliprange X %d %d ~ Y %d %d\n", m_clip_left, m_clip_right, m_clip_top, m_clip_bottom); + // (a very unlikely) sanity check + if (m_dst_pitch == 0) + { + LOG("\tWarning: dst pitch == 0, ignored!\n"); + return; + } + } + + // bits 15-14 are r/o + // TODO: currently using 256 colors only + // how this even acknowledge a change in color mode? + switch(cmd_type) + { + case 0: + { + LOG("\tBitBlt\n"); + LOG("\tSRC Addr %06x DST Addr %06x Sel %02x\n", m_src_start_addr, m_dst_start_addr, m_draw_sel); + LOG("\tSRC Pitch %d DST Pitch %d Rect %dx%d\n", m_src_pitch, m_dst_pitch, m_rect_width, m_rect_height); + LOG("\tFG ROP %02x Color %06x | BG ROP %02x Color %06x\n", m_fg_rop, m_fg_color, m_bg_rop, m_bg_color); + + for (s32 y = 0; y < m_rect_height; y++) + { + const s32 yi = y * y_dir; + if (clip_enable) + { + // clipping ranges are derived from the addresses (no explicit X/Y) + const s16 dst_y = yi + (m_dst_start_addr / m_dst_pitch); + if ((dst_y == std::clamp<u16>(dst_y, m_clip_top, m_clip_bottom)) ^ clip_external) + continue; + } + + const u32 src_base = (yi * m_src_pitch) + m_src_start_addr; + const u32 dst_base = (yi * m_dst_pitch) + m_dst_start_addr; + for (s32 x = 0; x < m_rect_width; x++) + { + const s32 xi = x * x_dir; + + if (clip_enable) + { + const u16 dst_x = xi + (m_dst_start_addr % m_dst_pitch); + if ((dst_x == std::clamp<u16>(dst_x, m_clip_left, m_clip_right)) ^ clip_external) + continue; + } + + const u8 src = (this->*get_src_table[src_select])(src_base, xi); + const u8 dst = m_vga->read_memory(xi + dst_base); + const u8 pat = (this->*get_pat_table[pat_select])(y, x); + const u8 res = GetROP(m_fg_rop, src, dst, pat) & 0xff; + m_vga->write_memory(xi + dst_base, res); + } + } + + break; + } + case 1: + { + LOG("\tBitBlt with mask\n"); + // ... + break; + } + case 2: + { + const bool color_exp = !!BIT(m_draw_command, 12); + const bool font_exp = !!BIT(m_draw_command, 13); + LOG("\tColor/Font expansion: Color enhanced %d Font enhanced %d\n", color_exp, font_exp); + LOG("\tSRC Addr %06x DST Addr %06x Sel %02x\n", m_src_start_addr, m_dst_start_addr, m_draw_sel); + LOG("\tSRC Pitch %d DST Pitch %d Rect %dx%d\n", m_src_pitch, m_dst_pitch, m_rect_width, m_rect_height); + LOG("\tFG ROP %02x Color %06x | BG ROP %02x Color %06x\n", m_fg_rop, m_fg_color, m_bg_rop, m_bg_color); + + if (m_rect_width > 8) + { + LOG("\tWarning: rect width > 8, ignored!\n"); + return; + } + + for (s32 y = 0; y < m_rect_height; y++) + { + const s32 yi = y * y_dir; + + if (clip_enable) + { + const u16 dst_y = yi + (m_dst_start_addr / m_dst_pitch); + if ((dst_y == std::clamp<u16>(dst_y, m_clip_top, m_clip_bottom)) ^ clip_external) + continue; + } + + const u8 pattern_base = y; + const u32 src_base = (y * m_src_pitch * y_dir) + m_src_start_addr; + const u32 dst_base = (y * m_dst_pitch * y_dir) + m_dst_start_addr; + + for (s32 x = 0; x < m_rect_width; x++) + { + const s32 xi = x * x_dir; + + if (clip_enable) + { + const u16 dst_x = xi + (m_dst_start_addr % m_dst_pitch); + if ((dst_x == std::clamp<u16>(dst_x, m_clip_left, m_clip_right)) ^ clip_external) + continue; + } + + const u8 src = (this->*get_src_table[src_select])(src_base, xi); + const u8 dst = m_vga->read_memory(xi + dst_base); + const u8 dot = (m_pattern_data[pattern_base] >> (7 - x) & 1); + // ROP and pattern depends on pattern + // win98se start menu hovering depends on this + const u8 res = GetROP(dot ? m_fg_rop : m_bg_rop, src, dst, dot ? m_fg_color : m_bg_color) & 0xff; + m_vga->write_memory(xi + dst_base, res & 0xff); + } + } + + break; + } + case 3: + { + const bool major_axis = !!BIT(m_draw_command, 10); + const bool last_pixel = !!BIT(m_draw_command, 11); + LOG("\tLine: major axis %s %d\n", major_axis ? "Y" : "X", !last_pixel); + // ... + break; + } + } + +} + +/* * AGP overrides */ diff --git a/src/devices/bus/pci/sis6326.h b/src/devices/bus/pci/sis6326.h index bd79771a13e..ab5db4f566b 100644 --- a/src/devices/bus/pci/sis6326.h +++ b/src/devices/bus/pci/sis6326.h @@ -14,7 +14,8 @@ class sis6326_pci_device : public pci_card_device public: sis6326_pci_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); - static constexpr feature_type unemulated_features() { return feature::GRAPHICS; } + // Partial working 2d graphics, no Turbo Queue, no 3d graphics, no TV Out + static constexpr feature_type imperfect_features() { return feature::GRAPHICS; } protected: sis6326_pci_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); @@ -42,6 +43,37 @@ private: u8 vram_r(offs_t offset); void vram_w(offs_t offset, uint8_t data); + + // BitBlt engine + void trigger_2d_command(); + u32 m_src_start_addr; + u32 m_dst_start_addr; + u8 m_draw_sel; + u16 m_src_pitch, m_dst_pitch; + u16 m_rect_width, m_rect_height; + u32 m_fg_color, m_bg_color; + u8 m_fg_rop, m_bg_rop; + u8 m_mask[8]; + u16 m_clip_top, m_clip_left, m_clip_bottom, m_clip_right; + + u16 m_draw_command; + u8 m_pattern_data[128]; + + typedef u8 (sis6326_pci_device::*get_src_func)(u32 offset_base, u32 x); + static const get_src_func get_src_table[4]; + u8 get_src_bgcol(u32 offset_base, u32 x); + u8 get_src_fgcol(u32 offset_base, u32 x); + u8 get_src_mem(u32 offset_base, u32 x); + u8 get_src_cpu(u32 offset_base, u32 x); + + typedef u8 (sis6326_pci_device::*get_pat_func)(u32 offset_base, u32 x); + static const get_pat_func get_pat_table[4]; + u8 get_pat_bgcol(u32 y, u32 x); + u8 get_pat_fgcol(u32 y, u32 x); + u8 get_pat_regs(u32 y, u32 x); + u8 get_pat_ddraw(u32 y, u32 x); + u32 GetROP(u8 rop, u32 src, u32 dst, u32 pat); + }; class sis6326_agp_device : public sis6326_pci_device diff --git a/src/devices/video/pc_vga_matrox.cpp b/src/devices/video/pc_vga_matrox.cpp index f9551f21935..27b65ac35dc 100644 --- a/src/devices/video/pc_vga_matrox.cpp +++ b/src/devices/video/pc_vga_matrox.cpp @@ -732,22 +732,22 @@ uint32_t matrox_vga_device::screen_update(screen_device &screen, bitmap_rgb32 &b static int m_test_trigger = 1; const int m_test_y = cliprect.max_y; - if(machine().input().code_pressed(JOYCODE_X_RIGHT_SWITCH)) + if(machine().input().code_pressed(JOYCODE_HAT1RIGHT)) m_test_x += 1 << (machine().input().code_pressed(JOYCODE_BUTTON2) ? 4 : 0); - if(machine().input().code_pressed(JOYCODE_X_LEFT_SWITCH)) + if(machine().input().code_pressed(JOYCODE_HAT1LEFT)) m_test_x -= 1 << (machine().input().code_pressed(JOYCODE_BUTTON2) ? 4 : 0); - //if(machine().input().code_pressed(JOYCODE_Y_DOWN_SWITCH)) + //if(machine().input().code_pressed(JOYCODE_HAT1DOWN)) // m_test_y++; - //if(machine().input().code_pressed(JOYCODE_Y_UP_SWITCH)) + //if(machine().input().code_pressed(JOYCODE_HAT1UP)) // m_test_y--; - if(machine().input().code_pressed(JOYCODE_Y_DOWN_SWITCH)) + if(machine().input().code_pressed(JOYCODE_HAT1DOWN)) m_start_offs+= 0x100 << (machine().input().code_pressed(JOYCODE_BUTTON2) ? 8 : 0); - if(machine().input().code_pressed(JOYCODE_Y_UP_SWITCH)) + if(machine().input().code_pressed(JOYCODE_HAT1UP)) m_start_offs-= 0x100 << (machine().input().code_pressed(JOYCODE_BUTTON2) ? 8 : 0); m_start_offs %= vga.svga_intf.vram_size; diff --git a/src/devices/video/pc_vga_sis.cpp b/src/devices/video/pc_vga_sis.cpp index 6302a6d9d34..0359520ff8c 100644 --- a/src/devices/video/pc_vga_sis.cpp +++ b/src/devices/video/pc_vga_sis.cpp @@ -78,6 +78,7 @@ void sis6326_vga_device::device_start() save_item(NAME(m_crtc_unlock_reg)); save_item(NAME(m_seq_unlock_reg)); + save_item(NAME(m_ramdac_mode)); save_item(NAME(m_ext_sr07)); save_item(NAME(m_ext_sr0b)); save_item(NAME(m_ext_sr0c)); @@ -115,6 +116,7 @@ void sis6326_vga_device::device_reset() m_crtc_unlock_reg = false; m_seq_unlock_reg = false; + m_ramdac_mode = 0; m_ext_sr07 = m_ext_sr0b = m_ext_sr0c = m_ext_sr23 = m_ext_sr33 = 0; m_ext_sr34 = m_ext_sr35 = m_ext_sr38 = m_ext_sr39 = m_ext_sr3c = 0; m_ext_ge26 = m_ext_ge27 = 0; @@ -803,26 +805,26 @@ uint32_t sis6326_vga_device::screen_update(screen_device &screen, bitmap_rgb32 & } #if DEBUG_VRAM_VIEWER - static int m_test_x = 640, m_start_offs; + static int m_test_x = 1024, m_start_offs; static int m_test_trigger = 1; const int m_test_y = cliprect.max_y; - if(machine().input().code_pressed(KEYCODE_RIGHT)) + if(machine().input().code_pressed(JOYCODE_HAT1RIGHT)) m_test_x += 1 << (machine().input().code_pressed(JOYCODE_BUTTON2) ? 4 : 0); - if(machine().input().code_pressed(KEYCODE_LEFT)) + if(machine().input().code_pressed(JOYCODE_HAT1LEFT)) m_test_x -= 1 << (machine().input().code_pressed(JOYCODE_BUTTON2) ? 4 : 0); - //if(machine().input().code_pressed(JOYCODE_Y_DOWN_SWITCH)) + //if(machine().input().code_pressed(JOYCODE_HAT1DOWN)) // m_test_y++; - //if(machine().input().code_pressed(JOYCODE_Y_UP_SWITCH)) + //if(machine().input().code_pressed(JOYCODE_HAT1UP)) // m_test_y--; - if(machine().input().code_pressed(KEYCODE_DOWN)) + if(machine().input().code_pressed(JOYCODE_HAT1DOWN)) m_start_offs+= 0x100 << (machine().input().code_pressed(JOYCODE_BUTTON2) ? 8 : 0); - if(machine().input().code_pressed(KEYCODE_UP)) + if(machine().input().code_pressed(JOYCODE_HAT1UP)) m_start_offs-= 0x100 << (machine().input().code_pressed(JOYCODE_BUTTON2) ? 8 : 0); m_start_offs %= vga.svga_intf.vram_size; diff --git a/src/devices/video/pc_vga_sis.h b/src/devices/video/pc_vga_sis.h index e903bc65bc7..0b771d75a90 100644 --- a/src/devices/video/pc_vga_sis.h +++ b/src/devices/video/pc_vga_sis.h @@ -31,6 +31,16 @@ public: void cursor_mmio_w(offs_t offset, u16 data, u16 mem_mask); + u8 read_memory(u32 address) + { + return vga.memory[address % vga.svga_intf.vram_size]; + } + + void write_memory(u32 address, u8 data) + { + vga.memory[address % vga.svga_intf.vram_size] = data; + } + protected: sis6326_vga_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); |
