summaryrefslogtreecommitdiffstatshomepage
path: root/trunk/src/emu/video/pc_vga.c
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/src/emu/video/pc_vga.c')
-rw-r--r--trunk/src/emu/video/pc_vga.c2873
1 files changed, 2873 insertions, 0 deletions
diff --git a/trunk/src/emu/video/pc_vga.c b/trunk/src/emu/video/pc_vga.c
new file mode 100644
index 00000000000..71b93c0286c
--- /dev/null
+++ b/trunk/src/emu/video/pc_vga.c
@@ -0,0 +1,2873 @@
+/***************************************************************************
+
+ Video Graphics Adapter (VGA) section
+
+ Nathan Woods npwoods@mess.org
+ Peter Trauner PeT mess@utanet.at
+
+ This code takes care of installing the various VGA memory and port
+ handlers
+
+ The VGA standard is compatible with MDA, CGA, Hercules, EGA
+ (mda, cga, hercules not real register compatible)
+ several vga cards drive also mda, cga, ega monitors
+ some vga cards have register compatible mda, cga, hercules modes
+
+ ega/vga
+ 64k (early ega 16k) words of 32 bit memory
+
+ TODO:
+ - modernize
+ - fix video update, still need to get that choosevideomode() out of it.
+ - rewrite video drawing functions (they are horrible)
+ - add per-gfx card VESA functions;
+ - (and many more ...)
+
+ per-game issues:
+ - The Incredible Machine: fix partial updates
+ - MAME 0.01: fix 92 Hz refresh rate bug (uses VESA register?).
+ - Alien Breed, Bio Menace: jerky H scrolling (uses VGA/EGA mode with pel shift)
+ - Virtual Pool: ET4k unrecognized;
+ - California Chase (calchase): various gfx bugs, CPU related?
+
+ ROM declarations:
+
+ (oti 037 chip)
+ ROM_LOAD("oakvga.bin", 0xc0000, 0x8000, 0x318c5f43)
+ (tseng labs famous et4000 isa vga card (oem))
+ ROM_LOAD("et4000b.bin", 0xc0000, 0x8000, 0xa903540d)
+ (tseng labs famous et4000 isa vga card)
+ ROM_LOAD("et4000.bin", 0xc0000, 0x8000, 0xf01e4be0)
+
+***************************************************************************/
+
+#include "emu.h"
+#include "pc_vga.h"
+#include "debugger.h"
+
+/***************************************************************************
+
+ Local variables
+
+***************************************************************************/
+
+static struct
+{
+ read8_space_func read_dipswitch;
+ struct pc_svga_interface svga_intf;
+
+ UINT8 *memory;
+ UINT32 pens[16]; /* the current 16 pens */
+
+ UINT8 miscellaneous_output;
+ UINT8 feature_control;
+
+ struct
+ {
+ UINT8 index;
+ UINT8 *data;
+ UINT8 map_mask;
+ struct
+ {
+ UINT8 A, B;
+ }char_sel;
+ } sequencer;
+
+ /* An empty comment at the start of the line indicates that register is currently unused */
+ struct
+ {
+ UINT8 index;
+ UINT8 *data;
+ UINT16 horz_total;
+ UINT16 horz_disp_end;
+/**/ UINT8 horz_blank_start;
+/**/ UINT8 horz_blank_end;
+/**/ UINT8 horz_retrace_start;
+/**/ UINT8 horz_retrace_skew;
+/**/ UINT8 horz_retrace_end;
+/**/ UINT8 disp_enable_skew;
+/**/ UINT8 evra;
+ UINT16 vert_total;
+ UINT16 vert_disp_end;
+/**/ UINT16 vert_retrace_start;
+/**/ UINT8 vert_retrace_end;
+/**/ UINT16 vert_blank_start;
+ UINT16 line_compare;
+/**/ UINT16 cursor_addr;
+/**/ UINT8 byte_panning;
+/**/ UINT8 preset_row_scan;
+ UINT8 scan_doubling;
+/**/ UINT8 maximum_scan_line;
+/**/ UINT8 cursor_enable;
+/**/ UINT8 cursor_scan_start;
+/**/ UINT8 cursor_skew;
+/**/ UINT8 cursor_scan_end;
+ UINT32 start_addr;
+/**/ UINT8 protect_enable;
+/**/ UINT8 bandwidth;
+/**/ UINT8 offset;
+/**/ UINT8 word_mode;
+/**/ UINT8 dw;
+/**/ UINT8 div4;
+/**/ UINT8 underline_loc;
+/**/ UINT8 vert_blank_end;
+ UINT8 sync_en;
+/**/ UINT8 aw;
+/**/ UINT8 div2;
+/**/ UINT8 sldiv;
+/**/ UINT8 map14;
+/**/ UINT8 map13;
+ } crtc;
+
+ struct
+ {
+ UINT8 index;
+ UINT8 latch[4];
+ UINT8 set_reset;
+ UINT8 enable_set_reset;
+ UINT8 color_compare;
+ UINT8 logical_op;
+ UINT8 rotate_count;
+ UINT8 shift256;
+ UINT8 shift_reg;
+ UINT8 read_map_sel;
+ UINT8 read_mode;
+ UINT8 write_mode;
+ UINT8 color_dont_care;
+ UINT8 bit_mask;
+ UINT8 alpha_dis;
+ UINT8 memory_map_sel;
+ UINT8 host_oe;
+ UINT8 chain_oe;
+ } gc;
+
+ struct
+ {
+ UINT8 index, data[0x15]; int state;
+ UINT8 prot_bit;
+ UINT8 pel_shift;
+ } attribute;
+
+
+ struct {
+ UINT8 read_index, write_index, mask;
+ int read;
+ int state;
+ struct { UINT8 red, green, blue; } color[0x100];
+ int dirty;
+ } dac;
+
+ struct {
+ UINT8 visible;
+ } cursor;
+
+ /* oak vga */
+ struct { UINT8 reg; } oak;
+} vga;
+
+static struct
+{
+ UINT8 bank_r,bank_w;
+ UINT8 rgb8_en;
+ UINT8 rgb15_en;
+ UINT8 rgb16_en;
+ UINT8 rgb24_en;
+ UINT8 rgb32_en;
+ UINT8 id;
+}svga;
+
+static struct
+{
+ UINT8 reg_3d8;
+ UINT8 dac_ctrl;
+ UINT8 dac_state;
+ UINT8 horz_overflow;
+ UINT8 aux_ctrl;
+ bool ext_reg_ena;
+}et4k;
+
+static struct
+{
+ UINT8 memory_config;
+ UINT8 ext_misc_ctrl_2;
+ UINT8 crt_reg_lock;
+ UINT8 reg_lock1;
+ UINT8 reg_lock2;
+}s3;
+
+#define CRTC_PORT_ADDR ((vga.miscellaneous_output&1)?0x3d0:0x3b0)
+
+//#define TEXT_LINES (LINES_HELPER)
+#define LINES (vga.crtc.vert_disp_end+1)
+#define TEXT_LINES (vga.crtc.vert_disp_end+1)
+
+#define GRAPHIC_MODE (vga.gc.alpha_dis) /* else text mode */
+
+#define EGA_COLUMNS (vga.crtc.horz_disp_end+1)
+#define EGA_START_ADDRESS (vga.crtc.start_addr)
+#define EGA_LINE_LENGTH (vga.crtc.offset<<1)
+
+#define VGA_COLUMNS (vga.crtc.horz_disp_end+1)
+#define VGA_START_ADDRESS (vga.crtc.start_addr)
+#define VGA_LINE_LENGTH (vga.crtc.offset<<3)
+
+#define CHAR_WIDTH ((vga.sequencer.data[1]&1)?8:9)
+
+#define TEXT_COLUMNS (vga.crtc.horz_disp_end+1)
+#define TEXT_START_ADDRESS (vga.crtc.start_addr<<3)
+#define TEXT_LINE_LENGTH (vga.crtc.offset<<1)
+
+#define TEXT_COPY_9COLUMN(ch) (((ch & 0xe0) == 0xc0)&&(vga.attribute.data[0x10]&4))
+
+// Special values for SVGA Trident - Mode Vesa 110h
+#define TLINES (LINES)
+#define TGA_COLUMNS (EGA_COLUMNS)
+#define TGA_START_ADDRESS (vga.crtc.start_addr<<2)
+#define TGA_LINE_LENGTH (vga.crtc.offset<<3)
+
+
+/***************************************************************************
+
+ Static declarations
+
+***************************************************************************/
+
+#define LOG_ACCESSES 0
+#define LOG_REGISTERS 0
+
+static VIDEO_RESET( vga );
+
+/***************************************************************************
+
+ MachineDriver stuff
+
+***************************************************************************/
+
+void pc_video_start(running_machine &machine)
+{
+ // ...
+
+ // Avoid an infinite loop when displaying. 0 is not possible anyway.
+ vga.crtc.maximum_scan_line = 1;
+}
+
+static void vga_vh_text(running_machine &machine, bitmap_rgb32 &bitmap, const rectangle &cliprect)
+{
+ UINT8 ch, attr;
+ UINT8 bits;
+ UINT32 font_base;
+ UINT32 *bitmapline;
+ int width=CHAR_WIDTH, height = (vga.crtc.maximum_scan_line) * (vga.crtc.scan_doubling + 1);
+ int pos, line, column, mask, w, h, addr;
+ UINT8 blink_en,fore_col,back_col;
+ pen_t pen;
+
+ if(vga.crtc.cursor_enable)
+ vga.cursor.visible = machine.primary_screen->frame_number() & 0x10;
+ else
+ vga.cursor.visible = 0;
+
+ for (addr = vga.crtc.start_addr, line = -vga.crtc.preset_row_scan; line < TEXT_LINES;
+ line += height, addr += TEXT_LINE_LENGTH)
+ {
+ for (pos = addr, column=0; column<TEXT_COLUMNS; column++, pos++)
+ {
+ ch = vga.memory[(pos<<1) + 0];
+ attr = vga.memory[(pos<<1) + 1];
+ font_base = 0x20000+(ch<<5);
+ font_base += ((attr & 8) ? vga.sequencer.char_sel.B : vga.sequencer.char_sel.A)*0x2000;
+ blink_en = (vga.attribute.data[0x10]&8&&machine.primary_screen->frame_number() & 0x20) ? attr & 0x80 : 0;
+
+ fore_col = attr & 0xf;
+ back_col = (attr & 0x70) >> 4;
+ back_col |= (vga.attribute.data[0x10]&8) ? 0 : ((attr & 0x80) >> 4);
+
+ for (h = MAX(-line, 0); (h < height) && (line+h < MIN(TEXT_LINES, bitmap.height())); h++)
+ {
+ bitmapline = &bitmap.pix32(line+h);
+ bits = vga.memory[font_base+(h>>(vga.crtc.scan_doubling))];
+
+ for (mask=0x80, w=0; (w<width)&&(w<8); w++, mask>>=1)
+ {
+ if (bits&mask)
+ pen = vga.pens[blink_en ? back_col : fore_col];
+ else
+ pen = vga.pens[back_col];
+
+ if(!machine.primary_screen->visible_area().contains(column*width+w, line+h))
+ continue;
+ bitmapline[column*width+w] = pen;
+
+ }
+ if (w<width)
+ {
+ /* 9 column */
+ if (TEXT_COPY_9COLUMN(ch)&&(bits&1))
+ pen = vga.pens[blink_en ? back_col : fore_col];
+ else
+ pen = vga.pens[back_col];
+
+ if(!machine.primary_screen->visible_area().contains(column*width+w, line+h))
+ continue;
+ bitmapline[column*width+w] = pen;
+ }
+ }
+ if (vga.cursor.visible&&(pos==vga.crtc.cursor_addr))
+ {
+ for (h=vga.crtc.cursor_scan_start;
+ (h<=vga.crtc.cursor_scan_end)&&(h<height)&&(line+h<TEXT_LINES);
+ h++)
+ {
+ if(!machine.primary_screen->visible_area().contains(column*width, line+h))
+ continue;
+ bitmap.plot_box(column*width, line+h, width, 1, vga.pens[attr&0xf]);
+ }
+ }
+ }
+ }
+}
+
+static void vga_vh_ega(running_machine &machine, bitmap_rgb32 &bitmap, const rectangle &cliprect)
+{
+ int pos, line, column, c, addr, i, yi;
+ int height = vga.crtc.maximum_scan_line * (vga.crtc.scan_doubling + 1);
+ UINT32 *bitmapline;
+ pen_t pen;
+
+ /**/
+ for (addr=EGA_START_ADDRESS, pos=0, line=0; line<LINES;
+ line += height, addr += EGA_LINE_LENGTH)
+ {
+ for(yi=0;yi<height;yi++)
+ {
+ bitmapline = &bitmap.pix32(line + yi);
+
+ for (pos=addr, c=0, column=0; column<EGA_COLUMNS; column++, c+=8, pos=(pos+1)&0xffff)
+ {
+ int data[4];
+
+ data[0]=vga.memory[(pos & 0xffff)];
+ data[1]=vga.memory[(pos & 0xffff)+0x10000]<<1;
+ data[2]=vga.memory[(pos & 0xffff)+0x20000]<<2;
+ data[3]=vga.memory[(pos & 0xffff)+0x30000]<<3;
+
+ for (i = 7; i >= 0; i--)
+ {
+ pen = vga.pens[(data[0]&1) | (data[1]&2) | (data[2]&4) | (data[3]&8)];
+ if(!machine.primary_screen->visible_area().contains(c+i, line + yi))
+ continue;
+ bitmapline[c+i] = pen;
+
+ data[0]>>=1;
+ data[1]>>=1;
+ data[2]>>=1;
+ data[3]>>=1;
+ }
+ }
+ }
+ }
+}
+
+/* TODO: I'm guessing that in 256 colors mode every pixel actually outputs two pixels. Is it right? */
+static void vga_vh_vga(running_machine &machine, bitmap_rgb32 &bitmap, const rectangle &cliprect)
+{
+ int pos, line, column, c, addr, curr_addr;
+ UINT32 *bitmapline;
+ UINT16 mask_comp;
+ int height = vga.crtc.maximum_scan_line * (vga.crtc.scan_doubling + 1);
+ int yi;
+ int xi;
+ int pel_shift = 0;//vga.attribute.pel_shift; /* TODO: timing bug with this */
+
+ /* line compare is screen sensitive */
+ mask_comp = 0x3ff; //| (LINES & 0x300);
+
+ curr_addr = 0;
+ if(!(vga.sequencer.data[4] & 0x08))
+ {
+ for (addr = VGA_START_ADDRESS, line=0; line<LINES; line+=height, addr+=VGA_LINE_LENGTH/4, curr_addr+=VGA_LINE_LENGTH/4)
+ {
+ for(yi = 0;yi < height; yi++)
+ {
+ if((line + yi) < (vga.crtc.line_compare & mask_comp))
+ curr_addr = addr;
+ if((line + yi) == (vga.crtc.line_compare & mask_comp))
+ curr_addr = 0;
+ bitmapline = &bitmap.pix32(line + yi);
+ for (pos=curr_addr, c=0, column=0; column<VGA_COLUMNS; column++, c+=8, pos++)
+ {
+ if(pos > 0x80000/4)
+ return;
+
+ for(xi=0;xi<8;xi++)
+ {
+ if(!machine.primary_screen->visible_area().contains(c+xi-pel_shift, line + yi))
+ continue;
+ bitmapline[c+xi-pel_shift] = machine.pens[vga.memory[(pos & 0xffff)+((xi >> 1)*0x10000)]];
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ for (addr = VGA_START_ADDRESS, line=0; line<LINES; line+=height, addr+=VGA_LINE_LENGTH, curr_addr+=VGA_LINE_LENGTH)
+ {
+ for(yi = 0;yi < height; yi++)
+ {
+ if((line + yi) < (vga.crtc.line_compare & mask_comp))
+ curr_addr = addr;
+ if((line + yi) == (vga.crtc.line_compare & mask_comp))
+ curr_addr = 0;
+ bitmapline = &bitmap.pix32(line + yi);
+ //addr %= 0x80000;
+ for (pos=curr_addr, c=0, column=0; column<VGA_COLUMNS; column++, c+=0x10, pos+=0x8)
+ {
+ if(pos + 0x08 > 0x80000)
+ return;
+
+ for(xi=0;xi<0x10;xi++)
+ {
+ if(!machine.primary_screen->visible_area().contains(c+xi-pel_shift, line + yi))
+ continue;
+ bitmapline[c+xi-pel_shift] = machine.pens[vga.memory[(pos+(xi >> 1)) & 0xffff]];
+ }
+ }
+ }
+ }
+ }
+}
+
+static void vga_vh_cga(running_machine &machine, bitmap_rgb32 &bitmap, const rectangle &cliprect)
+{
+ UINT32 *bitmapline;
+ int height = (vga.crtc.scan_doubling + 1);
+ int x,xi,y,yi;
+ UINT32 addr;
+ pen_t pen;
+ int width;
+
+ addr = 0;
+ width = (vga.crtc.horz_disp_end + 1) * 8;
+
+ for(y=0;y<LINES;y++)
+ {
+ addr = ((y & 1) * 0x2000) + (((y & ~1) >> 1) * width/4);
+
+ for(x=0;x<width;x+=4)
+ {
+ for(yi=0;yi<height;yi++)
+ {
+ bitmapline = &bitmap.pix32(y * height + yi);
+
+ for(xi=0;xi<4;xi++)
+ {
+ pen = vga.pens[(vga.memory[addr] >> (6-xi*2)) & 3];
+ if(!machine.primary_screen->visible_area().contains(x+xi, y * height + yi))
+ continue;
+ bitmapline[x+xi] = pen;
+ }
+ }
+
+ addr++;
+ }
+ }
+}
+
+static void vga_vh_mono(running_machine &machine, bitmap_rgb32 &bitmap, const rectangle &cliprect)
+{
+ UINT32 *bitmapline;
+ int height = (vga.crtc.scan_doubling + 1);
+ int x,xi,y,yi;
+ UINT32 addr;
+ pen_t pen;
+ int width;
+
+ addr = 0;
+ width = (vga.crtc.horz_disp_end + 1) * 8;
+
+ for(y=0;y<LINES;y++)
+ {
+ addr = ((y & 1) * 0x2000) + (((y & ~1) >> 1) * width/8);
+
+ for(x=0;x<width;x+=8)
+ {
+ for(yi=0;yi<height;yi++)
+ {
+ bitmapline = &bitmap.pix32(y * height + yi);
+
+ for(xi=0;xi<8;xi++)
+ {
+ pen = vga.pens[(vga.memory[addr] >> (7-xi)) & 1];
+ if(!machine.primary_screen->visible_area().contains(x+xi, y * height + yi))
+ continue;
+ bitmapline[x+xi] = pen;
+ }
+ }
+
+ addr++;
+ }
+ }
+}
+
+static void svga_vh_rgb8(running_machine &machine, bitmap_rgb32 &bitmap, const rectangle &cliprect)
+{
+ int pos, line, column, c, addr, curr_addr;
+ UINT32 *bitmapline;
+ UINT16 mask_comp;
+ int height = vga.crtc.maximum_scan_line * (vga.crtc.scan_doubling + 1);
+ int yi;
+ int xi;
+ UINT8 start_shift;
+
+ /* line compare is screen sensitive */
+ mask_comp = 0x3ff;
+ curr_addr = 0;
+
+ start_shift = (!(vga.sequencer.data[4] & 0x08)) ? 2 : 0;
+
+ {
+ for (addr = VGA_START_ADDRESS << start_shift, line=0; line<LINES; line+=height, addr+=VGA_LINE_LENGTH, curr_addr+=VGA_LINE_LENGTH)
+ {
+ for(yi = 0;yi < height; yi++)
+ {
+ if((line + yi) < (vga.crtc.line_compare & mask_comp))
+ curr_addr = addr;
+ if((line + yi) == (vga.crtc.line_compare & mask_comp))
+ curr_addr = 0;
+ bitmapline = &bitmap.pix32(line + yi);
+ addr %= vga.svga_intf.vram_size;
+ for (pos=curr_addr, c=0, column=0; column<VGA_COLUMNS; column++, c+=8, pos+=0x8)
+ {
+ if(pos + 0x08 > 0x100000)
+ return;
+
+ for(xi=0;xi<8;xi++)
+ {
+ if(!machine.primary_screen->visible_area().contains(c+xi, line + yi))
+ continue;
+ bitmapline[c+xi] = machine.pens[vga.memory[(pos+(xi))]];
+ }
+ }
+ }
+ }
+ }
+}
+
+static void svga_vh_rgb15(running_machine &machine, bitmap_rgb32 &bitmap, const rectangle &cliprect)
+{
+ #define MV(x) (vga.memory[x]+(vga.memory[x+1]<<8))
+ #define IV 0xff000000
+ int height = vga.crtc.maximum_scan_line * (vga.crtc.scan_doubling + 1);
+ int xi;
+ int yi;
+ int xm;
+ int pos, line, column, c, addr, curr_addr;
+
+ UINT32 *bitmapline;
+// UINT16 mask_comp;
+
+ /* line compare is screen sensitive */
+// mask_comp = 0xff | (TLINES & 0x300);
+ curr_addr = 0;
+ yi=0;
+ for (addr = TGA_START_ADDRESS, line=0; line<TLINES; line+=height, addr+=TGA_LINE_LENGTH, curr_addr+=TGA_LINE_LENGTH)
+ {
+ bitmapline = &bitmap.pix32(line);
+ addr %= vga.svga_intf.vram_size;
+ for (pos=addr, c=0, column=0; column<TGA_COLUMNS; column++, c+=8, pos+=0x10)
+ {
+ if(pos + 0x10 > 0x100000)
+ return;
+ for(xi=0,xm=0;xi<8;xi++,xm+=2)
+ {
+ int r,g,b;
+
+ if(!machine.primary_screen->visible_area().contains(c+xi, line + yi))
+ continue;
+
+ r = (MV(pos+xm)&0x7c00)>>10;
+ g = (MV(pos+xm)&0x03e0)>>5;
+ b = (MV(pos+xm)&0x001f)>>0;
+ r = (r << 3) | (r & 0x7);
+ g = (g << 3) | (g & 0x7);
+ b = (b << 3) | (b & 0x7);
+ bitmapline[c+xi] = IV|(r<<16)|(g<<8)|(b<<0);
+ }
+ }
+ }
+}
+
+static void svga_vh_rgb16(running_machine &machine, bitmap_rgb32 &bitmap, const rectangle &cliprect)
+{
+ #define MV(x) (vga.memory[x]+(vga.memory[x+1]<<8))
+ #define IV 0xff000000
+ int height = vga.crtc.maximum_scan_line * (vga.crtc.scan_doubling + 1);
+ int xi;
+ int yi;
+ int xm;
+ int pos, line, column, c, addr, curr_addr;
+
+ UINT32 *bitmapline;
+// UINT16 mask_comp;
+
+ /* line compare is screen sensitive */
+// mask_comp = 0xff | (TLINES & 0x300);
+ curr_addr = 0;
+ yi=0;
+ for (addr = TGA_START_ADDRESS, line=0; line<TLINES; line+=height, addr+=TGA_LINE_LENGTH, curr_addr+=TGA_LINE_LENGTH)
+ {
+ bitmapline = &bitmap.pix32(line);
+ addr %= vga.svga_intf.vram_size;
+ for (pos=addr, c=0, column=0; column<TGA_COLUMNS; column++, c+=8, pos+=0x10)
+ {
+ if(pos + 0x10 > 0x100000)
+ return;
+ for(xi=0,xm=0;xi<8;xi++,xm+=2)
+ {
+ int r,g,b;
+
+ if(!machine.primary_screen->visible_area().contains(c+xi, line + yi))
+ continue;
+
+ r = (MV(pos+xm)&0xf800)>>11;
+ g = (MV(pos+xm)&0x07e0)>>5;
+ b = (MV(pos+xm)&0x001f)>>0;
+ r = (r << 3) | (r & 0x7);
+ g = (g << 2) | (g & 0x3);
+ b = (b << 3) | (b & 0x7);
+ bitmapline[c+xi] = IV|(r<<16)|(g<<8)|(b<<0);
+ }
+ }
+ }
+}
+
+static void svga_vh_rgb24(running_machine &machine, bitmap_rgb32 &bitmap, const rectangle &cliprect)
+{
+ #define MD(x) (vga.memory[x]+(vga.memory[x+1]<<8)+(vga.memory[x+2]<<16))
+ #define ID 0xff000000
+ int height = vga.crtc.maximum_scan_line * (vga.crtc.scan_doubling + 1);
+ int xi;
+ int yi;
+ int xm;
+ int pos, line, column, c, addr, curr_addr;
+ UINT32 *bitmapline;
+
+// UINT16 mask_comp;
+
+ /* line compare is screen sensitive */
+// mask_comp = 0xff | (TLINES & 0x300);
+ curr_addr = 0;
+ yi=0;
+ for (addr = TGA_START_ADDRESS<<1, line=0; line<TLINES; line+=height, addr+=TGA_LINE_LENGTH, curr_addr+=TGA_LINE_LENGTH)
+ {
+ bitmapline = &bitmap.pix32(line);
+ addr %= vga.svga_intf.vram_size;
+ for (pos=addr, c=0, column=0; column<TGA_COLUMNS; column++, c+=8, pos+=24)
+ {
+ if(pos + 24 > 0x100000)
+ return;
+ for(xi=0,xm=0;xi<8;xi++,xm+=3)
+ {
+ int r,g,b;
+
+ if(!machine.primary_screen->visible_area().contains(c+xi, line + yi))
+ continue;
+
+ r = (MD(pos+xm)&0xff0000)>>16;
+ g = (MD(pos+xm)&0x00ff00)>>8;
+ b = (MD(pos+xm)&0x0000ff)>>0;
+ bitmapline[c+xi] = IV|(r<<16)|(g<<8)|(b<<0);
+ }
+ }
+ }
+}
+
+static void svga_vh_rgb32(running_machine &machine, bitmap_rgb32 &bitmap, const rectangle &cliprect)
+{
+ #define MD(x) (vga.memory[x]+(vga.memory[x+1]<<8)+(vga.memory[x+2]<<16))
+ #define ID 0xff000000
+ int height = vga.crtc.maximum_scan_line * (vga.crtc.scan_doubling + 1);
+ int xi;
+ int yi;
+ int xm;
+ int pos, line, column, c, addr, curr_addr;
+ UINT32 *bitmapline;
+
+// UINT16 mask_comp;
+
+ /* line compare is screen sensitive */
+// mask_comp = 0xff | (TLINES & 0x300);
+ curr_addr = 0;
+ yi=0;
+ for (addr = TGA_START_ADDRESS, line=0; line<TLINES; line+=height, addr+=(vga.crtc.offset * 4), curr_addr+=(vga.crtc.offset * 4))
+ {
+ bitmapline = &bitmap.pix32(line);
+ addr %= vga.svga_intf.vram_size;
+ for (pos=addr, c=0, column=0; column<TGA_COLUMNS; column++, c+=8, pos+=0x20)
+ {
+ if(pos + 0x20 > 0x100000)
+ return;
+ for(xi=0,xm=0;xi<8;xi++,xm+=4)
+ {
+ int r,g,b;
+
+ if(!machine.primary_screen->visible_area().contains(c+xi, line + yi))
+ continue;
+
+ r = (MD(pos+xm)&0xff0000)>>16;
+ g = (MD(pos+xm)&0x00ff00)>>8;
+ b = (MD(pos+xm)&0x0000ff)>>0;
+ bitmapline[c+xi] = IV|(r<<16)|(g<<8)|(b<<0);
+ }
+ }
+ }
+}
+
+enum
+{
+ SCREEN_OFF = 0,
+ TEXT_MODE,
+ VGA_MODE,
+ EGA_MODE,
+ CGA_MODE,
+ MONO_MODE,
+ RGB8_MODE,
+ RGB15_MODE,
+ RGB16_MODE,
+ RGB24_MODE,
+ RGB32_MODE,
+ SVGA_HACK
+};
+
+
+static UINT8 pc_vga_choosevideomode(running_machine &machine)
+{
+ int i;
+
+ if (vga.crtc.sync_en)
+ {
+ if (vga.dac.dirty)
+ {
+ for (i=0; i<256;i++)
+ {
+ palette_set_color_rgb(machine, i,(vga.dac.color[i].red & 0x3f) << 2,
+ (vga.dac.color[i].green & 0x3f) << 2,
+ (vga.dac.color[i].blue & 0x3f) << 2);
+ }
+ vga.dac.dirty = 0;
+ }
+
+ if (vga.attribute.data[0x10] & 0x80)
+ {
+ for (i=0; i<16;i++)
+ {
+ vga.pens[i] = machine.pens[(vga.attribute.data[i]&0x0f)
+ |((vga.attribute.data[0x14]&0xf)<<4)];
+ }
+ }
+ else
+ {
+ for (i=0; i<16;i++)
+ {
+ vga.pens[i]=machine.pens[(vga.attribute.data[i]&0x3f)
+ |((vga.attribute.data[0x14]&0xc)<<4)];
+ }
+ }
+
+ if (vga.svga_intf.choosevideomode) // TODO: remove this hack
+ {
+ return SVGA_HACK;
+ }
+ else if (svga.rgb32_en)
+ {
+ return RGB32_MODE;
+ }
+ else if (svga.rgb24_en)
+ {
+ return RGB24_MODE;
+ }
+ else if (svga.rgb16_en)
+ {
+ return RGB16_MODE;
+ }
+ else if (svga.rgb15_en)
+ {
+ return RGB15_MODE;
+ }
+ else if (svga.rgb8_en)
+ {
+ return RGB8_MODE;
+ }
+ else if (!GRAPHIC_MODE)
+ {
+ //proc = vga_vh_text;
+ //*height = TEXT_LINES;
+ //*width = TEXT_COLUMNS * CHAR_WIDTH;
+
+ return TEXT_MODE;
+ }
+ else if (vga.gc.shift256)
+ {
+ //proc = vga_vh_vga;
+ //*height = LINES;
+ //*width = VGA_COLUMNS * 8;
+ return VGA_MODE;
+ }
+ else if (vga.gc.shift_reg)
+ {
+ // cga
+ return CGA_MODE;
+ }
+ else if (vga.gc.memory_map_sel == 0x03)
+ {
+ // mono
+ return MONO_MODE;
+ }
+ else
+ {
+ //proc = vga_vh_ega;
+ //*height = LINES;
+ //*width = EGA_COLUMNS * 8;
+ return EGA_MODE;
+ }
+ }
+
+ return SCREEN_OFF;
+}
+
+SCREEN_UPDATE_RGB32( pc_video )
+{
+ UINT8 cur_mode = 0;
+ int w = 0, h = 0;
+
+ cur_mode = pc_vga_choosevideomode(screen.machine());
+
+ //popmessage("%02x %02x",cur_mode,vga.attribute.data[0x13]);
+ //popmessage("%d",vga.attribute.pel_shift);
+ //popmessage("%d %d %d",vga.crtc.vert_blank_start,vga.crtc.vert_blank_end,vga.crtc.vert_total);
+
+ switch(cur_mode)
+ {
+ case SCREEN_OFF: bitmap.fill (get_black_pen(screen.machine()), cliprect);break;
+ case TEXT_MODE: vga_vh_text (screen.machine(), bitmap, cliprect); break;
+ case VGA_MODE: vga_vh_vga (screen.machine(), bitmap, cliprect); break;
+ case EGA_MODE: vga_vh_ega (screen.machine(), bitmap, cliprect); break;
+ case CGA_MODE: vga_vh_cga (screen.machine(), bitmap, cliprect); break;
+ case MONO_MODE: vga_vh_mono (screen.machine(), bitmap, cliprect); break;
+ case RGB8_MODE: svga_vh_rgb8 (screen.machine(), bitmap, cliprect); break;
+ case RGB15_MODE: svga_vh_rgb15(screen.machine(), bitmap, cliprect); break;
+ case RGB16_MODE: svga_vh_rgb16(screen.machine(), bitmap, cliprect); break;
+ case RGB24_MODE: svga_vh_rgb24(screen.machine(), bitmap, cliprect); break;
+ case RGB32_MODE: svga_vh_rgb32(screen.machine(), bitmap, cliprect); break;
+ case SVGA_HACK: vga.svga_intf.choosevideomode(screen.machine(), bitmap, cliprect, vga.sequencer.data, vga.crtc.data, &w, &h); break;
+ }
+
+ return 0;
+}
+/***************************************************************************/
+
+INLINE UINT8 rotate_right(UINT8 val)
+{
+ return (val >> vga.gc.rotate_count) | (val << (8 - vga.gc.rotate_count));
+}
+
+INLINE UINT8 vga_logical_op(UINT8 data, UINT8 plane, UINT8 mask)
+{
+ UINT8 res = 0;
+
+ switch(vga.gc.logical_op & 3)
+ {
+ case 0: /* NONE */
+ res = (data & mask) | (vga.gc.latch[plane] & ~mask);
+ break;
+ case 1: /* AND */
+ res = (data | ~mask) & (vga.gc.latch[plane]);
+ break;
+ case 2: /* OR */
+ res = (data & mask) | (vga.gc.latch[plane]);
+ break;
+ case 3: /* XOR */
+ res = (data & mask) ^ (vga.gc.latch[plane]);
+ break;
+ }
+
+ return res;
+}
+
+INLINE UINT8 vga_latch_write(int offs, UINT8 data)
+{
+ UINT8 res = 0;
+
+ switch (vga.gc.write_mode & 3) {
+ case 0:
+ data = rotate_right(data);
+ if(vga.gc.enable_set_reset & 1<<offs)
+ res = vga_logical_op((vga.gc.set_reset & 1<<offs) ? vga.gc.bit_mask : 0, offs,vga.gc.bit_mask);
+ else
+ res = vga_logical_op(data, offs, vga.gc.bit_mask);
+ break;
+ case 1:
+ res = vga.gc.latch[offs];
+ break;
+ case 2:
+ res = vga_logical_op((data & 1<<offs) ? 0xff : 0x00,offs,vga.gc.bit_mask);
+ break;
+ case 3:
+ data = rotate_right(data);
+ res = vga_logical_op((vga.gc.set_reset & 1<<offs) ? 0xff : 0x00,offs,data&vga.gc.bit_mask);
+ break;
+ }
+
+ return res;
+}
+
+static UINT8 crtc_reg_read(UINT8 index)
+{
+ UINT8 res;
+
+ res = 0xff;
+
+ switch(index)
+ {
+ case 0x00:
+ res = vga.crtc.horz_total & 0xff;
+ break;
+ case 0x01:
+ res = vga.crtc.horz_disp_end & 0xff;
+ break;
+ case 0x02:
+ res = vga.crtc.horz_blank_start & 0xff;
+ break;
+ case 0x03:
+ res = vga.crtc.horz_blank_end & 0x1f;
+ res |= (vga.crtc.disp_enable_skew & 3) << 5;
+ res |= (vga.crtc.evra & 1) << 7;
+ break;
+ case 0x04:
+ res = vga.crtc.horz_retrace_start & 0xff;
+ break;
+ case 0x05:
+ res = (vga.crtc.horz_blank_end & 0x20) << 2;
+ res |= (vga.crtc.horz_retrace_skew & 3) << 5;
+ res |= (vga.crtc.horz_retrace_end & 0x1f);
+ break;
+ case 0x06:
+ res = vga.crtc.vert_total & 0xff;
+ break;
+ case 0x07: // Overflow Register
+ res = (vga.crtc.line_compare & 0x100) >> 4;
+ res |= (vga.crtc.vert_retrace_start & 0x200) >> 2;
+ res |= (vga.crtc.vert_disp_end & 0x200) >> 3;
+ res |= (vga.crtc.vert_retrace_start & 0x200) >> 6;
+ res |= (vga.crtc.vert_total & 0x200) >> 4;
+ res |= (vga.crtc.vert_blank_start & 0x100) >> 5;
+ res |= (vga.crtc.vert_retrace_start & 0x100) >> 6;
+ res |= (vga.crtc.vert_disp_end & 0x100) >> 7;
+ res |= (vga.crtc.vert_total & 0x100) >> 8;
+ break;
+ case 0x08: // Preset Row Scan Register
+ res = (vga.crtc.byte_panning & 3) << 5;
+ res |= (vga.crtc.preset_row_scan & 0x1f);
+ break;
+ case 0x09: // Maximum Scan Line Register
+ res = (vga.crtc.maximum_scan_line & 0x1f) - 1;
+ res |= (vga.crtc.scan_doubling & 1) << 7;
+ res |= (vga.crtc.line_compare & 0x200) >> 3;
+ res |= (vga.crtc.vert_blank_start & 0x200) >> 4;
+ break;
+ case 0x0a:
+ res = (vga.crtc.cursor_scan_start & 0x1f);
+ res |= ((vga.crtc.cursor_enable & 1) ^ 1) << 5;
+ break;
+ case 0x0b:
+ res = (vga.crtc.cursor_skew & 3) << 5;
+ res |= (vga.crtc.cursor_scan_end & 0x1f);
+ break;
+ case 0x0c:
+ case 0x0d:
+ res = (vga.crtc.start_addr >> ((index & 1) ^ 1)*8) & 0xff;
+ break;
+ case 0x0e:
+ case 0x0f:
+ res = (vga.crtc.cursor_addr >> ((index & 1) ^ 1)*8) & 0xff;
+ break;
+ case 0x10:
+ res = vga.crtc.vert_retrace_start & 0xff;
+ break;
+ case 0x11:
+ res = (vga.crtc.protect_enable & 1) << 7;
+ res |= (vga.crtc.bandwidth & 1) << 6;
+ res |= (vga.crtc.vert_retrace_end & 0xf);
+ break;
+ case 0x12:
+ res = vga.crtc.vert_disp_end & 0xff;
+ break;
+ case 0x13:
+ res = vga.crtc.offset & 0xff;
+ break;
+ case 0x14:
+ res = (vga.crtc.dw & 1) << 6;
+ res |= (vga.crtc.div4 & 1) << 5;
+ res |= (vga.crtc.underline_loc & 0x1f);
+ break;
+ case 0x15:
+ res = vga.crtc.vert_blank_start & 0xff;
+ break;
+ case 0x16:
+ res = vga.crtc.vert_blank_end & 0x7f;
+ break;
+ case 0x17:
+ res = (vga.crtc.sync_en & 1) << 7;
+ res |= (vga.crtc.word_mode & 1) << 6;
+ res |= (vga.crtc.aw & 1) << 5;
+ res |= (vga.crtc.div2 & 1) << 3;
+ res |= (vga.crtc.sldiv & 1) << 2;
+ res |= (vga.crtc.map14 & 1) << 1;
+ res |= (vga.crtc.map13 & 1) << 0;
+ break;
+ case 0x18:
+ res = vga.crtc.line_compare & 0xff;
+ break;
+ default:
+ printf("Unhandled CRTC reg r %02x\n",index);
+ break;
+ }
+
+ return res;
+}
+
+static void recompute_params_clock(running_machine &machine, int divisor, int xtal)
+{
+ int vblank_period,hblank_period;
+ attoseconds_t refresh;
+ UINT8 hclock_m = (!GRAPHIC_MODE) ? CHAR_WIDTH : 8;
+ int pixel_clock;
+
+ /* safety check */
+ if(!vga.crtc.horz_disp_end || !vga.crtc.vert_disp_end || !vga.crtc.horz_total || !vga.crtc.vert_total)
+ return;
+
+ rectangle visarea(0, ((vga.crtc.horz_disp_end + 1) * ((float)(hclock_m)/divisor))-1, 0, vga.crtc.vert_disp_end);
+
+ vblank_period = (vga.crtc.vert_total + 2);
+ hblank_period = ((vga.crtc.horz_total + 5) * ((float)(hclock_m)/divisor));
+
+ /* TODO: 10b and 11b settings aren't known */
+ pixel_clock = xtal / (((vga.sequencer.data[1]&8) >> 3) + 1);
+
+ refresh = HZ_TO_ATTOSECONDS(pixel_clock) * (hblank_period) * vblank_period;
+
+ machine.primary_screen->configure((hblank_period), (vblank_period), visarea, refresh );
+// popmessage("%d %d\n",vga.crtc.horz_total * 8,vga.crtc.vert_total);
+}
+
+static void recompute_params(running_machine &machine)
+{
+ recompute_params_clock(machine, 1, (vga.miscellaneous_output & 0xc) ? XTAL_28_63636MHz : XTAL_25_1748MHz);
+ if(vga.miscellaneous_output & 8)
+ logerror("Warning: VGA external clock latch selected\n");
+}
+
+static void crtc_reg_write(running_machine &machine, UINT8 index, UINT8 data)
+{
+ /* Doom does this */
+// if(vga.crtc.protect_enable && index <= 0x07)
+// printf("write to protected address %02x\n",index);
+
+ switch(index)
+ {
+ case 0x00:
+ if(vga.crtc.protect_enable)
+ break;
+ vga.crtc.horz_total = (vga.crtc.horz_total & ~0xff) | (data & 0xff);
+ recompute_params(machine);
+ break;
+ case 0x01:
+ if(vga.crtc.protect_enable)
+ break;
+ vga.crtc.horz_disp_end = (data & 0xff);
+ recompute_params(machine);
+ break;
+ case 0x02:
+ if(vga.crtc.protect_enable)
+ break;
+ vga.crtc.horz_blank_start = (data & 0xff);
+ break;
+ case 0x03:
+ if(vga.crtc.protect_enable)
+ break;
+ vga.crtc.horz_blank_end &= ~0x1f;
+ vga.crtc.horz_blank_end |= data & 0x1f;
+ vga.crtc.disp_enable_skew = (data & 0x60) >> 5;
+ vga.crtc.evra = (data & 0x80) >> 7;
+ break;
+ case 0x04:
+ if(vga.crtc.protect_enable)
+ break;
+ vga.crtc.horz_retrace_start = data & 0xff;
+ break;
+ case 0x05:
+ if(vga.crtc.protect_enable)
+ break;
+ vga.crtc.horz_blank_end &= ~0x20;
+ vga.crtc.horz_blank_end |= ((data & 0x80) >> 2);
+ vga.crtc.horz_retrace_skew = ((data & 0x60) >> 5);
+ vga.crtc.horz_retrace_end = data & 0x1f;
+ break;
+ case 0x06:
+ if(vga.crtc.protect_enable)
+ break;
+ vga.crtc.vert_total &= ~0xff;
+ vga.crtc.vert_total |= data & 0xff;
+ recompute_params(machine);
+ break;
+ case 0x07: // Overflow Register
+ vga.crtc.line_compare &= ~0x100;
+ vga.crtc.line_compare |= ((data & 0x10) << (8-4));
+ if(vga.crtc.protect_enable)
+ break;
+ vga.crtc.vert_total &= ~0x300;
+ vga.crtc.vert_retrace_start &= ~0x300;
+ vga.crtc.vert_disp_end &= ~0x300;
+ vga.crtc.vert_blank_start &= ~0x100;
+ vga.crtc.vert_retrace_start |= ((data & 0x80) << (9-7));
+ vga.crtc.vert_disp_end |= ((data & 0x40) << (9-6));
+ vga.crtc.vert_total |= ((data & 0x20) << (9-5));
+ vga.crtc.vert_blank_start |= ((data & 0x08) << (8-3));
+ vga.crtc.vert_retrace_start |= ((data & 0x04) << (8-2));
+ vga.crtc.vert_disp_end |= ((data & 0x02) << (8-1));
+ vga.crtc.vert_total |= ((data & 0x01) << (8-0));
+ recompute_params(machine);
+ break;
+ case 0x08: // Preset Row Scan Register
+ vga.crtc.byte_panning = (data & 0x60) >> 5;
+ vga.crtc.preset_row_scan = (data & 0x1f);
+ break;
+ case 0x09: // Maximum Scan Line Register
+ vga.crtc.line_compare &= ~0x200;
+ vga.crtc.vert_blank_start &= ~0x200;
+ vga.crtc.scan_doubling = ((data & 0x80) >> 7);
+ vga.crtc.line_compare |= ((data & 0x40) << (9-6));
+ vga.crtc.vert_blank_start |= ((data & 0x20) << (9-5));
+ vga.crtc.maximum_scan_line = (data & 0x1f) + 1;
+ break;
+ case 0x0a:
+ vga.crtc.cursor_enable = ((data & 0x20) ^ 0x20) >> 5;
+ vga.crtc.cursor_scan_start = data & 0x1f;
+ break;
+ case 0x0b:
+ vga.crtc.cursor_skew = (data & 0x60) >> 5;
+ vga.crtc.cursor_scan_end = data & 0x1f;
+ break;
+ case 0x0c:
+ case 0x0d:
+ vga.crtc.start_addr &= ~(0xff << (((index & 1)^1) * 8));
+ vga.crtc.start_addr |= (data << (((index & 1)^1) * 8));
+ break;
+ case 0x0e:
+ case 0x0f:
+ vga.crtc.cursor_addr &= ~(0xff << (((index & 1)^1) * 8));
+ vga.crtc.cursor_addr |= (data << (((index & 1)^1) * 8));
+ break;
+ case 0x10:
+ vga.crtc.vert_retrace_start &= ~0xff;
+ vga.crtc.vert_retrace_start |= data & 0xff;
+ break;
+ case 0x11:
+ vga.crtc.protect_enable = (data & 0x80) >> 7;
+ vga.crtc.bandwidth = (data & 0x40) >> 6;
+ vga.crtc.vert_retrace_end = data & 0x0f;
+ break;
+ case 0x12:
+ vga.crtc.vert_disp_end &= ~0xff;
+ vga.crtc.vert_disp_end |= data & 0xff;
+ recompute_params(machine);
+ break;
+ case 0x13:
+ vga.crtc.offset = data & 0xff;
+ break;
+ case 0x14:
+ vga.crtc.dw = (data & 0x40) >> 6;
+ vga.crtc.div4 = (data & 0x20) >> 5;
+ vga.crtc.underline_loc = (data & 0x1f);
+ break;
+ case 0x15:
+ vga.crtc.vert_blank_start &= ~0xff;
+ vga.crtc.vert_blank_start |= data & 0xff;
+ break;
+ case 0x16:
+ vga.crtc.vert_blank_end = data & 0x7f;
+ break;
+ case 0x17:
+ vga.crtc.sync_en = (data & 0x80) >> 7;
+ vga.crtc.word_mode = (data & 0x40) >> 6;
+ vga.crtc.aw = (data & 0x20) >> 5;
+ vga.crtc.div2 = (data & 0x08) >> 3;
+ vga.crtc.sldiv = (data & 0x04) >> 2;
+ vga.crtc.map14 = (data & 0x02) >> 1;
+ vga.crtc.map13 = (data & 0x01) >> 0;
+ break;
+ case 0x18:
+ vga.crtc.line_compare &= ~0xff;
+ vga.crtc.line_compare |= data & 0xff;
+ break;
+ default:
+ logerror("Unhandled CRTC reg w %02x %02x\n",index,data);
+ break;
+ }
+}
+
+static void seq_reg_write(running_machine &machine, UINT8 index, UINT8 data)
+{
+ switch(index)
+ {
+ case 0x02:
+ vga.sequencer.map_mask = data & 0xf;
+ break;
+ case 0x03:
+ /* --2- 84-- character select A
+ ---2 --84 character select B */
+ vga.sequencer.char_sel.A = (((data & 0xc) >> 2)<<1) | ((data & 0x20) >> 5);
+ vga.sequencer.char_sel.B = (((data & 0x3) >> 0)<<1) | ((data & 0x10) >> 4);
+ if(data)
+ popmessage("Char SEL checker, contact MAMEdev (%02x %02x)\n",vga.sequencer.char_sel.A,vga.sequencer.char_sel.B);
+ break;
+ }
+}
+
+static UINT8 vga_vblank(running_machine &machine)
+{
+ UINT8 res;
+ UINT16 vblank_start,vblank_end,vpos;
+
+ /* calculate vblank start / end positions */
+ res = 0;
+ vblank_start = vga.crtc.vert_blank_start;
+ vblank_end = vga.crtc.vert_blank_start + vga.crtc.vert_blank_end;
+ vpos = machine.primary_screen->vpos();
+
+ /* check if we are under vblank period */
+ if(vblank_end > vga.crtc.vert_total)
+ {
+ vblank_end -= vga.crtc.vert_total;
+ if(vpos >= vblank_start || vpos < vblank_end)
+ res = 1;
+ }
+ else
+ {
+ if(vpos >= vblank_start && vpos < vblank_end)
+ res = 1;
+ }
+
+// popmessage("%d %d %d",vblank_start,vblank_end,vga.crtc.vert_total);
+
+ return res;
+}
+
+static READ8_HANDLER(vga_crtc_r)
+{
+ UINT8 data = 0xff;
+
+ switch (offset) {
+ case 4:
+ data = vga.crtc.index;
+ break;
+ case 5:
+ data = crtc_reg_read(vga.crtc.index);
+ break;
+ case 0xa:
+ UINT8 hsync,vsync;
+ vga.attribute.state = 0;
+ data = 0;
+
+ hsync = space->machine().primary_screen->hblank() & 1;
+ vsync = vga_vblank(space->machine()); //space->machine().primary_screen->vblank() & 1;
+
+ data |= (hsync | vsync) & 1; // DD - display disable register
+ data |= (vsync & 1) << 3; // VRetrace register
+
+ /* ega diagnostic readback enough for oak bios */
+ switch (vga.attribute.data[0x12]&0x30) {
+ case 0:
+ if (vga.attribute.data[0x11]&1) data|=0x10;
+ if (vga.attribute.data[0x11]&4) data|=0x20;
+ break;
+ case 0x10:
+ data|=(vga.attribute.data[0x11]&0x30);
+ break;
+ case 0x20:
+ if (vga.attribute.data[0x11]&2) data|=0x10;
+ if (vga.attribute.data[0x11]&8) data|=0x20;
+ break;
+ case 0x30:
+ data|=(vga.attribute.data[0x11]&0xc0)>>2;
+ break;
+ }
+ break;
+ case 0xf:
+ /* oak test */
+ //data=0;
+ /* pega bios on/off */
+ data=0x80;
+ break;
+ }
+ return data;
+}
+
+static WRITE8_HANDLER(vga_crtc_w)
+{
+ switch (offset)
+ {
+ case 4:
+ vga.crtc.index = data;
+ break;
+
+ case 5:
+ if (LOG_REGISTERS)
+ {
+ logerror("vga_crtc_w(): CRTC[0x%02X%s] = 0x%02X\n",
+ vga.crtc.index,
+ (vga.crtc.index < vga.svga_intf.crtc_regcount) ? "" : "?",
+ data);
+ }
+
+ crtc_reg_write(space->machine(),vga.crtc.index,data);
+ //space->machine().primary_screen->update_partial(space->machine().primary_screen->vpos());
+ #if 0
+ if((vga.crtc.index & 0xfe) != 0x0e)
+ printf("%02x %02x %d\n",vga.crtc.index,data,space->machine().primary_screen->vpos());
+ #endif
+ break;
+
+ case 0xa:
+ vga.feature_control = data;
+ break;
+ }
+}
+
+
+
+READ8_HANDLER( vga_port_03b0_r )
+{
+ UINT8 data = 0xff;
+ if (CRTC_PORT_ADDR==0x3b0)
+ data=vga_crtc_r(space, offset);
+ return data;
+}
+
+static UINT8 gc_reg_read(running_machine &machine,UINT8 index)
+{
+ UINT8 res;
+
+ switch(index)
+ {
+ case 0x00:
+ res = vga.gc.set_reset & 0xf;
+ break;
+ case 0x01:
+ res = vga.gc.enable_set_reset & 0xf;
+ break;
+ case 0x02:
+ res = vga.gc.color_compare & 0xf;
+ break;
+ case 0x03:
+ res = (vga.gc.logical_op & 3) << 3;
+ res |= (vga.gc.rotate_count & 7);
+ break;
+ case 0x04:
+ res = vga.gc.read_map_sel & 3;
+ break;
+ case 0x05:
+ res = (vga.gc.shift256 & 1) << 6;
+ res |= (vga.gc.shift_reg & 1) << 5;;
+ res |= (vga.gc.host_oe & 1) << 4;
+ res |= (vga.gc.read_mode & 1) << 3;
+ res |= (vga.gc.write_mode & 3);
+ break;
+ case 0x06:
+ res = (vga.gc.memory_map_sel & 3) << 2;
+ res |= (vga.gc.chain_oe & 1) << 1;
+ res |= (vga.gc.alpha_dis & 1);
+ break;
+ case 0x07:
+ res = vga.gc.color_dont_care & 0xf;
+ break;
+ case 0x08:
+ res = vga.gc.bit_mask & 0xff;
+ break;
+ default:
+ res = 0xff;
+ break;
+ }
+
+ return res;
+}
+
+READ8_HANDLER( vga_port_03c0_r )
+{
+ UINT8 data = 0xff;
+
+ switch (offset)
+ {
+ case 0:
+ data = vga.attribute.index;
+ break;
+ case 1:
+ if(vga.attribute.index&0x20)
+ data = vga.attribute.index; // TODO: open bus
+ else if ((vga.attribute.index&0x1f)<sizeof(vga.attribute.data))
+ data=vga.attribute.data[vga.attribute.index&0x1f];
+ break;
+
+ case 2:
+ // TODO: in VGA bit 4 is actually always on?
+ data = 0x60; // is VGA
+ switch ((vga.miscellaneous_output>>2)&3)
+ {
+ case 3:
+ if (vga.read_dipswitch && vga.read_dipswitch(space, 0) & 0x01)
+ data |= 0x10;
+ break;
+ case 2:
+ if (vga.read_dipswitch && vga.read_dipswitch(space, 0) & 0x02)
+ data |= 0x10;
+ break;
+ case 1:
+ if (vga.read_dipswitch && vga.read_dipswitch(space, 0) & 0x04)
+ data |= 0x10;
+ break;
+ case 0:
+ if (vga.read_dipswitch && vga.read_dipswitch(space, 0) & 0x08)
+ data |= 0x10;
+ break;
+ }
+ break;
+
+ case 3:
+ data = vga.oak.reg;
+ break;
+
+ case 4:
+ data = vga.sequencer.index;
+ break;
+
+ case 5:
+ if (vga.sequencer.index < vga.svga_intf.seq_regcount)
+ data = vga.sequencer.data[vga.sequencer.index];
+ break;
+
+ case 6:
+ data = vga.dac.mask;
+ break;
+
+ case 7:
+ data = (vga.dac.read) ? 3 : 0;
+ break;
+
+ case 8:
+ data = vga.dac.write_index;
+ break;
+
+ case 9:
+ if (vga.dac.read)
+ {
+ switch (vga.dac.state++)
+ {
+ case 0:
+ data = vga.dac.color[vga.dac.read_index].red;
+ break;
+ case 1:
+ data = vga.dac.color[vga.dac.read_index].green;
+ break;
+ case 2:
+ data = vga.dac.color[vga.dac.read_index].blue;
+ break;
+ }
+
+ if (vga.dac.state==3)
+ {
+ vga.dac.state = 0;
+ vga.dac.read_index++;
+ }
+ }
+ break;
+
+ case 0xa:
+ data = vga.feature_control;
+ break;
+
+ case 0xc:
+ data = vga.miscellaneous_output;
+ break;
+
+ case 0xe:
+ data = vga.gc.index;
+ break;
+
+ case 0xf:
+ data = gc_reg_read(space->machine(),vga.gc.index);
+ break;
+ }
+ return data;
+}
+
+READ8_HANDLER(vga_port_03d0_r)
+{
+ UINT8 data = 0xff;
+ if (CRTC_PORT_ADDR == 0x3d0)
+ data = vga_crtc_r(space, offset);
+ if(offset == 8)
+ {
+ logerror("VGA: 0x3d8 read at %08x\n",cpu_get_pc(&space->device()));
+ data = 0; // TODO: PC-200 reads back CGA register here, everything else returns open bus OR CGA emulation of register 0x3d8
+ }
+
+ return data;
+}
+
+WRITE8_HANDLER( vga_port_03b0_w )
+{
+ if (LOG_ACCESSES)
+ logerror("vga_port_03b0_w(): port=0x%04x data=0x%02x\n", offset + 0x3b0, data);
+
+ if (CRTC_PORT_ADDR == 0x3b0)
+ vga_crtc_w(space, offset, data);
+}
+
+static void attribute_reg_write(UINT8 index, UINT8 data)
+{
+ if((index & 0x30) == 0)
+ {
+ //if(vga.sequencer.data[1]&0x20) // ok?
+ vga.attribute.data[index & 0x1f] = data & 0x3f;
+ }
+ else
+ {
+ switch(index & 0x1f)
+ {
+ /* TODO: intentional dirtiness, variable names to be properly changed */
+ case 0x10: vga.attribute.data[0x10] = data; break;
+ case 0x11: vga.attribute.data[0x11] = data; break;
+ case 0x12: vga.attribute.data[0x12] = data; break;
+ case 0x13: vga.attribute.pel_shift = vga.attribute.data[0x13] = data; break;
+ case 0x14: vga.attribute.data[0x14] = data; break;
+ }
+ }
+}
+
+static void gc_reg_write(running_machine &machine,UINT8 index,UINT8 data)
+{
+ switch(index)
+ {
+ case 0x00:
+ vga.gc.set_reset = data & 0xf;
+ break;
+ case 0x01:
+ vga.gc.enable_set_reset = data & 0xf;
+ break;
+ case 0x02:
+ vga.gc.color_compare = data & 0xf;
+ break;
+ case 0x03:
+ vga.gc.logical_op = (data & 0x18) >> 3;
+ vga.gc.rotate_count = data & 7;
+ break;
+ case 0x04:
+ vga.gc.read_map_sel = data & 3;
+ break;
+ case 0x05:
+ vga.gc.shift256 = (data & 0x40) >> 6;
+ vga.gc.shift_reg = (data & 0x20) >> 5;
+ vga.gc.host_oe = (data & 0x10) >> 4;
+ vga.gc.read_mode = (data & 8) >> 3;
+ vga.gc.write_mode = data & 3;
+ //if(data & 0x10 && vga.gc.alpha_dis)
+ // popmessage("Host O/E enabled, contact MAMEdev");
+ break;
+ case 0x06:
+ vga.gc.memory_map_sel = (data & 0xc) >> 2;
+ vga.gc.chain_oe = (data & 2) >> 1;
+ vga.gc.alpha_dis = (data & 1);
+ //if(data & 2 && vga.gc.alpha_dis)
+ // popmessage("Chain O/E enabled, contact MAMEdev");
+ break;
+ case 0x07:
+ vga.gc.color_dont_care = data & 0xf;
+ break;
+ case 0x08:
+ vga.gc.bit_mask = data & 0xff;
+ break;
+ }
+}
+
+WRITE8_HANDLER(vga_port_03c0_w)
+{
+ if (LOG_ACCESSES)
+ logerror("vga_port_03c0_w(): port=0x%04x data=0x%02x\n", offset + 0x3c0, data);
+
+ switch (offset) {
+ case 0:
+ if (vga.attribute.state==0)
+ {
+ vga.attribute.index=data;
+ }
+ else
+ {
+ attribute_reg_write(vga.attribute.index,data);
+ }
+ vga.attribute.state=!vga.attribute.state;
+ break;
+ case 2:
+ vga.miscellaneous_output=data;
+ recompute_params(space->machine());
+ break;
+ case 3:
+ vga.oak.reg = data;
+ break;
+ case 4:
+ vga.sequencer.index = data;
+ break;
+ case 5:
+ if (LOG_REGISTERS)
+ {
+ logerror("vga_port_03c0_w(): SEQ[0x%02X%s] = 0x%02X\n",
+ vga.sequencer.index,
+ (vga.sequencer.index < vga.svga_intf.seq_regcount) ? "" : "?",
+ data);
+ }
+ if (vga.sequencer.index < vga.svga_intf.seq_regcount)
+ {
+ vga.sequencer.data[vga.sequencer.index] = data;
+ }
+
+ seq_reg_write(space->machine(),vga.sequencer.index,data);
+ recompute_params(space->machine());
+ break;
+ case 6:
+ vga.dac.mask=data;
+ break;
+ case 7:
+ vga.dac.read_index=data;
+ vga.dac.state=0;
+ vga.dac.read=1;
+ break;
+ case 8:
+ vga.dac.write_index=data;
+ vga.dac.state=0;
+ vga.dac.read=0;
+ break;
+ case 9:
+ if (!vga.dac.read)
+ {
+ switch (vga.dac.state++) {
+ case 0:
+ vga.dac.color[vga.dac.write_index].red=data;
+ break;
+ case 1:
+ vga.dac.color[vga.dac.write_index].green=data;
+ break;
+ case 2:
+ vga.dac.color[vga.dac.write_index].blue=data;
+ break;
+ }
+ vga.dac.dirty=1;
+ if (vga.dac.state==3) {
+ vga.dac.state=0; vga.dac.write_index++;
+ }
+ }
+ break;
+ case 0xe:
+ vga.gc.index=data;
+ break;
+ case 0xf:
+ gc_reg_write(space->machine(),vga.gc.index,data);
+ break;
+ }
+}
+
+
+
+WRITE8_HANDLER(vga_port_03d0_w)
+{
+ if (LOG_ACCESSES)
+ logerror("vga_port_03d0_w(): port=0x%04x data=0x%02x\n", offset + 0x3d0, data);
+
+ if (CRTC_PORT_ADDR == 0x3d0)
+ vga_crtc_w(space, offset, data);
+}
+
+void pc_vga_reset(running_machine &machine)
+{
+ /* clear out the VGA structure */
+ memset(vga.pens, 0, sizeof(vga.pens));
+ vga.miscellaneous_output = 0;
+ vga.feature_control = 0;
+ vga.sequencer.index = 0;
+ memset(vga.sequencer.data, 0, vga.svga_intf.seq_regcount * sizeof(*vga.sequencer.data));
+ vga.crtc.index = 0;
+ memset(vga.crtc.data, 0, vga.svga_intf.crtc_regcount * sizeof(*vga.crtc.data));
+ vga.gc.index = 0;
+ memset(vga.gc.latch, 0, sizeof(vga.gc.latch));
+ memset(&vga.attribute, 0, sizeof(vga.attribute));
+ memset(&vga.dac, 0, sizeof(vga.dac));
+ memset(&vga.cursor, 0, sizeof(vga.cursor));
+ memset(&vga.oak, 0, sizeof(vga.oak));
+
+ vga.gc.memory_map_sel = 0x3; /* prevent xtbios excepting vga ram as system ram */
+/* amstrad pc1640 bios relies on the position of
+ the video memory area,
+ so I introduced the reset to switch to b8000 area */
+ vga.sequencer.data[4] = 0;
+
+ /* TODO: real defaults */
+ vga.crtc.line_compare = 0x3ff;
+}
+
+READ8_HANDLER(vga_mem_r)
+{
+ /* TODO: check me */
+ switch(vga.gc.memory_map_sel & 0x03)
+ {
+ case 0: break;
+ case 1: offset &= 0x0ffff; break;
+ case 2: offset -= 0x10000; offset &= 0x07fff; break;
+ case 3: offset -= 0x18000; offset &= 0x07fff; break;
+ }
+
+ if(vga.sequencer.data[4] & 4)
+ {
+ int data;
+ if (!space->debugger_access())
+ {
+ vga.gc.latch[0]=vga.memory[(offset)];
+ vga.gc.latch[1]=vga.memory[(offset)+0x10000];
+ vga.gc.latch[2]=vga.memory[(offset)+0x20000];
+ vga.gc.latch[3]=vga.memory[(offset)+0x30000];
+ }
+
+ if (vga.gc.read_mode)
+ {
+ UINT8 byte,layer;
+ UINT8 fill_latch;
+ data=0;
+
+ for(byte=0;byte<8;byte++)
+ {
+ fill_latch = 0;
+ for(layer=0;layer<4;layer++)
+ {
+ if(vga.gc.latch[layer] & 1 << byte)
+ fill_latch |= 1 << layer;
+ }
+ fill_latch &= vga.gc.color_dont_care;
+ if(fill_latch == vga.gc.color_compare)
+ data |= 1 << byte;
+ }
+ }
+ else
+ data=vga.gc.latch[vga.gc.read_map_sel];
+
+ return data;
+ }
+ else
+ {
+ // TODO: Guesswork, probably not right
+ UINT8 i,data;
+
+ data = 0;
+ //printf("%08x\n",offset);
+
+ for(i=0;i<4;i++)
+ {
+ if(vga.sequencer.map_mask & 1 << i)
+ data |= vga.memory[offset+i*0x10000];
+ }
+
+ return data;
+ }
+
+ return 0;
+}
+
+WRITE8_HANDLER(vga_mem_w)
+{
+ //Inside each case must prevent writes to non-mapped VGA memory regions, not only mask the offset.
+ switch(vga.gc.memory_map_sel & 0x03)
+ {
+ case 0: break;
+ case 1:
+ if(offset & 0x10000)
+ return;
+
+ offset &= 0x0ffff;
+ break;
+ case 2:
+ if((offset & 0x18000) != 0x10000)
+ return;
+
+ offset &= 0x07fff;
+ break;
+ case 3:
+ if((offset & 0x18000) != 0x18000)
+ return;
+
+ offset &= 0x07fff;
+ break;
+ }
+
+ {
+ UINT8 i;
+
+ for(i=0;i<4;i++)
+ {
+ if(vga.sequencer.map_mask & 1 << i)
+ vga.memory[offset+i*0x10000] = (vga.sequencer.data[4] & 4) ? vga_latch_write(i,data) : data;
+ }
+ return;
+ }
+}
+
+void pc_vga_init(running_machine &machine, read8_space_func read_dipswitch, const struct pc_svga_interface *svga_intf)
+{
+ memset(&vga, 0, sizeof(vga));
+
+ /* copy over interfaces */
+ vga.read_dipswitch = read_dipswitch;
+ if (svga_intf)
+ {
+ vga.svga_intf = *svga_intf;
+
+ if (vga.svga_intf.seq_regcount < 0x05)
+ fatalerror("Invalid SVGA sequencer register count");
+ if (vga.svga_intf.crtc_regcount < 0x19)
+ fatalerror("Invalid SVGA CRTC register count");
+ }
+ else
+ {
+ vga.svga_intf.vram_size = 0x100000;
+ vga.svga_intf.seq_regcount = 0x05;
+ vga.svga_intf.crtc_regcount = 0x19;
+ }
+
+ vga.memory = auto_alloc_array(machine, UINT8, vga.svga_intf.vram_size);
+ vga.sequencer.data = auto_alloc_array(machine, UINT8, vga.svga_intf.seq_regcount);
+ vga.crtc.data = auto_alloc_array(machine, UINT8, 0x100);
+ memset(vga.memory, '\0', vga.svga_intf.vram_size);
+ memset(vga.sequencer.data, '\0', vga.svga_intf.seq_regcount);
+ memset(vga.crtc.data, '\0', 0x100);
+
+ pc_vga_reset(machine);
+
+}
+
+void pc_vga_io_init(running_machine &machine, address_space *mem_space, offs_t mem_offset, address_space *io_space, offs_t port_offset)
+{
+ int buswidth;
+ UINT64 mask = 0;
+
+ buswidth = machine.firstcpu->memory().space_config(AS_PROGRAM)->m_databus_width;
+ switch(buswidth)
+ {
+ case 8:
+ mask = 0;
+ break;
+
+ case 16:
+ mask = 0xffff;
+ break;
+
+ case 32:
+ mask = 0xffffffff;
+ break;
+
+ case 64:
+ mask = -1;
+ break;
+
+ default:
+ fatalerror("VGA: Bus width %d not supported", buswidth);
+ break;
+ }
+ io_space->install_legacy_readwrite_handler(port_offset + 0x3b0, port_offset + 0x3bf, FUNC(vga_port_03b0_r), FUNC(vga_port_03b0_w), mask);
+ io_space->install_legacy_readwrite_handler(port_offset + 0x3c0, port_offset + 0x3cf, FUNC(vga_port_03c0_r), FUNC(vga_port_03c0_w), mask);
+ io_space->install_legacy_readwrite_handler(port_offset + 0x3d0, port_offset + 0x3df, FUNC(vga_port_03d0_r), FUNC(vga_port_03d0_w), mask);
+
+ mem_space->install_legacy_readwrite_handler(mem_offset + 0x00000, mem_offset + 0x1ffff, FUNC(vga_mem_r), FUNC(vga_mem_w), mask);
+}
+
+VIDEO_START( vga )
+{
+ int i;
+ for (i = 0; i < 0x100; i++)
+ palette_set_color_rgb(machine, i, 0, 0, 0);
+ pc_video_start(machine);
+}
+
+static VIDEO_RESET( vga )
+{
+ pc_vga_reset(machine);
+}
+
+
+
+void *pc_vga_memory(void)
+{
+ return vga.memory;
+}
+
+size_t pc_vga_memory_size(void)
+{
+ return vga.svga_intf.vram_size;
+}
+
+MACHINE_CONFIG_FRAGMENT( pcvideo_vga )
+ MCFG_SCREEN_ADD("screen", RASTER)
+ MCFG_SCREEN_RAW_PARAMS(XTAL_25_1748MHz,900,0,640,526,0,480)
+ MCFG_SCREEN_UPDATE_STATIC(pc_video)
+
+ MCFG_PALETTE_LENGTH(0x100)
+
+ MCFG_VIDEO_START(vga)
+ MCFG_VIDEO_RESET(vga)
+MACHINE_CONFIG_END
+
+MACHINE_CONFIG_FRAGMENT( pcvideo_vga_isa )
+ MCFG_SCREEN_ADD("screen", RASTER)
+ MCFG_SCREEN_RAW_PARAMS(XTAL_25_1748MHz,900,0,640,526,0,480)
+ MCFG_SCREEN_UPDATE_STATIC(pc_video)
+
+ MCFG_PALETTE_LENGTH(0x100)
+MACHINE_CONFIG_END
+
+/******************************************
+
+Tseng ET4000k implementation
+
+******************************************/
+
+static void tseng_define_video_mode(running_machine &machine)
+{
+ int divisor;
+ int xtal = 0;
+ svga.rgb8_en = 0;
+ svga.rgb15_en = 0;
+ svga.rgb16_en = 0;
+ svga.rgb24_en = 0;
+ switch(((et4k.aux_ctrl << 1) & 4)|(vga.miscellaneous_output & 0xc)>>2)
+ {
+ case 0:
+ xtal = XTAL_25_1748MHz;
+ break;
+ case 1:
+ xtal = XTAL_28_63636MHz;
+ break;
+ case 2:
+ xtal = 16257000*2; //2xEGA clock
+ break;
+ case 3:
+ xtal = XTAL_40MHz;
+ break;
+ case 4:
+ xtal = XTAL_36MHz;
+ break;
+ case 5:
+ xtal = XTAL_45MHz;
+ break;
+ case 6:
+ xtal = 31000000;
+ break;
+ case 7:
+ xtal = 38000000;
+ break;
+ }
+ switch(et4k.dac_ctrl & 0xe0)
+ {
+ case 0xa0:
+ svga.rgb15_en = 1;
+ divisor = 2;
+ break;
+ case 0xe0:
+ svga.rgb16_en = 1;
+ divisor = 2;
+ break;
+ case 0x60:
+ svga.rgb24_en = 1;
+ divisor = 3;
+ xtal *= 2.0f/3.0f;
+ break;
+ default:
+ svga.rgb8_en = (!(vga.sequencer.data[1] & 8) && (vga.sequencer.data[4] & 8) && vga.gc.shift256 && vga.crtc.div2 && GRAPHIC_MODE);
+ divisor = 1;
+ break;
+ }
+ recompute_params_clock(machine, divisor, xtal);
+}
+
+static UINT8 tseng_crtc_reg_read(running_machine &machine, UINT8 index)
+{
+ UINT8 res;
+
+ res = 0;
+ if(index <= 0x18)
+ res = crtc_reg_read(index);
+ else
+ {
+ switch(index)
+ {
+ case 0x34:
+ res = et4k.aux_ctrl;
+ break;
+ case 0x3f:
+ res = et4k.horz_overflow;
+ break;
+ default:
+ res = vga.crtc.data[index];
+ //printf("%02x\n",index);
+ break;
+ }
+ }
+
+ return res;
+}
+
+static void tseng_crtc_reg_write(running_machine &machine, UINT8 index, UINT8 data)
+{
+ if(index <= 0x18)
+ crtc_reg_write(machine,index,data);
+ else
+ {
+ switch(index)
+ {
+ case 0x34:
+ et4k.aux_ctrl = data;
+ break;
+ case 0x3f:
+ et4k.horz_overflow = data;
+ vga.crtc.horz_total = (vga.crtc.horz_total & 0xff) | ((data & 1) << 8);
+ break;
+ default:
+ //printf("%02x %02x\n",index,data);
+ break;
+ }
+ }
+}
+
+static UINT8 tseng_seq_reg_read(running_machine &machine, UINT8 index)
+{
+ UINT8 res;
+
+ res = 0xff;
+
+ if(index <= 0x04)
+ res = vga.sequencer.data[index];
+ else
+ {
+ switch(index)
+ {
+ case 0x06:
+ case 0x07:
+ //printf("%02x\n",index);
+ break;
+ }
+ }
+
+ return res;
+}
+
+static void tseng_seq_reg_write(running_machine &machine, UINT8 index, UINT8 data)
+{
+ if(index <= 0x04)
+ {
+ vga.sequencer.data[vga.sequencer.index] = data;
+ seq_reg_write(machine,vga.sequencer.index,data);
+ }
+ else
+ {
+ switch(index)
+ {
+ case 0x06:
+ case 0x07:
+ //printf("%02x %02x\n",index,data);
+ break;
+ }
+ }
+}
+
+READ8_HANDLER(tseng_et4k_03b0_r)
+{
+ UINT8 res = 0xff;
+
+ if (CRTC_PORT_ADDR == 0x3b0)
+ {
+ switch(offset)
+ {
+ case 5:
+ res = tseng_crtc_reg_read(space->machine(),vga.crtc.index);
+ break;
+ case 8:
+ res = et4k.reg_3d8;
+ break;
+ default:
+ res = vga_port_03b0_r(space,offset);
+ break;
+ }
+ }
+
+ return res;
+}
+
+WRITE8_HANDLER(tseng_et4k_03b0_w)
+{
+ if (CRTC_PORT_ADDR == 0x3b0)
+ {
+ switch(offset)
+ {
+ case 5:
+ vga.crtc.data[vga.crtc.index] = data;
+ tseng_crtc_reg_write(space->machine(),vga.crtc.index,data);
+ break;
+ case 8:
+ et4k.reg_3d8 = data;
+ if(data == 0xa0)
+ et4k.ext_reg_ena = true;
+ else if(data == 0x29)
+ et4k.ext_reg_ena = false;
+ break;
+ default:
+ vga_port_03b0_w(space,offset,data);
+ break;
+ }
+ }
+ tseng_define_video_mode(space->machine());
+}
+
+
+READ8_HANDLER(tseng_et4k_03c0_r)
+{
+ UINT8 res;
+
+ switch(offset)
+ {
+ case 0x05:
+ res = tseng_seq_reg_read(space->machine(),vga.sequencer.index);
+ break;
+ case 0x0d:
+ res = svga.bank_w & 0xf;
+ res |= (svga.bank_r & 0xf) << 4;
+ break;
+ case 0x06:
+ if(et4k.dac_state == 4)
+ {
+ if(!et4k.dac_ctrl)
+ et4k.dac_ctrl = 0x80;
+ res = et4k.dac_ctrl;
+ break;
+ }
+ et4k.dac_state++;
+ res = vga_port_03c0_r(space,offset);
+ break;
+ case 0x08:
+ et4k.dac_state = 0;
+ default:
+ res = vga_port_03c0_r(space,offset);
+ break;
+ }
+
+ return res;
+}
+
+WRITE8_HANDLER(tseng_et4k_03c0_w)
+{
+ switch(offset)
+ {
+ case 0x05:
+ tseng_seq_reg_write(space->machine(),vga.sequencer.index,data);
+ break;
+ case 0x0d:
+ svga.bank_w = data & 0xf;
+ svga.bank_r = (data & 0xf0) >> 4;
+ break;
+ case 0x06:
+ if(et4k.dac_state == 4)
+ {
+ et4k.dac_ctrl = data;
+ break;
+ }
+ default:
+ vga_port_03c0_w(space,offset,data);
+ break;
+ }
+ tseng_define_video_mode(space->machine());
+}
+
+READ8_HANDLER(tseng_et4k_03d0_r)
+{
+ UINT8 res = 0xff;
+
+ if (CRTC_PORT_ADDR == 0x3d0)
+ {
+ switch(offset)
+ {
+ case 5:
+ res = tseng_crtc_reg_read(space->machine(),vga.crtc.index);
+ break;
+ case 8:
+ res = et4k.reg_3d8;
+ break;
+ default:
+ res = vga_port_03d0_r(space,offset);
+ break;
+ }
+ }
+
+ return res;
+}
+
+WRITE8_HANDLER(tseng_et4k_03d0_w)
+{
+ if (CRTC_PORT_ADDR == 0x3d0)
+ {
+ switch(offset)
+ {
+ case 5:
+ vga.crtc.data[vga.crtc.index] = data;
+ tseng_crtc_reg_write(space->machine(),vga.crtc.index,data);
+ //if((vga.crtc.index & 0xfe) != 0x0e)
+ // printf("%02x %02x %d\n",vga.crtc.index,data,space->machine().primary_screen->vpos());
+ break;
+ case 8:
+ et4k.reg_3d8 = data;
+ if(data == 0xa0)
+ et4k.ext_reg_ena = true;
+ else if(data == 0x29)
+ et4k.ext_reg_ena = false;
+ break;
+ default:
+ vga_port_03d0_w(space,offset,data);
+ break;
+ }
+ }
+ tseng_define_video_mode(space->machine());
+}
+
+READ8_HANDLER( tseng_mem_r )
+{
+ if(svga.rgb8_en || svga.rgb15_en || svga.rgb16_en || svga.rgb24_en)
+ {
+ offset &= 0xffff;
+ return vga.memory[(offset+svga.bank_r*0x10000)];
+ }
+
+ return vga_mem_r(space,offset);
+}
+
+WRITE8_HANDLER( tseng_mem_w )
+{
+ if(svga.rgb8_en || svga.rgb15_en || svga.rgb16_en || svga.rgb24_en)
+ {
+ offset &= 0xffff;
+ vga.memory[(offset+svga.bank_w*0x10000)] = data;
+ }
+ else
+ vga_mem_w(space,offset,data);
+}
+
+/******************************************
+
+Trident implementation
+
+******************************************/
+
+void pc_svga_trident_io_init(running_machine &machine, address_space *mem_space, offs_t mem_offset, address_space *io_space, offs_t port_offset)
+{
+ int buswidth;
+ UINT64 mask = 0;
+
+ buswidth = machine.firstcpu->memory().space_config(AS_PROGRAM)->m_databus_width;
+ switch(buswidth)
+ {
+ case 8:
+ mask = 0;
+ break;
+
+ case 16:
+ mask = 0xffff;
+ break;
+
+ case 32:
+ mask = 0xffffffff;
+ break;
+
+ case 64:
+ mask = -1;
+ break;
+
+ default:
+ fatalerror("VGA: Bus width %d not supported", buswidth);
+ break;
+ }
+ io_space->install_legacy_readwrite_handler(port_offset + 0x3b0, port_offset + 0x3bf, FUNC(vga_port_03b0_r), FUNC(vga_port_03b0_w), mask);
+ io_space->install_legacy_readwrite_handler(port_offset + 0x3c0, port_offset + 0x3cf, FUNC(trident_03c0_r), FUNC(trident_03c0_w), mask);
+ io_space->install_legacy_readwrite_handler(port_offset + 0x3d0, port_offset + 0x3df, FUNC(trident_03d0_r), FUNC(trident_03d0_w), mask);
+
+ mem_space->install_legacy_readwrite_handler(mem_offset + 0x00000, mem_offset + 0x1ffff, FUNC(trident_mem_r), FUNC(trident_mem_w), mask);
+
+ // D3h = TGUI9660XGi
+ svga.id = 0xd3; // TODO: hardcoded for California Chase
+}
+
+static UINT8 trident_seq_reg_read(running_machine &machine, UINT8 index)
+{
+ UINT8 res;
+
+ res = 0xff;
+
+ if(index <= 0x04)
+ res = vga.sequencer.data[index];
+ else
+ {
+ switch(index)
+ {
+ case 0x0b:
+ res = svga.id;
+ // TODO: new mode registers selected
+ break;
+ case 0x0d:
+ res = svga.rgb15_en;
+ break;
+ }
+ }
+
+ return res;
+}
+
+static void trident_seq_reg_write(running_machine &machine, UINT8 index, UINT8 data)
+{
+ if(index <= 0x04)
+ {
+ vga.sequencer.data[vga.sequencer.index] = data;
+ seq_reg_write(machine,vga.sequencer.index,data);
+ recompute_params(machine);
+ }
+ else
+ {
+ switch(index)
+ {
+ case 0x0b:
+ // TODO: old mode registers selected
+ break;
+ case 0x0d:
+ svga.rgb15_en = data & 0x30; // TODO: doesn't match documentation
+ break;
+ }
+ }
+}
+
+
+READ8_HANDLER(trident_03c0_r)
+{
+ UINT8 res;
+
+ switch(offset)
+ {
+ case 0x05:
+ res = trident_seq_reg_read(space->machine(),vga.sequencer.index);
+ break;
+ default:
+ res = vga_port_03c0_r(space,offset);
+ break;
+ }
+
+ return res;
+}
+
+WRITE8_HANDLER(trident_03c0_w)
+{
+ switch(offset)
+ {
+ case 0x05:
+ trident_seq_reg_write(space->machine(),vga.sequencer.index,data);
+ break;
+ default:
+ vga_port_03c0_w(space,offset,data);
+ break;
+ }
+}
+
+
+READ8_HANDLER(trident_03d0_r)
+{
+ UINT8 res = 0xff;
+
+ if (CRTC_PORT_ADDR == 0x3d0)
+ {
+ switch(offset)
+ {
+ case 8:
+ res = svga.bank_w & 0x1f; // TODO: a lot more complex than this
+ break;
+ default:
+ res = vga_port_03d0_r(space,offset);
+ break;
+ }
+ }
+
+ return res;
+}
+
+WRITE8_HANDLER(trident_03d0_w)
+{
+ if (CRTC_PORT_ADDR == 0x3d0)
+ {
+ switch(offset)
+ {
+ case 8:
+ svga.bank_w = data & 0x1f; // TODO: a lot more complex than this
+ break;
+ default:
+ vga_port_03d0_w(space,offset,data);
+ break;
+ }
+ }
+}
+
+READ8_HANDLER( trident_mem_r )
+{
+ if (svga.rgb15_en & 0x30)
+ {
+ int data;
+ if(offset & 0x10000) // TODO: old reg mode actually CAN read to the upper bank
+ return 0;
+ data=vga.memory[offset + (svga.bank_w*0x10000)];
+ return data;
+ }
+
+ return vga_mem_r(space,offset);
+}
+
+WRITE8_HANDLER( trident_mem_w )
+{
+ if (svga.rgb15_en & 0x30)
+ {
+ if(offset & 0x10000) // TODO: old reg mode actually CAN write to the upper bank
+ return;
+ vga.memory[offset + (svga.bank_w*0x10000)]= data;
+ return;
+ }
+
+ vga_mem_w(space,offset,data);
+}
+
+/******************************************
+
+S3 implementation
+
+******************************************/
+
+static UINT8 s3_crtc_reg_read(running_machine &machine, UINT8 index)
+{
+ UINT8 res;
+
+ res = 0;
+ if(index <= 0x18)
+ res = crtc_reg_read(index);
+ else
+ {
+ switch(index)
+ {
+ case 0x30: // CR30 Chip ID/REV register
+ res = 0xc0; // TODO: hardcoded to Vision 86c864
+ break;
+ case 0x31:
+ res = s3.memory_config;
+ break;
+ case 0x35:
+ res = s3.crt_reg_lock;
+ break;
+ case 0x38:
+ res = s3.reg_lock1;
+ break;
+ case 0x39:
+ res = s3.reg_lock2;
+ break;
+ case 0x42: // CR42 Mode Control
+ res = 0x0d; // hardcode to non-interlace
+ break;
+ case 0x67:
+ res = s3.ext_misc_ctrl_2;
+ break;
+ case 0x6a:
+ res = svga.bank_r & 0x7f;
+ break;
+ default:
+ res = vga.crtc.data[index];
+ //debugger_break(machine);
+ //printf("%02x\n",index);
+ break;
+ }
+ }
+
+ return res;
+}
+
+static void s3_define_video_mode(void)
+{
+ if((s3.ext_misc_ctrl_2) >> 4)
+ {
+ svga.rgb8_en = 0;
+ svga.rgb15_en = 0;
+ svga.rgb16_en = 0;
+ svga.rgb32_en = 0;
+ switch((s3.ext_misc_ctrl_2) >> 4)
+ {
+ case 0x03: svga.rgb15_en = 1; break;
+ case 0x05: svga.rgb16_en = 1; break;
+ case 0x0d: svga.rgb32_en = 1; break;
+ default: fatalerror("TODO: s3 video mode not implemented %02x",((s3.ext_misc_ctrl_2) >> 4)); break;
+ }
+ }
+ else
+ {
+ svga.rgb8_en = (s3.memory_config & 8) >> 3;
+ svga.rgb15_en = 0;
+ svga.rgb16_en = 0;
+ svga.rgb32_en = 0;
+ }
+}
+
+static void s3_crtc_reg_write(running_machine &machine, UINT8 index, UINT8 data)
+{
+ if(index <= 0x18)
+ crtc_reg_write(machine,index,data);
+ else
+ {
+ switch(index)
+ {
+ case 0x31: // CR31 Memory Configuration Register
+ s3.memory_config = data;
+ vga.crtc.start_addr &= ~0x30000;
+ vga.crtc.start_addr |= ((data & 0x30) << 12);
+ //popmessage("%02x",data);
+ s3_define_video_mode();
+ break;
+ case 0x35:
+ if((s3.reg_lock1 & 0xc) != 8 || ((s3.reg_lock1 & 0xc0) == 0)) // lock register
+ return;
+ s3.crt_reg_lock = data;
+ svga.bank_w = data & 0xf;
+ svga.bank_r = svga.bank_w;
+ break;
+ case 0x38:
+ s3.reg_lock1 = data;
+ break;
+ case 0x39:
+ /* TODO: reg lock mechanism */
+ s3.reg_lock2 = data;
+ break;
+ case 0x51:
+ vga.crtc.start_addr &= ~0xc0000;
+ vga.crtc.start_addr |= ((data & 0x3) << 18);
+ break;
+ case 0x67:
+ s3.ext_misc_ctrl_2 = data;
+ s3_define_video_mode();
+ //printf("%02x X\n",data);
+ //debugger_break(machine);
+ break;
+ case 0x6a:
+ svga.bank_w = data & 0xf;
+ svga.bank_r = svga.bank_w;
+ if(data & 0x60)
+ fatalerror("TODO: s3 bank selects above 1M");
+ break;
+ default:
+ //printf("%02x %02x\n",index,data);
+ break;
+ }
+ }
+}
+
+
+READ8_HANDLER(s3_port_03b0_r)
+{
+ UINT8 res = 0xff;
+
+ if (CRTC_PORT_ADDR == 0x3b0)
+ {
+ switch(offset)
+ {
+ case 5:
+ res = s3_crtc_reg_read(space->machine(),vga.crtc.index);
+ break;
+ default:
+ res = vga_port_03b0_r(space,offset);
+ break;
+ }
+ }
+
+ return res;
+}
+
+WRITE8_HANDLER(s3_port_03b0_w)
+{
+ if (CRTC_PORT_ADDR == 0x3b0)
+ {
+ switch(offset)
+ {
+ case 5:
+ vga.crtc.data[vga.crtc.index] = data;
+ s3_crtc_reg_write(space->machine(),vga.crtc.index,data);
+ break;
+ default:
+ vga_port_03b0_w(space,offset,data);
+ break;
+ }
+ }
+}
+
+READ8_HANDLER(s3_port_03c0_r)
+{
+ UINT8 res;
+
+ switch(offset)
+ {
+ default:
+ res = vga_port_03c0_r(space,offset);
+ break;
+ }
+
+ return res;
+}
+
+WRITE8_HANDLER(s3_port_03c0_w)
+{
+ switch(offset)
+ {
+ default:
+ vga_port_03c0_w(space,offset,data);
+ break;
+ }
+}
+
+READ8_HANDLER(s3_port_03d0_r)
+{
+ UINT8 res = 0xff;
+
+ if (CRTC_PORT_ADDR == 0x3d0)
+ {
+ switch(offset)
+ {
+ case 5:
+ res = s3_crtc_reg_read(space->machine(),vga.crtc.index);
+ break;
+ default:
+ res = vga_port_03d0_r(space,offset);
+ break;
+ }
+ }
+
+ return res;
+}
+
+WRITE8_HANDLER(s3_port_03d0_w)
+{
+ if (CRTC_PORT_ADDR == 0x3d0)
+ {
+ switch(offset)
+ {
+ case 5:
+ vga.crtc.data[vga.crtc.index] = data;
+ s3_crtc_reg_write(space->machine(),vga.crtc.index,data);
+ break;
+ default:
+ vga_port_03d0_w(space,offset,data);
+ break;
+ }
+ }
+}
+
+/* accelerated ports, TBD ... */
+READ8_HANDLER(s3_port_9ae8_r)
+{
+ return 0;
+}
+
+WRITE8_HANDLER(s3_port_9ae8_w)
+{
+ // ...
+}
+
+READ8_HANDLER( s3_mem_r )
+{
+ if (svga.rgb8_en || svga.rgb15_en || svga.rgb16_en || svga.rgb32_en)
+ {
+ int data;
+ if(offset & 0x10000)
+ return 0;
+ data = 0;
+ if(vga.sequencer.data[4] & 0x8)
+ data = vga.memory[offset + (svga.bank_r*0x10000)];
+ else
+ {
+ int i;
+
+ for(i=0;i<4;i++)
+ {
+ if(vga.sequencer.map_mask & 1 << i)
+ data |= vga.memory[offset*4+i+(svga.bank_r*0x10000)];
+ }
+ }
+ return data;
+ }
+ return vga_mem_r(space,offset);
+}
+
+WRITE8_HANDLER( s3_mem_w )
+{
+ if (svga.rgb8_en || svga.rgb15_en || svga.rgb16_en || svga.rgb32_en)
+ {
+ //printf("%08x %02x (%02x %02x) %02X\n",offset,data,vga.sequencer.map_mask,svga.bank_w,(vga.sequencer.data[4] & 0x08));
+ if(offset & 0x10000)
+ return;
+ if(vga.sequencer.data[4] & 0x8)
+ vga.memory[offset + (svga.bank_w*0x10000)] = data;
+ else
+ {
+ int i;
+ for(i=0;i<4;i++)
+ {
+ if(vga.sequencer.map_mask & 1 << i)
+ vga.memory[offset*4+i+(svga.bank_w*0x10000)] = data;
+ }
+ }
+ return;
+ }
+
+ vga_mem_w(space,offset,data);
+}
+
+/******************************************
+
+gamtor.c implementation (TODO: identify the video card)
+
+******************************************/
+
+READ8_HANDLER(vga_gamtor_mem_r)
+{
+ return vga.memory[offset];
+}
+
+WRITE8_HANDLER(vga_gamtor_mem_w)
+{
+ vga.memory[offset] = data;
+}
+
+
+READ8_HANDLER(vga_port_gamtor_03b0_r)
+{
+ UINT8 res;
+
+ switch(offset)
+ {
+ default:
+ res = vga_port_03b0_r(space,offset ^ 3);
+ break;
+ }
+
+ return res;
+}
+
+WRITE8_HANDLER(vga_port_gamtor_03b0_w)
+{
+ switch(offset)
+ {
+ default:
+ vga_port_03b0_w(space,offset ^ 3,data);
+ break;
+ }
+}
+
+READ8_HANDLER(vga_port_gamtor_03c0_r)
+{
+ UINT8 res;
+
+ switch(offset)
+ {
+ default:
+ res = vga_port_03c0_r(space,offset ^ 3);
+ break;
+ }
+
+ return res;
+}
+
+WRITE8_HANDLER(vga_port_gamtor_03c0_w)
+{
+ switch(offset)
+ {
+ default:
+ vga_port_03c0_w(space,offset ^ 3,data);
+ break;
+ }
+}
+
+READ8_HANDLER(vga_port_gamtor_03d0_r)
+{
+ UINT8 res;
+
+ switch(offset)
+ {
+ default:
+ res = vga_port_03d0_r(space,offset ^ 3);
+ break;
+ }
+
+ return res;
+}
+
+WRITE8_HANDLER(vga_port_gamtor_03d0_w)
+{
+ switch(offset)
+ {
+ default:
+ vga_port_03d0_w(space,offset ^ 3,data);
+ break;
+ }
+}
+
+void pc_vga_gamtor_io_init(running_machine &machine, address_space *mem_space, offs_t mem_offset, address_space *io_space, offs_t port_offset)
+{
+ int buswidth;
+ UINT64 mask = 0;
+
+ buswidth = machine.firstcpu->memory().space_config(AS_PROGRAM)->m_databus_width;
+ switch(buswidth)
+ {
+ case 8:
+ mask = 0;
+ break;
+
+ case 16:
+ mask = 0xffff;
+ break;
+
+ case 32:
+ mask = 0xffffffff;
+ break;
+
+ case 64:
+ mask = -1;
+ break;
+
+ default:
+ fatalerror("VGA: Bus width %d not supported", buswidth);
+ break;
+ }
+ io_space->install_legacy_readwrite_handler(port_offset + 0x3b0, port_offset + 0x3bf, FUNC(vga_port_gamtor_03b0_r), FUNC(vga_port_gamtor_03b0_w), mask);
+ io_space->install_legacy_readwrite_handler(port_offset + 0x3c0, port_offset + 0x3cf, FUNC(vga_port_gamtor_03c0_r), FUNC(vga_port_gamtor_03c0_w), mask);
+ io_space->install_legacy_readwrite_handler(port_offset + 0x3d0, port_offset + 0x3df, FUNC(vga_port_gamtor_03d0_r), FUNC(vga_port_gamtor_03d0_w), mask);
+
+ mem_space->install_legacy_readwrite_handler(mem_offset + 0x00000, mem_offset + 0x1ffff, FUNC(vga_gamtor_mem_r), FUNC(vga_gamtor_mem_w), mask);
+}
+