summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/bus/isa/trident.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/bus/isa/trident.cpp')
-rw-r--r--src/devices/bus/isa/trident.cpp1612
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
+ }
+}