diff --git a/include/callback.h b/include/callback.h index b09a3822..5b557460 100644 --- a/include/callback.h +++ b/include/callback.h @@ -30,7 +30,7 @@ extern CallBack_Handler CallBack_Handlers[]; enum { CB_RETN,CB_RETF,CB_RETF8,CB_IRET,CB_IRETD,CB_IRET_STI,CB_IRET_EOI_PIC1, CB_IRQ0,CB_IRQ1,CB_IRQ9,CB_IRQ12,CB_IRQ12_RET,CB_IRQ6_PCJR,CB_MOUSE, CB_INT29,CB_INT16,CB_HOOKABLE,CB_TDE_IRET,CB_IPXESR,CB_IPXESR_RET, - CB_INT21,CB_INT13 }; + CB_INT21,CB_INT13,CB_VESA_WAIT,CB_VESA_PM }; #define CB_MAX 128 #define CB_SIZE 32 diff --git a/src/cpu/callback.cpp b/src/cpu/callback.cpp index a503e944..1200dd27 100644 --- a/src/cpu/callback.cpp +++ b/src/cpu/callback.cpp @@ -458,6 +458,48 @@ Bitu CALLBACK_SetupExtra(Bitu callback, Bitu type, PhysPt physAddress, bool use_ phys_writew(physAddress+0x02,(Bit16u)0x0ECD); // int 0e phys_writeb(physAddress+0x04,(Bit8u)0xCF); //An IRET Instruction return (use_cb?9:5); + case CB_VESA_WAIT: + if (use_cb) E_Exit("VESA wait must not implement a callback handler!"); + phys_writeb(physAddress+0x00,(Bit8u)0xFB); // sti + phys_writeb(physAddress+0x01,(Bit8u)0x50); // push ax + phys_writeb(physAddress+0x02,(Bit8u)0x52); // push dx + phys_writeb(physAddress+0x03,(Bit8u)0xBA); // mov dx, + phys_writew(physAddress+0x04,(Bit16u)0x03DA); // 0x3da + phys_writeb(physAddress+0x06,(Bit8u)0xEC); // in al,dx + phys_writew(physAddress+0x07,(Bit16u)0x08A8); // test al,8 + phys_writew(physAddress+0x09,(Bit16u)0xFB75); // jne $-5 + phys_writeb(physAddress+0x0B,(Bit8u)0xEC); // in al,dx + phys_writew(physAddress+0x0C,(Bit16u)0x08A8); // test al,8 + phys_writew(physAddress+0x0E,(Bit16u)0xFB74); // je $-5 + phys_writeb(physAddress+0x10,(Bit8u)0x5A); // pop dx + phys_writeb(physAddress+0x11,(Bit8u)0x58); // pop ax + phys_writeb(physAddress+0x12,(Bit8u)0xCB); //A RETF Instruction + return 19; + case CB_VESA_PM: + if (use_cb) { + phys_writeb(physAddress+0x00,(Bit8u)0xFE); //GRP 4 + phys_writeb(physAddress+0x01,(Bit8u)0x38); //Extra Callback instruction + phys_writew(physAddress+0x02,(Bit16u)callback); //The immediate word + physAddress+=4; + } + phys_writew(physAddress+0x00,(Bit16u)0xC3F6); // test bl, + phys_writeb(physAddress+0x02,(Bit8u)0x80); // 0x80 + phys_writew(physAddress+0x03,(Bit16u)0x1674); // je $+22 + phys_writew(physAddress+0x05,(Bit16u)0x5066); // push ax + phys_writew(physAddress+0x07,(Bit16u)0x5266); // push dx + phys_writew(physAddress+0x09,(Bit16u)0xBA66); // mov dx, + phys_writew(physAddress+0x0B,(Bit16u)0x03DA); // 0x3da + phys_writeb(physAddress+0x0D,(Bit8u)0xEC); // in al,dx + phys_writew(physAddress+0x0E,(Bit16u)0x08A8); // test al,8 + phys_writew(physAddress+0x10,(Bit16u)0xFB75); // jne $-5 + phys_writeb(physAddress+0x12,(Bit8u)0xEC); // in al,dx + phys_writew(physAddress+0x13,(Bit16u)0x08A8); // test al,8 + phys_writew(physAddress+0x15,(Bit16u)0xFB74); // je $-5 + phys_writew(physAddress+0x17,(Bit16u)0x5A66); // pop dx + phys_writew(physAddress+0x19,(Bit16u)0x5866); // pop ax + if (use_cb) + phys_writeb(physAddress+0x1B,(Bit8u)0xC3); //A RETN Instruction + return (use_cb?32:27); default: E_Exit("CALLBACK:Setup:Illegal type %d",type); } diff --git a/src/ints/int10.cpp b/src/ints/int10.cpp index 1a8d614d..a9cfda2b 100644 --- a/src/ints/int10.cpp +++ b/src/ints/int10.cpp @@ -592,10 +592,10 @@ graphics_chars: break; case 0x07: switch (reg_bl) { - case 0x80: /* Set Display Start during retrace ?? */ + case 0x80: /* Set Display Start during retrace */ case 0x00: /* Set display Start */ reg_al=0x4f; - reg_ah=VESA_SetDisplayStart(reg_cx,reg_dx); + reg_ah=VESA_SetDisplayStart(reg_cx,reg_dx,reg_bl==0x80); break; case 0x01: reg_al=0x4f; @@ -611,9 +611,8 @@ graphics_chars: case 0x09: switch (reg_bl) { case 0x80: /* Set Palette during retrace */ - //TODO case 0x00: /* Set Palette */ - reg_ah=VESA_SetPalette(SegPhys(es)+reg_di,reg_dx,reg_cx); + reg_ah=VESA_SetPalette(SegPhys(es)+reg_di,reg_dx,reg_cx,reg_bl==0x80); reg_al=0x4f; break; case 0x01: /* Get Palette */ @@ -633,27 +632,27 @@ graphics_chars: } switch (reg_bl) { case 0x00: - reg_edi=RealOff(int10.rom.pmode_interface); SegSet16(es,RealSeg(int10.rom.pmode_interface)); + reg_di=RealOff(int10.rom.pmode_interface); reg_cx=int10.rom.pmode_interface_size; reg_ax=0x004f; break; case 0x01: /* Get code for "set window" */ - reg_edi=RealOff(int10.rom.pmode_interface)+int10.rom.pmode_interface_window; SegSet16(es,RealSeg(int10.rom.pmode_interface)); - reg_cx=0x10; //0x10 should be enough for the callbacks + reg_di=RealOff(int10.rom.pmode_interface)+int10.rom.pmode_interface_window; + reg_cx=int10.rom.pmode_interface_start-int10.rom.pmode_interface_window; reg_ax=0x004f; break; case 0x02: /* Get code for "set display start" */ - reg_edi=RealOff(int10.rom.pmode_interface)+int10.rom.pmode_interface_start; SegSet16(es,RealSeg(int10.rom.pmode_interface)); - reg_cx=0x10; //0x10 should be enough for the callbacks + reg_di=RealOff(int10.rom.pmode_interface)+int10.rom.pmode_interface_start; + reg_cx=int10.rom.pmode_interface_palette-int10.rom.pmode_interface_start; reg_ax=0x004f; break; case 0x03: /* Get code for "set palette" */ - reg_edi=RealOff(int10.rom.pmode_interface)+int10.rom.pmode_interface_palette; SegSet16(es,RealSeg(int10.rom.pmode_interface)); - reg_cx=0x10; //0x10 should be enough for the callbacks + reg_di=RealOff(int10.rom.pmode_interface)+int10.rom.pmode_interface_palette; + reg_cx=int10.rom.pmode_interface_size-int10.rom.pmode_interface_palette; reg_ax=0x004f; break; default: diff --git a/src/ints/int10.h b/src/ints/int10.h index 93f985b9..e9b622b0 100644 --- a/src/ints/int10.h +++ b/src/ints/int10.h @@ -133,6 +133,8 @@ typedef struct { RealPt video_dcc_table; RealPt oemstring; RealPt vesa_modes; + RealPt wait_retrace; + RealPt set_window; RealPt pmode_interface; Bit16u pmode_interface_size; Bit16u pmode_interface_start; @@ -208,9 +210,9 @@ Bit8u VESA_GetSVGAMode(Bit16u & mode); Bit8u VESA_SetCPUWindow(Bit8u window,Bit8u address); Bit8u VESA_GetCPUWindow(Bit8u window,Bit16u & address); Bit8u VESA_ScanLineLength(Bit8u subcall, Bit16u val, Bit16u & bytes,Bit16u & pixels,Bit16u & lines); -Bit8u VESA_SetDisplayStart(Bit16u x,Bit16u y); +Bit8u VESA_SetDisplayStart(Bit16u x,Bit16u y,bool wait); Bit8u VESA_GetDisplayStart(Bit16u & x,Bit16u & y); -Bit8u VESA_SetPalette(PhysPt data,Bitu index,Bitu count); +Bit8u VESA_SetPalette(PhysPt data,Bitu index,Bitu count,bool wait); Bit8u VESA_GetPalette(PhysPt data,Bitu index,Bitu count); /* Sub Groups */ diff --git a/src/ints/int10_vesa.cpp b/src/ints/int10_vesa.cpp index 32559e23..e17ea4f2 100644 --- a/src/ints/int10_vesa.cpp +++ b/src/ints/int10_vesa.cpp @@ -36,7 +36,7 @@ #define VESA_UNIMPLEMENTED 0xFF static struct { - Bitu setwindow; + Bitu rmWindow; Bitu pmStart; Bitu pmWindow; Bitu pmPalette; @@ -254,7 +254,7 @@ foundit: var_write(&minfo.XResolution,mblock->swidth); var_write(&minfo.YResolution,mblock->sheight); } - var_write(&minfo.WinFuncPtr,CALLBACK_RealPointer(callback.setwindow)); + var_write(&minfo.WinFuncPtr,int10.rom.set_window); var_write(&minfo.NumberOfBanks,0x1); var_write(&minfo.Reserved_page,0x1); var_write(&minfo.XCharSize,mblock->cwidth); @@ -297,11 +297,15 @@ Bit8u VESA_GetCPUWindow(Bit8u window,Bit16u & address) { } -Bit8u VESA_SetPalette(PhysPt data,Bitu index,Bitu count) { +Bit8u VESA_SetPalette(PhysPt data,Bitu index,Bitu count,bool wait) { //Structure is (vesa 3.0 doc): blue,green,red,alignment Bit8u r,g,b; if (index>255) return VESA_FAIL; if (index+count>256) return VESA_FAIL; + + // Wait for retrace if requested + if (wait) CALLBACK_RunRealFar(RealSeg(int10.rom.wait_retrace),RealOff(int10.rom.wait_retrace)); + IO_Write(0x3c8,(Bit8u)index); while (count) { b = mem_readb(data++); @@ -422,8 +426,7 @@ Bit8u VESA_ScanLineLength(Bit8u subcall,Bit16u val, Bit16u & bytes,Bit16u & pixe return VESA_SUCCESS; } -Bit8u VESA_SetDisplayStart(Bit16u x,Bit16u y) { - // TODO wait for retrace in case bl==0x80 +Bit8u VESA_SetDisplayStart(Bit16u x,Bit16u y,bool wait) { Bitu pixels_per_offset; Bitu panning_factor = 1; @@ -467,6 +470,9 @@ Bit8u VESA_SetDisplayStart(Bit16u x,Bit16u y) { IO_Write(0x3c0,0x13 | 0x20); // panning register, screen on IO_Write(0x3c0,new_panning); + // Wait for retrace if requested + if (wait) CALLBACK_RunRealFar(RealSeg(int10.rom.wait_retrace),RealOff(int10.rom.wait_retrace)); + return VESA_SUCCESS; } @@ -514,25 +520,30 @@ static Bitu VESA_SetWindow(void) { if (reg_bh) reg_ah=VESA_GetCPUWindow(reg_bl,reg_dx); else reg_ah=VESA_SetCPUWindow(reg_bl,(Bit8u)reg_dx); reg_al=0x4f; - return 0; + return CBRET_NONE; } static Bitu VESA_PMSetWindow(void) { - VESA_SetCPUWindow(0,(Bit8u)reg_dx); - return 0; + IO_Write(0x3d4,0x6a); + IO_Write(0x3d5,reg_dl); + return CBRET_NONE; } static Bitu VESA_PMSetPalette(void) { - VESA_SetPalette(SegPhys(es) + reg_edi, reg_dx, reg_cx ); - return 0; + PhysPt data=SegPhys(es)+reg_edi; + Bit32u count=reg_cx; + IO_Write(0x3c8,reg_dl); + do { + IO_Write(0x3c9,mem_readb(data+2)); + IO_Write(0x3c9,mem_readb(data+1)); + IO_Write(0x3c9,mem_readb(data)); + data+=4; + } while (--count); + return CBRET_NONE; } static Bitu VESA_PMSetStart(void) { - // This function is from VBE2 and directly sets the VGA - // display start address. - - // TODO wait for retrace in case bl==0x80 Bit32u start = (reg_dx << 16) | reg_cx; vga.config.display_start = start; - return 0; + return CBRET_NONE; } @@ -569,10 +580,12 @@ void INT10_SetupVESA(void) { case SVGA_S3Trio: break; } - callback.setwindow=CALLBACK_Allocate(); - callback.pmPalette=CALLBACK_Allocate(); - callback.pmStart=CALLBACK_Allocate(); - CALLBACK_Setup(callback.setwindow,VESA_SetWindow,CB_RETF, "VESA Real Set Window"); + /* Prepare the real mode interface */ + int10.rom.wait_retrace=RealMake(0xc000,int10.rom.used); + int10.rom.used += (Bit16u)CALLBACK_Setup(0, NULL, CB_VESA_WAIT, PhysMake(0xc000,int10.rom.used), ""); + callback.rmWindow=CALLBACK_Allocate(); + int10.rom.set_window=RealMake(0xc000,int10.rom.used); + int10.rom.used += (Bit16u)CALLBACK_Setup(callback.rmWindow, VESA_SetWindow, CB_RETF, PhysMake(0xc000,int10.rom.used), "VESA Real Set Window"); /* Prepare the pmode interface */ int10.rom.pmode_interface=RealMake(0xc000,int10.rom.used); int10.rom.used += 8; //Skip the byte later used for offsets @@ -585,11 +598,12 @@ void INT10_SetupVESA(void) { int10.rom.pmode_interface_start = int10.rom.used - RealOff( int10.rom.pmode_interface ); phys_writew( Real2Phys(int10.rom.pmode_interface) + 2, int10.rom.pmode_interface_start); callback.pmStart=CALLBACK_Allocate(); - int10.rom.used += (Bit16u)CALLBACK_Setup(callback.pmStart, VESA_PMSetStart, CB_RETN, PhysMake(0xc000,int10.rom.used), "VESA PM Set Start"); + int10.rom.used += (Bit16u)CALLBACK_Setup(callback.pmStart, VESA_PMSetStart, CB_VESA_PM, PhysMake(0xc000,int10.rom.used), "VESA PM Set Start"); /* PM Set Palette call */ int10.rom.pmode_interface_palette = int10.rom.used - RealOff( int10.rom.pmode_interface ); phys_writew( Real2Phys(int10.rom.pmode_interface) + 4, int10.rom.pmode_interface_palette); callback.pmPalette=CALLBACK_Allocate(); + int10.rom.used += (Bit16u)CALLBACK_Setup(0, NULL, CB_VESA_PM, PhysMake(0xc000,int10.rom.used), ""); int10.rom.used += (Bit16u)CALLBACK_Setup(callback.pmPalette, VESA_PMSetPalette, CB_RETN, PhysMake(0xc000,int10.rom.used), "VESA PM Set Palette"); /* Finalize the size and clear the required ports pointer */ phys_writew( Real2Phys(int10.rom.pmode_interface) + 6, 0);