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"