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)); };