From 1a5fe419c24e23fb1bdeec231471e2849ce5bf5d Mon Sep 17 00:00:00 2001 From: cracyc Date: Sun, 17 Oct 2021 16:47:13 -0500 Subject: pc_vga: add xga blits --- src/devices/video/pc_vga.cpp | 318 ++++++++++++++++++++++++++++++++++++++++++- src/devices/video/pc_vga.h | 3 + 2 files changed, 319 insertions(+), 2 deletions(-) diff --git a/src/devices/video/pc_vga.cpp b/src/devices/video/pc_vga.cpp index eb8b9c58c37..8eba8f54afb 100644 --- a/src/devices/video/pc_vga.cpp +++ b/src/devices/video/pc_vga.cpp @@ -5881,7 +5881,7 @@ void xga_copro_device::start_command() logerror("line draw write\n"); break; case 8: - logerror("pxblt\n"); + do_pxblt(); break; case 9: logerror("inverting pxblt\n"); @@ -5892,9 +5892,309 @@ void xga_copro_device::start_command() } } -void do_pxblt() +// Can maps be not byte aligned? XGA manual says they must be 32bit aligned in at least some cases. +u32 xga_copro_device::read_map_pixel(int x, int y, int map) { + offs_t addr = m_pelmap_base[map]; + int width = m_pelmap_width[map] + 1; + int height = m_pelmap_height[map] + 1; + int endian = m_pelmap_format[map] & 8; + int wbytes, bits; + u8 byte; + if((x > width) || (y > height) || (x < 0) || (y < 0)) + return 0; + switch(m_pelmap_format[map] & 7) + { + case 0: + wbytes = m_pelmap_width[map] / 8; + addr += y * wbytes; + addr += x / 8; + byte = m_mem_read_cb(addr); + bits = (x % 8) - (endian ? 8 : 0); + return (byte >> bits) & 1; + case 1: + wbytes = m_pelmap_width[map] / 4; + addr += y * wbytes; + addr += x / 4; + byte = m_mem_read_cb(addr); + bits = (x % 4) - (endian ? 4 : 0); + return (byte >> (bits * 2)) & 3; + case 2: + wbytes = m_pelmap_width[map] / 2; + addr += y * wbytes; + addr += x / 2; + byte = m_mem_read_cb(addr); + bits = (x % 2) - (endian ? 2 : 0); + return (byte >> (bits * 4)) & 0xf; + case 3: + wbytes = m_pelmap_width[map]; + addr += y * wbytes; + addr += x; + return m_mem_read_cb(addr); + case 4: + wbytes = m_pelmap_width[map] * 2; + addr += y * wbytes; + addr += x * 2; + if(endian) + return m_mem_read_cb(addr + 1) | (m_mem_read_cb(addr) << 8); + return m_mem_read_cb(addr) | (m_mem_read_cb(addr + 1) << 8); + case 5: + wbytes = m_pelmap_width[map] * 4; + addr += y * wbytes; + addr += x * 4; + if(endian) + return m_mem_read_cb(addr + 3) | (m_mem_read_cb(addr + 2) << 8) | + (m_mem_read_cb(addr + 1) << 16) | (m_mem_read_cb(addr) << 24); + return m_mem_read_cb(addr) | (m_mem_read_cb(addr + 1) << 8) | + (m_mem_read_cb(addr + 2) << 16) | (m_mem_read_cb(addr + 3) << 24); + } + logerror("invalid pixel map mode %d %d\n", map, m_pelmap_format[map] & 7); + return 0; +} +void xga_copro_device::write_map_pixel(int x, int y, int map, u32 pixel) +{ + offs_t addr = m_pelmap_base[map]; + int width = m_pelmap_width[map] + 1; + int height = m_pelmap_height[map] + 1; + int endian = m_pelmap_format[map] & 8; + int wbytes; + u8 byte, mask; + if((x > width) || (y > height) || (x < 0) || (y < 0)) + return; + switch(m_pelmap_format[map] & 7) + { + case 0: + wbytes = m_pelmap_width[map] / 8; + addr += y * wbytes; + addr += x / 8; + byte = m_mem_read_cb(addr); + mask = 1 << ((x % 8) - (endian ? 8 : 0)); + byte = (byte & ~mask) | ((pixel ? 0xff : 0) & mask); + m_mem_write_cb(addr, byte); + break; + case 1: + wbytes = m_pelmap_width[map] / 4; + addr += y * wbytes; + addr += x / 4; + byte = m_mem_read_cb(addr); + mask = 3 << (((x % 4) - (endian ? 4 : 0)) * 2); + byte = (byte & ~mask) | ((pixel ? 0xff : 0) & mask); + m_mem_write_cb(addr, byte); + break; + case 2: + wbytes = m_pelmap_width[map] / 2; + addr += y * wbytes; + addr += x / 2; + byte = m_mem_read_cb(addr); + mask = 0xf << (((x % 2) - (endian ? 2 : 0)) * 4); + byte = (byte & ~mask) | ((pixel ? 0xff : 0) & mask); + m_mem_write_cb(addr, byte); + break; + case 3: + wbytes = m_pelmap_width[map]; + addr += y * wbytes; + addr += x; + m_mem_write_cb(addr, (u8)pixel); + break; + case 4: + wbytes = m_pelmap_width[map] * 2; + addr += y * wbytes; + addr += x * 2; + if(endian) + { + m_mem_write_cb(addr + 1, pixel & 0xff); + m_mem_write_cb(addr, pixel >> 8); + } + else + { + m_mem_write_cb(addr, pixel & 0xff); + m_mem_write_cb(addr + 1, pixel >> 8); + } + break; + case 5: + wbytes = m_pelmap_width[map] * 4; + addr += y * wbytes; + addr += x * 4; + if(endian) + { + m_mem_write_cb(addr + 3, pixel & 0xff); + m_mem_write_cb(addr + 2, pixel >> 8); + m_mem_write_cb(addr + 1, pixel >> 16); + m_mem_write_cb(addr, pixel >> 24); + } + else + { + m_mem_write_cb(addr, pixel & 0xff); + m_mem_write_cb(addr + 1, pixel >> 8); + m_mem_write_cb(addr + 2, pixel >> 16); + m_mem_write_cb(addr + 3, pixel >> 24); + } + break; + default: + logerror("invalid pixel map mode %d %d\n", map, m_pelmap_format[map] & 7); + break; + } +} + +u32 xga_copro_device::rop(u32 s, u32 d, u8 op) +{ + if(m_var == TYPE::OTI111) + { + switch(op) + { + default: + case 0: + return 0; + case 1: + return ~s & ~d; + case 2: + return ~s & d; + case 3: + return ~s; + case 4: + return s & ~d; + case 5: + return ~s; + case 6: + return s ^ d; + case 7: + return ~s | ~d; + case 8: + return s & d; + case 9: + return s ^ ~d; + case 10: + return d; + case 11: + return ~s | d; + case 12: + return s; + case 13: + return s | ~d; + case 14: + return s | d; + case 15: + return -1; + } + } + switch(op) + { + default: + case 0: + return 0; + case 1: + return s & d; + case 2: + return s & ~d; + case 3: + return s; + case 4: + return ~s & d; + case 5: + return d; + case 6: + return s ^ d; + case 7: + return s | d; + case 8: + return ~s & ~d; + case 9: + return s ^ ~d; + case 10: + return ~d; + case 11: + return s | ~d; + case 12: + return ~s; + case 13: + return ~s | d; + case 14: + return ~s | ~d; + case 15: + return -1; + case 16: + return std::max(s, d); + case 17: + return std::min(s, d); + case 18: + return 0; // saturate add + case 19: + return 0; // saturate sub d - s + case 20: + return 0; // saturate sub s - d + case 21: + return 0; // avg + } +} + +void xga_copro_device::do_pxblt() +{ + u8 dir = (m_pelop >> 25) & 2; + int xstart, xend, xdir, ystart, yend, ydir; + u8 srcmap = ((m_pelop >> 20) & 0xf) - 1; + u8 dstmap = ((m_pelop >> 16) & 0xf) - 1; + u8 patmap = ((m_pelop >> 12) & 0xf) - 1; + logerror("pxblt src %d pat %d dst %d dim1 %d dim2 %d\n", srcmap, dstmap, patmap, m_opdim1, m_opdim2); + if((srcmap > 3) || (dstmap > 3) || ((patmap > 3) && (patmap != 7) && (patmap != 8))) + { + logerror("invalid pelmap\n"); + return; + } + if(dir & 1) + { + ystart = m_opdim2 + 1; + yend = 0; + ydir = -1; + } + else + { + ystart = 0; + yend = m_opdim2 + 1; + ydir = 1; + } + if(dir & 2) + { + xstart = m_opdim1 + 1; + xend = 0; + xdir = -1; + } + else + { + xstart = 0; + xend = m_opdim1 + 1; + xdir = 1; + } + + for(int y = ystart; y != yend; y += ydir) + { + u16 patxaddr = m_patxaddr; + u16 srcxaddr = m_srcxaddr; + u16 dstxaddr = m_dstxaddr; + for(int x = xstart; x != xend; x += xdir) + { + u32 src, dst, pat; + if(patmap <= 3) + { + pat = read_map_pixel(patxaddr, m_patyaddr, patmap + 1); + patxaddr += xdir; + } + else + pat = 1; //TODO: generate from source mode + if(pat) + src = (((m_pelop >> 28) & 3) == 2) ? read_map_pixel(srcxaddr, m_srcyaddr, srcmap + 1) : m_fcolor; + else + src = (((m_pelop >> 30) & 3) == 2) ? read_map_pixel(srcxaddr, m_srcyaddr, srcmap + 1) : m_bcolor; + srcxaddr += xdir; + dst = read_map_pixel(dstxaddr, m_dstyaddr, dstmap + 1); + dst = (dst & ~m_pelbmask) | (rop(src, dst, pat ? m_fmix : m_bmix) & m_pelbmask); + write_map_pixel(dstxaddr, m_dstyaddr, dstmap + 1, dst); // TODO: color compare + dstxaddr += xdir; + } + m_patyaddr += ydir; + m_srcyaddr += ydir; + m_dstyaddr += ydir; + } } u8 xga_copro_device::xga_read(offs_t offset) @@ -5942,8 +6242,12 @@ u8 xga_copro_device::xga_read(offs_t offset) case 0x2f: return m_dir >> 24; case 0x48: + if(m_var == TYPE::OTI111) + return m_fmix << 4 | m_bmix; return m_fmix; case 0x49: + if(m_var == TYPE::OTI111) + return 0; return m_bmix; case 0x4a: return m_destccc; @@ -6104,9 +6408,17 @@ void xga_copro_device::xga_write(offs_t offset, u8 data) m_dir = (m_dir & ~0xff000000) | (data << 24); break; case 0x48: + if(m_var == TYPE::OTI111) + { + m_fmix = data >> 4; + m_bmix = data & 0xf; + break; + } m_fmix = data; break; case 0x49: + if(m_var == TYPE::OTI111) + break; m_bmix = data; break; case 0x4a: @@ -6250,6 +6562,8 @@ void xga_copro_device::xga_write(offs_t offset, u8 data) void xga_copro_device::device_start() { + m_mem_read_cb.resolve_safe(0); + m_mem_write_cb.resolve_safe(); } void xga_copro_device::device_reset() diff --git a/src/devices/video/pc_vga.h b/src/devices/video/pc_vga.h index 25fdb1ce723..78d709ff518 100644 --- a/src/devices/video/pc_vga.h +++ b/src/devices/video/pc_vga.h @@ -716,6 +716,9 @@ protected: private: void start_command(); void do_pxblt(); + u32 read_map_pixel(int x, int y, int map); + void write_map_pixel(int x, int y, int map, u32 pixel); + u32 rop(u32 src, u32 dst, u8 rop); u8 m_pelmap; u32 m_pelmap_base[4]; -- cgit v1.2.3