diff options
Diffstat (limited to 'src/devices/bus/isa/trident.cpp')
-rw-r--r-- | src/devices/bus/isa/trident.cpp | 1612 |
1 files changed, 1612 insertions, 0 deletions
diff --git a/src/devices/bus/isa/trident.cpp b/src/devices/bus/isa/trident.cpp new file mode 100644 index 00000000000..03f646139be --- /dev/null +++ b/src/devices/bus/isa/trident.cpp @@ -0,0 +1,1612 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald +/* + * trident.c + * + * Implementation of Trident VGA GUI accelerators + * + * + */ + +#include "emu.h" +#include "trident.h" +#include "debugger.h" + +const device_type TRIDENT_VGA = &device_creator<trident_vga_device>; + +#define CRTC_PORT_ADDR ((vga.miscellaneous_output&1)?0x3d0:0x3b0) + +#define LOG (1) +#define LOG_ACCEL (1) + +trident_vga_device::trident_vga_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : svga_device(mconfig, TRIDENT_VGA, "Trident TGUI9680", tag, owner, clock, "trident_vga", __FILE__) +{ +} + +UINT8 trident_vga_device::READPIXEL8(INT16 x, INT16 y) +{ + return (vga.memory[((y & 0xfff)*offset() + (x & 0xfff)) % vga.svga_intf.vram_size]); +} + +UINT16 trident_vga_device::READPIXEL15(INT16 x, INT16 y) +{ + return (vga.memory[((y & 0xfff)*offset() + (x & 0xfff)*2) % vga.svga_intf.vram_size] | + (vga.memory[((y & 0xfff)*offset() + ((x & 0xfff)*2)+1) % vga.svga_intf.vram_size] << 8)); +} + +UINT16 trident_vga_device::READPIXEL16(INT16 x, INT16 y) +{ + return (vga.memory[((y & 0xfff)*offset() + (x & 0xfff)*2) % vga.svga_intf.vram_size] | + (vga.memory[((y & 0xfff)*offset() + ((x & 0xfff)*2)+1) % vga.svga_intf.vram_size] << 8)); +} + +UINT32 trident_vga_device::READPIXEL32(INT16 x, INT16 y) +{ + return (vga.memory[((y & 0xfff)*offset() + (x & 0xfff)*4) % vga.svga_intf.vram_size] | + (vga.memory[((y & 0xfff)*offset() + ((x & 0xfff)*4)+1) % vga.svga_intf.vram_size] << 8) | + (vga.memory[((y & 0xfff)*offset() + ((x & 0xfff)*4)+2) % vga.svga_intf.vram_size] << 16) | + (vga.memory[((y & 0xfff)*offset() + ((x & 0xfff)*4)+3) % vga.svga_intf.vram_size] << 24)); +} + +void trident_vga_device::WRITEPIXEL8(INT16 x, INT16 y, UINT8 data) +{ + if((x & 0xfff)<tri.accel_dest_x_clip && (y & 0xfff)<tri.accel_dest_y_clip) + { + data = handle_rop(data,READPIXEL8(x,y)) & 0xff; + vga.memory[((y & 0xfff)*offset() + (x & 0xfff)) % vga.svga_intf.vram_size] = data; + } +} + +void trident_vga_device::WRITEPIXEL15(INT16 x, INT16 y, UINT16 data) +{ + if((x & 0xfff)<tri.accel_dest_x_clip && (y & 0xfff)<tri.accel_dest_y_clip) + { + data = handle_rop(data,READPIXEL8(x,y)) & 0x7fff; + vga.memory[((y & 0xfff)*offset() + (x & 0xfff)*2) % vga.svga_intf.vram_size] = data & 0x00ff; + vga.memory[((y & 0xfff)*offset() + ((x & 0xfff)*2)+1) % vga.svga_intf.vram_size] = (data & 0x7f00) >> 8; + } +} + +void trident_vga_device::WRITEPIXEL16(INT16 x, INT16 y, UINT16 data) +{ + if((x & 0xfff)<tri.accel_dest_x_clip && (y & 0xfff)<tri.accel_dest_y_clip) + { + data = handle_rop(data,READPIXEL8(x,y)) & 0xffff; + vga.memory[((y & 0xfff)*offset() + (x & 0xfff)*2) % vga.svga_intf.vram_size] = data & 0x00ff; + vga.memory[((y & 0xfff)*offset() + ((x & 0xfff)*2)+1) % vga.svga_intf.vram_size] = (data & 0xff00) >> 8; + } +} + +void trident_vga_device::WRITEPIXEL32(INT16 x, INT16 y, UINT32 data) +{ + if((x & 0xfff)<tri.accel_dest_x_clip && (y & 0xfff)<tri.accel_dest_y_clip) + { + data = handle_rop(data,READPIXEL8(x,y)); + vga.memory[((y & 0xfff)*offset() + (x & 0xfff)*4) % vga.svga_intf.vram_size] = data & 0x000000ff; + vga.memory[((y & 0xfff)*offset() + ((x & 0xfff)*4)+1) % vga.svga_intf.vram_size] = (data & 0x0000ff00) >> 8; + vga.memory[((y & 0xfff)*offset() + ((x & 0xfff)*4)+2) % vga.svga_intf.vram_size] = (data & 0x00ff0000) >> 16; + vga.memory[((y & 0xfff)*offset() + ((x & 0xfff)*4)+3) % vga.svga_intf.vram_size] = (data & 0xff000000) >> 24; + } +} + +UINT32 trident_vga_device::handle_rop(UINT32 src, UINT32 dst) +{ + switch(tri.accel_fmix) // TODO: better understand this register + { + case 0xf0: // PAT + case 0xcc: // SRC + break; // pass data through + case 0x00: // 0 + src = 0; + break; + case 0xff: // 1 + src = 0xffffffff; + break; + case 0x66: // XOR + case 0x5a: // XOR PAT + src = dst ^ src; + break; + case 0xb8: // PAT xor (SRC and (DST xor PAT)) (correct?) + src = src & (dst ^ src); + break; + } + return src; +} + +UINT32 trident_vga_device::READPIXEL(INT16 x,INT16 y) +{ + if(svga.rgb8_en) + return READPIXEL8(x,y) & 0xff; + if(svga.rgb15_en) + return READPIXEL15(x,y) & 0x7fff; + if(svga.rgb16_en) + return READPIXEL16(x,y) & 0xffff; + if(svga.rgb32_en) + return READPIXEL32(x,y); + return 0; // should never reach here +} + +void trident_vga_device::WRITEPIXEL(INT16 x,INT16 y, UINT32 data) +{ + if(svga.rgb8_en) + WRITEPIXEL8(x,y,(((data >> 8) & 0xff) | (data & 0xff))); // XFree86 3.3 sets bits 0-7 to 0 when using mono patterns, does it OR each byte? + if(svga.rgb15_en) + WRITEPIXEL15(x,y,data & 0x7fff); + if(svga.rgb16_en) + WRITEPIXEL16(x,y,data & 0xffff); + if(svga.rgb32_en) + WRITEPIXEL32(x,y,data); +} + + +void trident_vga_device::device_start() +{ + zero(); + + int i; + for (i = 0; i < 0x100; i++) + m_palette->set_pen_color(i, 0, 0, 0); + + // Avoid an infinite loop when displaying. 0 is not possible anyway. + vga.crtc.maximum_scan_line = 1; + + + // copy over interfaces + vga.read_dipswitch = read8_delegate(); //read_dipswitch; + vga.svga_intf.vram_size = 0x200000; + + vga.memory.resize(vga.svga_intf.vram_size); + memset(&vga.memory[0], 0, vga.svga_intf.vram_size); + save_item(NAME(vga.memory)); + save_pointer(vga.crtc.data,"CRTC Registers",0x100); + save_pointer(vga.sequencer.data,"Sequencer Registers",0x100); + save_pointer(vga.attribute.data,"Attribute Registers", 0x15); + save_pointer(tri.accel_pattern,"Pattern Data", 0x80); + save_pointer(tri.lutdac_reg,"LUTDAC registers", 0x100); + + m_vblank_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(vga_device::vblank_timer_cb),this)); + vga.svga_intf.seq_regcount = 0x0f; + vga.svga_intf.crtc_regcount = 0x60; + memset(&tri, 0, sizeof(tri)); +} + +void trident_vga_device::device_reset() +{ + svga_device::device_reset(); + svga.id = 0xd3; // 0xd3 identifies at TGUI9660XGi (set to 0xe3 to identify at TGUI9440AGi) + tri.revision = 0x01; // revision identifies as TGUI9680 + tri.new_mode = false; // start up in old mode + tri.dac_active = false; + tri.linear_active = false; + tri.mmio_active = false; + tri.sr0f = 0x6f; + tri.sr0c = 0x70; + tri.cr2a = 0x03; // set ISA interface? + tri.mem_clock = 0x2c6; // 50MHz default + tri.vid_clock = 0; + tri.port_3c3 = true; + tri.accel_busy = false; + tri.accel_memwrite_active = false; + // Windows 3.1 TGUI9440AGi drivers do not set the pointer colour registers? + tri.cursor_bg = 0x00000000; + tri.cursor_fg = 0xffffffff; +} + +UINT32 trident_vga_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + UINT8 cur_mode = 0; + + svga_device::screen_update(screen,bitmap,cliprect); + cur_mode = pc_vga_choosevideomode(); + + // draw hardware graphics cursor + if(tri.cursor_ctrl & 0x80) // if cursor is enabled + { + UINT32 src; + UINT32* dst; + UINT8 val; + int x,y; + UINT16 cx = tri.cursor_x & 0x0fff; + UINT16 cy = tri.cursor_y & 0x0fff; + UINT32 bg_col; + UINT32 fg_col; + UINT8 cursor_size = (tri.cursor_ctrl & 0x01) ? 64 : 32; + + if(cur_mode == SCREEN_OFF || cur_mode == TEXT_MODE || cur_mode == MONO_MODE || cur_mode == CGA_MODE || cur_mode == EGA_MODE) + return 0; // cursor only works in VGA or SVGA modes + + src = tri.cursor_loc * 1024; // start address is in units of 1024 bytes + + if(cur_mode == RGB16_MODE) + { + bg_col = tri.cursor_bg; + fg_col = tri.cursor_fg; + } + else /* TODO: other modes */ + { + bg_col = m_palette->pen(tri.cursor_bg & 0xff); + fg_col = m_palette->pen(tri.cursor_fg & 0xff); + } + + for(y=0;y<cursor_size;y++) + { + UINT8 bitcount = 31; + dst = &bitmap.pix32(cy + y, cx); + for(x=0;x<cursor_size;x++) + { + UINT32 bitb = (vga.memory[(src+3) % vga.svga_intf.vram_size] + | ((vga.memory[(src+2) % vga.svga_intf.vram_size]) << 8) + | ((vga.memory[(src+1) % vga.svga_intf.vram_size]) << 16) + | ((vga.memory[(src+0) % vga.svga_intf.vram_size]) << 24)); + UINT32 bita = (vga.memory[(src+7) % vga.svga_intf.vram_size] + | ((vga.memory[(src+6) % vga.svga_intf.vram_size]) << 8) + | ((vga.memory[(src+5) % vga.svga_intf.vram_size]) << 16) + | ((vga.memory[(src+4) % vga.svga_intf.vram_size]) << 24)); + val = (BIT(bita << 1,bitcount+1) << 1 | BIT(bitb,bitcount)); + if(tri.cursor_ctrl & 0x40) + { // X11 mode + switch(val) + { + case 0x00: + // no change + break; + case 0x01: + dst[x] = bg_col; + break; + case 0x02: + // no change + break; + case 0x03: + dst[x] = fg_col; + break; + } + } + else + { // Windows mode + switch(val) + { + case 0x00: + dst[x] = bg_col; + break; + case 0x01: + // no change + break; + case 0x02: // screen data + dst[x] = fg_col; + break; + case 0x03: // inverted screen data + dst[x] = ~(dst[x]); + break; + } + } + bitcount--; + if(x % 32 == 31) + { + src+=8; + bitcount=31; + } + } + } + } + + return 0; +} + +UINT16 trident_vga_device::offset() +{ + UINT16 off = svga_device::offset(); + + if (svga.rgb8_en || svga.rgb15_en || svga.rgb16_en || svga.rgb32_en) + return vga.crtc.offset << 3; // don't know if this is right, but Eggs Playing Chicken switches off doubleword mode, but expects the same offset length + else + return off; +} + +int trident_vga_device::calculate_clock() +{ + // Bits 0-6: M + // Bits 7-11: N + // Bit 12: K + // Later formula extends each variable by one extra bit (Providia 9685 and later) + double freq; + UINT8 m,n,k; + + m = tri.vid_clock & 0x007f; + n = (tri.vid_clock & 0x0f80) >> 7; + k = (tri.vid_clock & 0x1000) >> 12; + freq = ((double)(m+8) / (double)((n+2)*(pow(2.0,k)))) * 14.31818; // there is a 14.31818MHz clock on the board + + return freq * 1000000; +} + +void trident_vga_device::trident_define_video_mode() +{ + int divisor = 1; + int xtal; + + /* // clock select for TGUI9440CXi and earlier + switch(tri.clock) + { + case 0: + default: xtal = XTAL_25_1748MHz; break; + case 1: xtal = XTAL_28_63636MHz; break; + case 2: xtal = 44900000; break; + case 3: xtal = 36000000; break; + case 4: xtal = 57272000; break; + case 5: xtal = 65000000; break; + case 6: xtal = 50350000; break; + case 7: xtal = 40000000; break; + case 8: xtal = 88000000; break; + case 9: xtal = 98000000; break; + case 10: xtal = 118800000; break; + case 11: xtal = 108000000; break; + case 12: xtal = 72000000; break; + case 13: xtal = 77000000; break; + case 14: xtal = 80000000; break; + case 15: xtal = 75000000; break; + } + + switch((tri.sr0d_new & 0x06) >> 1) + { + case 0: + default: break; // no division + case 1: xtal = xtal / 2; break; + case 2: xtal = xtal / 4; break; + case 3: xtal = xtal / 1.5; break; + }*/ + + + // TGUI9440AGi/9660/9680/9682 programmable clock + switch((vga.miscellaneous_output & 0x0c) >> 2) + { + case 0: + default: xtal = XTAL_25_1748MHz; break; + case 1: xtal = XTAL_28_63636MHz; break; + case 2: xtal = calculate_clock(); break; + } + + if(tri.gc0f & 0x08) // 16 pixels per character clock + xtal = xtal / 2; + + if(tri.port_3db & 0x20) + xtal = xtal / 2; // correct? + + svga.rgb8_en = svga.rgb15_en = svga.rgb16_en = svga.rgb32_en = 0; + switch((tri.pixel_depth & 0x0c) >> 2) + { + case 0: + default: if(!(tri.pixel_depth & 0x10)) svga.rgb8_en = 1; break; + case 1: if((tri.dac & 0xf0) == 0x30) svga.rgb16_en = 1; else svga.rgb15_en = 1; break; + case 2: svga.rgb32_en = 1; break; + } + + recompute_params_clock(divisor, xtal); +} + +UINT8 trident_vga_device::trident_seq_reg_read(UINT8 index) +{ + UINT8 res; + + res = 0xff; + + if(index <= 0x04) + res = vga.sequencer.data[index]; + else + { + switch(index) + { + case 0x09: + res = tri.revision; + break; + case 0x0b: + res = svga.id; + tri.new_mode = true; + break; + case 0x0c: // Power Up Mode register 1 + res = tri.sr0c & 0xef; + if(tri.port_3c3) + res |= 0x10; + break; + case 0x0d: // Mode Control 2 + //res = svga.rgb15_en; + if(tri.new_mode) + res = tri.sr0d_new; + else + res = tri.sr0d_old; + break; + case 0x0e: // Mode Control 1 + if(tri.new_mode) + res = tri.sr0e_new; + else + res = tri.sr0e_old; + break; + case 0x0f: // Power Up Mode 2 + res = tri.sr0f; + break; + default: + res = vga.sequencer.data[index]; + if(!LOG) logerror("Trident: Sequencer index %02x read\n",index); + } + } + if(LOG) logerror("Trident SR%02X: read %02x\n",index,res); + return res; +} + +void trident_vga_device::trident_seq_reg_write(UINT8 index, UINT8 data) +{ + vga.sequencer.data[vga.sequencer.index] = data; + if(index <= 0x04) + { + seq_reg_write(vga.sequencer.index,data); + recompute_params(); + } + else + { + if(LOG) logerror("Trident SR%02X: %s mode write %02x\n",index,tri.new_mode ? "new" : "old",data); + switch(index) + { + case 0x0b: + tri.new_mode = false; + break; + case 0x0c: // Power Up Mode register 1 + if(data & 0x10) + tri.port_3c3 = true; // 'post port at 0x3c3' + else + tri.port_3c3 = false; // 'post port at 0x46e8' + tri.sr0c = data; + break; + case 0x0d: // Mode Control 2 + if(tri.new_mode) + { + tri.sr0d_new = data; + tri.clock = ((vga.miscellaneous_output & 0x0c) >> 2) | ((data & 0x01) << 2) | ((data & 0x40) >> 3); + trident_define_video_mode(); + } + else + tri.sr0d_old = data; + break; + case 0x0e: // Mode Control 1 + if(tri.new_mode) + { + tri.sr0e_new = data ^ 0x02; + svga.bank_w = (data & 0x3f) ^ 0x02; // bit 1 is inverted, used for card detection, it is not XORed on reading + if(!(tri.gc0f & 0x01)) + svga.bank_r = (data & 0x3f) ^ 0x02; + // TODO: handle planar modes, where bits 0 and 2 only are used + } + else + { + tri.sr0e_old = data; + svga.bank_w = data & 0x0e; + if(!(tri.gc0f & 0x01)) + svga.bank_r = data & 0x0e; + } + break; + case 0x0f: // Power Up Mode 2 + tri.sr0f = data; + break; + default: + if(!LOG) logerror("Trident: Sequencer index %02x read\n",index); + } + } +} + +UINT8 trident_vga_device::trident_crtc_reg_read(UINT8 index) +{ + UINT8 res = 0; + + if(index <= 0x18) + res = crtc_reg_read(index); + else + { + switch(index) + { + case 0x1e: + res = tri.cr1e; + break; + case 0x1f: + res = tri.cr1f; + break; + case 0x20: + res = tri.cr20; + break; + case 0x21: + res = tri.cr21; + break; + case 0x24: + if(vga.attribute.state != 0) + res |= 0x80; + break; + case 0x26: + res = vga.attribute.index; + break; + case 0x27: + res = (vga.crtc.start_addr & 0x60000) >> 17; + break; + case 0x29: + res = tri.cr29; + break; + case 0x2a: + res = tri.cr2a; + break; + case 0x38: + res = tri.pixel_depth; + break; + case 0x39: + res = tri.cr39; + break; + case 0x40: + res = (tri.cursor_x & 0x00ff); + break; + case 0x41: + res = (tri.cursor_x & 0xff00) >> 8; + break; + case 0x42: + res = (tri.cursor_y & 0x00ff); + break; + case 0x43: + res = (tri.cursor_y & 0xff00) >> 8; + break; + case 0x44: + res = (tri.cursor_loc & 0x00ff); + break; + case 0x45: + res = (tri.cursor_loc & 0xff00) >> 8; + break; + case 0x46: + res = tri.cursor_x_off; + break; + case 0x47: + res = tri.cursor_y_off; + break; + case 0x48: + res = (tri.cursor_fg & 0x000000ff); + break; + case 0x49: + res = (tri.cursor_fg & 0x0000ff00) >> 8; + break; + case 0x4a: + res = (tri.cursor_fg & 0x00ff0000) >> 16; + break; + case 0x4b: + res = (tri.cursor_fg & 0xff000000) >> 24; + break; + case 0x4c: + res = (tri.cursor_bg & 0x000000ff); + break; + case 0x4d: + res = (tri.cursor_bg & 0x0000ff00) >> 8; + break; + case 0x4e: + res = (tri.cursor_bg & 0x00ff0000) >> 16; + break; + case 0x4f: + res = (tri.cursor_bg & 0xff000000) >> 24; + break; + case 0x50: + res = tri.cursor_ctrl; + break; + default: + res = vga.crtc.data[index]; + if(!LOG) logerror("Trident: CRTC index %02x read\n",index); + break; + } + } + if(LOG) logerror("Trident CR%02X: read %02x\n",index,res); + return res; +} +void trident_vga_device::trident_crtc_reg_write(UINT8 index, UINT8 data) +{ + if(index <= 0x18) + { + crtc_reg_write(index,data); + trident_define_video_mode(); + } + else + { + if(LOG) logerror("Trident CR%02X: write %02x\n",index,data); + switch(index) + { + case 0x1e: // Module Testing Register + tri.cr1e = data; + vga.crtc.start_addr = (vga.crtc.start_addr & 0xfffeffff) | ((data & 0x20)<<11); + break; + case 0x1f: + tri.cr1f = data; // "Software Programming Register" written to by the BIOS + break; + case 0x20: // FIFO Control (old MMIO enable? no documentation of this register) + tri.cr20 = data; + break; + case 0x21: // Linear aperture + tri.cr21 = data; + tri.linear_address = ((data & 0xc0)<<18) | ((data & 0x0f)<<20); + tri.linear_active = data & 0x20; + if(tri.linear_active) + popmessage("Trident: Linear Aperture active - %08x, %s",tri.linear_address,(tri.cr21 & 0x10) ? "2MB" : "1MB" ); + break; + case 0x27: + vga.crtc.start_addr = (vga.crtc.start_addr & 0xfff9ffff) | ((data & 0x03)<<17); + break; + case 0x29: + tri.cr29 = data; + vga.crtc.offset = (vga.crtc.offset & 0xfeff) | ((data & 0x10)<<4); + break; + case 0x2a: + tri.cr2a = data; + break; + case 0x38: + // bit 0: 16 bit bus + // bits 2-3: pixel depth (1=15/16bit, 2=24/32bit, 0=anything else) + // bit 5: packed mode + tri.pixel_depth = data; + trident_define_video_mode(); + break; + case 0x39: + tri.cr39 = data; + tri.mmio_active = data & 0x01; + if(tri.mmio_active) + popmessage("Trident: MMIO activated"); + break; + case 0x40: + tri.cursor_x = (tri.cursor_x & 0xff00) | data; + break; + case 0x41: + tri.cursor_x = (tri.cursor_x & 0x00ff) | (data << 8); + break; + case 0x42: + tri.cursor_y = (tri.cursor_y & 0xff00) | data; + break; + case 0x43: + tri.cursor_y = (tri.cursor_y & 0x00ff) | (data << 8); + break; + case 0x44: + tri.cursor_loc = (tri.cursor_loc & 0xff00) | data; + break; + case 0x45: + tri.cursor_loc = (tri.cursor_loc & 0x00ff) | (data << 8); + break; + case 0x46: + tri.cursor_x_off = data; + break; + case 0x47: + tri.cursor_y_off = data; + break; + case 0x48: + tri.cursor_fg = (tri.cursor_fg & 0xffffff00) | data; + break; + case 0x49: + tri.cursor_fg = (tri.cursor_fg & 0xffff00ff) | (data << 8); + break; + case 0x4a: + tri.cursor_fg = (tri.cursor_fg & 0xff00ffff) | (data << 16); + break; + case 0x4b: + tri.cursor_fg = (tri.cursor_fg & 0x00ffffff) | (data << 24); + break; + case 0x4c: + tri.cursor_bg = (tri.cursor_bg & 0xffffff00) | data; + break; + case 0x4d: + tri.cursor_bg = (tri.cursor_bg & 0xffff00ff) | (data << 8); + break; + case 0x4e: + tri.cursor_bg = (tri.cursor_bg & 0xff00ffff) | (data << 16); + break; + case 0x4f: + tri.cursor_bg = (tri.cursor_bg & 0x00ffffff) | (data << 24); + break; + case 0x50: + tri.cursor_ctrl = data; + break; + default: + if(!LOG) logerror("Trident: 3D4 index %02x write %02x\n",index,data); + break; + } + } +} + +UINT8 trident_vga_device::trident_gc_reg_read(UINT8 index) +{ + UINT8 res; + + if(index <= 0x0d) + res = gc_reg_read(index); + else + { + switch(index) + { + case 0x0e: + res = tri.gc0e; + break; + case 0x0f: + res = tri.gc0f; + break; + case 0x2f: + res = tri.gc2f; + break; + default: + res = 0xff; + if(!LOG) logerror("Trident: Sequencer index %02x read\n",index); + break; + } + } + if(LOG) logerror("Trident GC%02X: read %02x\n",index,res); + return res; +} + +void trident_vga_device::trident_gc_reg_write(UINT8 index, UINT8 data) +{ + if(index <= 0x0d) + gc_reg_write(index,data); + else + { + if(LOG) logerror("Trident GC%02X: write %02x\n",index,data); + switch(index) + { + case 0x0e: // New Source Address Register (bit 1 is inverted here, also) + tri.gc0e = data ^ 0x02; + if(!(tri.gc0f & 0x04)) // if bank regs at 0x3d8/9 are not enabled + { + if(tri.gc0f & 0x01) // if bank regs are separated + svga.bank_r = (data & 0x1f) ^ 0x02; + } + break; + case 0x0f: + tri.gc0f = data; + trident_define_video_mode(); + break; + case 0x2f: // XFree86 refers to this register as "MiscIntContReg", setting bit 2, but gives no indication as to what it does + tri.gc2f = data; + break; + default: + if(!LOG) logerror("Trident: Unimplemented GC register %02x write %02x\n",index,data); + break; + } + } +} + +READ8_MEMBER(trident_vga_device::port_03c0_r) +{ + UINT8 res; + + switch(offset) + { + case 0x05: + res = trident_seq_reg_read(vga.sequencer.index); + break; + case 0x06: + tri.dac_count++; + if(tri.dac_count > 3) + tri.dac_active = true; + if(tri.dac_active) + res = tri.dac; + else + res = vga_device::port_03c0_r(space,offset,mem_mask); + break; + case 0x07: + case 0x08: + case 0x09: + tri.dac_active = false; + tri.dac_count = 0; + res = vga_device::port_03c0_r(space,offset,mem_mask); + break; + case 0x0f: + res = trident_gc_reg_read(vga.gc.index); + break; + default: + res = vga_device::port_03c0_r(space,offset,mem_mask); + break; + } + + return res; +} + +WRITE8_MEMBER(trident_vga_device::port_03c0_w) +{ + switch(offset) + { + case 0x05: + trident_seq_reg_write(vga.sequencer.index,data); + break; + case 0x06: + if(tri.dac_active) + { + tri.dac = data; // DAC command register + tri.dac_active = false; + tri.dac_count = 0; + trident_define_video_mode(); + } + else + vga_device::port_03c0_w(space,offset,data,mem_mask); + break; + case 0x07: + case 0x08: + case 0x09: + tri.dac_active = false; + tri.dac_count = 0; + vga_device::port_03c0_w(space,offset,data,mem_mask); + break; + case 0x0f: + trident_gc_reg_write(vga.gc.index,data); + break; + default: + vga_device::port_03c0_w(space,offset,data,mem_mask); + break; + } +} + + +READ8_MEMBER(trident_vga_device::port_03d0_r) +{ + UINT8 res = 0xff; + + if (CRTC_PORT_ADDR == 0x3d0) + { + switch(offset) + { + case 5: + res = trident_crtc_reg_read(vga.crtc.index); + break; + case 8: + if(tri.gc0f & 0x04) // if enabled + { + res = svga.bank_w & 0x3f; + } + else + res = 0xff; + break; + case 9: + if(tri.gc0f & 0x04) // if enabled + if(tri.gc0f & 0x01) // and if bank regs are separated + res = svga.bank_r & 0x3f; + else + res = 0xff; + else + res = 0xff; + break; + case 11: + res = tri.port_3db; + break; + default: + res = vga_device::port_03d0_r(space,offset,mem_mask); + break; + } + } + + return res; +} + +WRITE8_MEMBER(trident_vga_device::port_03d0_w) +{ + if (CRTC_PORT_ADDR == 0x3d0) + { + switch(offset) + { + case 5: + vga.crtc.data[vga.crtc.index] = data; + trident_crtc_reg_write(vga.crtc.index,data); + break; + case 8: + if(tri.gc0f & 0x04) // if enabled + { + svga.bank_w = data & 0x3f; + if(LOG) logerror("Trident: Write Bank set to %02x\n",data); + if(!(tri.gc0f & 0x01)) // if bank regs are not separated + { + svga.bank_r = data & 0x3f; // then this is also the read bank register + if(LOG) logerror("Trident: Read Bank set to %02x\n",data); + } + } + break; + case 9: + if(tri.gc0f & 0x04) // if enabled + { + if(tri.gc0f & 0x01) // and if bank regs are separated + { + svga.bank_r = data & 0x3f; + if(LOG) logerror("Trident: Read Bank set to %02x\n",data); + } + } + break; + case 11: + tri.port_3db = data; // no info on this port? Bit 5 appears to be a clock divider... + break; + default: + vga_device::port_03d0_w(space,offset,data,mem_mask); + break; + } + } +} + +READ8_MEMBER(trident_vga_device::port_43c6_r) +{ + UINT8 res = 0xff; + switch(offset) + { + case 2: + res = tri.mem_clock & 0xff; + break; + case 3: + res = tri.mem_clock >> 8; + break; + case 4: + res = tri.vid_clock & 0xff; + break; + case 5: + res = tri.vid_clock >> 8; + break; + } + return res; +} + +WRITE8_MEMBER(trident_vga_device::port_43c6_w) +{ + switch(offset) + { + case 2: + if(!(tri.sr0e_new & 0x02) && (tri.sr0e_new & 0x80)) + { + tri.mem_clock = (tri.mem_clock & 0xff00) | (data); + if(LOG) logerror("Trident: Memory clock write %04x\n",tri.mem_clock); + } + break; + case 3: + if(!(tri.sr0e_new & 0x02) && (tri.sr0e_new & 0x80)) + { + tri.mem_clock = (tri.mem_clock & 0x00ff) | (data << 8); + if(LOG) logerror("Trident: Memory clock write %04x\n",tri.mem_clock); + } + break; + case 4: + if(!(tri.sr0e_new & 0x02) && (tri.sr0e_new & 0x80)) + { + tri.vid_clock = (tri.vid_clock & 0xff00) | (data); + if(LOG) logerror("Trident: Video clock write %04x\n",tri.vid_clock); + } + break; + case 5: + if(!(tri.sr0e_new & 0x02) && (tri.sr0e_new & 0x80)) + { + tri.vid_clock = (tri.vid_clock & 0x00ff) | (data << 8); + if(LOG) logerror("Trident: Video clock write %04x\n",tri.vid_clock); + } + break; + } +} + +// Trident refers to these registers as a LUTDAC +// Not much else is known. XFree86 uses register 4 for something related to DPMS +READ8_MEMBER(trident_vga_device::port_83c6_r) +{ + UINT8 res = 0xff; + switch(offset) + { + case 2: + res = tri.lutdac_reg[tri.lutdac_index]; + if(LOG) logerror("Trident: LUTDAC reg read %02x\n",res); + break; + case 4: + res = tri.lutdac_index; + if(LOG) logerror("Trident: LUTDAC index read %02x\n",res); + break; + } + return res; +} + +WRITE8_MEMBER(trident_vga_device::port_83c6_w) +{ + switch(offset) + { + case 2: + if(LOG) logerror("Trident: LUTDAC reg write %02x\n",data); + tri.lutdac_reg[tri.lutdac_index] = data; + break; + case 4: + if(LOG) logerror("Trident: LUTDAC index write %02x\n",data); + tri.lutdac_index = data; + break; + } +} + +READ8_MEMBER(trident_vga_device::vram_r) +{ + if (tri.linear_active) + return vga.memory[offset % vga.svga_intf.vram_size]; + else + return 0xff; +} + +WRITE8_MEMBER(trident_vga_device::vram_w) +{ + if (tri.linear_active) + { + if(tri.accel_memwrite_active) + { + tri.accel_transfer = (tri.accel_transfer & (~(0x000000ff << (24-(8*(offset % 4)))))) | (data << (24-(8 * (offset % 4)))); + if(offset % 4 == 3) + accel_data_write(tri.accel_transfer); + return; + } + vga.memory[offset % vga.svga_intf.vram_size] = data; + } +} + +READ8_MEMBER(trident_vga_device::mem_r ) +{ + if((tri.cr20 & 0x10) && (offset >= 0x1ff00)) // correct for old MMIO? + { + return old_mmio_r(space,offset-0x1ff00); + } + + if (svga.rgb8_en || svga.rgb15_en || svga.rgb16_en || svga.rgb32_en) + { + int data; + + if(tri.new_mode) // 64k from 0xA0000-0xAFFFF + { + offset &= 0xffff; + data=vga.memory[(offset + (svga.bank_r*0x10000)) % vga.svga_intf.vram_size]; + } + else // 128k from 0xA0000-0xBFFFF + { + data=vga.memory[(offset + (svga.bank_r*0x10000)) % vga.svga_intf.vram_size]; + } + return data; + } + + return vga_device::mem_r(space,offset,mem_mask); +} + +WRITE8_MEMBER(trident_vga_device::mem_w) +{ + if((tri.cr20 & 0x10) && (offset >= 0x1ff00)) // correct for old MMIO? + { + old_mmio_w(space,offset-0x1ff00,data); + return; + } + + if(tri.accel_memwrite_active) + { + tri.accel_transfer = (tri.accel_transfer & (~(0x000000ff << (24-(8*(offset % 4)))))) | (data << (24-(8 * (offset % 4)))); + if(offset % 4 == 3) + accel_data_write(tri.accel_transfer); + return; + } + + if (svga.rgb8_en || svga.rgb15_en || svga.rgb16_en || svga.rgb32_en) + { + if(tri.new_mode) // 64k from 0xA0000-0xAFFFF + { + offset &= 0xffff; + vga.memory[(offset + (svga.bank_w*0x10000)) % vga.svga_intf.vram_size] = data; + } + else // 128k from 0xA0000-0xBFFFF + { + vga.memory[(offset + (svga.bank_w*0x10000)) % vga.svga_intf.vram_size] = data; + } + return; + } + + vga_device::mem_w(space,offset,data,mem_mask); +} + +// Old style MMIO (maps to 0xbff00) +void trident_vga_device::old_mmio_w(address_space& space, UINT32 offset, UINT8 data) +{ + if(offset >= 0x20) + accel_w(space,offset-0x20,data); +} + +UINT8 trident_vga_device::old_mmio_r(address_space& space, UINT32 offset) +{ + if(offset == 0x20) + { + if(tri.accel_busy) + return 0x20; + } + if(offset > 0x20) + return accel_r(space,offset-0x20); + else + return 0x00; +} + + +// 2D Acceleration functions (very WIP) + +// From XFree86 source: +/* +Graphics Engine for 9440/9660/9680 + +#define GER_STATUS 0x2120 +#define GE_BUSY 0x80 +#define GER_OPERMODE 0x2122 Byte for 9440, Word for 96xx +#define DST_ENABLE 0x200 // Destination Transparency +#define GER_COMMAND 0x2124 +#define GE_NOP 0x00 // No Operation +#define GE_BLT 0x01 // BitBLT ROP3 only +#define GE_BLT_ROP4 0x02 // BitBLT ROP4 (96xx only) +#define GE_SCANLINE 0x03 // Scan Line +#define GE_BRESLINE 0x04 // Bresenham Line +#define GE_SHVECTOR 0x05 // Short Vector +#define GE_FASTLINE 0x06 // Fast Line (96xx only) +#define GE_TRAPEZ 0x07 // Trapezoidal fill (96xx only) +#define GE_ELLIPSE 0x08 // Ellipse (96xx only) (RES) +#define GE_ELLIP_FILL 0x09 // Ellipse Fill (96xx only) (RES) +#define GER_FMIX 0x2127 +#define GER_DRAWFLAG 0x2128 // long +#define FASTMODE 1<<28 +#define STENCIL 0x8000 +#define SOLIDFILL 0x4000 +#define TRANS_ENABLE 0x1000 +#define TRANS_REVERSE 0x2000 +#define YMAJ 0x0400 +#define XNEG 0x0200 +#define YNEG 0x0100 +#define SRCMONO 0x0040 +#define PATMONO 0x0020 +#define SCR2SCR 0x0004 +#define PAT2SCR 0x0002 +#define GER_FCOLOUR 0x212C // Word for 9440, long for 96xx +#define GER_BCOLOUR 0x2130 // Word for 9440, long for 96xx +#define GER_PATLOC 0x2134 // Word +#define GER_DEST_XY 0x2138 +#define GER_DEST_X 0x2138 // Word +#define GER_DEST_Y 0x213A // Word +#define GER_SRC_XY 0x213C +#define GER_SRC_X 0x213C // Word +#define GER_SRC_Y 0x213E // Word +#define GER_DIM_XY 0x2140 +#define GER_DIM_X 0x2140 // Word +#define GER_DIM_Y 0x2142 // Word +#define GER_STYLE 0x2144 // Long +#define GER_CKEY 0x2168 // Long +#define GER_FPATCOL 0x2178 +#define GER_BPATCOL 0x217C +#define GER_PATTERN 0x2180 // from 0x2180 to 0x21FF + + Additional - Graphics Engine for 96xx +#define GER_SRCCLIP_XY 0x2148 +#define GER_SRCCLIP_X 0x2148 // Word +#define GER_SRCCLIP_Y 0x214A // Word +#define GER_DSTCLIP_XY 0x214C +#define GER_DSTCLIP_X 0x214C // Word +#define GER_DSTCLIP_Y 0x214E // Word +*/ + +READ8_MEMBER(trident_vga_device::accel_r) +{ + UINT8 res = 0xff; + + if(offset >= 0x60) + return tri.accel_pattern[(offset-0x60) % 0x80]; + + switch(offset) + { + case 0x00: // Status + if(tri.accel_busy) + res = 0x80; + else + res = 0x00; + break; + // Operation mode: + // bit 8: disable clipping if set + case 0x02: // Operation Mode + res = tri.accel_opermode & 0x00ff; + break; + case 0x03: + res = (tri.accel_opermode & 0xff00) >> 8; + break; + case 0x04: // Command register + res = tri.accel_command; + break; + case 0x07: // Foreground Mix? + res = tri.accel_fmix; + break; + default: + logerror("Trident: unimplemented acceleration register offset %02x read\n",offset); + } + return res; +} + +WRITE8_MEMBER(trident_vga_device::accel_w) +{ + if(offset >= 0x60) + { + tri.accel_pattern[(offset-0x60) % 0x80] = data; + return; + } + + switch(offset) + { + case 0x02: // Operation Mode + tri.accel_opermode = (tri.accel_opermode & 0xff00) | data; + if(LOG_ACCEL) logerror("Trident: Operation Mode set to %04x\n",tri.accel_opermode); + break; + case 0x03: + tri.accel_opermode = (tri.accel_opermode & 0x00ff) | (data << 8); + if(LOG_ACCEL) logerror("Trident: Operation Mode set to %04x\n",tri.accel_opermode); + break; + case 0x04: // Command register + tri.accel_command = data; + accel_command(); + break; + case 0x07: // Foreground Mix? + tri.accel_fmix = data; + if(LOG_ACCEL) logerror("Trident: FMIX set to %02x\n",data); + break; + case 0x08: // Draw flags + tri.accel_drawflags = (tri.accel_drawflags & 0xffffff00) | data; + if(LOG_ACCEL) logerror("Trident: Draw flags set to %08x\n",tri.accel_drawflags); + break; + case 0x09: + tri.accel_drawflags = (tri.accel_drawflags & 0xffff00ff) | (data << 8); + if(LOG_ACCEL) logerror("Trident: Draw flags set to %08x\n",tri.accel_drawflags); + break; + case 0x0a: + tri.accel_drawflags = (tri.accel_drawflags & 0xff00ffff) | (data << 16); + if(LOG_ACCEL) logerror("Trident: Draw flags set to %08x\n",tri.accel_drawflags); + break; + case 0x0b: + tri.accel_drawflags = (tri.accel_drawflags & 0x00ffffff) | (data << 24); + if(LOG_ACCEL) logerror("Trident: Draw flags set to %08x\n",tri.accel_drawflags); + break; + case 0x0c: // Foreground Colour + tri.accel_fgcolour = (tri.accel_fgcolour & 0xffffff00) | data; + if(LOG_ACCEL) logerror("Trident: Foreground Colour set to %08x\n",tri.accel_fgcolour); + break; + case 0x0d: + tri.accel_fgcolour = (tri.accel_fgcolour & 0xffff00ff) | (data << 8); + if(LOG_ACCEL) logerror("Trident: Foreground Colour set to %08x\n",tri.accel_fgcolour); + break; + case 0x0e: + tri.accel_fgcolour = (tri.accel_fgcolour & 0xff00ffff) | (data << 16); + if(LOG_ACCEL) logerror("Trident: Foreground Colour set to %08x\n",tri.accel_fgcolour); + break; + case 0x0f: + tri.accel_fgcolour = (tri.accel_fgcolour & 0x00ffffff) | (data << 24); + if(LOG_ACCEL) logerror("Trident: Foreground Colour set to %08x\n",tri.accel_fgcolour); + break; + case 0x10: // Background Colour + tri.accel_bgcolour = (tri.accel_bgcolour & 0xffffff00) | data; + if(LOG_ACCEL) logerror("Trident: Background Colour set to %08x\n",tri.accel_bgcolour); + break; + case 0x11: + tri.accel_bgcolour = (tri.accel_bgcolour & 0xffff00ff) | (data << 8); + if(LOG_ACCEL) logerror("Trident: Background Colour set to %08x\n",tri.accel_bgcolour); + break; + case 0x12: + tri.accel_bgcolour = (tri.accel_bgcolour & 0xff00ffff) | (data << 16); + if(LOG_ACCEL) logerror("Trident: Background Colour set to %08x\n",tri.accel_bgcolour); + break; + case 0x13: + tri.accel_bgcolour = (tri.accel_bgcolour & 0x00ffffff) | (data << 24); + if(LOG_ACCEL) logerror("Trident: Background Colour set to %08x\n",tri.accel_bgcolour); + break; + case 0x14: // Pattern Location + tri.accel_pattern_loc = (tri.accel_pattern_loc & 0xff00) | data; + if(LOG_ACCEL) logerror("Trident: Pattern Location set to %04x\n",tri.accel_pattern_loc); + break; + case 0x15: + tri.accel_pattern_loc = (tri.accel_pattern_loc & 0x00ff) | (data << 8); + if(LOG_ACCEL) logerror("Trident: Pattern Location set to %04x\n",tri.accel_pattern_loc); + break; + case 0x18: // Destination X + tri.accel_dest_x = (tri.accel_dest_x & 0xff00) | data; + if(LOG_ACCEL) logerror("Trident: Destination X set to %04x\n",tri.accel_dest_x); + break; + case 0x19: + tri.accel_dest_x = (tri.accel_dest_x & 0x00ff) | (data << 8); + if(LOG_ACCEL) logerror("Trident: Destination X set to %04x\n",tri.accel_dest_x); + break; + case 0x1a: // Destination Y + tri.accel_dest_y = (tri.accel_dest_y & 0xff00) | data; + if(LOG_ACCEL) logerror("Trident: Destination Y set to %04x\n",tri.accel_dest_y); + break; + case 0x1b: + tri.accel_dest_y = (tri.accel_dest_y & 0x00ff) | (data << 8); + if(LOG_ACCEL) logerror("Trident: Destination Y set to %04x\n",tri.accel_dest_y); + break; + case 0x1c: // Source X + tri.accel_source_x = (tri.accel_source_x & 0xff00) | data; + if(LOG_ACCEL) logerror("Trident: Source X set to %04x\n",tri.accel_source_x); + break; + case 0x1d: + tri.accel_source_x = (tri.accel_source_x & 0x00ff) | (data << 8); + if(LOG_ACCEL) logerror("Trident: Source X set to %04x\n",tri.accel_source_x); + break; + case 0x1e: // Source Y + tri.accel_source_y = (tri.accel_source_y & 0xff00) | data; + if(LOG_ACCEL) logerror("Trident: Source Y set to %04x\n",tri.accel_source_y); + break; + case 0x1f: + tri.accel_source_y = (tri.accel_source_y & 0x00ff) | (data << 8); + if(LOG_ACCEL) logerror("Trident: Source Y set to %04x\n",tri.accel_source_y); + break; + case 0x20: // Dimension(?) X + tri.accel_dim_x = (tri.accel_dim_x & 0xff00) | data; + if(LOG_ACCEL) logerror("Trident: Dimension X set to %04x\n",tri.accel_dim_x); + break; + case 0x21: + tri.accel_dim_x = (tri.accel_dim_x & 0x00ff) | (data << 8); + if(LOG_ACCEL) logerror("Trident: Dimension X set to %04x\n",tri.accel_dim_x); + break; + case 0x22: // Dimension(?) Y + tri.accel_dim_y = (tri.accel_dim_y & 0xff00) | data; + if(LOG_ACCEL) logerror("Trident: Dimension y set to %04x\n",tri.accel_dim_y); + break; + case 0x23: + tri.accel_dim_y = (tri.accel_dim_y & 0x00ff) | (data << 8); + if(LOG_ACCEL) logerror("Trident: Dimension y set to %04x\n",tri.accel_dim_y); + break; + case 0x24: // Style + tri.accel_style = (tri.accel_style & 0xffffff00) | data; + if(LOG_ACCEL) logerror("Trident: Style set to %08x\n",tri.accel_style); + break; + case 0x25: + tri.accel_style = (tri.accel_style & 0xffff00ff) | (data << 8); + if(LOG_ACCEL) logerror("Trident: Style set to %08x\n",tri.accel_style); + break; + case 0x26: + tri.accel_style = (tri.accel_style & 0xff00ffff) | (data << 16); + if(LOG_ACCEL) logerror("Trident: Style set to %08x\n",tri.accel_style); + break; + case 0x27: + tri.accel_style = (tri.accel_style & 0x00ffffff) | (data << 24); + if(LOG_ACCEL) logerror("Trident: Style set to %08x\n",tri.accel_style); + break; + case 0x28: // Source Clip X + tri.accel_source_x_clip = (tri.accel_source_x_clip & 0xff00) | data; + if(LOG_ACCEL) logerror("Trident: Source X Clip set to %04x\n",tri.accel_source_x_clip); + break; + case 0x29: + tri.accel_source_x_clip = (tri.accel_source_x_clip & 0x00ff) | (data << 8); + if(LOG_ACCEL) logerror("Trident: Source X Clip set to %04x\n",tri.accel_source_x_clip); + break; + case 0x2a: // Source Clip Y + tri.accel_source_y_clip = (tri.accel_source_y_clip & 0xff00) | data; + if(LOG_ACCEL) logerror("Trident: Source Y Clip set to %04x\n",tri.accel_source_y_clip); + break; + case 0x2b: + tri.accel_source_y_clip = (tri.accel_source_y_clip & 0x00ff) | (data << 8); + if(LOG_ACCEL) logerror("Trident: Source Y Clip set to %04x\n",tri.accel_source_y_clip); + break; + case 0x2c: // Destination Clip X + tri.accel_dest_x_clip = (tri.accel_dest_x_clip & 0xff00) | data; + if(LOG_ACCEL) logerror("Trident: Destination X Clip set to %04x\n",tri.accel_dest_x_clip); + break; + case 0x2d: + tri.accel_dest_x_clip = (tri.accel_dest_x_clip & 0x00ff) | (data << 8); + if(LOG_ACCEL) logerror("Trident: Destination X Clip set to %04x\n",tri.accel_dest_x_clip); + break; + case 0x2e: // Destination Clip Y + tri.accel_dest_y_clip = (tri.accel_dest_y_clip & 0xff00) | data; + if(LOG_ACCEL) logerror("Trident: Destination Y Clip set to %04x\n",tri.accel_dest_y_clip); + break; + case 0x2f: + tri.accel_dest_y_clip = (tri.accel_dest_y_clip & 0x00ff) | (data << 8); + if(LOG_ACCEL) logerror("Trident: Destination Y Clip set to %04x\n",tri.accel_dest_y_clip); + break; + case 0x48: // CKEY (Chromakey?) + tri.accel_ckey = (tri.accel_ckey & 0xffffff00) | data; + if(LOG_ACCEL) logerror("Trident: CKey set to %08x\n",tri.accel_ckey); + break; + case 0x49: + tri.accel_ckey = (tri.accel_ckey & 0xffff00ff) | (data << 8); + if(LOG_ACCEL) logerror("Trident: CKey set to %08x\n",tri.accel_ckey); + break; + case 0x4a: + tri.accel_ckey = (tri.accel_ckey & 0xff00ffff) | (data << 16); + if(LOG_ACCEL) logerror("Trident: CKey set to %08x\n",tri.accel_ckey); + break; + case 0x4b: + tri.accel_ckey = (tri.accel_ckey & 0x00ffffff) | (data << 24); + if(LOG_ACCEL) logerror("Trident: CKey set to %08x\n",tri.accel_ckey); + break; + case 0x58: // Foreground Pattern Colour + tri.accel_fg_pattern_colour = (tri.accel_fg_pattern_colour & 0xffffff00) | data; + if(LOG_ACCEL) logerror("Trident: FG Pattern Colour set to %08x\n",tri.accel_fg_pattern_colour); + break; + case 0x59: + tri.accel_fg_pattern_colour = (tri.accel_fg_pattern_colour & 0xffff00ff) | (data << 8); + if(LOG_ACCEL) logerror("Trident: FG Pattern Colour set to %08x\n",tri.accel_fg_pattern_colour); + break; + case 0x5a: + tri.accel_fg_pattern_colour = (tri.accel_fg_pattern_colour & 0xff00ffff) | (data << 16); + if(LOG_ACCEL) logerror("Trident: FG Pattern Colour set to %08x\n",tri.accel_fg_pattern_colour); + break; + case 0x5b: + tri.accel_fg_pattern_colour = (tri.accel_fg_pattern_colour & 0x00ffffff) | (data << 24); + if(LOG_ACCEL) logerror("Trident: FG Pattern Colour set to %08x\n",tri.accel_fg_pattern_colour); + break; + case 0x5c: // Background Pattern Colour + tri.accel_bg_pattern_colour = (tri.accel_bg_pattern_colour & 0xffffff00) | data; + if(LOG_ACCEL) logerror("Trident: BG Pattern Colour set to %08x\n",tri.accel_bg_pattern_colour); + break; + case 0x5d: + tri.accel_bg_pattern_colour = (tri.accel_bg_pattern_colour & 0xffff00ff) | (data << 8); + if(LOG_ACCEL) logerror("Trident: BG Pattern Colour set to %08x\n",tri.accel_bg_pattern_colour); + break; + case 0x5e: + tri.accel_bg_pattern_colour = (tri.accel_bg_pattern_colour & 0xff00ffff) | (data << 16); + if(LOG_ACCEL) logerror("Trident: BG Pattern Colour set to %08x\n",tri.accel_bg_pattern_colour); + break; + case 0x5f: + tri.accel_bg_pattern_colour = (tri.accel_bg_pattern_colour & 0x00ffffff) | (data << 24); + if(LOG_ACCEL) logerror("Trident: BG Pattern Colour set to %08x\n",tri.accel_bg_pattern_colour); + break; + default: + logerror("Trident: unimplemented acceleration register offset %02x write %02x\n",offset,data); + } +} + +void trident_vga_device::accel_command() +{ + switch(tri.accel_command) + { + case 0x00: + if(LOG) logerror("Trident: Command: NOP\n"); + break; + case 0x01: + if(LOG) logerror("Trident: Command: BitBLT ROP3 (Source %i,%i Dest %i,%i Size %i,%i)\n",tri.accel_source_x,tri.accel_source_y,tri.accel_dest_x,tri.accel_dest_y,tri.accel_dim_x,tri.accel_dim_y); + if(LOG) logerror("BitBLT: Drawflags = %08x FMIX = %02x\n",tri.accel_drawflags,tri.accel_fmix); + accel_bitblt(); + break; + case 0x02: + if(LOG) logerror("Trident: Command: BitBLT ROP4\n"); + break; + case 0x03: + if(LOG) logerror("Trident: Command: Scanline\n"); + break; + case 0x04: + if(LOG) logerror("Trident: Command: Bresenham Line (Source %i,%i Dest %i,%i Size %i,%i)\n",tri.accel_source_x,tri.accel_source_y,tri.accel_dest_x,tri.accel_dest_y,tri.accel_dim_x,tri.accel_dim_y); + if(LOG) logerror("BLine: Drawflags = %08x FMIX = %02x\n",tri.accel_drawflags,tri.accel_fmix); + accel_line(); + break; + case 0x05: + if(LOG) logerror("Trident: Command: Short Vector\n"); + break; + case 0x06: + if(LOG) logerror("Trident: Command: Fast Line\n"); + break; + case 0x07: + if(LOG) logerror("Trident: Command: Trapezoid Fill\n"); + break; + case 0x08: + if(LOG) logerror("Trident: Command: Ellipse\n"); + break; + case 0x09: + if(LOG) logerror("Trident: Command: Ellipse Fill\n"); + break; + default: + logerror("Trident: Unknown acceleration command %02x\n",tri.accel_command); + } +} + +void trident_vga_device::accel_bitblt() +{ + int x,y; + int sx,sy; + int xdir,ydir; + int xstart,xend,ystart,yend; + + if(tri.accel_drawflags & 0x0040) // TODO: handle PATMONO also + { + tri.accel_mem_x = tri.accel_dest_x; + tri.accel_mem_y = tri.accel_dest_y; + tri.accel_memwrite_active = true; + return; + } + + if(tri.accel_drawflags & 0x0200) + { + xdir = -1; + xstart = tri.accel_dest_x; + xend = tri.accel_dest_x-tri.accel_dim_x-1; + } + else + { + xdir = 1; + xstart = tri.accel_dest_x; + xend = tri.accel_dest_x+tri.accel_dim_x+1; + } + if(tri.accel_drawflags & 0x0100) + { + ydir = -1; + ystart = tri.accel_dest_y; + yend = tri.accel_dest_y-tri.accel_dim_y-1; + } + else + { + ydir = 1; + ystart = tri.accel_dest_y; + yend = tri.accel_dest_y+tri.accel_dim_y+1; + } + sy = tri.accel_source_y; + + for(y=ystart;y!=yend;y+=ydir,sy+=ydir) + { + sx = tri.accel_source_x; + for(x=xstart;x!=xend;x+=xdir,sx+=xdir) + { + if(tri.accel_drawflags & 0x4000) // Solid fill + { + WRITEPIXEL(x,y,tri.accel_fgcolour); + } + else + { + WRITEPIXEL(x,y,READPIXEL(sx,sy)); + } + } + } +} + +void trident_vga_device::accel_line() +{ + UINT32 col = tri.accel_fgcolour; +// TGUI_SRC_XY(dmin-dmaj,dmin); +// TGUI_DEST_XY(x,y); +// TGUI_DIM_XY(dmin+e,len); + INT16 dx = tri.accel_source_y - tri.accel_source_x; + INT16 dy = tri.accel_source_y; + INT16 err = tri.accel_dim_x + tri.accel_source_y; + int sx = (tri.accel_drawflags & 0x0200) ? -1 : 1; + int sy = (tri.accel_drawflags & 0x0100) ? -1 : 1; + int x,y,z; + + x = tri.accel_dest_x; + y = tri.accel_dest_y; + + WRITEPIXEL(x,y,col); + for(z=0;z<tri.accel_dim_y;z++) + { + if(tri.accel_drawflags & 0x0400) + y += sy; + else + x += sx; + if(err > 0) + { + if(tri.accel_drawflags & 0x0400) + x += sx; + else + y += sy; + WRITEPIXEL(x,y,col); + err += (dy-dx); + } + else + { + WRITEPIXEL(x,y,col); + err += dy; + } + } +} + +// feed data written to VRAM to an active BitBLT command +void trident_vga_device::accel_data_write(UINT32 data) +{ + int xdir = 1,ydir = 1; + + if(tri.accel_drawflags & 0x0200) // XNEG + xdir = -1; + if(tri.accel_drawflags & 0x0100) // YNEG + ydir = -1; + + for(int x=31;x>=0;x--) + { + if(tri.accel_mem_x <= tri.accel_dest_x+tri.accel_dim_x && tri.accel_mem_x >= tri.accel_dest_x-tri.accel_dim_x) + { + if(((data >> x) & 0x01) != 0) + WRITEPIXEL(tri.accel_mem_x,tri.accel_mem_y,tri.accel_fgcolour); + else + WRITEPIXEL(tri.accel_mem_x,tri.accel_mem_y,tri.accel_bgcolour); + } + tri.accel_mem_x+=xdir; + } + if(tri.accel_mem_x > tri.accel_dest_x+tri.accel_dim_x || tri.accel_mem_x < tri.accel_dest_x-tri.accel_dim_x) + { + tri.accel_mem_x = tri.accel_dest_x; + tri.accel_mem_y+=ydir; + if(tri.accel_mem_y > tri.accel_dest_y+tri.accel_dim_y || tri.accel_mem_y < tri.accel_dest_y-tri.accel_dim_y) + tri.accel_memwrite_active = false; // completed + } +} |