mirror of
https://github.com/holub/mame
synced 2025-06-02 02:49:44 +03:00
2324 lines
51 KiB
C
2324 lines
51 KiB
C
/***************************************************************************
|
|
|
|
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
|
|
- add emulated mc6845 hook-up
|
|
- fix video update.
|
|
- rewrite video drawing functions (they are horrible)
|
|
- add VESA etc.
|
|
- (and many more ...)
|
|
|
|
per-game issues:
|
|
- The Incredible Machine: fix partial updates
|
|
- MAME 0.01: fix 92 Hz refresh rate bug (uses VESA register?).
|
|
- Bio Menace: jerky H scrolling (uses EGA mode)
|
|
- 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;
|
|
} 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 id;
|
|
}svga;
|
|
|
|
static struct
|
|
{
|
|
UINT8 reg_3d8;
|
|
bool ext_reg_ena;
|
|
}et4k;
|
|
|
|
static struct
|
|
{
|
|
UINT8 memory_config;
|
|
UINT8 ext_misc_ctrl_2;
|
|
UINT8 crt_reg_lock;
|
|
UINT8 reg_lock1;
|
|
}s3;
|
|
|
|
#define REG(x) vga.crtc.data[x]
|
|
|
|
#define CRTC_CHAR_HEIGHT ((REG(9)&0x1f)+1)
|
|
#define CRTC_CURSOR_MODE (REG(0xa)&0x60)
|
|
#define CRTC_CURSOR_OFF 0x20
|
|
#define CRTC_SKEW (REG(8)&15)
|
|
#define CRTC_CURSOR_POS ((REG(0xe)<<8)|REG(0xf))
|
|
#define CRTC_CURSOR_TOP (REG(0xa)&0x1f)
|
|
#define CRTC_CURSOR_BOTTOM REG(0xb)
|
|
|
|
#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=CRTC_CHAR_HEIGHT * (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 = -CRTC_SKEW; 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 = 0x40000+(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 ((CRTC_CURSOR_MODE!=CRTC_CURSOR_OFF)
|
|
&&vga.cursor.visible&&(pos==CRTC_CURSOR_POS))
|
|
{
|
|
for (h=CRTC_CURSOR_TOP;
|
|
(h<=CRTC_CURSOR_BOTTOM)&&(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)+0x20000]<<1;
|
|
data[2]=vga.memory[(pos & 0xffff)+0x40000]<<2;
|
|
data[3]=vga.memory[(pos & 0xffff)+0x60000]<<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;
|
|
|
|
/* line compare is screen sensitive */
|
|
mask_comp = 0x0ff | (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);
|
|
addr %= vga.svga_intf.vram_size;
|
|
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, line + yi))
|
|
continue;
|
|
bitmapline[c+xi] = machine.pens[vga.memory[pos+((xi >> 1)*0x20000)]];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
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 %= vga.svga_intf.vram_size;
|
|
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, line + yi))
|
|
continue;
|
|
bitmapline[c+xi] = machine.pens[vga.memory[pos+(xi >> 1)]];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
enum
|
|
{
|
|
SCREEN_OFF = 0,
|
|
TEXT_MODE,
|
|
VGA_MODE,
|
|
EGA_MODE,
|
|
CGA_MODE,
|
|
MONO_MODE,
|
|
RGB8_MODE,
|
|
RGB15_MODE,
|
|
RGB16_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.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",cur_mode);
|
|
|
|
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 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;
|
|
|
|
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;
|
|
|
|
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;
|
|
}
|
|
|
|
#if 0
|
|
static UINT8 crtc_reg_read(UINT8 index)
|
|
{
|
|
UINT8 res;
|
|
|
|
res = 0xff;
|
|
|
|
switch(index)
|
|
{
|
|
default:
|
|
printf("Unhandled CRTC reg r %02x\n",index);
|
|
}
|
|
|
|
return res;
|
|
}
|
|
#endif
|
|
|
|
static void recompute_params(running_machine &machine)
|
|
{
|
|
int vblank_period,hblank_period;
|
|
attoseconds_t refresh;
|
|
UINT8 hclock_m;
|
|
int pixel_clock;
|
|
|
|
hclock_m = (!GRAPHIC_MODE) ? CHAR_WIDTH : 8;
|
|
|
|
/* 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) * hclock_m)-1, 0, vga.crtc.vert_disp_end);
|
|
|
|
vblank_period = (vga.crtc.vert_total + 2);
|
|
hblank_period = ((vga.crtc.horz_total + 5) * hclock_m);
|
|
|
|
/* TODO: 10b and 11b settings aren't known */
|
|
pixel_clock = (vga.miscellaneous_output & 0xc) ? XTAL_28_63636MHz : XTAL_25_1748MHz;
|
|
pixel_clock /= (((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 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:
|
|
vga.crtc.horz_total = (data & 0xff);
|
|
recompute_params(machine);
|
|
break;
|
|
case 0x01:
|
|
vga.crtc.horz_disp_end = (data & 0xff);
|
|
recompute_params(machine);
|
|
break;
|
|
case 0x02: vga.crtc.horz_blank_start = (data & 0xff); break;
|
|
case 0x03:
|
|
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:
|
|
vga.crtc.horz_retrace_start = data & 0xff;
|
|
break;
|
|
case 0x05:
|
|
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:
|
|
vga.crtc.vert_total &= ~0xff;
|
|
vga.crtc.vert_total |= data & 0xff;
|
|
recompute_params(machine);
|
|
break;
|
|
case 0x07: // Overflow Register
|
|
vga.crtc.vert_total &= ~0x300;
|
|
vga.crtc.vert_retrace_start &= ~0x300;
|
|
vga.crtc.vert_disp_end &= ~0x300;
|
|
vga.crtc.line_compare &= ~0x100;
|
|
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.line_compare |= ((data & 0x10) << (8-4));
|
|
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 READ8_HANDLER(vga_crtc_r)
|
|
{
|
|
UINT8 data = 0xff;
|
|
|
|
switch (offset) {
|
|
case 4:
|
|
data = vga.crtc.index;
|
|
break;
|
|
case 5:
|
|
if (vga.crtc.index < vga.svga_intf.crtc_regcount)
|
|
data = vga.crtc.data[vga.crtc.index];
|
|
break;
|
|
case 0xa:
|
|
UINT8 hsync,vsync;
|
|
vga.attribute.state = 0;
|
|
data = 0;
|
|
|
|
hsync = space->machine().primary_screen->hblank() & 1;
|
|
vsync = 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);
|
|
}
|
|
|
|
if (vga.crtc.index < vga.svga_intf.crtc_regcount)
|
|
vga.crtc.data[vga.crtc.index] = 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) // protection bit
|
|
data = vga.attribute.index;
|
|
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)
|
|
{
|
|
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.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)+0x20000];
|
|
vga.gc.latch[2]=vga.memory[(offset)+0x40000];
|
|
vga.gc.latch[3]=vga.memory[(offset)+0x60000];
|
|
}
|
|
|
|
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*0x20000];
|
|
}
|
|
|
|
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*0x20000] = (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 UINT8 tseng_crtc_reg_read(running_machine &machine, UINT8 index)
|
|
{
|
|
UINT8 res;
|
|
|
|
res = 0;
|
|
if(index <= 0x18)
|
|
res = vga.crtc.data[index];
|
|
else
|
|
{
|
|
switch(index)
|
|
{
|
|
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)
|
|
{
|
|
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);
|
|
recompute_params(machine);
|
|
}
|
|
else
|
|
{
|
|
switch(index)
|
|
{
|
|
case 0x06:
|
|
case 0x07:
|
|
//printf("%02x %02x\n",index,data);
|
|
break;
|
|
}
|
|
}
|
|
|
|
svga.rgb8_en = (!(vga.sequencer.data[1] & 8) && (vga.sequencer.data[4] & 8) && vga.gc.shift256 && vga.crtc.div2 && GRAPHIC_MODE);
|
|
}
|
|
|
|
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;
|
|
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;
|
|
default:
|
|
vga_port_03c0_w(space,offset,data);
|
|
break;
|
|
}
|
|
}
|
|
|
|
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);
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
|
|
READ8_HANDLER( tseng_mem_r )
|
|
{
|
|
if(svga.rgb8_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)
|
|
{
|
|
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
|
|
|
|
******************************************/
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
static UINT8 s3_crtc_reg_read(running_machine &machine, UINT8 index)
|
|
{
|
|
UINT8 res;
|
|
|
|
res = 0;
|
|
if(index <= 0x18)
|
|
res = vga.crtc.data[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 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;
|
|
switch((s3.ext_misc_ctrl_2) >> 4)
|
|
{
|
|
case 5: svga.rgb16_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;
|
|
}
|
|
}
|
|
|
|
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 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_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)
|
|
{
|
|
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)
|
|
{
|
|
//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);
|
|
}
|