From c908fa9a094621fa42e53a4be6728297a54d9d92 Mon Sep 17 00:00:00 2001 From: Sjoerd van der Berg Date: Sun, 15 Jun 2003 19:44:58 +0000 Subject: [PATCH] SVGA support by emulating an S3/trio 64 card with 2 mb Support for dual CGA palette and background colors Support for attribute palette group changing Changes to work together with bios somewhat in supporting different video cards Basic support for Tandy pcjr 320x200x16 color mode Text mode support for changing font and panning support. Support for data rotate in 16 color modes. Imported-from: https://svn.code.sf.net/p/dosbox/code-0/dosbox/trunk@1063 --- src/hardware/vga.cpp | 238 +++++------------------- src/hardware/vga.h | 146 +++++++++------ src/hardware/vga_attr.cpp | 63 +++++-- src/hardware/vga_crtc.cpp | 311 ++++++++++++++++++++++++++++--- src/hardware/vga_dac.cpp | 27 ++- src/hardware/vga_draw.cpp | 355 +++++++++++++++++++++++++++++++----- src/hardware/vga_gfx.cpp | 20 +- src/hardware/vga_memory.cpp | 99 ++++++---- src/hardware/vga_misc.cpp | 101 +++++++++- src/hardware/vga_seq.cpp | 53 +++++- 10 files changed, 1009 insertions(+), 404 deletions(-) diff --git a/src/hardware/vga.cpp b/src/hardware/vga.cpp index bf94677b..17a03739 100644 --- a/src/hardware/vga.cpp +++ b/src/hardware/vga.cpp @@ -22,221 +22,65 @@ #include "dosbox.h" #include "video.h" #include "pic.h" -#include "render.h" #include "timer.h" #include "vga.h" +#include "inout.h" VGA_Type vga; -Bit32u CGAWriteTable[256]; +Bit32u CGA_4_Table[256]; Bit32u ExpandTable[256]; Bit32u Expand16Table[4][16]; Bit32u Expand16BigTable[0x10000]; Bit32u FillTable[16]; -static void EndRetrace(void) { - /* start the actual display update now */ - RENDER_DoUpdate(); - vga.config.retrace=false; -} -static void VGA_BlankTimer() { - PIC_AddEvent(VGA_BlankTimer,vga.draw.blank); - PIC_AddEvent(EndRetrace,667); - /* Setup a timer to destroy the vertical retrace bit in a few microseconds */ - vga.config.real_start=vga.config.display_start; - vga.config.retrace=true; -} - -static void VGA_DrawHandler(RENDER_Part_Handler part_handler) { - Bit8u * buf,* bufsplit; - /* Draw the current frame */ - if (!vga.draw.resizing) { - if (vga.config.line_compare=vga.draw.height){ - LOG(LOG_VGAGFX,LOG_NORMAL)("Split at %d",stop); - goto drawnormal; - } - switch (vga.mode) { - case GFX_16: - buf=&vga.buffer[vga.config.real_start*8+vga.config.pel_panning]; - bufsplit=vga.buffer; - break; - case GFX_256U: - buf=&vga.mem.linear[vga.config.real_start*4+vga.config.pel_panning/2]; - bufsplit=vga.mem.linear; - break; - case GFX_256C: - buf=memory+0xa0000; - bufsplit=memory+0xa0000; - break; - default: - LOG(LOG_VGAGFX,LOG_NORMAL)("VGA:Unhandled split screen mode %d",vga.mode); - goto norender; - } - part_handler(buf,0,0,vga.draw.width,stop); - part_handler(bufsplit,0,stop,vga.draw.width,vga.draw.height-stop); - } else { -drawnormal: - switch (vga.mode) { - case GFX_2: - VGA_DrawGFX2_Fast(vga.buffer,vga.draw.width); - buf=vga.buffer; - break; - case GFX_4: - VGA_DrawGFX4_Fast(vga.buffer,vga.draw.width); - buf=vga.buffer; - break; - case TEXT_16: - VGA_DrawTEXT(vga.buffer,vga.draw.width); - buf=vga.buffer; - break; - case GFX_16: - buf=&vga.buffer[vga.config.real_start*8+vga.config.pel_panning]; - break; - case GFX_256C: - buf=memory+0xa0000; - break; - case GFX_256U: - buf=&vga.mem.linear[vga.config.real_start*4+vga.config.pel_panning/2]; - break; - } - part_handler(buf,0,0,vga.draw.width,vga.draw.height); - } -norender:; - } - -} - -void VGA_FindSettings(void) { - /* Sets up the correct memory handler from the vga.mode setting */ - MEM_ClearPageHandlers(PAGE_COUNT(0xa0000),PAGE_COUNT(0x20000)); - /* Detect the kind of video mode this is */ - if (vga.config.gfxmode) { - if (vga.config.vga_enabled) { - if (vga.config.chained) { - /* 256 color chained vga */ - vga.mode=GFX_256C; - //Doesn't need a memory handler - } else { - /* 256 color unchained vga */ - vga.mode=GFX_256U; - MEM_SetupPageHandlers(PAGE_COUNT(0xa0000),PAGE_COUNT(0x10000), - &VGA_NormalReadHandler,&VGA_GFX_256U_WriteHandler); - } - } else if (vga.config.cga_enabled) { - /* 4 color cga */ - //TODO Detect hercules modes, probably set them up in bios too - if (vga.seq.clocking_mode & 0x8) { - vga.mode=GFX_4; -// MEM_SetupPageHandlers(PAGE_COUNT(0x0b8000),PAGE_COUNT(0x10000),&VGA_GFX_4_ReadHandler,&VGA_GFX_4_WriteHandler); - } else vga.mode=GFX_2; - //TODO Maybe also use a page handler for cga mode - } else { - /* 16 color ega */ - vga.mode=GFX_16; - MEM_SetupPageHandlers(PAGE_COUNT(0xa0000),PAGE_COUNT(0x10000), - &VGA_NormalReadHandler,&VGA_GFX_16_WriteHandler); - } - } else { - vga.mode=TEXT_16; - } +void VGA_SetMode(VGAModes mode) { + vga.mode=mode; + VGA_SetupHandlers(); VGA_StartResize(); } -static void VGA_DoResize(void) { - /* Calculate the FPS for this screen */ - double fps; - Bitu vtotal=2 + (vga.crtc.vertical_total | ((vga.crtc.overflow & 1) << 8) | ((vga.crtc.overflow & 0x20) << 4) ); - Bitu htotal=5 + vga.crtc.horizontal_total; - Bitu vdispend = 1 + (vga.crtc.vertical_display_end | ((vga.crtc.overflow & 2)<<7) | ((vga.crtc.overflow & 0x40) << 3) ); - Bitu hdispend = 1 + (vga.crtc.horizontal_display_end); - //TODO Maybe check if blanking comes before display_end - - double clock=(double)vga.config.clock; - /* Check for 8 for 9 character clock mode */ - if (vga.seq.clocking_mode & 1 ) clock/=8; else clock/=9; - /* Check for pixel doubling, master clock/2 */ - if (vga.seq.clocking_mode & 0x8) clock/=2; - - LOG(LOG_VGA,LOG_NORMAL)("H total %d, V Total %d",htotal,vtotal); - LOG(LOG_VGA,LOG_NORMAL)("H D End %d, V D End %d",hdispend,vdispend); - fps=clock/(vtotal*htotal); - - vga.draw.resizing=false; - Bitu width,height,pitch,flags; - - flags=0; - vga.draw.lines=height=vdispend; - width=hdispend; - vga.draw.double_height=vga.config.vline_double; - vga.draw.double_width=(vga.seq.clocking_mode & 0x8)>0; - vga.draw.font_height=vga.config.vline_height+1; - switch (vga.mode) { - case GFX_256C: - case GFX_256U: - vga.draw.double_width=true; //Hack since 256 color modes use 2 clocks for a pixel - /* Don't know might do this different sometime, will have to do for now */ - if (!vga.draw.double_height) { - if (vga.config.vline_height&1) { - vga.draw.double_height=true; - vga.draw.font_height/=2; - } - } - width<<=2; - pitch=vga.config.scan_len*8; - break; - case GFX_16: - width<<=3; - pitch=vga.config.scan_len*16; - break; - case GFX_4: - width<<=3; - pitch=width; - break; - case GFX_2: - width<<=3; - pitch=width; - break; - case TEXT_16: - /* probably a 16-color text mode, got to detect mono mode somehow */ - width<<=3; /* 8 bit wide text font */ - if (width>640) width=640; - if (height>480) height=480; - pitch=width; - }; - if (vga.draw.double_height) { - flags|=DoubleHeight; - height/=2; - } - if (vga.draw.double_width) { - flags|=DoubleWidth; - /* Double width is dividing main clock, the width should be correct already for this */ - } - if (( width != vga.draw.width) || (height != vga.draw.height) || (pitch != vga.draw.pitch)) { - PIC_RemoveEvents(VGA_BlankTimer); - vga.draw.width=width; - vga.draw.height=height; - vga.draw.pitch=pitch; - - LOG(LOG_VGA,LOG_NORMAL)("Width %d, Height %d",width,height); - LOG(LOG_VGA,LOG_NORMAL)("Flags %X, fps %f",flags,fps); - RENDER_SetSize(width,height,8,pitch,((float)width/(float)height),flags,&VGA_DrawHandler); - vga.draw.blank=(Bitu)(1000000/fps); - PIC_AddEvent(VGA_BlankTimer,vga.draw.blank); - } -}; - void VGA_StartResize(void) { if (!vga.draw.resizing) { vga.draw.resizing=true; /* Start a resize after 50 ms */ - PIC_AddEvent(VGA_DoResize,50000); + PIC_AddEvent(VGA_SetupDrawing,50000); } } +void VGA_SetClock(Bitu which,Bitu target) { + struct{ + Bitu n,m; + Bits err; + } best; + best.err=target; + Bitu n,m,r; + + for (r = 0; r <= 3; r++) { + Bitu f_vco = target * (1 << r); + if (MIN_VCO <= f_vco && f_vco < MAX_VCO) break; + } + for (n=1;n<=31;n++) { + m=(target * (n + 2) * (1 << r) + (S3_CLOCK_REF/2)) / S3_CLOCK_REF - 2; + if (0 <= m && m <= 127) { + Bitu temp_target = S3_CLOCK(m,n,r); + Bits err = target - temp_target; + if (err < 0) err = -err; + if (err < best.err) { + best.err = err; + best.m = m; + best.n = n; + } + } + } + /* Program the s3 clock chip */ + vga.s3.clk[which].m=best.m; + vga.s3.clk[which].r=r; + vga.s3.clk[which].n=best.n; + VGA_StartResize(); +} + void VGA_Init(Section* sec) { vga.draw.resizing=false; VGA_SetupMemory(); @@ -245,14 +89,16 @@ void VGA_Init(Section* sec) { VGA_SetupGFX(); VGA_SetupSEQ(); VGA_SetupAttr(); + VGA_SetClock(0,CLK_25); + VGA_SetClock(1,CLK_28); /* Generate tables */ Bitu i,j; for (i=0;i<256;i++) { ExpandTable[i]=i | (i << 8)| (i <<16) | (i << 24); #ifdef WORDS_BIGENDIAN - CGAWriteTable[i]=((i>>0)&3) | (((i>>2)&3) << 8)| (((i>>4)&3) <<16) | (((i>>6)&3) << 24); + CGA_4_Table[i]=((i>>0)&3) | (((i>>2)&3) << 8)| (((i>>4)&3) <<16) | (((i>>6)&3) << 24); #else - CGAWriteTable[i]=((i>>6)&3) | (((i>>4)&3) << 8)| (((i>>2)&3) <<16) | (((i>>0)&3) << 24); + CGA_4_Table[i]=((i>>6)&3) | (((i>>4)&3) << 8)| (((i>>2)&3) <<16) | (((i>>0)&3) << 24); #endif } for (i=0;i<16;i++) { diff --git a/src/hardware/vga.h b/src/hardware/vga.h index 9ce4b993..c3a7f9b0 100644 --- a/src/hardware/vga.h +++ b/src/hardware/vga.h @@ -22,39 +22,53 @@ #include #include "dosbox.h" -#undef TEXT -#undef GRAPH -/* conflicts with int10.h */ -enum { TEXT, GRAPH }; -enum { GFX_256C,GFX_256U,GFX_16,GFX_4,GFX_2, TEXT_16 }; +enum VGAModes { + M_TEXT16, + M_CGA2,M_CGA4, + M_TANDY16, + M_EGA2,M_EGA4,M_EGA16, + M_VGA, + M_LIN8, + M_ERROR, +}; + +#define CLK_25 25175 +#define CLK_28 28322 + +#define MIN_VCO 180000 +#define MAX_VCO 360000 + +#define S3_CLOCK_REF 14318 /* KHz */ +#define S3_CLOCK(_M,_N,_R) ((S3_CLOCK_REF * ((_M) + 2)) / (((_N) + 2) * (1 << (_R)))) +#define S3_MAX_CLOCK 150000 /* KHz */ + +/* Different functions that should be handle by memory handler */ + +#define MH_ROTATEOP 0x0001; +#define MH_SETRESET 0x0002; +#define MH_BITMASK 0x0004; typedef struct { - bool attrindex; - Bit16u cursor; } VGA_Internal; typedef struct { +/* Memory handlers */ + Bitu mh_mask; /* Video drawing */ - Bit16u display_start; - Bit16u real_start; - bool retrace; /* A retrace has started */ + Bitu display_start; + Bitu real_start; + bool retrace; /* A retrace is active */ Bitu scan_len; + Bitu cursor_start; /* Some other screen related variables */ Bitu line_compare; - Bitu clock; - bool clock_half; - bool chained; /* Enable or Disabled Chain 4 Mode */ - bool gfxmode; /* Yes or No Easy no */ bool blinking; /* Attribute bit 7 is blinking */ - bool vga_enabled; - bool cga_enabled; - bool vline_double; Bit8u vline_height; @@ -64,6 +78,7 @@ typedef struct { Bit8u bytes_skip; /* Specific stuff memory write/read handling */ + PhysPt mem_base; Bit8u read_mode; Bit8u write_mode; Bit8u read_map_select; @@ -91,13 +106,48 @@ typedef struct { bool double_width; bool double_height; Bitu lines; - Bit8u * font; Bit8u font_height; + Bit8u font[64*1024]; + Bitu rows,cols; struct { - Bitu row,col,sline,eline,count; + Bit8u sline,eline; + Bit8u count,delay; + Bit8u enabled; } cursor; } VGA_Draw; +typedef struct { + Bit8u bank; + Bit8u reg_lock1; + Bit8u reg_lock2; + Bit8u reg_31; + Bit8u reg_35; + Bit8u reg_43; + Bit8u reg_58; + Bit8u reg_51; + Bit8u reg_55; + Bit8u ex_hor_overflow; + Bit8u ex_ver_overflow; + struct { + Bit8u r; + Bit8u n; + Bit8u m; + } clk[4],mclk; + struct { + Bit8u lock; + Bit8u cmd; + } pll; +} VGA_S3; + +typedef struct { + Bit8u color_select; +} VGA_CGA; + +typedef struct { + Bit8u mem_bank; + Bit8u disp_bank; + Bit8u reg_index; +} VGA_TANDY; typedef struct { Bit8u index; @@ -109,7 +159,6 @@ typedef struct { Bit8u memory_mode; } VGA_Seq; - typedef struct { Bit8u palette[16]; Bit8u mode_control; @@ -118,9 +167,9 @@ typedef struct { Bit8u color_plane_enable; Bit8u color_select; Bit8u index; + Bit8u enabled; } VGA_Attr; - typedef struct { Bit8u horizontal_total; Bit8u horizontal_display_end; @@ -143,12 +192,13 @@ typedef struct { Bit8u vertical_display_end; Bit8u offset; Bit8u underline_location; - Bit8u start_vertical_blank; - Bit8u end_vertical_blank; + Bit8u start_vertical_blanking; + Bit8u end_vertical_blanking; Bit8u mode_control; Bit8u line_compare; Bit8u index; + bool read_only; } VGA_Crtc; typedef struct { @@ -188,15 +238,14 @@ union VGA_Latch { }; union VGA_Memory { - Bit8u linear[64*1024*4]; - Bit8u paged[64*1024][4]; - VGA_Latch latched[64*1024]; + Bit8u linear[512*1024*4]; + Bit8u paged[512*1024][4]; + VGA_Latch latched[512*1024]; }; - - typedef struct { - Bitu mode; /* The mode the vga system is in */ + VGAModes mode; /* The mode the vga system is in */ + Bit8u misc_output; VGA_Draw draw; VGA_Config config; VGA_Internal internal; @@ -207,40 +256,21 @@ typedef struct { VGA_Gfx gfx; VGA_Dac dac; VGA_Latch latch; + VGA_S3 s3; + VGA_CGA cga; + VGA_TANDY tandy; VGA_Memory mem; -/* Extra buffer following main video ram with double data for overflowing of addresses */ - Bit8u buffer[1024*1024]; /* 256 kb vid ram with 16 colors and double addresses */ } VGA_Type; - - - - /* Functions for different resolutions */ -//void VGA_FindSize(void); -void VGA_FindSettings(void); +void VGA_SetMode(VGAModes mode); +void VGA_SetupHandlers(void); void VGA_StartResize(void); - -/* The Different Drawing functions */ -void VGA_DrawTEXT(Bit8u * bitdata,Bitu next_line); -void VGA_DrawGFX256U_Full(Bit8u * bitdata,Bitu next_line); -void VGA_DrawGFX16_Fast(Bit8u * bitdata,Bitu next_line); -void VGA_DrawGFX4_Fast(Bit8u * bitdata,Bitu next_line); -void VGA_DrawGFX2_Fast(Bit8u * bitdata,Bitu next_line); -/* The Different Memory Read/Write Handlers */ -Bit8u VGA_NormalReadHandler(Bit32u start); - -void VGA_GFX_256U_WriteHandler(Bit32u start,Bit8u val); -void VGA_GFX_16_WriteHandler(Bit32u start,Bit8u val); -void VGA_GFX_4_WriteHandler(Bit32u start,Bit8u val); - -Bit8u VGA_GFX_4_ReadHandler(Bit32u start); - - +void VGA_SetupDrawing(void); /* Some support functions */ void VGA_DAC_CombineColor(Bit8u attr,Bit8u pal); - +void VGA_ATTR_SetPalette(Bit8u index,Bit8u val); /* The VGA Subfunction startups */ void VGA_SetupAttr(void); @@ -252,17 +282,15 @@ void VGA_SetupGFX(void); void VGA_SetupSEQ(void); /* Some Support Functions */ +void VGA_SetClock(Bitu which,Bitu target); void VGA_DACSetEntirePalette(void); void VGA_StartRetrace(void); extern VGA_Type vga; -extern Bit8u vga_rom_08[256 * 8]; -extern Bit8u vga_rom_14[256 * 14]; -extern Bit8u vga_rom_16[256 * 16]; extern Bit32u ExpandTable[256]; extern Bit32u FillTable[16]; -extern Bit32u CGAWriteTable[256]; +extern Bit32u CGA_4_Table[256]; extern Bit32u Expand16Table[4][16]; extern Bit32u Expand16BigTable[0x10000]; diff --git a/src/hardware/vga_attr.cpp b/src/hardware/vga_attr.cpp index c105d3e1..e94936c2 100644 --- a/src/hardware/vga_attr.cpp +++ b/src/hardware/vga_attr.cpp @@ -22,14 +22,23 @@ #define attr(blah) vga.attr.blah + +void VGA_ATTR_SetPalette(Bit8u index,Bit8u val) { + vga.attr.palette[index]=val; + if (vga.attr.mode_control & 0x80) val=(val&0xf) | (vga.attr.color_select << 4); + else val|=(vga.attr.color_select & 0xc) << 4; + VGA_DAC_CombineColor(index,val); +} + void write_p3c0(Bit32u port,Bit8u val) { if (!vga.internal.attrindex) { attr(index)=val & 0x1F; vga.internal.attrindex=true; + attr(enabled)=val & 0x20; /* - 0-4 Address of data register to write to port 3C0h or read from port 3C1h - If set screen output is enabled and the palette can not be modified, - if clear screen output is disabled and the palette can be modified. + 0-4 Address of data register to write to port 3C0h or read from port 3C1h + 5 If set screen output is enabled and the palette can not be modified, + if clear screen output is disabled and the palette can be modified. */ return; } else { @@ -40,20 +49,29 @@ void write_p3c0(Bit32u port,Bit8u val) { case 0x04: case 0x05: case 0x06: case 0x07: case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: - val&=0x3f; - attr(palette[attr(index)])=val; - VGA_DAC_CombineColor(attr(index),val); + if (!attr(enabled)) VGA_ATTR_SetPalette(attr(index),val); /* 0-5 Index into the 256 color DAC table. May be modified by 3C0h index 10h and 14h. */ break; case 0x10: /* Mode Control Register */ - if (val != attr(mode_control)) { + if ((attr(mode_control) ^ val) & 0x80) { attr(mode_control)=val; - vga.config.gfxmode=val&1; - vga.config.vga_enabled=(val & 0x40)>0; - VGA_FindSettings(); + for (Bitu i=0;i<0x10;i++) { + VGA_ATTR_SetPalette(i,vga.attr.palette[i]); + } + } + attr(mode_control)=val; + /* + Special hacks for games programming registers themselves, + Doesn't work if they program EGA16 themselves, + but haven't encountered that yet + */ + if (val&0x40) { + if (vga.mode0x7) vga.config.pel_panning=0; + else vga.config.pel_panning=val+1; + break; + case M_VGA: + case M_LIN8: + vga.config.pel_panning=(val & 0x7)/2; + break; + default: + vga.config.pel_panning=(val & 0x7); + } /* 0-3 Indicates number of pixels to shift the display left Value 9bit textmode 256color mode Other modes @@ -114,7 +141,12 @@ void write_p3c0(Bit32u port,Bit8u val) { */ break; case 0x14: /* Color Select Register */ - attr(color_select)=val; + if (attr(color_select) ^ val) { + attr(color_select)=val; + for (Bitu i=0;i<0x10;i++) { + VGA_ATTR_SetPalette(i,vga.attr.palette[i]); + } + } /* 0-1 If 3C0h index 10h bit 7 is set these 2 bits are used as bits 4-5 of the index into the DAC table. @@ -122,7 +154,6 @@ void write_p3c0(Bit32u port,Bit8u val) { except in 256 color mode. Note: this register does not affect 256 color modes. */ - if (val) LOG(LOG_VGAGFX,LOG_NORMAL)("VGA:ATTR:DAC index set to %d",val); break; default: LOG(LOG_VGAMISC,LOG_NORMAL)("VGA:ATTR:Write to unkown Index %2X",attr(index)); diff --git a/src/hardware/vga_crtc.cpp b/src/hardware/vga_crtc.cpp index e2c40f0a..fe704ed2 100644 --- a/src/hardware/vga_crtc.cpp +++ b/src/hardware/vga_crtc.cpp @@ -19,7 +19,8 @@ #include "dosbox.h" #include "inout.h" #include "vga.h" - +#include "debug.h" +#include "cpu.h" #define crtc(blah) vga.crtc.blah @@ -34,12 +35,15 @@ Bit8u read_p3d4(Bit32u port) { void write_p3d5(Bit32u port,Bit8u val) { +// if (crtc(index)>0x18) LOG_MSG("VGA CRCT write %X to reg %X",val,crtc(index)); switch(crtc(index)) { case 0x00: /* Horizontal Total Register */ + if (crtc(read_only)) break; crtc(horizontal_total)=val; /* 0-7 Horizontal Total Character Clocks-5 */ break; case 0x01: /* Horizontal Display End Register */ + if (crtc(read_only)) break; if (val != crtc(horizontal_display_end)) { crtc(horizontal_display_end)=val; VGA_StartResize(); @@ -47,10 +51,12 @@ void write_p3d5(Bit32u port,Bit8u val) { /* 0-7 Number of Character Clocks Displayed -1 */ break; case 0x02: /* Start Horizontal Blanking Register */ + if (crtc(read_only)) break; crtc(start_horizontal_blanking)=val; /* 0-7 The count at which Horizontal Blanking starts */ break; case 0x03: /* End Horizontal Blanking Register */ + if (crtc(read_only)) break; crtc(end_horizontal_blanking)=val; /* 0-4 Horizontal Blanking ends when the last 6 bits of the character @@ -62,10 +68,12 @@ void write_p3d5(Bit32u port,Bit8u val) { */ break; case 0x04: /* Start Horizontal Retrace Register */ + if (crtc(read_only)) break; crtc(start_horizontal_retrace)=val; /* 0-7 Horizontal Retrace starts when the Character Counter reaches this value. */ break; case 0x05: /* End Horizontal Retrace Register */ + if (crtc(read_only)) break; crtc(end_horizontal_retrace)=val; /* 0-4 Horizontal Retrace ends when the last 5 bits of the character counter @@ -76,6 +84,7 @@ void write_p3d5(Bit32u port,Bit8u val) { */ break; case 0x06: /* Vertical Total Register */ + if (crtc(read_only)) break; if (val != crtc(vertical_total)) { crtc(vertical_total)=val; VGA_StartResize(); @@ -86,9 +95,10 @@ void write_p3d5(Bit32u port,Bit8u val) { */ break; case 0x07: /* Overflow Register */ - crtc(overflow)=val; - vga.config.line_compare=(vga.config.line_compare & 0x2ff) | (val & 0x10) << 4; - if ((vga.crtc.overflow ^ val) & 0xef) { + //Line compare bit ignores read only */ + vga.config.line_compare=(vga.config.line_compare & 0x6ff) | (val & 0x10) << 4; + if (crtc(read_only)) break; + if ((vga.crtc.overflow ^ val) & 0xd6) { crtc(overflow)=val; VGA_StartResize(); } else crtc(overflow)=val; @@ -119,7 +129,7 @@ void write_p3d5(Bit32u port,Bit8u val) { case 0x09: /* Maximum Scan Line Register */ vga.config.vline_double=(val & 128)>1; vga.config.vline_height=(val & 0xf); - vga.config.line_compare=(vga.config.line_compare & 0x1ff)|(val&0x40)<<3; + vga.config.line_compare=(vga.config.line_compare & 0x5ff)|(val&0x40)<<3; if ((vga.crtc.maximum_scan_line ^ val) & 0xbf) { crtc(maximum_scan_line)=val; VGA_StartResize(); @@ -137,6 +147,8 @@ void write_p3d5(Bit32u port,Bit8u val) { break; case 0x0A: /* Cursor Start Register */ crtc(cursor_start)=val; + vga.draw.cursor.sline=val&0x1f; + vga.draw.cursor.enabled=!(val&0x20); /* 0-4 First scanline of cursor within character. 5 Turns Cursor off if set @@ -144,6 +156,9 @@ void write_p3d5(Bit32u port,Bit8u val) { break; case 0x0B: /* Cursor End Register */ crtc(cursor_end)=val; + vga.draw.cursor.eline=val&0x1f; + vga.draw.cursor.delay=(val>>5)&0x3; + /* 0-4 Last scanline of cursor within character 5-6 Delay of cursor data in character clocks. @@ -151,27 +166,25 @@ void write_p3d5(Bit32u port,Bit8u val) { break; case 0x0C: /* Start Address High Register */ crtc(start_address_high)=val; - vga.config.display_start=(vga.config.display_start & 0x00FF)| (val << 8); + vga.config.display_start=(vga.config.display_start & 0xFF00FF)| (val << 8); /* 0-7 Upper 8 bits of the start address of the display buffer */ break; case 0x0D: /* Start Address Low Register */ crtc(start_address_low)=val; - vga.config.display_start=(vga.config.display_start & 0xFF00)| val; + vga.config.display_start=(vga.config.display_start & 0xFFFF00)| val; /* 0-7 Lower 8 bits of the start address of the display buffer */ break; case 0x0E: /*Cursor Location High Register */ crtc(cursor_location_high)=val; - if (vga.config.scan_len<2) break; - vga.draw.cursor.row=(crtc(cursor_location_high)<<8|crtc(cursor_location_low))/(vga.config.scan_len*2); - vga.draw.cursor.col=(crtc(cursor_location_high)<<8|crtc(cursor_location_low))%(vga.config.scan_len*2); + vga.config.cursor_start&=0xff00ff; + vga.config.cursor_start|=val << 8; /* 0-7 Upper 8 bits of the address of the cursor */ break; case 0x0F: /* Cursor Location Low Register */ //TODO update cursor on screen crtc(cursor_location_low)=val; - if (vga.config.scan_len<2) break; - vga.draw.cursor.row=(crtc(cursor_location_high)<<8|crtc(cursor_location_low))/(vga.config.scan_len*2); - vga.draw.cursor.col=(crtc(cursor_location_high)<<8|crtc(cursor_location_low))%(vga.config.scan_len*2); + vga.config.cursor_start&=0xffff00; + vga.config.cursor_start|=val; /* 0-7 Lower 8 bits of the address of the cursor */ break; case 0x10: /* Vertical Retrace Start Register */ @@ -184,6 +197,7 @@ void write_p3d5(Bit32u port,Bit8u val) { break; case 0x11: /* Vertical Retrace End Register */ crtc(vertical_retrace_end)=val; + crtc(read_only)=(val & 128)>0; /* 0-3 Vertical Retrace ends when the last 4 bits of the line counter equals this value. @@ -209,7 +223,8 @@ void write_p3d5(Bit32u port,Bit8u val) { case 0x13: /* Offset register */ if (val!=crtc(offset)) { crtc(offset)=val; - vga.config.scan_len=val; + vga.config.scan_len&=0x300; + vga.config.scan_len|=val; VGA_StartResize(); } /* @@ -226,7 +241,10 @@ void write_p3d5(Bit32u port,Bit8u val) { */ break; case 0x15: /* Start Vertical Blank Register */ - crtc(start_vertical_blank)=val; + if (val!=crtc(start_vertical_blanking)) { + crtc(start_vertical_blanking)=val; + VGA_StartResize(); + } /* 0-7 Lower 8 bits of Vertical Blank Start. Vertical blanking starts when the line counter reaches this value. Bit 8 is found in 3d4h index 7 @@ -234,18 +252,14 @@ void write_p3d5(Bit32u port,Bit8u val) { */ break; case 0x16: /* End Vertical Blank Register */ - crtc(end_vertical_blank)=val; + crtc(end_vertical_blanking)=val; /* 0-6 Vertical blanking stops when the lower 7 bits of the line counter equals this field. Some SVGA chips uses all 8 bits! */ break; case 0x17: /* Mode Control Register */ - if (val!=crtc(mode_control)) { - crtc(mode_control)=val; - vga.config.cga_enabled=!((val&1)>0); - VGA_FindSettings(); - } + crtc(mode_control)=val; /* 0 If clear use CGA compatible memory addressing system by substituting character row scan counter bit 0 for address bit 13, @@ -264,21 +278,217 @@ void write_p3d5(Bit32u port,Bit8u val) { break; case 0x18: /* Line Compare Register */ crtc(line_compare)=val; - vga.config.line_compare=(vga.config.line_compare & 0x300) | val; + vga.config.line_compare=(vga.config.line_compare & 0x700) | val; /* 0-7 Lower 8 bits of the Line Compare. When the Line counter reaches this value, the display address wraps to 0. Provides Split Screen facilities. Bit 8 is found in 3d4h index 7 bit 4. Bit 9 is found in 3d4h index 9 bit 6. */ - break; +/* S3 specific group */ + case 0x31: /* CR31 Memory Configuration */ +//TODO Base address + vga.s3.reg_31=val; + break; + /* + 0 Enable Base Address Offset (CPUA BASE). Enables bank operation if + set, disables if clear. + 1 Two Page Screen Image. If set enables 2048 pixel wide screen setup + 2 VGA 16bit Memory Bus Width. Set for 16bit, clear for 8bit + 3 Use Enhanced Mode Memory Mapping (ENH MAP). Set to enable access to + video memory above 256k. + 4-5 Bit 16-17 of the Display Start Address. For the 801/5,928 see index + 51h, for the 864/964 see index 69h. + 6 High Speed Text Display Font Fetch Mode. If set enables Page Mode + for Alpha Mode Font Access. + 7 (not 864/964) Extended BIOS ROM Space Mapped out. If clear the area + C6800h-C7FFFh is mapped out, if set it is accessible. + */ + case 0x35: /* CR35 CRT Register Lock */ + if (vga.s3.reg_lock1 != 0x48) return; //Needed for uvconfig detection + vga.s3.reg_35=val & 0xf0; + if ((vga.s3.bank & 0xf) ^ (val & 0xf)) { + vga.s3.bank&=0xf0; + vga.s3.bank|=val & 0xf; + VGA_SetupHandlers(); + } + break; + /* + 0-3 CPU Base Address. 64k bank number. For the 801/5 and 928 see 3d4h + index 51h bits 2-3. For the 864/964 see index 6Ah. + 4 Lock Vertical Timing Registers (LOCK VTMG). Locks 3d4h index 6, 7 + (bits 0,2,3,5,7), 9 bit 5, 10h, 11h bits 0-3, 15h, 16h if set + 5 Lock Horizontal Timing Registers (LOCK HTMG). Locks 3d4h index + 0,1,2,3,4,5,17h bit 2 if set + 6 (911/924) Lock VSync Polarity. + 7 (911/924) Lock HSync Polarity. + */ + case 0x38: /* CR38 Register Lock 1 */ + vga.s3.reg_lock1=val; + break; + case 0x39: /* CR39 Register Lock 2 */ + vga.s3.reg_lock2=val; + break; + case 0x43: /* CR43 Extended Mode */ + vga.s3.reg_43=val & ~0x4; + if (((val & 0x4) ^ (vga.config.scan_len >> 6)) & 0x4) { + vga.config.scan_len&=0x2ff; + vga.config.scan_len|=(val & 0x4) << 6; + VGA_StartResize(); + } + break; + /* + 2 Logical Screen Width bit 8. Bit 8 of the Display Offset Register/ + (3d4h index 13h). (801/5,928) Only active if 3d4h index 51h bits 4-5 + are 0 + */ + case 0x51: /* Extended System Control 2 */ + vga.s3.reg_51=val & 0xc0; //Only store bits 6,7 + //TODO Display start + vga.config.display_start&=0xFCFFFF; + vga.config.display_start|=(val & 3) << 16; + if ((vga.s3.bank&0xcf) ^ ((val&0xc)<<2)) { + vga.s3.bank&=0xcf; + vga.s3.bank|=(val&0xc)<<2; + VGA_SetupHandlers(); + } + if (((val & 0x30) ^ (vga.config.scan_len >> 4)) & 0x30) { + vga.config.scan_len&=0xff; + vga.config.scan_len|=(val & 0x30) << 4; + VGA_StartResize(); + } + break; + /* + 0 (80x) Display Start Address bit 18 + 0-1 (928 +) Display Start Address bit 18-19 + Bits 16-17 are in index 31h bits 4-5, Bits 0-15 are in 3d4h index + 0Ch,0Dh. For the 864/964 see 3d4h index 69h + 2 (80x) CPU BASE. CPU Base Address Bit 18. + 2-3 (928 +) Old CPU Base Address Bits 19-18. + 64K Bank register bits 4-5. Bits 0-3 are in 3d4h index 35h. + For the 864/964 see 3d4h index 6Ah + 4-5 Logical Screen Width Bit [8-9]. Bits 8-9 of the CRTC Offset register + (3d4h index 13h). If this field is 0, 3d4h index 43h bit 2 is active + 6 (928,964) DIS SPXF. Disable Split Transfers if set. Spilt Transfers + allows transferring one half of the VRAM shift register data while + the other half is being output. For the 964 Split Transfers + must be enabled in enhanced modes (4AE8h bit 0 set). Guess: They + probably can't time the VRAM load cycle closely enough while the + graphics engine is running. + 7 (not 864/964) Enable EPROM Write. If set enables flash memory write + control to the BIOS ROM address + */ + case 0x55: /* Extended Video DAC Control */ + vga.s3.reg_55=val; + break; + /* + 0-1 DAC Register Select Bits. Passed to the RS2 and RS3 pins on the + RAMDAC, allowing access to all 8 or 16 registers on advanced RAMDACs. + If this field is 0, 3d4h index 43h bit 1 is active. + 2 Enable General Input Port Read. If set DAC reads are disabled and the + STRD strobe for reading the General Input Port is enabled for reading + while DACRD is active, if clear DAC reads are enabled. + 3 (928) Enable External SID Operation if set. If set video data is + passed directly from the VRAMs to the DAC rather than through the + VGA chip + 4 Hardware Cursor MS/X11 Mode. If set the Hardware Cursor is in X11 + mode, if clear in MS-Windows mode + 5 (80x,928) Hardware Cursor External Operation Mode. If set the two + bits of cursor data ,is output on the HC[0-1] pins for the video DAC + The SENS pin becomes HC1 and the MID2 pin becomes HC0. + 6 ?? + 7 (80x,928) Disable PA Output. If set PA[0-7] and VCLK are tristated. + (864/964) TOFF VCLK. Tri-State Off VCLK Output. VCLK output tri + -stated if set + */ + case 0x58: /* Linear Address Window Control */ + vga.s3.reg_58=val; + break; + /* + 0-1 Linear Address Window Size. Must be less than or equal to video + memory size. 0: 64K, 1: 1MB, 2: 2MB, 3: 4MB (928)/8Mb (864/964) + 2 (not 864/964) Enable Read Ahead Cache if set + 3 (80x,928) ISA Latch Address. If set latches address during every ISA + cycle, unlatches during every ISA cycle if clear. + (864/964) LAT DEL. Address Latch Delay Control (VL-Bus only). If set + address latching occours in the T1 cycle, if clear in the T2 cycle + (I.e. one clock cycle delayed). + 4 ENB LA. Enable Linear Addressing if set. + 5 (not 864/964) Limit Entry Depth for Write-Post. If set limits Write + -Post Entry Depth to avoid ISA bus timeout due to wait cycle limit. + 6 (928,964) Serial Access Mode (SAM) 256 Words Control. If set SAM + control is 256 words, if clear 512 words. + 7 (928) RAS 6-MCLK. If set the random read/write cycle time is 6MCLKs, + if clear 7MCLKs + */ + case 0x5D: /* Extended Horizontal Overflow */ + if ((val & vga.s3.ex_hor_overflow) ^ 3) { + vga.s3.ex_hor_overflow=val; + VGA_StartResize(); + } else vga.s3.ex_hor_overflow=val; + break; + /* + 0 Horizontal Total bit 8. Bit 8 of the Horizontal Total register (3d4h + index 0) + 1 Horizontal Display End bit 8. Bit 8 of the Horizontal Display End + register (3d4h index 1) + 2 Start Horizontal Blank bit 8. Bit 8 of the Horizontal Start Blanking + register (3d4h index 2). + 3 (864,964) EHB+64. End Horizontal Blank +64. If set the /BLANK pulse + is extended by 64 DCLKs. Note: Is this bit 6 of 3d4h index 3 or + does it really extend by 64 ? + 4 Start Horizontal Sync Position bit 8. Bit 8 of the Horizontal Start + Retrace register (3d4h index 4). + 5 (864,964) EHS+32. End Horizontal Sync +32. If set the HSYNC pulse + is extended by 32 DCLKs. Note: Is this bit 5 of 3d4h index 5 or + does it really extend by 32 ? + 6 (928,964) Data Transfer Position bit 8. Bit 8 of the Data Transfer + Position register (3d4h index 3Bh) + 7 (928,964) Bus-Grant Terminate Position bit 8. Bit 8 of the Bus Grant + Termination register (3d4h index 5Fh). + */ + case 0x5e: /* Extended Vertical Overflow */ + vga.config.line_compare=(vga.config.line_compare & 0x3ff) | (val & 0x40) << 4; + if ((val ^ vga.s3.ex_ver_overflow) & 0x3) { + vga.s3.ex_ver_overflow=val; + VGA_StartResize(); + } else vga.s3.ex_ver_overflow=val; + break; + /* + 0 Vertical Total bit 10. Bit 10 of the Vertical Total register (3d4h + index 6). Bits 8 and 9 are in 3d4h index 7 bit 0 and 5. + 1 Vertical Display End bit 10. Bit 10 of the Vertical Display End + register (3d4h index 12h). Bits 8 and 9 are in 3d4h index 7 bit 1 + and 6 + 2 Start Vertical Blank bit 10. Bit 10 of the Vertical Start Blanking + register (3d4h index 15h). Bit 8 is in 3d4h index 7 bit 3 and bit 9 + in 3d4h index 9 bit 5 + 4 Vertical Retrace Start bit 10. Bit 10 of the Vertical Start Retrace + register (3d4h index 10h). Bits 8 and 9 are in 3d4h index 7 bit 2 + and 7. + 6 Line Compare Position bit 10. Bit 10 of the Line Compare register + (3d4h index 18h). Bit 8 is in 3d4h index 7 bit 4 and bit 9 in 3d4h + index 9 bit 6. + */ + case 0x69: /* Extended System Control 3 */ + if (((vga.config.display_start & 0x1f0000)>>16) ^ (val & 0x1f)) { + vga.config.display_start&=0xffff; + vga.config.display_start|=(val & 0x1f) << 16; + } + break; + case 0x6a: /* Extended System Control 4 */ + vga.s3.bank=val & 0x3f; + VGA_SetupHandlers(); + break; + default: - LOG(LOG_VGAMISC,LOG_NORMAL)("VGA:CRTC:Write to unknown index %2X",val,crtc(index)); + LOG(LOG_VGAMISC,LOG_NORMAL)("VGA:CRTC:Write %X to unknown index %2X",val,crtc(index)); } } Bit8u read_p3d5(Bit32u port) { +// LOG_MSG("VGA CRCT read from reg %X",crtc(index)); switch(crtc(index)) { case 0x00: /* Horizontal Total Register */ return crtc(horizontal_total); @@ -323,17 +533,64 @@ Bit8u read_p3d5(Bit32u port) { case 0x14: /* Underline Location Register */ return crtc(underline_location); case 0x15: /* Start Vertical Blank Register */ - return crtc(start_vertical_blank); + return crtc(start_vertical_blanking); case 0x16: /* End Vertical Blank Register */ - return crtc(end_vertical_blank); + return crtc(end_vertical_blanking); case 0x17: /* Mode Control Register */ return crtc(mode_control); case 0x18: /* Line Compare Register */ return crtc(line_compare); + + +/* Additions for S3 SVGA Support */ + case 0x2d: /* Extended Chip ID. */ + return 0x88; + // Always 88h ? + case 0x2e: /* New Chip ID */ + return 0x11; + //Trio 64 id + case 0x2f: /* Revision */ + return 0x80; + case 0x30: /* CR30 Chip ID/REV register */ + return 0xe0; //Trio+ dual byte + // Trio32/64 has 0xe0. extended + case 0x31: /* CR31 Memory Configuration */ +//TODO mix in bits from baseaddress; + return vga.s3.reg_31; + case 0x35: /* CR35 CRT Register Lock */ + return vga.s3.reg_35|(vga.s3.bank & 0xf); + case 0x36: /* CR36 Reset State Read 1 */ + return 0x8f; + //2 Mb PCI and some bios settings + case 0x37: /* Reset state read 2 */ + return 0x2b; + case 0x38: /* CR38 Register Lock 1 */ + return vga.s3.reg_lock1; + case 0x39: /* CR39 Register Lock 2 */ + return vga.s3.reg_lock2; + case 0x43: /* CR43 Extended Mode */ + return vga.s3.reg_43|((vga.config.scan_len>>6)&0x4); + case 0x51: /* Extended System Control 2 */ + return ((vga.config.display_start >> 16) & 3 ) | + ((vga.s3.bank & 0x30) >> 2) | + ((vga.config.scan_len & 0x300) >> 4) | + vga.s3.reg_51; + case 0x55: /* Extended Video DAC Control */ + return vga.s3.reg_55; + case 0x58: /* Linear Address Window Control */ + return vga.s3.reg_58; + case 0x5D: /* Extended Horizontal Overflow */ + return vga.s3.ex_hor_overflow; + case 0x5e: /* Extended Vertical Overflow */ + return vga.s3.ex_ver_overflow; + case 0x69: /* Extended System Control 3 */ + return (Bit8u)((vga.config.display_start & 0x1f0000)>>16); + case 0x6a: /* Extended System Control 4 */ + return (Bit8u)(vga.s3.bank & 0x3f); default: LOG(LOG_VGAMISC,LOG_NORMAL)("VGA:CRTC:Read from unknown index %X",crtc(index)); } - return 0; + return 0x0; } diff --git a/src/hardware/vga_dac.cpp b/src/hardware/vga_dac.cpp index f9c7051c..b387d91b 100644 --- a/src/hardware/vga_dac.cpp +++ b/src/hardware/vga_dac.cpp @@ -68,6 +68,12 @@ static void write_p3c7(Bit32u port,Bit8u val) { vga.dac.read_index=val; vga.dac.pel_index=0; vga.dac.state=DAC_READ; + +} + +static Bit8u read_p3c7(Bit32u port) { + if (vga.dac.state==DAC_READ) return 0x3; + else return 0x0; } static void write_p3c8(Bit32u port,Bit8u val) { @@ -89,8 +95,8 @@ static void write_p3c9(Bit32u port,Bit8u val) { case 2: vga.dac.rgb[vga.dac.write_index].blue=val; switch (vga.mode) { - case GFX_256C: - case GFX_256U: + case M_VGA: + case M_LIN8: RENDER_SetPal(vga.dac.write_index, vga.dac.rgb[vga.dac.write_index].red << 2, vga.dac.rgb[vga.dac.write_index].green << 2, @@ -141,12 +147,17 @@ static Bit8u read_p3c9(Bit32u port) { void VGA_DAC_CombineColor(Bit8u attr,Bit8u pal) { /* Check if this is a new color */ vga.dac.attr[attr]=pal; - if (vga.mode != GFX_256U && vga.mode != GFX_256C) - RENDER_SetPal(attr, - vga.dac.rgb[pal].red << 2, - vga.dac.rgb[pal].green << 2, - vga.dac.rgb[pal].blue << 2 + switch (vga.mode) { + case M_VGA: + case M_LIN8: + break; + default: + RENDER_SetPal(attr, + vga.dac.rgb[pal].red << 2, + vga.dac.rgb[pal].green << 2, + vga.dac.rgb[pal].blue << 2 ); + } } void VGA_SetupDAC(void) { @@ -157,11 +168,11 @@ void VGA_SetupDAC(void) { vga.dac.state=DAC_READ; vga.dac.read_index=0; vga.dac.write_index=0; - /* Setup the DAC IO port Handlers */ IO_RegisterWriteHandler(0x3c6,write_p3c6,"PEL Mask"); IO_RegisterReadHandler(0x3c6,read_p3c6,"PEL Mask"); IO_RegisterWriteHandler(0x3c7,write_p3c7,"PEL Read Mode"); + IO_RegisterReadHandler(0x3c7,read_p3c7,"PEL Status Mode"); IO_RegisterWriteHandler(0x3c8,write_p3c8,"PEL Write Mode"); IO_RegisterWriteHandler(0x3c9,write_p3c9,"PEL Data"); IO_RegisterReadHandler(0x3c9,read_p3c9,"PEL Data"); diff --git a/src/hardware/vga_draw.cpp b/src/hardware/vga_draw.cpp index 337d04d0..ca517d30 100644 --- a/src/hardware/vga_draw.cpp +++ b/src/hardware/vga_draw.cpp @@ -19,11 +19,13 @@ #include #include "dosbox.h" #include "video.h" +#include "render.h" #include "vga.h" +#include "pic.h" //TODO Make the full draw like the vga really does from video memory. -void VGA_DrawGFX2_Fast(Bit8u * bitdata,Bitu pitch) { +static void VGA_CGA2_Draw(Bit8u * bitdata,Bitu pitch) { Bit8u * reader=HostMake(0xB800,0); Bit8u * flip=HostMake(0xB800,8*1024); Bit8u * draw; @@ -36,7 +38,7 @@ void VGA_DrawGFX2_Fast(Bit8u * bitdata,Bitu pitch) { }; draw=bitdata; //TODO Look up table like in 4color mode - for (Bit32u x=vga.draw.width>>3;x>0;x--) { + for (Bitu x=vga.draw.width>>3;x>0;x--) { Bit8u val=*(tempread++); *(draw+0)=(val>>7)&1; *(draw+1)=(val>>6)&1; @@ -52,7 +54,7 @@ void VGA_DrawGFX2_Fast(Bit8u * bitdata,Bitu pitch) { } } -void VGA_DrawGFX4_Fast(Bit8u * bitdata,Bitu pitch) { +static void VGA_CGA4_Draw(Bit8u * bitdata,Bitu pitch) { Bit8u * reader=HostMake(0xB800,vga.config.display_start*2); Bit8u * flip=HostMake(0xB800,8*1024); Bit8u * draw; @@ -65,74 +67,333 @@ void VGA_DrawGFX4_Fast(Bit8u * bitdata,Bitu pitch) { if (reader>=flip) reader-=8*1024; } draw=bitdata; - for (Bit32u x=0;x>2;x++) { + for (Bitu x=0;x>2;x++) { Bit8u val=*(tempread++); - *(Bit32u *)draw=CGAWriteTable[val]; + *(Bit32u *)draw=CGA_4_Table[val]; draw+=4; } bitdata+=pitch; } } -/* Draw the screen using the lookup buffer */ -void VGA_DrawGFX16_Fast(Bit8u * bitdata,Bitu next_line) { - Bit8u * reader=&vga.buffer[vga.config.display_start*8+vga.config.pel_panning]; - for (Bitu y=0;y>2;x++) { - for (Bit32u dx=0;dx<4;dx++) { - (*bitdata++)=vga.mem.paged[xreader][dx]; - } - xreader++; + Bit8u val1=*(tempread++); + Bit8u val2=*(tempread++); + Bit32u full=(val1 & 0x0f) << 8 | + (val1 & 0xf0) >> 4 | + (val2 & 0x0f) << 24 | + (val2 & 0xf0) << 12; + *(Bit32u *)draw=full; + draw+=4; } - yreader+=vga.config.scan_len*2; - bitdata+=next_line; + bitdata+=pitch; + if ((y & 3)==3)reader+=160; } } -void VGA_DrawTEXT(Bit8u * bitdata,Bitu pitch) { - - Bit8u * reader=HostMake((vga.gfx.miscellaneous & 0x4 ?0xB800:0xB000),0); + +void VGA_TEXT_Draw(Bit8u * bitdata,Bitu start,Bitu panning,Bitu rows) { + Bit8u * reader=HostMake(0xb800,start); Bit8u * draw_start=bitdata; /* Todo Blinking and high intensity colors */ - for (Bitu cy=0;cy<(vga.draw.height/16);cy++) { + Bitu next_charline=vga.draw.font_height*vga.draw.width; + Bitu next_line=vga.draw.width; + Bitu next_start=(vga.config.scan_len*2)-vga.draw.cols; + for (Bitu cy=rows;cy>0;cy--) { Bit8u * draw_char=draw_start; - for (Bitu cx=0;cx<(vga.draw.width/8);cx++) { + /* Do first character keeping track of panning */ + { Bit8u c=*(reader++); - Bit8u * findex=&vga_rom_16[c*16]; + Bit8u * findex=&vga.draw.font[c*32]; + Bit8u col=*(reader++); + Bit8u fg=col & 0xF; + Bit8u bg=(col>> 4); + Bit8u * draw_line=draw_char; + Bit8u bit_index=1 << (7-panning); + for (Bitu y=vga.draw.font_height;y>0;y--) { + Bit8u * draw=draw_line; + draw_line+=next_line; + Bit8u bit=bit_index; + Bit8u bit_mask=*findex++; + while (bit) { + if (bit_mask & bit) *draw=fg; + else *draw=bg; + draw++;bit>>=1; + } + } + draw_char+=8-panning; + } + for (Bitu cx=vga.draw.cols-1;cx>0;cx--) { + Bit8u c=*(reader++); + Bit8u * findex=&vga.draw.font[c*32]; Bit8u col=*(reader++); Bit8u fg=col & 0xF; Bit8u bg=(col>> 4); Bit8u * draw=draw_char; - for (Bitu y=0;y<16;y++) { + for (Bitu y=vga.draw.font_height;y>0;y--) { Bit8u bit_mask=*findex++; #include "font-switch.h" - draw+=pitch; - }; + draw+=next_line; + } draw_char+=8; - }; - draw_start+=16*pitch; - }; - if(!(vga.internal.cursor & 0x2000)) { - /* Draw a cursor */ - if (((Bitu)vga.draw.cursor.col*8)>=vga.draw.width) return; - if (((Bitu)vga.draw.cursor.row*16)>=vga.draw.height) return; - Bit8u * cursor_draw=bitdata+(vga.draw.cursor.row*16+15)*pitch+vga.draw.cursor.col*8; - if (vga.draw.cursor.count>8) { - for (Bit8u loop=0;loop<8;loop++) *cursor_draw++=15; } - vga.draw.cursor.count++; - if (vga.draw.cursor.count>16) vga.draw.cursor.count=0; - } -}; + /* Do last character if needed */ + if (panning) { + Bit8u c=*(reader); + Bit8u * findex=&vga.draw.font[c*32]; + Bit8u col=*(reader+1); + Bit8u fg=col & 0xF; + Bit8u bg=(col>> 4); + Bit8u * draw_line=draw_char; + Bit8u bit_index=1 << panning; + for (Bitu y=vga.draw.font_height;y>0;y--) { + Bit8u * draw=draw_line; + draw_line+=next_line; + Bit8u bit=bit_index; + Bit8u bit_mask=*findex++; + while (bit) { + if (bit_mask & bit) *draw=fg; + else *draw=bg; + draw++;bit>>=1; + } + } + } + draw_start+=next_charline; + reader+=next_start; + } +/* Cursor handling */ + vga.draw.cursor.count++; + if (vga.draw.cursor.count>16) vga.draw.cursor.count=0; + if(vga.draw.cursor.enabled && (vga.draw.cursor.count>8)) { /* Draw a cursor if enabled */ + Bits cur_start=vga.config.cursor_start-start; + if (cur_start<0) return; + + Bitu row=cur_start / (vga.config.scan_len*2); + Bitu col=cur_start % (vga.config.scan_len*2); + Bit32u att=*HostMake(0xb800,vga.config.cursor_start*2+1)&0xf; + att=(att << 8) | att; + att=(att << 16) | att; + + if ((col*8)>=vga.draw.width) return; + if ((row*vga.draw.font_height)>=vga.draw.height) return; + if (vga.draw.cursor.sline>=vga.draw.font_height) return; + if (vga.draw.cursor.sline>vga.draw.cursor.eline) return; + Bit8u * cursor_draw=bitdata+(row*vga.draw.font_height+vga.draw.cursor.sline)*vga.draw.width+col*8; + + for (Bits loop=vga.draw.cursor.eline-vga.draw.cursor.sline;loop>=0;loop--) { + *((Bit32u *)cursor_draw)=att; + *((Bit32u *)(cursor_draw+4))=att; + cursor_draw+=vga.draw.width; + } + } +} + +static void EndRetrace(void) { + /* start the actual display update now */ + RENDER_DoUpdate(); + vga.config.retrace=false; +} + +static void VGA_BlankTimer() { + PIC_AddEvent(VGA_BlankTimer,vga.draw.blank); + PIC_AddEvent(EndRetrace,667); + /* Setup a timer to destroy the vertical retrace bit in a few microseconds */ + vga.config.real_start=vga.config.display_start; + vga.config.retrace=true; +} + + +void VGA_DrawHandler(RENDER_Part_Handler part_handler) { + Bit8u * buf,* bufsplit; + /* Draw the current frame */ + if (!vga.draw.resizing) { + if (vga.config.line_compare=vga.draw.height){ + LOG(LOG_VGAGFX,LOG_NORMAL)("Split at %d",stop); + goto drawnormal; + } + switch (vga.mode) { + case M_EGA16: + buf=&vga.mem.linear[512*1024+vga.config.real_start*8+vga.config.pel_panning]; + bufsplit=&vga.mem.linear[512*1024]; + break; + case M_VGA: + case M_LIN8: + buf=&vga.mem.linear[vga.config.real_start*4+vga.config.pel_panning]; + bufsplit=vga.mem.linear; + break; + case M_TEXT16: + { + Bitu first_rows=stop/vga.draw.font_height; + if (vga.config.hlines_skip) first_rows++; + if (stop%vga.draw.font_height) first_rows++; + Bitu next_rows=(vga.draw.height-stop)/vga.draw.font_height; + if ((vga.draw.height-stop)%vga.draw.font_height) next_rows++; + VGA_TEXT_Draw(&vga.mem.linear[512*1024],vga.config.real_start,vga.config.pel_panning,first_rows); + VGA_TEXT_Draw(&vga.mem.linear[1024*1024],0,0,next_rows); + buf=&vga.mem.linear[512*1024+vga.config.hlines_skip*vga.draw.width]; + bufsplit=&vga.mem.linear[1024*1024]; + } + break; + default: + LOG(LOG_VGAGFX,LOG_NORMAL)("VGA:Unhandled split screen mode %d",vga.mode); + goto norender; + } + if (stop) part_handler(buf,0,0,vga.draw.width,stop); + if (vga.draw.height-stop) part_handler(bufsplit,0,stop,vga.draw.width,vga.draw.height-stop); + } else { +drawnormal: + switch (vga.mode) { + case M_CGA2: + VGA_CGA2_Draw(&vga.mem.linear[512*1024],vga.draw.width); + buf=&vga.mem.linear[512*1024]; + break; + case M_CGA4: + VGA_CGA4_Draw(&vga.mem.linear[512*1024],vga.draw.width); + buf=&vga.mem.linear[512*1024]; + break; + case M_TANDY16: + VGA_TANDY16_Draw(&vga.mem.linear[512*1024],vga.draw.width); + buf=&vga.mem.linear[512*1024]; + break; + case M_EGA16: + buf=&vga.mem.linear[512*1024+vga.config.real_start*8+vga.config.pel_panning]; + break; + case M_VGA: + case M_LIN8: + buf=&vga.mem.linear[vga.config.real_start*4+vga.config.pel_panning]; + break; + case M_TEXT16: + { + Bitu rows=vga.draw.rows; + if (vga.config.hlines_skip) rows++; + VGA_TEXT_Draw(&vga.mem.linear[512*1024],vga.config.real_start,vga.config.pel_panning,rows); + buf=&vga.mem.linear[512*1024+vga.config.hlines_skip*vga.draw.width]; + } + break; + default: + return; + } + part_handler(buf,0,0,vga.draw.width,vga.draw.height); + } +norender:; + } + +} + + +void VGA_SetupDrawing(void) { + /* Calculate the FPS for this screen */ + double fps; + Bitu vtotal=2 + (vga.crtc.vertical_total | ((vga.crtc.overflow & 1) << 8) | ((vga.crtc.overflow & 0x20) << 4) ); + Bitu htotal=5 + vga.crtc.horizontal_total; + Bitu vdispend = 1 + (vga.crtc.vertical_display_end | ((vga.crtc.overflow & 2)<<7) | ((vga.crtc.overflow & 0x40) << 3) ); + Bitu hdispend = 1 + (vga.crtc.horizontal_display_end); + + Bitu hbstart = vga.crtc.start_horizontal_blanking; + Bitu vbstart = vga.crtc.start_vertical_blanking | ((vga.crtc.overflow & 0x08) << 5) | ((vga.crtc.maximum_scan_line & 0x20) << 4) ; + + if (hbstart> 2) & 3; + clock=1000*S3_CLOCK(vga.s3.clk[clock].m,vga.s3.clk[clock].n,vga.s3.clk[clock].r); + /* Check for 8 for 9 character clock mode */ + if (vga.seq.clocking_mode & 1 ) clock/=8; else clock/=9; + /* Check for pixel doubling, master clock/2 */ + if (vga.seq.clocking_mode & 0x8) clock/=2; + /* Check for dual transfer whatever thing,master clock/2 */ + if (vga.s3.pll.cmd & 0x10) clock/=2; + + + LOG(LOG_VGA,LOG_NORMAL)("H total %d, V Total %d",htotal,vtotal); + LOG(LOG_VGA,LOG_NORMAL)("H D End %d, V D End %d",hdispend,vdispend); + fps=clock/(vtotal*htotal); + + vga.draw.resizing=false; + Bitu width,height,pitch,flags; + + flags=0; + vga.draw.lines=height=vdispend; + width=hdispend; + vga.draw.double_height=vga.config.vline_double; + vga.draw.double_width=(vga.seq.clocking_mode & 0x8)>0; + vga.draw.font_height=vga.config.vline_height+1; + switch (vga.mode) { + case M_VGA: + vga.draw.double_width=true; //Hack since 256 color modes use 2 clocks for a pixel + /* Don't know might do this different sometime, will have to do for now */ + if (!vga.draw.double_height) { + if (vga.config.vline_height&1) { + vga.draw.double_height=true; + vga.draw.font_height/=2; + } + } + width<<=2; + pitch=vga.config.scan_len*8; + break; + case M_LIN8: + width<<=3; + pitch=vga.config.scan_len*8; + break; + case M_EGA16: + width<<=3; + pitch=vga.config.scan_len*16; + break; + case M_CGA4: + width<<=3; + pitch=width; + break; + case M_CGA2: + width<<=3; + pitch=width; + break; + case M_TANDY16: + width<<=3; + pitch=width; + break; + case M_TEXT16: + /* probably a 16-color text mode, got to detect mono mode somehow */ + vga.draw.font_height=vga.config.vline_height+1; + vga.draw.cols=width; + vga.draw.rows=(height/vga.draw.font_height); + if (height % vga.draw.font_height) vga.draw.rows++; + width<<=3; /* 8 bit wide text font */ + if (width>640) width=640; + if (height>480) height=480; + pitch=width; + break; + default: + LOG(LOG_VGA,LOG_ERROR)("Unhandled VGA type %d while checking for resolution"); + }; + if (vga.draw.double_height) { + flags|=DoubleHeight; + height/=2; + } + if (vga.draw.double_width) { + flags|=DoubleWidth; + /* Double width is dividing main clock, the width should be correct already for this */ + } + if (( width != vga.draw.width) || (height != vga.draw.height) || (pitch != vga.draw.pitch)) { + PIC_RemoveEvents(VGA_BlankTimer); + vga.draw.width=width; + vga.draw.height=height; + vga.draw.pitch=pitch; + + LOG(LOG_VGA,LOG_NORMAL)("Width %d, Height %d",width,height); + LOG(LOG_VGA,LOG_NORMAL)("Flags %X, fps %f",flags,fps); + RENDER_SetSize(width,height,8,pitch,((float)width/(float)height),flags,&VGA_DrawHandler); + vga.draw.blank=(Bitu)(1000000/fps); + PIC_AddEvent(VGA_BlankTimer,vga.draw.blank); + } +}; diff --git a/src/hardware/vga_gfx.cpp b/src/hardware/vga_gfx.cpp index cc363bb0..dafe1ada 100644 --- a/src/hardware/vga_gfx.cpp +++ b/src/hardware/vga_gfx.cpp @@ -56,6 +56,8 @@ void write_p3cf(Bit32u port,Bit8u val) { vga.config.full_not_enable_set_reset=~vga.config.full_enable_set_reset; vga.config.full_enable_and_set_reset=vga.config.full_set_reset & vga.config.full_enable_set_reset; +// if (gfx(enable_set_reset)) vga.config.mh_mask|=MH_SETRESET else vga.config.mh_mask&=~MH_SETRESET; + break; case 2: /* Color Compare Register */ gfx(color_compare)=val & 0x0f; /* @@ -70,7 +72,7 @@ void write_p3cf(Bit32u port,Bit8u val) { case 3: /* Data Rotate */ gfx(data_rotate)=val; vga.config.data_rotate=val & 7; - if (vga.config.data_rotate) LOG(LOG_VGAGFX,LOG_NORMAL)("VGA:Data Rotate used %d",val &7); +// if (val) vga.config.mh_mask|=MH_ROTATEOP else vga.config.mh_mask&=~MH_ROTATEOP; vga.config.raster_op=(val>>3) & 3; /* 0-2 Number of positions to rotate data right before it is written to @@ -83,7 +85,6 @@ void write_p3cf(Bit32u port,Bit8u val) { 2: CPU data is ORed with the latch data. 3: CPU data is XORed with the latched data. */ -// if (vga.config.data_rotate || vga.config.raster_op ) LOG_DEBUG("Data Rotate = %2X Raster op %2X",val & 7,(val>>3) & 3 ); break; case 4: /* Read Map Select Register */ /* 0-1 number of the plane Read Mode 0 will read from */ @@ -138,6 +139,19 @@ void write_p3cf(Bit32u port,Bit8u val) { break; case 6: /* Miscellaneous Register */ gfx(miscellaneous)=val; + switch ((val >> 2) & 3) { + case 0: + case 1: + vga.config.mem_base=0xa0000; + break; + case 2: + vga.config.mem_base=0xb0000; + break; + case 3: + vga.config.mem_base=0xb8000; + break; + } + if (vga.mode==M_TEXT16) VGA_SetupHandlers(); /* 0 Indicates Graphics Mode if set, Alphanumeric mode else. 1 Enables Odd/Even mode if set. @@ -182,7 +196,7 @@ void write_p3cf(Bit32u port,Bit8u val) { } Bit8u read_p3cf(Bit32u port) { -switch (gfx(index)) { + switch (gfx(index)) { case 0: /* Set/Reset Register */ return gfx(set_reset); case 1: /* Enable Set/Reset Register */ diff --git a/src/hardware/vga_memory.cpp b/src/hardware/vga_memory.cpp index 81d2ee05..f87385d2 100644 --- a/src/hardware/vga_memory.cpp +++ b/src/hardware/vga_memory.cpp @@ -26,16 +26,7 @@ #include "vga.h" -Bit8u VGA_ChainedReadHandler(Bit32u start) { - return vga.mem.linear[start]; -} - -void VGA_ChainedWriteHandler(Bit32u start,Bit8u val) { - vga.mem.linear[start]=val; -}; - - -Bit8u VGA_NormalReadHandler(PhysPt start) { +static Bit8u VGA_NormalReadHandler(PhysPt start) { start-=0xa0000; vga.latch.d=vga.mem.latched[start].d; switch (vga.config.read_mode) { @@ -50,6 +41,7 @@ Bit8u VGA_NormalReadHandler(PhysPt start) { } //Nice one from DosEmu + INLINE static Bit32u RasterOp(Bit32u input,Bit32u mask) { switch (vga.config.raster_op) { case 0x00: /* None */ @@ -64,6 +56,7 @@ INLINE static Bit32u RasterOp(Bit32u input,Bit32u mask) { return 0; } + INLINE static Bit32u ModeOperation(Bit8u val) { Bit32u full; switch (vga.config.write_mode) { @@ -91,26 +84,27 @@ INLINE static Bit32u ModeOperation(Bit8u val) { return full; } -Bit8u VGA_GFX_4_ReadHandler(Bit32u start) { +static Bit8u VGA_CGA_4_ReadHandler(PhysPt start) { return vga.mem.linear[start-0xb8000]; } -void VGA_GFX_4_WriteHandler(Bit32u start,Bit8u val) { +static void VGA_CGA_4_WriteHandler(PhysPt start,Bit8u val) { start-=0xb8000; vga.mem.linear[start]=val; Bitu off; if (start>0x2000) off=320*(((start-0x2000)/80)*2+1)+((start-0x2000) % 80)*4; else off=320*(((start)/80)*2)+(start % 80)*4; - Bit32u * draw=(Bit32u *)&vga.buffer[off]; + Bit32u * draw=(Bit32u *)&vga.mem.linear[512*1024+off]; /* TODO Could also use a Bit32u lookup table for this */ - *draw=CGAWriteTable[val]; - draw=(Bit32u *)&vga.buffer[off+0x4000*4]; - *draw=CGAWriteTable[val]; + *draw=CGA_4_Table[val]; + draw=(Bit32u *)&vga.mem.linear[512*1024+off+0x4000*4]; + *draw=CGA_4_Table[val]; } -void VGA_GFX_16_WriteHandler(Bit32u start,Bit8u val) { +static void VGA_GFX_16_WriteHandler(PhysPt start,Bit8u val) { start-=0xa0000; + val=(val >> vga.config.data_rotate) | (val << (8-vga.config.data_rotate)); Bit32u data=ModeOperation(val); /* Update video memory and the pixel buffer */ VGA_Latch pixels; @@ -118,7 +112,7 @@ void VGA_GFX_16_WriteHandler(Bit32u start,Bit8u val) { pixels.d&=vga.config.full_not_map_mask; pixels.d|=(data & vga.config.full_map_mask); vga.mem.latched[start].d=pixels.d; - Bit8u * write_pixels=&vga.buffer[start<<3]; + Bit8u * write_pixels=&vga.mem.linear[512*1024+(start<<3)]; Bit32u colors0_3, colors4_7; VGA_Latch temp;temp.d=(pixels.d>>4) & 0x0f0f0f0f; @@ -140,36 +134,75 @@ void VGA_GFX_16_WriteHandler(Bit32u start,Bit8u val) { } -void VGA_GFX_256U_WriteHandler(Bit32u start,Bit8u val) { +static void VGA_GFX_256U_WriteHandler(PhysPt start,Bit8u val) { start-=0xa0000; Bit32u data=ModeOperation(val); +// Bit32u data=ExpandTable[val]; VGA_Latch pixels; pixels.d=vga.mem.latched[start].d; pixels.d&=vga.config.full_not_map_mask; pixels.d|=(data & vga.config.full_map_mask); vga.mem.latched[start].d=pixels.d; vga.mem.latched[start+64*1024].d=pixels.d; -}; - - - - - - - - +} +static void VGA_TEXT16_Write(PhysPt start,Bit8u val) { + start-=vga.config.mem_base; + /* Check for page 2 being enabled for writing */ + if (vga.seq.map_mask & 0x4) { + vga.draw.font[start]=val; + } + //TODO Check for writes to other pages with normal text characters/attributes +} +static Bit8u VGA_TEXT16_Read(PhysPt start) { + start-=vga.config.mem_base; + return vga.draw.font[start]; +} +void VGA_SetupHandlers(void) { + /* Sets up the correct memory handler from the vga.mode setting */ + MEM_ClearPageHandlers(PAGE_COUNT(0xa0000),PAGE_COUNT(0x20000)); + switch (vga.mode) { + case M_LIN8: + MEM_SetupMapping(PAGE_COUNT(0xa0000),PAGE_COUNT(0x10000),&vga.mem.linear[vga.s3.bank*64*1024]); + break; + case M_VGA: + if (vga.config.chained) { + MEM_SetupMapping(PAGE_COUNT(0xa0000),PAGE_COUNT(0x10000),&vga.mem.linear[vga.s3.bank*64*1024]); + } else { + MEM_SetupPageHandlers(PAGE_COUNT(0xa0000),PAGE_COUNT(0x10000), + &VGA_NormalReadHandler,&VGA_GFX_256U_WriteHandler); + } + break; + case M_EGA16: + MEM_SetupPageHandlers(PAGE_COUNT(0xa0000),PAGE_COUNT(0x10000), + &VGA_NormalReadHandler,&VGA_GFX_16_WriteHandler); + break; + case M_TEXT16: + /* Check if we're not in odd/even mode */ + if (vga.gfx.miscellaneous & 0x2) break; + MEM_SetupPageHandlers(PAGE_COUNT(0xa0000),PAGE_COUNT(0x10000),&VGA_TEXT16_Read,&VGA_TEXT16_Write); + //Could also do it using 0xb8000, let's double map + MEM_SetupPageHandlers(PAGE_COUNT(0xb8000),PAGE_COUNT(0x8000),&VGA_TEXT16_Read,&VGA_TEXT16_Write); + break; + case M_TANDY16: + MEM_SetupMapping(PAGE_COUNT(0xb8000),PAGE_COUNT(0x8000),&vga.mem.linear[vga.tandy.mem_bank << 14]); + break; + case M_CGA4: + case M_CGA2: + break; + default: + LOG_MSG("Unhandled vga mode %X",vga.mode); + } +} void VGA_SetupMemory() { - memset((void *)&vga.mem,0,256*1024); - /* Alocate Video Memory */ - /* Not needed for VGA memory it gets allocated together with emulator maybe - later for VESA memory */ - + memset((void *)&vga.mem,0,512*1024*4); + /* Map linear frame buffer at 32 mb */ + MEM_SetupMapping(PAGE_COUNT(32*1024*1024),PAGE_COUNT(2*1024*1024),&vga.mem); } diff --git a/src/hardware/vga_misc.cpp b/src/hardware/vga_misc.cpp index 82d5d984..b08f322b 100644 --- a/src/hardware/vga_misc.cpp +++ b/src/hardware/vga_misc.cpp @@ -48,16 +48,95 @@ static Bit8u read_p3da(Bit32u port) { static void write_p3d8(Bit32u port,Bit8u val) { - LOG(LOG_VGAMISC,LOG_NORMAL)("Write %2X to 3da",val); + switch (vga.mode) { + case M_CGA4: + + break; + default: + break; + } + LOG(LOG_VGAMISC,LOG_NORMAL)("Write %2X to 3d8",val); /* 3 Vertical Sync Select. If set Vertical Sync to the monitor is the logical OR of the vertical sync and the vertical display enable. */ } -static void write_p3c2(Bit32u port,Bit8u val) { - p3c2data=val; +static void write_p3d9(Bit32u port,Bit8u val) { + switch (vga.mode) { + case M_CGA2: + vga.cga.color_select=val; + /* changes attribute 1 */ + vga.attr.palette[1]=(val & 7) + ((val & 8) ? 0x38 : 0); + VGA_DAC_CombineColor(1,vga.attr.palette[0]); + break; + case M_CGA4: + vga.cga.color_select=val; + /* changes attribute 0 */ + VGA_ATTR_SetPalette(0,(val & 7) + ((val & 8) ? 0x38 : 0)); + if (val & 0x020) { + VGA_ATTR_SetPalette(1,0x13); + VGA_ATTR_SetPalette(2,0x15); + VGA_ATTR_SetPalette(3,0x17); + } else { + VGA_ATTR_SetPalette(1,0x02); + VGA_ATTR_SetPalette(2,0x04); + VGA_ATTR_SetPalette(3,0x06); + } + break; + /* Color Select register + Text modes: 320x200 modes: 640x200 mode: + 0 Blue border Blue background Blue ForeGround + 1 Green border Green background Green ForeGround + 2 Red border Red background Red ForeGround + 3 Bright border Bright background Bright ForeGround + 4 Backgr. color Alt. intens. colors Alt. intens colors + 5 No func. Selects palette + Palette 0 is Green, red and brown, + Palette 1 is Cyan, magenta and white. + */ + default: + LOG(LOG_VGAMISC,LOG_NORMAL)("Unhandled Write %2X to %X in mode %d",val,port,vga.mode); + } +} +static void write_p3df(Bit32u port,Bit8u val) { + switch (vga.mode) { + case M_TANDY16: + vga.tandy.disp_bank=val & ((val & 0x80) ? 0x6 : 0x7); + vga.tandy.mem_bank=(val >> 3) & ((val & 0x80) ? 0x6 : 0x7); + VGA_SetupHandlers(); + + break; + /* + 0-2 Identifies the page of main memory being displayed in units of 16K. + 0: 0K, 1: 16K...7: 112K. In 32K modes (bits 6-7 = 2) only 0,2,4 and + 6 are valid, as the next page will also be used. + 3-5 Identifies the page of main memory that can be read/written at B8000h + in units of 16K. 0: 0K, 1: 16K...7: 112K. In 32K modes (bits 6-7 = 2) + only 0,2,4 and 6 are valid, as the next page will also be used. + 6-7 Display mode. 0: Text, 1: 16K graphics mode (4,5,6,8) + 2: 32K graphics mode (9,Ah) + */ + default: + LOG(LOG_VGAMISC,LOG_NORMAL)("Unhandled Write %2X to %X in mode %d",val,port,vga.mode); + break; + } +} + +static Bit8u read_p3d9(Bit32u port) { + switch (vga.mode) { + case M_CGA2: + case M_CGA4: + return vga.cga.color_select; + default: + return 0xff; + } +} + + +static void write_p3c2(Bit32u port,Bit8u val) { + vga.misc_output=val; if (val & 0x1) { IO_RegisterWriteHandler(0x3d4,write_p3d4,"VGA:CRTC Index Select"); IO_RegisterReadHandler(0x3d4,read_p3d4,"VGA:CRTC Index Select"); @@ -77,11 +156,6 @@ static void write_p3c2(Bit32u port,Bit8u val) { IO_FreeWriteHandler(0x3d5); IO_FreeReadHandler(0x3d5); } - if (val & 0x4) vga.config.clock=28322000; - else vga.config.clock=25175000; - - VGA_StartResize(); - /* 0 If set Color Emulation. Base Address=3Dxh else Mono Emulation. Base Address=3Bxh. 2-3 Clock Select. 0: 25MHz, 1: 28MHz @@ -97,7 +171,7 @@ static void write_p3c2(Bit32u port,Bit8u val) { static Bit8u read_p3cc(Bit32u port) { - return p3c2data; + return vga.misc_output; } void VGA_SetupMisc(void) { @@ -105,8 +179,17 @@ void VGA_SetupMisc(void) { IO_RegisterReadHandler(0x3ba,read_p3da,"VGA Input Status 1"); IO_RegisterWriteHandler(0x3d8,write_p3d8,"VGA Feature Control Register"); + + + IO_RegisterWriteHandler(0x3d9,write_p3d9,"CGA Color Select Register"); + IO_RegisterReadHandler(0x3d9,read_p3d9,"CGA Color Select Register"); + + IO_RegisterWriteHandler(0x3c2,write_p3c2,"VGA Misc Output"); + IO_RegisterReadHandler(0x3cc,read_p3cc,"VGA Misc Output"); + IO_RegisterWriteHandler(0x3df,write_p3df,"PCJR Setting"); + } diff --git a/src/hardware/vga_seq.cpp b/src/hardware/vga_seq.cpp index c4b6f198..c608cc69 100644 --- a/src/hardware/vga_seq.cpp +++ b/src/hardware/vga_seq.cpp @@ -31,6 +31,8 @@ void write_p3c4(Bit32u port,Bit8u val) { }; void write_p3c5(Bit32u port,Bit8u val) { + if (seq(index)>0x8 && vga.s3.pll.lock!=0x6) return; +// LOG_MSG("SEQ WRITE reg %X val %X",seq(index),val); switch(seq(index)) { case 0: /* Reset */ seq(reset)=val; @@ -88,8 +90,31 @@ void write_p3c5(Bit32u port,Bit8u val) { /* Changing this means changing the VGA Memory Read/Write Handler */ if (val&0x08) vga.config.chained=true; else vga.config.chained=false; - VGA_FindSettings(); + VGA_SetupHandlers(); break; +/* S3 specific group */ + case 0x08: + vga.s3.pll.lock=val; + break; + case 0x10: /* Memory PLL Data Low */ + vga.s3.mclk.n=val & 0x1f; + vga.s3.mclk.r=val >> 5; + break; + case 0x11: /* Memory PLL Data High */ + vga.s3.mclk.m=val & 0x7f; + break; + case 0x12: /* Video PLL Data Low */ + vga.s3.clk[3].n=val & 0x1f; + vga.s3.clk[3].r=val >> 5; + break; + case 0x13: /* Video PLL Data High */ + vga.s3.clk[3].m=val & 0x7f; + break; + case 0x15: + vga.s3.pll.cmd=val; + VGA_StartResize(); + break; + default: LOG(LOG_VGAMISC,LOG_NORMAL)("VGA:SEQ:Write to illegal index %2X",seq(index)); }; @@ -97,21 +122,37 @@ void write_p3c5(Bit32u port,Bit8u val) { Bit8u read_p3c5(Bit32u port) { +// LOG_MSG("VGA:SEQ:Read from index %2X",seq(index)); + if (seq(index)>0x8 && vga.s3.pll.lock!=0x6) return seq(index); switch(seq(index)) { - case 0: /* Reset */ + case 0: /* Reset */ return seq(reset); break; - case 1: /* Clocking Mode */ + case 1: /* Clocking Mode */ return seq(clocking_mode); break; - case 2: /* Map Mask */ + case 2: /* Map Mask */ return seq(map_mask); break; - case 3: /* Character Map Select */ + case 3: /* Character Map Select */ return seq(character_map_select); break; - case 4: /* Memory Mode */ + case 4: /* Memory Mode */ return seq(memory_mode); + /* S3 specific group */ + case 0x08: /* PLL Unlock */ + return vga.s3.pll.lock; + case 0x10: /* Memory PLL Data Low */ + return vga.s3.mclk.n || (vga.s3.mclk.r << 5); + case 0x11: /* Memory PLL Data High */ + return vga.s3.mclk.m; + case 0x12: /* Video PLL Data Low */ + return vga.s3.clk[3].n || (vga.s3.clk[3].r << 5); + case 0x13: /* Video Data High */ + return vga.s3.clk[3].m; + case 0x15: + return vga.s3.pll.cmd; + default: LOG(LOG_VGAMISC,LOG_NORMAL)("VGA:SEQ:Read from illegal index %2X",seq(index)); };