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.c1276
1 files changed, 1276 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..d645b91581f
--- /dev/null
+++ b/trunk/src/emu/video/pc_vga.c
@@ -0,0 +1,1276 @@
+/***************************************************************************
+
+ 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
+
+
+ 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"
+
+/***************************************************************************
+
+ Local variables
+
+***************************************************************************/
+
+static pc_video_update_proc (*pc_choosevideomode)(running_machine &machine, int *width, int *height);
+
+static int pc_current_height;
+static int pc_current_width;
+/***************************************************************************
+
+ Static declarations
+
+***************************************************************************/
+
+#define LOG_ACCESSES 0
+#define LOG_REGISTERS 0
+
+static PALETTE_INIT( vga );
+static VIDEO_START( vga );
+static VIDEO_RESET( vga );
+
+static pc_video_update_proc pc_vga_choosevideomode(running_machine &machine, int *width, int *height);
+
+/***************************************************************************
+
+ MachineDriver stuff
+
+***************************************************************************/
+
+void pc_video_start(running_machine &machine, pc_video_update_proc (*choosevideomode)(running_machine &machine, int *width, int *height))
+{
+ pc_choosevideomode = choosevideomode;
+ pc_current_height = -1;
+ pc_current_width = -1;
+}
+
+
+
+SCREEN_UPDATE( pc_video )
+{
+ UINT32 rc = 0;
+ int w = 0, h = 0;
+ pc_video_update_proc video_update = pc_choosevideomode(screen->machine(), &w, &h);
+
+ if (video_update)
+ {
+ if ((pc_current_width != w) || (pc_current_height != h))
+ {
+ int width = screen->width();
+ int height = screen->height();
+
+ pc_current_width = w;
+ pc_current_height = h;
+
+ if (pc_current_width > width)
+ pc_current_width = width;
+ if (pc_current_height > height)
+ pc_current_height = height;
+
+ if ((pc_current_width > 100) && (pc_current_height > 100))
+ screen->set_visible_area(0, pc_current_width-1, 0, pc_current_height-1);
+
+ bitmap_fill(bitmap, cliprect, 0);
+ }
+
+ video_update(bitmap);
+ }
+ return rc;
+}
+/***************************************************************************/
+
+static PALETTE_INIT( vga )
+{
+ int i;
+ for (i = 0; i < 0x100; i++)
+ palette_set_color_rgb(machine, i, 0, 0, 0);
+}
+
+static UINT8 color_bitplane_to_packed[4/*plane*/][8/*pixel*/][256];
+
+static struct
+{
+ struct pc_vga_interface vga_intf;
+ struct pc_svga_interface svga_intf;
+
+ UINT8 *memory;
+ UINT8 *fontdirty;
+ UINT16 pens[16]; /* the current 16 pens */
+
+ UINT8 miscellaneous_output;
+ UINT8 feature_control;
+ UINT16 line_compare; // for split-screen use.
+
+ struct
+ {
+ UINT8 index;
+ UINT8 *data;
+ } sequencer;
+ struct
+ {
+ UINT8 index;
+ UINT8 *data;
+ } crtc;
+ struct
+ {
+ UINT8 index;
+ UINT8 *data;
+ UINT8 latch[4];
+ } gc;
+ struct { UINT8 index, data[0x15]; int state; } attribute;
+
+
+ struct {
+ UINT8 read_index, write_index, mask;
+ int read;
+ int state;
+ struct { UINT8 red, green, blue; } color[0x100];
+ int dirty;
+ } dac;
+
+ struct {
+ int time;
+ int visible;
+ } cursor;
+
+ struct {
+ int (*get_clock)(void);
+
+ int (*get_lines)(void);
+ int (*get_sync_lines)(void);
+
+ int (*get_columns)(void);
+ int (*get_sync_columns)(void);
+
+ attotime start_time;
+ int retrace;
+ } monitor;
+
+ /* oak vga */
+ struct { UINT8 reg; } oak;
+
+ int log;
+} vga;
+
+
+#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 DOUBLESCAN ((vga.crtc.data[9]&0x80)||((vga.crtc.data[9]&0x1f)!=0))
+#define CRTC_PORT_ADDR ((vga.miscellaneous_output&1)?0x3d0:0x3b0)
+
+#define CRTC_ON (vga.crtc.data[0x17]&0x80)
+
+#define LINES_HELPER ( (vga.crtc.data[0x12] \
+ |((vga.crtc.data[7]&2)<<7) \
+ |((vga.crtc.data[7]&0x40)<<3))+1 )
+//#define TEXT_LINES (LINES_HELPER)
+#define LINES (DOUBLESCAN?LINES_HELPER>>1:LINES_HELPER)
+#define TEXT_LINES (LINES_HELPER >> ((vga.crtc.data[9]&0x80) ? 1 : 0))
+
+#define GRAPHIC_MODE (vga.gc.data[6]&1) /* else textmodus */
+
+#define EGA_COLUMNS (vga.crtc.data[1]+1)
+#define EGA_START_ADDRESS ((vga.crtc.data[0xd]|(vga.crtc.data[0xc]<<8))<<2)
+#define EGA_LINE_LENGTH (vga.crtc.data[0x13]<<3)
+
+#define VGA_COLUMNS (EGA_COLUMNS>>1)
+#define VGA_START_ADDRESS (EGA_START_ADDRESS)
+#define VGA_LINE_LENGTH (EGA_LINE_LENGTH<<2)
+
+#define CHAR_WIDTH ((vga.sequencer.data[1]&1)?8:9)
+
+#define TEXT_COLUMNS (vga.crtc.data[1]+1)
+#define TEXT_START_ADDRESS (EGA_START_ADDRESS)
+#define TEXT_LINE_LENGTH (EGA_LINE_LENGTH>>2)
+
+#define TEXT_COPY_9COLUMN(ch) ((ch>=192)&&(ch<=223)&&(vga.attribute.data[0x10]&4))
+
+#define FONT1 ( ((vga.sequencer.data[3]&0x3) |((vga.sequencer.data[3]&0x10)<<2))*0x2000 )
+#define FONT2 ( (((vga.sequencer.data[3]&0xc)>>2)|((vga.sequencer.data[3]&0x20)<<3))*0x2000 )
+
+
+INLINE UINT8 rotate_right(UINT8 val, UINT8 rot)
+{
+ return (val >> rot) | (val << (8 - rot));
+}
+
+
+
+static int vga_get_clock(void)
+{
+ int clck=0;
+ switch(vga.miscellaneous_output&0xc) {
+ case 0: clck=25000000;break;
+ case 4: clck=28000000;break;
+ /* case 8: external */
+ /* case 0xc: reserved */
+ }
+ if (vga.sequencer.data[1]&8) clck/=2;
+ return clck;
+}
+
+static int vga_get_crtc_columns(void) /* in clocks! */
+{
+ int columns=vga.crtc.data[0]+5;
+
+ if (!GRAPHIC_MODE)
+ columns *= CHAR_WIDTH;
+ else if (vga.gc.data[5]&0x40)
+ columns *= 4;
+ else
+ columns *= 8;
+
+ return columns;
+}
+
+static int vga_get_crtc_lines(void)
+{
+ int lines=(vga.crtc.data[6]
+ |((vga.crtc.data[7]&1)<<8)
+ |((vga.crtc.data[7]&0x20)<<(8-4)))+2;
+
+ return lines;
+}
+
+static int vga_get_crtc_sync_lines(void)
+{
+ return 10;
+}
+
+static int vga_get_crtc_sync_columns(void)
+{
+ return 40;
+}
+
+INLINE WRITE8_HANDLER(vga_dirty_w)
+{
+ vga.memory[offset] = data;
+}
+
+INLINE WRITE8_HANDLER(vga_dirty_font_w)
+{
+ if (vga.memory[offset] != data)
+ {
+ vga.memory[offset] = data;
+ if ((offset&3)==2)
+ vga.fontdirty[offset>>7]=1;
+ }
+}
+
+static READ8_HANDLER(vga_text_r)
+{
+ int data;
+ data=vga.memory[((offset&~1)<<1)|(offset&1)];
+
+ return data;
+}
+
+static WRITE8_HANDLER(vga_text_w)
+{
+ vga_dirty_w(space, ((offset&~1)<<1)|(offset&1),data);
+}
+
+INLINE UINT8 ega_bitplane_to_packed(UINT8 *latch, int number)
+{
+ return color_bitplane_to_packed[0][number][latch[0]]
+ |color_bitplane_to_packed[1][number][latch[1]]
+ |color_bitplane_to_packed[2][number][latch[2]]
+ |color_bitplane_to_packed[3][number][latch[3]];
+}
+
+static READ8_HANDLER(vga_ega_r)
+{
+ int data;
+ vga.gc.latch[0]=vga.memory[(offset<<2)];
+ vga.gc.latch[1]=vga.memory[(offset<<2)+1];
+ vga.gc.latch[2]=vga.memory[(offset<<2)+2];
+ vga.gc.latch[3]=vga.memory[(offset<<2)+3];
+ if (vga.gc.data[5]&8) {
+ data=0;
+ if (!(ega_bitplane_to_packed(vga.gc.latch, 0)^(vga.gc.data[2]&0xf&~vga.gc.data[7]))) data|=1;
+ if (!(ega_bitplane_to_packed(vga.gc.latch, 1)^(vga.gc.data[2]&0xf&~vga.gc.data[7]))) data|=2;
+ if (!(ega_bitplane_to_packed(vga.gc.latch, 2)^(vga.gc.data[2]&0xf&~vga.gc.data[7]))) data|=4;
+ if (!(ega_bitplane_to_packed(vga.gc.latch, 3)^(vga.gc.data[2]&0xf&~vga.gc.data[7]))) data|=8;
+ if (!(ega_bitplane_to_packed(vga.gc.latch, 4)^(vga.gc.data[2]&0xf&~vga.gc.data[7]))) data|=0x10;
+ if (!(ega_bitplane_to_packed(vga.gc.latch, 5)^(vga.gc.data[2]&0xf&~vga.gc.data[7]))) data|=0x20;
+ if (!(ega_bitplane_to_packed(vga.gc.latch, 6)^(vga.gc.data[2]&0xf&~vga.gc.data[7]))) data|=0x40;
+ if (!(ega_bitplane_to_packed(vga.gc.latch, 7)^(vga.gc.data[2]&0xf&~vga.gc.data[7]))) data|=0x80;
+ } else {
+ data=vga.gc.latch[vga.gc.data[4]&3];
+ }
+
+ return data;
+}
+
+INLINE UINT8 vga_latch_helper(UINT8 cpu, UINT8 latch, UINT8 mask)
+{
+ switch (vga.gc.data[3] & 0x18)
+ {
+ case 0x00:
+ return rotate_right((cpu&mask)|(latch&~mask), vga.gc.data[3] & 0x07);
+ case 0x08:
+ return rotate_right(((cpu&latch)&mask)|(latch&~mask), vga.gc.data[3] & 0x07);
+ case 0x10:
+ return rotate_right(((cpu|latch)&mask)|(latch&~mask), vga.gc.data[3] & 0x07);
+ case 0x18:
+ return rotate_right(((cpu^latch)&mask)|(latch&~mask), vga.gc.data[3] & 0x07);
+ }
+ return 0; /* must not be reached, suppress compiler warning */
+}
+
+INLINE UINT8 vga_latch_write(int offs, UINT8 data)
+{
+ switch (vga.gc.data[5]&3) {
+ case 0:
+ if (vga.gc.data[1]&(1<<offs)) {
+ return vga_latch_helper( (vga.gc.data[0]&(1<<offs))?vga.gc.data[8]:0,
+ vga.gc.latch[offs],vga.gc.data[8] );
+ } else {
+ return vga_latch_helper(data, vga.gc.latch[offs], vga.gc.data[8]);
+ }
+ break;
+ case 1:
+ return vga.gc.latch[offs];
+ case 2:
+ if (data&(1<<offs)) {
+ return vga_latch_helper(0xff, vga.gc.latch[offs], vga.gc.data[8]);
+ } else {
+ return vga_latch_helper(0, vga.gc.latch[offs], vga.gc.data[8]);
+ }
+ break;
+ case 3:
+ if (vga.gc.data[0]&(1<<offs)) {
+ return vga_latch_helper(0xff, vga.gc.latch[offs], data&vga.gc.data[8]);
+ } else {
+ return vga_latch_helper(0, vga.gc.latch[offs], data&vga.gc.data[8]);
+ }
+ break;
+ }
+ return 0; /* must not be reached, suppress compiler warning */
+}
+
+static WRITE8_HANDLER(vga_ega_w)
+{
+ if (vga.sequencer.data[2]&1)
+ vga_dirty_w(space, offset<<2, vga_latch_write(0,data));
+ if (vga.sequencer.data[2]&2)
+ vga_dirty_w(space, (offset<<2)+1, vga_latch_write(1,data));
+ if (vga.sequencer.data[2]&4)
+ vga_dirty_font_w(space, (offset<<2)+2, vga_latch_write(2,data));
+ if (vga.sequencer.data[2]&8)
+ vga_dirty_w(space, (offset<<2)+3, vga_latch_write(3,data));
+ if ((offset==0xffff)&&(data==0)) vga.log=1;
+}
+
+static READ8_HANDLER(vga_vga_r)
+{
+ int data;
+ data=vga.memory[((offset&~3)<<2)|(offset&3)];
+
+ return data;
+}
+
+static WRITE8_HANDLER(vga_vga_w)
+{
+ vga_dirty_font_w(space, ((offset&~3)<<2)|(offset&3),data);
+}
+
+static void vga_cpu_interface(running_machine &machine)
+{
+ address_space *space = machine.firstcpu->memory().space(AS_PROGRAM);
+ static int sequencer, gc;
+ read8_space_func read_handler; const char *read_handler_name;
+ write8_space_func write_handler; const char *write_handler_name;
+ UINT8 sel;
+ int buswidth;
+ UINT64 mask = 0;
+
+ if ((gc==vga.gc.data[6])&&(sequencer==vga.sequencer.data[4])) return;
+
+ gc=vga.gc.data[6];
+ sequencer=vga.sequencer.data[4];
+
+ if (vga.sequencer.data[4]&8)
+ {
+ read_handler = vga_vga_r; read_handler_name = "vga_vga_r";
+ write_handler = vga_vga_w; write_handler_name = "vga_vga_w";
+ }
+ else if (vga.sequencer.data[4] & 4)
+ {
+ read_handler = vga_ega_r; read_handler_name = "vga_ega_r";
+ write_handler = vga_ega_w; write_handler_name = "vga_ega_w";
+ }
+ else
+ {
+ read_handler = vga_text_r; read_handler_name = "vga_text_r";
+ write_handler = vga_text_w; write_handler_name = "vga_text_w";
+ }
+
+ /* remap the VGA memory */
+
+ if (vga.vga_intf.map_vga_memory)
+ {
+ sel = vga.gc.data[6] & 0x0c;
+ switch(sel)
+ {
+ case 0x00:
+ if (vga.vga_intf.vga_memory_bank != NULL)
+ {
+ vga.vga_intf.map_vga_memory(machine, 0xA0000, 0xBFFFF, read_handler, read_handler_name, write_handler, write_handler_name);
+ memory_set_bankptr(machine, vga.vga_intf.vga_memory_bank, vga.memory);
+ }
+ break;
+ case 0x04:
+ vga.vga_intf.map_vga_memory(machine, 0xA0000, 0xAFFFF, read_handler, read_handler_name, write_handler, write_handler_name);
+ break;
+ case 0x08:
+ vga.vga_intf.map_vga_memory(machine, 0xB0000, 0xB7FFF, read_handler, read_handler_name, write_handler, write_handler_name);
+ break;
+ case 0x0C:
+ vga.vga_intf.map_vga_memory(machine, 0xB8000, 0xBFFFF, read_handler, read_handler_name, write_handler, write_handler_name);
+ break;
+ }
+ }
+ else
+ {
+ buswidth = downcast<legacy_cpu_device *>(machine.firstcpu)->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;
+ }
+
+ sel = vga.gc.data[6] & 0x0c;
+ if (sel)
+ {
+ if (sel == 0x04) space->install_legacy_read_handler(0xa0000, 0xaffff, read_handler, read_handler_name, mask); else space->nop_read(0xa0000, 0xaffff);
+ if (sel == 0x08) space->install_legacy_read_handler(0xb0000, 0xb7fff, read_handler, read_handler_name, mask); else space->nop_read(0xb0000, 0xb7fff);
+ if (sel == 0x0C) space->install_legacy_read_handler(0xb8000, 0xbffff, read_handler, read_handler_name, mask); else space->nop_read(0xb8000, 0xbffff);
+ if (sel == 0x04) space->install_legacy_write_handler(0xa0000, 0xaffff, write_handler, write_handler_name, mask); else space->nop_write(0xa0000, 0xaffff);
+ if (sel == 0x08) space->install_legacy_write_handler(0xb0000, 0xb7fff, write_handler, write_handler_name, mask); else space->nop_write(0xb0000, 0xb7fff);
+ if (sel == 0x0C) space->install_legacy_write_handler(0xb8000, 0xbffff, write_handler, write_handler_name, mask); else space->nop_write(0xb8000, 0xbffff);
+ }
+ else
+ {
+ memory_set_bankptr(machine,"bank1", vga.memory);
+ space->install_read_bank(0xa0000, 0xbffff, "bank1" );
+ space->install_write_bank(0xa0000, 0xbffff, "bank1" );
+ }
+
+ }
+}
+
+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:
+ vga.attribute.state = 0;
+ data = 0;/*4; */
+#if 0 /* slow */
+ {
+ int clock=vga.monitor.get_clock();
+ int lines=vga.monitor.get_lines();
+ int columns=vga.monitor.get_columns();
+ int diff = (((space->machine().time() - vga.monitor.start_time) * clock).seconds)
+ %(lines*columns);
+ if (diff<columns*vga.monitor.get_sync_lines()) data|=8;
+ diff=diff/lines;
+ if (diff%columns<vga.monitor.get_sync_columns()) data|=1;
+ }
+#elif 1
+ if (vga.monitor.retrace)
+ {
+ data |= 1;
+ if ((space->machine().time() - vga.monitor.start_time) > attotime::from_usec(300))
+ {
+ data |= 8;
+ vga.monitor.retrace=0;
+ }
+ }
+ else
+ {
+ if ((space->machine().time() - vga.monitor.start_time) > attotime::from_msec(15))
+ vga.monitor.retrace=1;
+ vga.monitor.start_time=space->machine().time();
+ }
+#else
+ // not working with ps2m30
+ if (vga.monitor.retrace) data|=9;
+ vga.monitor.retrace=0;
+#endif
+ /* 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 0xa:
+ vga.feature_control = data;
+ break;
+
+ 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 == 0x18 || vga.crtc.index == 0x07 || vga.crtc.index == 0x19 ) // Line compare
+ vga.line_compare = (((vga.crtc.data[0x09] & 0x40) << 3) | ((vga.crtc.data[0x07] & 0x10) << 4) | vga.crtc.data[0x18])/2;
+ if (vga.crtc.index < vga.svga_intf.crtc_regcount)
+ vga.crtc.data[vga.crtc.index] = data;
+ break;
+ }
+}
+
+
+
+READ8_HANDLER( vga_port_03b0_r )
+{
+ UINT8 data = 0xff;
+ if (CRTC_PORT_ADDR==0x3b0)
+ data=vga_crtc_r(space, offset);
+ return data;
+}
+
+READ8_HANDLER( vga_port_03c0_r )
+{
+ UINT8 data = 0xff;
+
+ switch (offset)
+ {
+ case 1:
+ if (vga.attribute.state==0)
+ {
+ 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:
+ data = 0;
+ switch ((vga.miscellaneous_output>>2)&3)
+ {
+ case 3:
+ if (vga.vga_intf.read_dipswitch && vga.vga_intf.read_dipswitch(space, 0) & 0x01)
+ data |= 0x10;
+ break;
+ case 2:
+ if (vga.vga_intf.read_dipswitch && vga.vga_intf.read_dipswitch(space, 0) & 0x02)
+ data |= 0x10;
+ break;
+ case 1:
+ if (vga.vga_intf.read_dipswitch && vga.vga_intf.read_dipswitch(space, 0) & 0x04)
+ data |= 0x10;
+ break;
+ case 0:
+ if (vga.vga_intf.read_dipswitch && vga.vga_intf.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:
+ if (vga.dac.read)
+ data = 0;
+ else
+ data = 3;
+ 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:
+ if (vga.gc.index < vga.svga_intf.gc_regcount)
+ data = vga.gc.data[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);
+ 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);
+}
+
+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
+ {
+ if ((vga.attribute.index&0x1f)<sizeof(vga.attribute.data))
+ vga.attribute.data[vga.attribute.index&0x1f]=data;
+ }
+ vga.attribute.state=!vga.attribute.state;
+ break;
+ case 2:
+ vga.miscellaneous_output=data;
+ 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;
+ vga_cpu_interface(space->machine());
+
+ if (vga.sequencer.index == 0)
+ vga.monitor.start_time = space->machine().time();
+ }
+ 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++;
+#if 0
+ if (vga.dac.write_index==64) {
+ int i;
+ mame_printf_debug("start palette\n");
+ for (i=0;i<64;i++) {
+ mame_printf_debug(" 0x%.2x, 0x%.2x, 0x%.2x,\n",
+ vga.dac.color[i].red*4,
+ vga.dac.color[i].green*4,
+ vga.dac.color[i].blue*4);
+ }
+ }
+#endif
+ }
+ }
+ break;
+ case 0xe:
+ vga.gc.index=data;
+ break;
+ case 0xf:
+ if (LOG_REGISTERS)
+ {
+ logerror("vga_port_03c0_w(): GC[0x%02X%s] = 0x%02X\n",
+ vga.gc.index,
+ (vga.gc.index < vga.svga_intf.gc_regcount) ? "" : "?",
+ data);
+ }
+ if (vga.gc.index < vga.svga_intf.gc_regcount)
+ {
+ vga.gc.data[vga.gc.index] = data;
+ vga_cpu_interface(space->machine());
+ }
+ 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.data, 0, vga.svga_intf.gc_regcount * sizeof(*vga.gc.data));
+ 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.monitor, 0, sizeof(vga.monitor));
+ memset(&vga.oak, 0, sizeof(vga.oak));
+ vga.log = 0;
+
+ vga.gc.data[6] = 0xc; /* 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;
+ vga_cpu_interface(machine);
+
+ vga.line_compare = 0x3ff;
+ // set CRTC register to match the line compare value
+ vga.crtc.data[0x18] = vga.line_compare & 0xff;
+ if(vga.line_compare & 0x100)
+ vga.crtc.data[0x07] |= 0x10;
+ if(vga.line_compare & 0x200)
+ vga.crtc.data[0x09] |= 0x40;
+}
+
+void pc_vga_init(running_machine &machine, const struct pc_vga_interface *vga_intf, const struct pc_svga_interface *svga_intf)
+{
+ int i, j, k, mask1, buswidth;
+ address_space *spacevga;
+
+ memset(&vga, 0, sizeof(vga));
+
+ for (k=0;k<4;k++)
+ {
+ for (mask1=0x80, j=0; j<8; j++, mask1>>=1)
+ {
+ for (i=0; i<256; i++)
+ color_bitplane_to_packed[k][j][i]=(i&mask1)?(1<<k):0;
+ }
+ }
+ UINT64 mask = 0;
+ /* copy over interfaces */
+ vga.vga_intf = *vga_intf;
+ 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.gc_regcount < 0x09)
+ fatalerror("Invalid SVGA GC register count");
+ if (vga.svga_intf.crtc_regcount < 0x19)
+ fatalerror("Invalid SVGA CRTC register count");
+ }
+ else
+ {
+ vga.svga_intf.vram_size = 0x40000;
+ vga.svga_intf.seq_regcount = 0x05;
+ vga.svga_intf.gc_regcount = 0x09;
+ vga.svga_intf.crtc_regcount = 0x19;
+ }
+
+ vga.memory = auto_alloc_array(machine, UINT8, vga.svga_intf.vram_size);
+ vga.fontdirty = auto_alloc_array(machine, UINT8, 0x800);
+ vga.sequencer.data = auto_alloc_array(machine, UINT8, vga.svga_intf.seq_regcount);
+ vga.crtc.data = auto_alloc_array(machine, UINT8, vga.svga_intf.crtc_regcount);
+ vga.gc.data = auto_alloc_array(machine, UINT8, vga.svga_intf.gc_regcount);
+ memset(vga.memory, '\0', vga.svga_intf.vram_size);
+ memset(vga.fontdirty, '\0', 0x800);
+ memset(vga.sequencer.data, '\0', vga.svga_intf.seq_regcount);
+ memset(vga.crtc.data, '\0', vga.svga_intf.crtc_regcount);
+ memset(vga.gc.data, '\0', vga.svga_intf.gc_regcount);
+
+ buswidth = downcast<legacy_cpu_device *>(machine.firstcpu)->space_config(AS_PROGRAM)->m_databus_width;
+ spacevga =machine.firstcpu->memory().space(vga.vga_intf.port_addressspace);
+ 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;
+ }
+ spacevga->install_legacy_read_handler(vga.vga_intf.port_offset + 0x3b0, vga.vga_intf.port_offset + 0x3bf, FUNC(vga_port_03b0_r), mask);
+ spacevga->install_legacy_read_handler(vga.vga_intf.port_offset + 0x3c0, vga.vga_intf.port_offset + 0x3cf, FUNC(vga_port_03c0_r), mask);
+ spacevga->install_legacy_read_handler(vga.vga_intf.port_offset + 0x3d0, vga.vga_intf.port_offset + 0x3df, FUNC(vga_port_03d0_r), mask);
+
+ spacevga->install_legacy_write_handler(vga.vga_intf.port_offset + 0x3b0, vga.vga_intf.port_offset + 0x3bf, FUNC(vga_port_03b0_w), mask);
+ spacevga->install_legacy_write_handler(vga.vga_intf.port_offset + 0x3c0, vga.vga_intf.port_offset + 0x3cf, FUNC(vga_port_03c0_w), mask);
+ spacevga->install_legacy_write_handler(vga.vga_intf.port_offset + 0x3d0, vga.vga_intf.port_offset + 0x3df, FUNC(vga_port_03d0_w), mask);
+
+ pc_vga_reset(machine);
+}
+
+static TIMER_CALLBACK(vga_timer)
+{
+ vga.monitor.retrace=1;
+}
+static VIDEO_START( vga )
+{
+ vga.monitor.get_clock=vga_get_clock;
+ vga.monitor.get_lines=vga_get_crtc_lines;
+ vga.monitor.get_columns=vga_get_crtc_columns;
+ vga.monitor.get_sync_lines=vga_get_crtc_sync_lines;
+ vga.monitor.get_sync_columns=vga_get_crtc_sync_columns;
+ machine.scheduler().timer_pulse(attotime::from_hz(60), FUNC(vga_timer));
+ pc_video_start(machine, pc_vga_choosevideomode);
+}
+
+static VIDEO_RESET( vga )
+{
+ pc_vga_reset(machine);
+}
+
+static void vga_vh_text(bitmap_t *bitmap)
+{
+ UINT8 ch, attr;
+ UINT8 bits;
+ UINT8 *font;
+ UINT16 *bitmapline;
+ int width=CHAR_WIDTH, height=CRTC_CHAR_HEIGHT;
+ int pos, line, column, mask, w, h, addr;
+ pen_t pen;
+
+ if (CRTC_CURSOR_MODE!=CRTC_CURSOR_OFF)
+ {
+ if (++vga.cursor.time>=0x10)
+ {
+ vga.cursor.visible^=1;
+ vga.cursor.time=0;
+ }
+ }
+
+ for (addr = TEXT_START_ADDRESS, 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<<2) + 0];
+ attr = vga.memory[(pos<<2) + 1];
+ font = vga.memory+2+(ch<<(5+2))+FONT1;
+
+ for (h = MAX(-line, 0); (h < height) && (line+h < MIN(TEXT_LINES, bitmap->height)); h++)
+ {
+ bitmapline = BITMAP_ADDR16(bitmap, line+h, 0);
+ bits = font[h<<2];
+
+ assert(bitmapline);
+
+ for (mask=0x80, w=0; (w<width)&&(w<8); w++, mask>>=1)
+ {
+ if (bits&mask)
+ pen = vga.pens[attr & 0x0f];
+ else
+ pen = vga.pens[attr >> 4];
+ bitmapline[column*width+w] = pen;
+ }
+ if (w<width)
+ {
+ /* 9 column */
+ if (TEXT_COPY_9COLUMN(ch)&&(bits&1))
+ pen = vga.pens[attr & 0x0f];
+ else
+ pen = vga.pens[attr >> 4];
+ 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++)
+ {
+ plot_box(bitmap, column*width, line+h, width, 1, vga.pens[attr&0xf]);
+ }
+ }
+ }
+ }
+}
+
+static void vga_vh_ega(bitmap_t *bitmap)
+{
+ int pos, line, column, c, addr, i;
+ int height = CRTC_CHAR_HEIGHT;
+ UINT16 *bitmapline;
+ UINT16 *newbitmapline;
+ pen_t pen;
+
+ for (addr=EGA_START_ADDRESS, pos=0, line=0; line<LINES;
+ line += height, addr=(addr+EGA_LINE_LENGTH)&0x3ffff)
+ {
+ bitmapline = BITMAP_ADDR16(bitmap, line, 0);
+
+ for (pos=addr, c=0, column=0; column<EGA_COLUMNS; column++, c+=8, pos=(pos+4)&0x3ffff)
+ {
+ int data[4];
+
+ data[0]=vga.memory[pos];
+ data[1]=vga.memory[pos+1]<<1;
+ data[2]=vga.memory[pos+2]<<2;
+ data[3]=vga.memory[pos+3]<<3;
+
+ for (i = 7; i >= 0; i--)
+ {
+ pen = vga.pens[(data[0]&1) | (data[1]&2) | (data[2]&4) | (data[3]&8)];
+ bitmapline[c+i] = pen;
+
+ data[0]>>=1;
+ data[1]>>=1;
+ data[2]>>=1;
+ data[3]>>=1;
+ }
+ }
+
+ for (i = 1; i < height; i++)
+ {
+ if (line + i >= LINES)
+ break;
+
+ newbitmapline = BITMAP_ADDR16(bitmap, line+i, 0);
+ memcpy(newbitmapline, bitmapline, EGA_COLUMNS * 8 * sizeof(UINT16));
+ }
+ }
+}
+
+static void vga_vh_vga(bitmap_t *bitmap)
+{
+ int pos, line, column, c, addr, curr_addr;
+ UINT16 *bitmapline;
+
+ curr_addr = 0;
+ if(vga.sequencer.data[4] & 0x08)
+ {
+ for (addr = VGA_START_ADDRESS, line=0; line<LINES; line++, addr+=VGA_LINE_LENGTH, curr_addr+=VGA_LINE_LENGTH)
+ {
+ if(line < (vga.line_compare & 0xff))
+ curr_addr = addr;
+ if(line == (vga.line_compare & 0xff))
+ curr_addr = 0;
+ bitmapline = BITMAP_ADDR16(bitmap, line, 0);
+ addr %= vga.svga_intf.vram_size;
+ for (pos=curr_addr, c=0, column=0; column<VGA_COLUMNS; column++, c+=8, pos+=0x20)
+ {
+ if(pos + 0x20 > vga.svga_intf.vram_size)
+ return;
+ bitmapline[c+0] = vga.memory[pos+0];
+ bitmapline[c+1] = vga.memory[pos+1];
+ bitmapline[c+2] = vga.memory[pos+2];
+ bitmapline[c+3] = vga.memory[pos+3];
+ bitmapline[c+4] = vga.memory[pos+0x10];
+ bitmapline[c+5] = vga.memory[pos+0x11];
+ bitmapline[c+6] = vga.memory[pos+0x12];
+ bitmapline[c+7] = vga.memory[pos+0x13];
+ }
+ }
+ }
+ else
+ {
+ for (addr = VGA_START_ADDRESS, line=0; line<LINES; line++, addr+=VGA_LINE_LENGTH/4, curr_addr+=VGA_LINE_LENGTH/4)
+ {
+ if(line < (vga.line_compare & 0xff))
+ curr_addr = addr;
+ if(line == (vga.line_compare & 0xff))
+ curr_addr = 0;
+ bitmapline = BITMAP_ADDR16(bitmap, line, 0);
+ addr %= vga.svga_intf.vram_size;
+ for (pos=curr_addr, c=0, column=0; column<VGA_COLUMNS; column++, c+=8, pos+=0x08)
+ {
+ if(pos + 0x08 > vga.svga_intf.vram_size)
+ return;
+ bitmapline[c+0] = vga.memory[pos+0];
+ bitmapline[c+1] = vga.memory[pos+1];
+ bitmapline[c+2] = vga.memory[pos+2];
+ bitmapline[c+3] = vga.memory[pos+3];
+ bitmapline[c+4] = vga.memory[pos+4];
+ bitmapline[c+5] = vga.memory[pos+5];
+ bitmapline[c+6] = vga.memory[pos+6];
+ bitmapline[c+7] = vga.memory[pos+7];
+ }
+ }
+ }
+}
+
+static pc_video_update_proc pc_vga_choosevideomode(running_machine &machine, int *width, int *height)
+{
+ pc_video_update_proc proc = NULL;
+ int i;
+
+ if (CRTC_ON)
+ {
+ 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)
+ proc = vga.svga_intf.choosevideomode(vga.sequencer.data, vga.crtc.data, vga.gc.data, width, height);
+
+ if (!proc)
+ {
+ if (!GRAPHIC_MODE)
+ {
+ proc = vga_vh_text;
+ *height = TEXT_LINES;
+ *width = TEXT_COLUMNS * CHAR_WIDTH;
+ }
+ else if (vga.gc.data[5]&0x40)
+ {
+ proc = vga_vh_vga;
+ *height = LINES;
+ *width = VGA_COLUMNS * 8;
+ }
+ else
+ {
+ proc = vga_vh_ega;
+ *height = LINES;
+ *width = EGA_COLUMNS * 8;
+ }
+ }
+ }
+ return proc;
+}
+
+
+
+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_FORMAT(BITMAP_FORMAT_INDEXED16)
+ MCFG_SCREEN_SIZE(720, 480)
+ MCFG_SCREEN_VISIBLE_AREA(0,720-1, 0,480-1)
+ MCFG_SCREEN_UPDATE(pc_video)
+ MCFG_SCREEN_REFRESH_RATE(60)
+ MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500)) /* not accurate */
+
+ MCFG_PALETTE_LENGTH(0x100)
+ MCFG_PALETTE_INIT(vga)
+
+ MCFG_VIDEO_START(vga)
+ MCFG_VIDEO_RESET(vga)
+MACHINE_CONFIG_END