www.pudn.com > virtual_gameboy-0.8.8.zip > IBMMSDOS.C
/* IbmMsdos.c This file is part of the VGB-DOS project Copyright (C) Marcel de Kogel (m.dekogel@student.utwente.nl), 1996 You may not use this file for commercial purposes Please notify me if you make any changes to this file */ #include#include #include #include #include #include #include #include #include #include "GB.h" #include "IbmMsDos.h" /* Define if you've installed ANSI.SYS on your terminal */ /* #define USE_ANSI */ extern char szGifFile[]; int _crt0_startup_flags = _CRT0_FLAG_NONMOVE_SBRK | _CRT0_FLAG_LOCK_MEMORY | _CRT0_FLAG_DROP_EXE_SUFFIX; struct _SB_Info SB_Info; int swapbuttons=0; int videomode=0; int soundmode=1; int IntSync=1; static int OldTimer,NewTimer,ReadTimerMin; int brightness=0; int spritebrightness=1000,windowbrightness=1000,backgroundbrightness=1000; unsigned short cs_alias; static int KEY_LEFT,KEY_RIGHT,KEY_UP,KEY_DOWN, KEY_BUTTONA,KEY_BUTTONB,KEY_START,KEY_SELECT; char *szKeys="CBCDC8D0381D2A2C"; #ifdef DEBUG int nDebugKey=0; static int showwindow=1; #else #define showwindow 1 #endif #define NUM_STACKS 16 #define STACK_SIZE 8192 #ifdef DEBUG /* Called when one of the keys 1-9 is pressed */ static void ParseDebugKey (void) { const char *szRegNames[16] = { "LCDCONT", "LCDSTAT", "SCROLLY", "SCROLLX", "CURLINE", "CMPLINE", " ", "BGRDPAL", "SPR0PAL", "SPR1PAL", "WNDPOSX", "WNDPOSY", " ", " ", " ", " " }; int i; switch (nDebugKey) { case 1: Trace=!Trace; break; case 2: #ifdef USE_ANSI fprintf(stdout,"\033[H\033[2J"); #endif fprintf(stdout,"*** REGISTERS: ***\n"); for(i=0xFF40;i<0xFF50;i++) fprintf(stdout,"%s (%04Xh) = %02Xh\n",szRegNames[i-0xFF40],i,RAM[i]); fprintf(stdout,"ISWITCH = %02Xh\n",ISWITCH); fflush(stdout); break; case 3: #ifdef USE_ANSI fprintf(stdout,"\033[H\033[2J"); #endif fprintf(stdout,"*** SPRITES: ***\n"); for(i=0xFE9C;i<0xFE9C+4*40;i+=4) fprintf (stdout,"SPRITE %d: %d,%d Pat %d Attr %d\n", (i-0xFE9C)/4,RAM[i+1],RAM[i],RAM[i+2],RAM[i+3]); fflush(stdout); break; case 4: showwindow=!showwindow; break; } nDebugKey=0; } #endif /* Parse the BLASTER environment variable */ static void GetSBInfo (void) { char *blaster=getenv ("BLASTER"); memset (&SB_Info,0,sizeof(SB_Info)); if (blaster) { strupr (blaster); while (*blaster) { while (*blaster==' ' || *blaster=='\t') ++blaster; switch (*blaster++) { case 'A': SB_Info.baseport=(word)strtol(blaster,NULL,16); break; case 'I': SB_Info.irq=(byte)strtol(blaster,NULL,10); break; case 'D': SB_Info.dma_low=(byte)strtol(blaster,NULL,10); break; case 'H': SB_Info.dma_high=(byte)strtol(blaster,NULL,10); break; case 'T': SB_Info.type=(byte)strtol(blaster,NULL,10); break; case 'E': SB_Info.emu_baseport=(word)strtol(blaster,NULL,16); break; case 'P': SB_Info.mpu_baseport=(word)strtol(blaster,NULL,16); break; } while (*blaster && *blaster!=' ' && *blaster!='\t') ++blaster; } } } /** Various variables and short functions ********************/ #define WIDTH 176 #define HEIGHT 160 int DosSelector; /* Used by the assembly routines */ byte *XBuf,XPal[16]; /* Screen buffer and palette */ static void VGA_SetPalette (byte *pal,int start,int numcolors) { int i; disable (); while ((inportb(0x3DA)&0x08)!=0); /* Wait until vertical retrace is off */ while ((inportb(0x3DA)&0x08)==0); /* Now wait until it is on */ outportb (0x3C8,start); for (i=0;i =0) { *pal++=(tmp>>16)&0xFF; *pal++=(tmp>>8)&0xFF; *pal++=tmp&0xFF; } else pal+=3; } } static void _brightness (byte *pal,int brightness) { int tmp; tmp=(int)(unsigned)*pal; tmp=tmp*(brightness+200)/200; if (tmp>255) tmp=255; *pal=(byte)tmp; } /* Set mode and palette, put decoded GIF on screen */ static int VGA_Init (char *pGifPalette,char *pGifBytes) { static byte fspal[256*3]; static byte pal[64*3]={ 0,0,0, /* Overscan colour */ 0xFF,0xFF,0xFF, /* Background colours */ 0xB0,0xB0,0xB0, 0x60,0x60,0x60, 0x00,0x00,0x00, 0xFF,0xFF,0xFF, /* Sprite colours */ 0xB0,0xB0,0xB0, 0x60,0x60,0x60, 0x00,0x00,0x00, 0xFF,0xFF,0xFF, /* Window colours */ 0xB0,0xB0,0xB0, 0x60,0x60,0x60, 0x00,0x00,0x00 }; int a,b; __dpmi_regs r; r.x.ax=0x0F00; __dpmi_int (0x10,&r); nOldVideoMode=(int)(r.h.al & 0x7F); r.x.ax=0x0013; __dpmi_int (0x10,&r); if (videomode==2 || videomode==3) { VGA_SetFullScreenMode (); } else { if (videomode==4 || videomode==5) { VGA_Set256x200 (); videomode-=4; } if (videomode!=1) { if (pGifBytes) { VGA_SetPalette (pGifPalette,0,256); dosmemput (pGifBytes,64000,0xA0000); } } videomode=0; } ParseColorNames (pal+3); if (brightness<-100 || brightness>100) brightness=0; if (backgroundbrightness>100) backgroundbrightness=brightness; if (backgroundbrightness<-100 || backgroundbrightness>100) backgroundbrightness=0; for (a=1;a<5;++a) { _brightness (&pal[a*3+0],backgroundbrightness); _brightness (&pal[a*3+1],backgroundbrightness); _brightness (&pal[a*3+2],backgroundbrightness); } if (spritebrightness>100) spritebrightness=brightness; if (spritebrightness<-100 || spritebrightness>100) spritebrightness=0; for (a=5;a<9;++a) { _brightness (&pal[a*3+0],spritebrightness); _brightness (&pal[a*3+1],spritebrightness); _brightness (&pal[a*3+2],spritebrightness); } if (windowbrightness>100) windowbrightness=brightness; if (windowbrightness<-100 || windowbrightness>100) windowbrightness=0; for (a=9;a<13;++a) { _brightness (&pal[a*3+0],windowbrightness); _brightness (&pal[a*3+1],windowbrightness); _brightness (&pal[a*3+2],windowbrightness); } if (videomode==2 || videomode==3) { for (a=0;a<15;++a) for (b=0;b<15;++b) if (b==0 || videomode==3) { fspal[a*3+b*16*3+0]=pal[a*3+0]; fspal[a*3+b*16*3+1]=pal[a*3+1]; fspal[a*3+b*16*3+2]=pal[a*3+2]; } else { fspal[a*3+b*16*3+0]=pal[a*3+0]/2+pal[b*3+0]/2; fspal[a*3+b*16*3+1]=pal[a*3+1]/2+pal[b*3+1]/2; fspal[a*3+b*16*3+2]=pal[a*3+2]/2+pal[b*3+2]/2; } VGA_SetPalette (fspal,0,256); } else { /* Handy for debugging */ for (a=0,b=16;a<16;++a,++b) { pal[b*3+0]=pal[a*3+0]; pal[b*3+1]=255; pal[b*3+2]=pal[a*3+2]; } for (a=0,b=32;a<32;++a,++b) { pal[b*3+0]=255; pal[b*3+1]=pal[a*3+1]; pal[b*3+2]=pal[a*3+2]; } VGA_SetPalette (pal,0,64); } return 1; } static __volatile__ int PausePressed=0; static __volatile__ byte keybstatus[256]; /* 1 if key is pressed */ static _go32_dpmi_seginfo newirqkeyb,oldirqkeyb; void keyb_interrupt (void) { unsigned code; static int extkey; code=inportb (0x60); /* get scancode */ if (code<0xE0) /* ignore codes >0xE0 */ { if (code & 0x80) /* key is released */ { code&=0x7F; if (extkey) keybstatus[code+128]=0; else keybstatus[code]=0; } else /* key is pressed */ { if (extkey) { if (!keybstatus[code+128]) { keybstatus[code+128]=1; PausePressed=0; } } else { if (!keybstatus[code]) { keybstatus[code]=1; if (code==VK_F8) PausePressed=(PausePressed)? 0:2; else if (code==VK_F9) PausePressed=(PausePressed)? 0:1; else PausePressed=0; switch (code) { case VK_F11: Adlib_DecreaseVolume (); break; case VK_F12: Adlib_IncreaseVolume (); break; case VK_Escape: case VK_F10: CPURunning=0; break; case VK_F5: Adlib_ToggleSound (); break; case VK_F4: Adlib_ToggleChannel (3); break; case VK_F3: Adlib_ToggleChannel (2); break; case VK_F2: Adlib_ToggleChannel (1); break; case VK_F1: Adlib_ToggleChannel (0); break; #ifdef DEBUG case VK_1: case VK_2: case VK_3: case VK_4: case VK_5: case VK_6: case VK_7: case VK_8: case VK_9: nDebugKey=code-VK_1+1; break; #endif } } } } extkey=0; } else if (code==0xE0) extkey=1; code=inportb (0x61); /* acknowledge interrupt */ outportb (0x61,code | 0x80); outportb (0x61,code); outportb (0x20,0x20); } extern void keyb_interrupt_asm (void); static int Keyb_Init (void) { _go32_dpmi_get_protected_mode_interrupt_vector (9,&oldirqkeyb); newirqkeyb.pm_offset=(int)keyb_interrupt_asm; newirqkeyb.pm_selector=_go32_my_cs(); _go32_dpmi_set_protected_mode_interrupt_vector (9,&newirqkeyb); return 1; } static void Keyb_Reset (void) { _go32_dpmi_set_protected_mode_interrupt_vector (9,&oldirqkeyb); } /* Acknowledge interrupt and check sound updates. This is called about 290 times per second */ void timer_interrupt (void) { outportb (0x20,0x20); Adlib_InterruptRoutine (); } typedef struct joyposstruct { int x,y; } joypos; static int gotjoy=0; static joypos joycentre; /* Get absolute position in jp */ static int _JoyGetPos (joypos *jp) { unsigned tmp; tmp=JoyGetPos (); jp->x=(unsigned) (tmp&0xFFFF); if (jp->x>=10000) return 0; jp->y=(unsigned) (tmp>>16); if (jp->y>=10000) return 0; return 1; } /* Initialise the joystick routines. Return 0 if no joystick found */ static int Joy_Init (void) { joypos jp; if (!_JoyGetPos (&jp)) return 0; joycentre.x=jp.x; joycentre.y=jp.y; gotjoy=1; return 1; } /* Check joystick and set JoyState accordingly */ static byte Joy_Check (void) { joypos jp; unsigned char joystatus; static byte JoyState=0xFF; static byte count=2; if (!gotjoy) return JoyState; if (--count) return JoyState; count=2; JoyState=0xFF; _JoyGetPos (&jp); joystatus=inportb (0x201); if (jp.x<(joycentre.x/2)) JoyState&=0xFD; else if (jp.x>(joycentre.x*3/2)) JoyState&=0xFE; if (jp.y<(joycentre.y/2)) JoyState&=0xFB; else if (jp.y>((joycentre.y*3)/2)) JoyState&=0xF7; if ((joystatus&0x10)==0) JoyState&=(swapbuttons&1)? 0xDF:0xEF; if ((joystatus&0x20)==0) JoyState&=(swapbuttons&1)? 0xEF:0xDF; if ((joystatus&0x40)==0) JoyState&=0xBF; if ((joystatus&0x80)==0) JoyState&=0x7F; return JoyState; } /* Flush stdout because it is buffered */ static void _printf (char *szMessage) { printf (szMessage); fflush (stdout); } /** InitMachine **********************************************/ /** Allocate resources needed by MS-DOS dependent code. **/ /*************************************************************/ int InitMachine() { int tmp,i; char GifPalette[768]; char *pGifBytes; pGifBytes=0; DosSelector=_dos_ds; cs_alias=_my_ds(); GetSBInfo (); if (Verbose) _printf ("Allocating stack space... "); i=InitStacks (NUM_STACKS,STACK_SIZE); if (Verbose) _printf ((i)? "OK\n":"Failed\n"); if (!i) return 0; if(Verbose) _printf("Allocating screen buffer..."); XBuf=(byte *)malloc(sizeof(byte)*HEIGHT*WIDTH*4); if (Verbose) printf ((XBuf)? "OK\n":"FAILED\n"); if(!XBuf) return(0); memset (XBuf,0,sizeof(byte)*HEIGHT*WIDTH); for (i=0;i<16;++i) XPal[i]=i+1; if (soundmode==1) { if (Verbose) _printf ("Detecting sound card..."); tmp=Adlib_Init (); if (Verbose) if (tmp) { switch (tmp&0x70000) { case 0: printf ("OPL2"); break; case 0x10000: printf ("OPL3"); break; case 0x20000: printf ("Sound Blaster Pro"); break; case 0x30000: printf ("Sound Blaster Pro 2"); break; default: printf ("Sound Blaster 16"); break; } printf (" found at 0x%x\n",tmp&0xFFFF); } else printf ("Not found\n"); } else soundmode=0; if (Verbose) _printf ("Detecting joystick..."); tmp=Joy_Init (); if (Verbose) printf ((tmp)? "Found\n" : "Not found\n"); if (Verbose) printf ("Initializing timer...\n"); install_timer_int (); if (IntSync) { ReadTimerMin=1192380/IFreq; OldTimer=ReadTimer (); } pGifBytes=0; if (videomode==0 || videomode==4) { if (Verbose) _printf ("Allocating GIF decoding space..."); pGifBytes=malloc(64000); if (Verbose) printf ((pGifBytes)? "OK\n":"FAILED\n"); if (pGifBytes) { if (!LoadGif (szGifFile,GifPalette,pGifBytes)) { free (pGifBytes); pGifBytes=0; } } } if (Verbose) { fprintf (stderr,"Press any key to run ROM code..."); getch (); } VGA_Init (GifPalette,pGifBytes); if (pGifBytes) free (pGifBytes); /* Parse keyboard mapping string */ sscanf (szKeys,"%02X%02X%02X%02X%02X%02X%02X%02X", &KEY_LEFT,&KEY_RIGHT,&KEY_UP,&KEY_DOWN, &KEY_BUTTONA,&KEY_BUTTONB,&KEY_START,&KEY_SELECT); Keyb_Init (); return(1); } /** TrashMachine *********************************************/ /** Deallocate all resources taken by InitMachine(). **/ /*************************************************************/ void TrashMachine() { VGA_Reset (); if(Verbose) printf("Shutting down...\n"); restore_timer_int (); Keyb_Reset (); Adlib_Reset (); ExitStacks (); fflush (stdin); /* Clear keyboard buffer */ } /** PutImage *************************************************/ /** Put an image on the screen. **/ /*************************************************************/ void PutImage() { switch (videomode) { case 3: case 2: PutImage_FullScreen (); break; default: PutImage_Standard (); break; } } /** Joystick *************************************************/ /** Return the current joystick state. **/ /*************************************************************/ byte Joystick(void) { byte JoyState; #ifdef DEBUG ParseDebugKey (); #endif JoyState=Joy_Check (); if (keybstatus[KEY_START]) JoyState&=0x7F; if (keybstatus[KEY_SELECT]) JoyState&=0xBF; if (keybstatus[KEY_DOWN]) JoyState&=0xF7; if (keybstatus[KEY_UP]) JoyState&=0xFB; if (keybstatus[KEY_LEFT]) JoyState&=0xFD; if (keybstatus[KEY_RIGHT]) JoyState&=0xFE; if (keybstatus[KEY_BUTTONA]) JoyState&=(swapbuttons&2)? 0xDF:0xEF; if (keybstatus[KEY_BUTTONB]) JoyState&=(swapbuttons&2)? 0xEF:0xDF; if (keybstatus[VK_Ctrl] && keybstatus[VK_Ctrl+128] && keybstatus[VK_Alt] && keybstatus[VK_Alt+128]) ResetGB (); return(JoyState); } static int NumRefreshSkipped=0; int CheckRefresh (void) { int DoRefresh=0; do NewTimer=ReadTimer (); while ((NewTimer-OldTimer)<0); OldTimer+=ReadTimerMin; if ((OldTimer-NewTimer)>0) DoRefresh=1; else if (++NumRefreshSkipped>10) { DoRefresh=1; OldTimer=ReadTimer(); } if (DoRefresh) { NumRefreshSkipped=0; } return DoRefresh; } /* Returns: 0 - Do not refresh screen 1 - Refresh screen 2 - Refresh screen according to the -uperiod parameter Return value is ignored if uperiod!=0 */ int MachineInterrupt (void) { int tmp; if (PausePressed) { Adlib_SoundOff (); tmp=0; if (PausePressed==2) /* Blank screen */ { tmp=1; inportb (0x3BA); inportb (0x3DA); outportb (0x3C0,0); } while (PausePressed); if (tmp) { inportb (0x3BA); inportb (0x3DA); outportb (0x3C0,0x20); } Adlib_SoundOn (); if (IntSync) OldTimer=ReadTimer (); } if (IntSync) return CheckRefresh(); return 2; } /*** SIOSend ****************************************************/ /*** Send a byte onto the serial line. ***/ /****************************************************************/ byte SIOSend(register byte V) { return(0); } /*** SIOReceive *************************************************/ /*** Receive a byte from the serial line. Returns 1 on ***/ /*** success, 0 otherwise. ***/ /****************************************************************/ byte SIOReceive(register byte *V) { return(0); } /****************************************************************/ /*** Write value into sound chip register (Reg #0 at FF10h). ***/ /****************************************************************/ void Sound(byte R,byte V) { Adlib_WriteSoundReg (R,V); } /** Common.h ****************************************************/ /** Parts of the drivers common for Unix/X and MSDOS. **/ /****************************************************************/ #include "Common.h"