/** ADAMEm: Coleco ADAM emulator ********************************************/ /** **/ /** MSDOS.c **/ /** **/ /** This file contains generic MS-DOS specific routines. It does not **/ /** include the sound emulation code **/ /** **/ /** Copyright (C) Marcel de Kogel 1996,1997,1998,1999 **/ /** You are not allowed to distribute this software commercially **/ /** Please, notify me, if you make any changes to this file **/ /****************************************************************************/ #include "Coleco.h" #include "MSDOS.h" #include "Bitmap.h" #include "INT.h" #include "Asm.h" #include #include #include #include #include #include #include #include #include #include #include #include #include /* Title for -help output */ char Title[]="ADAMEm MS-DOS 1.0"; #define NUM_STACKS 8 /* Number of IRQ stacks */ #define STACK_SIZE 16384 /* Stack size */ /* DJGPP startup flags */ int _crt0_startup_flags = _CRT0_FLAG_NONMOVE_SBRK | _CRT0_FLAG_LOCK_MEMORY; /* Key mapping */ static int KEY_LEFT,KEY_RIGHT,KEY_UP,KEY_DOWN, KEY_BUTTONA,KEY_BUTTONB,KEY_BUTTONC,KEY_BUTTOND; /* Current VGA palette */ static byte VGA_Palette[17*3]; static byte PalBuf[16]; /* Palette buffer */ static int default_mouse_sens=200;/* Default mouse sensitivity */ static int keyboardmode; /* 0=joystick, 1=keyboard */ static word MouseJoyState[2]; /* Current mouse status */ static word JoystickJoyState[2]; /* Current joystick status */ static int nOldVideoMode; /* Videomode when ADAMem was started */ static unsigned font2screen[16*16*16]; /* Used by screen refresh driver */ #ifdef DEBUG static int dumpram=0; #endif static int makeshot=0; /* 1 if screen shot should be taken */ static int makesnap=0; /* 1 if snapshot should be written */ static int OldTimer=0; /* Last value of timer */ static int NewTimer=0; /* New value of timer */ static int calloptions=0; /* If 1, OptionsDialogue() is called */ static int in_options_dialogue=0; /* If 1, chain to old keyboard IRQ handler*/ static int SwitchVideoMode=0; /* If 1, switch video mode in Keyboard() */ word cs_alias; /* Our data selector */ word DosSelector; /* Selector of DOS memory */ byte DisplayBuf[WIDTH*HEIGHT]; /* Screen buffer */ char szBitmapFile[256]; /* Next screen shot file */ char szSnapshotFile[256]; /* Next snapshot file */ char szJoystickFileName[256]; /* File holding joystick information */ char *szKeys="CBCDC8D0381D2A2C"; /* Key scancodes */ int mouse_sens=200; /* Mouse sensitivity */ int keypadmode=0; /* 1 if keypad should be reversed */ int joystick=1; /* Joystick support */ int calibrate=0; /* Set to 1 to force joystick calibration */ int swapbuttons=0; /* 1=joystick, 2=keyboard, 4=mouse */ int expansionmode=0; /* Expansion module emulated */ int useoverscan=1; /* Overscan colour support */ int videomode=0; /* 0=320x200 1=256x192 */ int syncemu=1; /* 0 - Don't sync emulation */ /* 1 - Sync emulation to PC timer */ int Text80; /* 1 if in Text80 mode */ int Text80Colour; /* Text80 foreground colour */ int AutoText80; /* 1 if auto-switch to Text80 mode on */ /****************************************************************************/ /** VGA routines **/ /****************************************************************************/ static void VGA_SetPalette (int n,unsigned char *pal) { 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,0); /* Start updating palette */ for (i=0;i','?',0, '*',0,' ',0,137,138,139,140,141,142,152,153,0,0, 0,0,0,0,0,'-',0,0,0,'+',0,0,0,156,159, 0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* extended keys */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,'/',0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,154,0,158,0,0,0,0,0,155, 0,157,156,159,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; static const byte scan2ascii_ctrl[256] = { 0,27,0,255,0,0,0,30,0,0,0,0,31,0,127, 0,17,23,5,18,20,25,21,9,15,16,27,29,13, 0,1,19,4,6,7,8,10,11,12,0,0,0, 0,28,26,24,3,22,2,14,13,0,0,0,0, 0,0,32,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,164,0,0,167,0,165,0,0,166,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* extended keys */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,164,0,0,167,0,165,0,0, 166,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; static inline int AltPressed (void) { return keybstatus[VK_Alt]||keybstatus[VK_Alt+128]; } static inline int CtrlPressed (void) { return keybstatus[VK_Ctrl]||keybstatus[VK_Ctrl+128]; } static int keyb_interrupt (void) { unsigned code; static int extkey; static int CapsLock=0; 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; if (in_options_dialogue) /* jump to old interrupt handler */ return 1; PausePressed=0; switch (code) { case VK_Insert: if (!keyboardmode || AltPressed()) joystick=1; break; case VK_Home: if (!keyboardmode || AltPressed()) joystick=2; break; case VK_PageUp: if (!keyboardmode || AltPressed()) joystick=3; break; case VK_Del: if (!keyboardmode || AltPressed()) swapbuttons^=1; break; case VK_End: if (!keyboardmode || AltPressed()) swapbuttons^=2; break; case VK_PageDown: if (!keyboardmode || AltPressed()) swapbuttons^=4; break; } } } else { if (!keybstatus[code]) { keybstatus[code]=1; if (in_options_dialogue) return 1; if (CtrlPressed() && (code==VK_F11 || code==VK_F12)) { if (code==VK_F11) PausePressed=2; else PausePressed=1; } else PausePressed=0; switch (code) { case VK_CapsLock: CapsLock^=1; break; case VK_F1: if (!keyboardmode || AltPressed()) ToggleSoundChannel (0); break; case VK_F2: if (!keyboardmode || AltPressed()) ToggleSoundChannel (1); break; case VK_F3: if (!keyboardmode || AltPressed()) ToggleSoundChannel (2); break; case VK_F4: if (!keyboardmode || AltPressed()) ToggleSoundChannel (3); break; case VK_F5: if (!keyboardmode || AltPressed()) ToggleSound (); break; case VK_F11: if (!PausePressed && !AltPressed()) DecreaseSoundVolume (); break; case VK_F12: if (!PausePressed && !AltPressed()) IncreaseSoundVolume (); break; case VK_F10: Z80_Running=0; break; case VK_F7: #ifdef DEBUG if (CtrlPressed()) { Z80_Trace=!Z80_Trace; break; } #endif if (!keyboardmode || AltPressed()) makesnap=1; break; case VK_F8: #ifdef DEBUG if (CtrlPressed()) dumpram=1; else #endif if (!keyboardmode || AltPressed()) makeshot=1; break; case VK_F9: if (EmuMode) { if (AltPressed()) SwitchVideoMode=1; else if (CtrlPressed()) calloptions=1; else keyboardmode=(keyboardmode)? 0:1; } break; } } } if (keyboardmode && !AltPressed()) /* Modify keyboard buffer */ { /* Check for HOME+Cursor key and Cursor key combinations */ if (code==VK_NumPad5 && !extkey) { if (keybstatus[VK_Left] || keybstatus[VK_Left+128]) { code=175; goto put_char_in_buf; } if (keybstatus[VK_Right] || keybstatus[VK_Right+128]) { code=173; goto put_char_in_buf; } if (keybstatus[VK_Up] || keybstatus[VK_Up+128]) { code=172; goto put_char_in_buf; } if (keybstatus[VK_Down] || keybstatus[VK_Down+128]) { code=170; goto put_char_in_buf; } } if (keybstatus[VK_NumPad5]) { if (code==VK_Left) { code=175; goto put_char_in_buf; } if (code==VK_Right) { code=173; goto put_char_in_buf; } if (code==VK_Up) { code=172; goto put_char_in_buf; } if (code==VK_Down) { code=170; goto put_char_in_buf; } } if (code==VK_Up) { if (keybstatus[VK_Right] || keybstatus[VK_Right+128]) { code=168; goto put_char_in_buf; } if (keybstatus[VK_Left] || keybstatus[VK_Left+128]) { code=171; goto put_char_in_buf; } } if (code==VK_Right) { if (keybstatus[VK_Up] || keybstatus[VK_Up+128]) { code=168; goto put_char_in_buf; } if (keybstatus[VK_Down] || keybstatus[VK_Down+128]) { code=169; goto put_char_in_buf; } } if (code==VK_Down) { if (keybstatus[VK_Right] || keybstatus[VK_Right+128]) { code=169; goto put_char_in_buf; } if (keybstatus[VK_Left] || keybstatus[VK_Left+128]) { code=170; goto put_char_in_buf; } } if (code==VK_Left) { if (keybstatus[VK_Up] || keybstatus[VK_Up+128]) { code=171; goto put_char_in_buf; } if (keybstatus[VK_Down] || keybstatus[VK_Down+128]) { code=170; goto put_char_in_buf; } } if (extkey) code+=128; if (keybstatus[VK_Ctrl] || keybstatus[VK_Ctrl+128]) code=scan2ascii_ctrl[code]; else if (keybstatus[VK_RightShift] || keybstatus[VK_LeftShift]) code=scan2ascii_shift[code]; else code=scan2ascii[code]; put_char_in_buf: if (CapsLock) { if (code>='a' && code<='z') code+='A'-'a'; else if (code>='A' && code<='Z') code+='a'-'A'; } if (code) LocalAddToKeyboardBuffer (code); } } extkey=0; } else if (code==0xE0) extkey=1; if (in_options_dialogue) return 1; code=inportb (0x61); /* acknowledge interrupt */ outportb (0x61,code | 0x80); outportb (0x61,code); outportb (0x20,0x20); return 0; /* Do not chain to old handler */ } static int Keyb_Init (void) /* get old handler and install our own */ { keybirq.pm_offset=(int)keyb_interrupt; keybirq.pm_selector=_go32_my_cs(); SetInt (9,&keybirq); return 1; } static void Keyb_Reset (void) /* install the old handler */ { ResetInt (9,&keybirq); } /****************************************************************************/ /** Mouse routines **/ /****************************************************************************/ static _go32_dpmi_seginfo mouse_seginfo; static _go32_dpmi_registers mouse_regs; static int mouse_buttons=0; /* mouse buttons pressed */ static int mouse_xpos=500; /* horizontal position (0 - 1000) */ static int mouse_ypos=500; /* vertical position (0 - 1000) */ static int mouse_x=0; /* horizontal position (-500 - 500) */ static int mouse_y=0; /* vertical position (-500 - 500) */ static int got_mouse=0; /* 1 if mouse was properly initialised */ static void Mouse_SetJoyState () { if (mouse_buttons&1) MouseJoyState[0]&=0xBFFF; if (mouse_buttons&2) MouseJoyState[0]&=0xFFBF; if (mouse_buttons&4) MouseJoyState[1]&=0xBFFF; if (mouse_buttons&8) MouseJoyState[1]&=0xFFBF; SpinnerPosition[0]=(default_mouse_sens*mouse_x*(abs(mouse_x)+mouse_sens))/ (mouse_sens*mouse_sens); SpinnerPosition[1]=(default_mouse_sens*mouse_y*(abs(mouse_y)+mouse_sens))/ (mouse_sens*mouse_sens); } static void Mouse_Callback (_go32_dpmi_registers *r) { mouse_buttons=r->x.bx&7; mouse_xpos=r->x.cx; mouse_ypos=r->x.dx; } static void Mouse_Check (void) { __dpmi_regs r; int tmp; if (!got_mouse) return; mouse_x=mouse_xpos-500; mouse_y=mouse_ypos-500; tmp=mouse_buttons; if (mouse_x || mouse_y) { r.x.ax=0x04; r.x.cx=500; r.x.dx=500; __dpmi_int (0x33,&r); mouse_xpos=mouse_ypos=500; } switch (expansionmode) { case 4: /* emulate driving module */ if (mouse_buttons&7) MouseJoyState[0]&=0xFEFF; mouse_x/=4; mouse_y=0; mouse_buttons=0; break; case 5: /* emulate SA speed roller on both ports */ mouse_x=(-mouse_x)/4; mouse_y=-mouse_x; mouse_buttons=0; break; case 6: /* emulate SA speed roller on port 1 */ mouse_x=(-mouse_x)/4; mouse_y=0; mouse_buttons=0; break; case 7: /* emulate SA speed roller on port 2 */ mouse_y=mouse_x/4; mouse_x=0; mouse_buttons=0; break; } if (swapbuttons&4) mouse_buttons=(mouse_buttons&(~3))| ((mouse_buttons&1)<<1)| ((mouse_buttons&2)>>1); Mouse_SetJoyState (); mouse_buttons=tmp; } static int Mouse_Detect (void) { __dpmi_regs r; r.x.ax=0; __dpmi_int (0x33,&r); if (r.x.ax==0) return 0; got_mouse=1; return 1; } static void Mouse_Init (void) { __dpmi_regs r; if (!got_mouse) return; r.x.ax=0x07; /* set horizontal range */ r.x.cx=0; r.x.dx=1000; __dpmi_int (0x33,&r); r.x.ax=0x08; /* set vertical range */ r.x.cx=0; r.x.dx=1000; __dpmi_int (0x33,&r); r.x.ax=0x04; /* set position */ r.x.cx=500; r.x.dx=500; __dpmi_int (0x33,&r); r.x.ax=0x0F; /* set sensitivity */ r.x.cx=3; r.x.dx=3; __dpmi_int (0x33,&r); mouse_seginfo.pm_selector=_my_cs(); mouse_seginfo.pm_offset=(unsigned)Mouse_Callback; _go32_dpmi_allocate_real_mode_callback_retf (&mouse_seginfo,&mouse_regs); r.x.ax=0x0C; r.x.cx=0x1F; r.x.dx=mouse_seginfo.rm_offset; r.x.es=mouse_seginfo.rm_segment; __dpmi_int (0x33,&r); return; } static void Mouse_Exit (void) { __dpmi_regs r; if (!got_mouse) return; r.x.ax=0x0C; r.x.cx=0; r.x.dx=0; r.x.es=0; __dpmi_int (0x33,&r); r.x.ax=0; __dpmi_int (0x33,&r); _go32_dpmi_free_real_mode_callback (&mouse_seginfo); } /****************************************************************************/ /** Joystick routines **/ /****************************************************************************/ typedef struct joyposstruct { int x,y; } joypos; static int gotjoy=0; /* 1 if joystick was properly initialised */ static joypos joycentre; /* joystick centre position */ static joypos joymin; /* left-upper corner position */ static joypos joymax; /* right-lower corner position */ static joypos joy_lowmargin; /* start of 'dead' region */ static joypos joy_highmargin; /* end of 'dead' region */ 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; } static int Joy_Init (void) { joypos jp; if (!_JoyGetPos (&jp)) return 0; joycentre.x=jp.x; joycentre.y=jp.y; gotjoy=1; return 1; } static void CalibrateJoystick (void) { FILE *joyfile=NULL; if (!calibrate) joyfile=fopen(szJoystickFileName,"rb"); if (!joyfile) { fprintf (stderr,"Move joystick to top left and press any key\n"); getch (); _JoyGetPos (&joymin); fprintf (stderr,"Move joystick to bottom right and press any key\n"); getch (); _JoyGetPos (&joymax); joyfile=fopen(szJoystickFileName,"wb"); if (joyfile) { fwrite (&joymin,sizeof(joymin),1,joyfile); fwrite (&joymax,sizeof(joymax),1,joyfile); fclose (joyfile); } } else { fread (&joymin,sizeof(joymin),1,joyfile); fread (&joymax,sizeof(joymax),1,joyfile); fclose (joyfile); } joy_lowmargin.x=joycentre.x-(joycentre.x-joymin.x)/8; joy_lowmargin.y=joycentre.y-(joycentre.y-joymin.y)/8; joy_highmargin.x=joycentre.x+(joymax.x-joycentre.x)/8; joy_highmargin.y=joycentre.y+(joymax.y-joycentre.y)/8; /* prevent a divide by zero in JoySortOutAnalogue() */ if (joy_lowmargin.x-joymin.x==0) joy_lowmargin.x++; if (joymax.x-joy_highmargin.x==0) joy_highmargin.x--; if (joy_lowmargin.y-joymin.y==0) joy_lowmargin.y++; if (joymax.y-joy_highmargin.y==0) joy_highmargin.y--; } #define JOY_RANGE 128 static void JoySortOutAnalogue (joypos *jp) { if (jp->x < joymin.x) jp->x=-JOY_RANGE; else if (jp->x > joymax.x) jp->x=JOY_RANGE; else if ((jp->x > joy_lowmargin.x) && (jp->x < joy_highmargin.x)) jp->x=0; else if (jp->x < joy_lowmargin.x) jp->x=-JOY_RANGE+(jp->x-joymin.x)*JOY_RANGE/(joy_lowmargin.x-joymin.x); else jp->x=JOY_RANGE-(joymax.x-jp->x)*JOY_RANGE/(joymax.x-joy_highmargin.x); if (jp->y < joymin.y) jp->y=-JOY_RANGE; else if (jp->y > joymax.y) jp->y=JOY_RANGE; else if ((jp->y > joy_lowmargin.y) && (jp->y < joy_highmargin.y)) jp->y=0; else if (jp->y < joy_lowmargin.y) jp->y=-JOY_RANGE+(jp->y-joymin.y)*JOY_RANGE/(joy_lowmargin.y-joymin.y); else jp->y=JOY_RANGE-(joymax.y-jp->y)*JOY_RANGE/(joymax.y-joy_highmargin.y); } static void Joy_Check (void) { joypos jp; unsigned char joystatus; if (!gotjoy) return; _JoyGetPos (&jp); joystatus=inportb (0x201); switch (expansionmode) { case 0: case 5: case 6: case 7: if (jp.x<(joycentre.x*3/4)) JoystickJoyState[0]&=0xF7FF; else if (jp.x>(joycentre.x*5/4)) JoystickJoyState[0]&=0xFDFF; if (jp.y<(joycentre.y*3/4)) JoystickJoyState[0]&=0xFEFF; else if (jp.y>(joycentre.y*5/4)) JoystickJoyState[0]&=0xFBFF; if ((joystatus&0x10)==0) JoystickJoyState[0]&=(swapbuttons&1)? 0xFFBF:0xBFFF; if ((joystatus&0x20)==0) JoystickJoyState[0]&=(swapbuttons&1)? 0xBFFF:0xFFBF; if ((joystatus&0x40)==0) JoystickJoyState[0]=(JoyState[0]&0xFFF0)|12; if ((joystatus&0x80)==0) JoystickJoyState[0]=(JoyState[0]&0xFFF0)|13; break; case 2: JoySortOutAnalogue (&jp); mouse_x=jp.x; mouse_y=jp.y; mouse_buttons=0; if ((joystatus&0x10)==0) mouse_buttons|=(swapbuttons&1)? 2:1; if ((joystatus&0x20)==0) mouse_buttons|=(swapbuttons&1)? 1:2; if ((joystatus&0x40)==0) mouse_buttons|=4; if ((joystatus&0x80)==0) mouse_buttons|=8; Mouse_SetJoyState (); break; case 3: if (jp.y<(joycentre.y*3/4)) JoystickJoyState[0]&=0xFEFF; JoySortOutAnalogue (&jp); mouse_x=(jp.x/2); mouse_y=0; Mouse_SetJoyState (); if ((joystatus&0x10)==0) JoystickJoyState[1]&=(swapbuttons&1)? 0xFBFF:0xFEFF; if ((joystatus&0x20)==0) JoystickJoyState[1]&=(swapbuttons&1)? 0xFEFF:0xFBFF; if ((joystatus&0x40)==0) JoystickJoyState[1]&=0xF7FF; if ((joystatus&0x80)==0) JoystickJoyState[1]&=0xFDFF; break; } } /****************************************************************************/ /** Deallocate all resources taken by InitMachine() **/ /****************************************************************************/ void TrashMachine(void) { Mouse_Exit (); VGA_Reset (); if(Verbose) printf("\n\nShutting down...\n"); TrashSound (); RestoreTimer (); Keyb_Reset (); ExitStacks (); } static int NextFile (char *s) { char *p; p=s+strlen(s)-1; if (*p=='9') { *p='0'; --p; if (*p=='9') { (*p)++; if (*p=='0') return 0; } else (*p)++; } else (*p)++; return 1; } static int NextBitmapFile (void) { return NextFile (szBitmapFile); } static int NextSnapshotFile (void) { return NextFile (szSnapshotFile); } /****************************************************************************/ /** Allocate resources needed by MS-DOS-dependent code **/ /****************************************************************************/ int InitMachine(void) { int i,j,c; FILE *bitmapfile,*snapshotfile; if (Verbose) printf ("Initialising MSDOS drivers...\n"); if (videomode>2 || videomode<0) videomode=0; JoyState[0]=JoyState[1]=MouseJoyState[0]=MouseJoyState[1]= JoystickJoyState[0]=JoystickJoyState[1]=0x7F7F; cs_alias=_my_ds(); DosSelector=_dos_ds; if (Verbose) printf (" Allocating stack space... "); i=InitStacks (NUM_STACKS,STACK_SIZE); if (!i) { if (Verbose) puts ("FAILED\n"); return 0; } memset (DisplayBuf,0,sizeof(DisplayBuf)); for (i=0;i<16;++i) PalBuf[i]=i+1; if (Verbose) printf ("OK\n Initialising conversion buffer... "); for (i=0;i<16;++i) for (j=0;j<16;++j) for (c=0;c<16;++c) { unsigned a; a=0; #ifdef LSB_FIRST if (c&0x08) a|=PalBuf[i]; else a|=PalBuf[j]; if (c&0x04) a|=(PalBuf[i]<<8); else a|=(PalBuf[j]<<8); if (c&0x02) a|=(PalBuf[i]<<16); else a|=(PalBuf[j]<<16); if (c&0x01) a|=(PalBuf[i]<<24); else a|=(PalBuf[j]<<24); #else if (c&0x01) a|=PalBuf[i]; else a|=PalBuf[j]; if (c&0x02) a|=(PalBuf[i]<<8); else a|=(PalBuf[j]<<8); if (c&0x04) a|=(PalBuf[i]<<16); else a|=(PalBuf[j]<<16); if (c&0x08) a|=(PalBuf[i]<<24); else a|=(PalBuf[j]<<24); #endif font2screen[i*16*16+j*16+c]=a; } if (Verbose) puts ("OK"); InitSound (); if (expansionmode==2 || expansionmode==3 || (expansionmode!=1 && expansionmode!=4 && joystick)) { if (Verbose) printf (" Detecting joystick... "); i=Joy_Init (); if (Verbose) printf ((i)? "Found\n" : "Not found\n"); } if (expansionmode==1 || expansionmode==4 || expansionmode==5 || expansionmode==6 || expansionmode==7) { if (Verbose) printf (" Detecting mouse... "); i=Mouse_Detect (); if (Verbose) printf ((i)? "Found\n" : "Not found\n"); } if (mouse_sens<=0 || mouse_sens>1000) mouse_sens=default_mouse_sens; switch (expansionmode) { case 2: case 3: if (!gotjoy) { expansionmode=0; break; } CalibrateJoystick (); break; case 1: case 4: case 5: case 6: case 7: if (!got_mouse) expansionmode=0; break; default: expansionmode=0; default_mouse_sens*=5; break; } StartTimer (); if (syncemu) OldTimer=ReadTimer (); /* 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_BUTTONC,&KEY_BUTTOND); Keyb_Init (); while ((bitmapfile=fopen(szBitmapFile,"rb"))!=NULL) { fclose (bitmapfile); if (!NextBitmapFile()) break; } while ((snapshotfile=fopen(szSnapshotFile,"rb"))!=NULL) { fclose (snapshotfile); if (!NextSnapshotFile()) break; } if (Verbose) { printf (" Next screenshot will be %s\n" " Next snapshot will be %s\n", szBitmapFile,szSnapshotFile); } if (Verbose) { fprintf (stderr,"Press space to run rom code...\n"); while (!keybstatus[VK_Space]); } makeshot=0; makesnap=0; for (i=0;i<16*3;++i) VGA_Palette[i+3]=Coleco_Palette[i]; VGA_Init (); VGA_SetBkColour (0); Mouse_Init (); keyboardmode=(EmuMode)? 1:0; return 1; } /****************************************************************************/ /** Routines to modify the Coleco gamport status **/ /****************************************************************************/ static int numkeypressed (int nScanCode) { int nOr; switch (nScanCode) { case VK_1: case VK_End: nOr=1; break; case VK_2: case VK_Down: nOr=2; break; case VK_3: case VK_PageDown: nOr=3; break; case VK_4: case VK_Left: nOr=4; break; case VK_5: case VK_NumPad5: nOr=5; break; case VK_6: case VK_Right: nOr=6; break; case VK_7: case VK_Home: nOr=7; break; case VK_8: case VK_Up: nOr=8; break; case VK_9: case VK_PageUp: nOr=9; break; case VK_Equal: case VK_Enter: nOr=10; break; case VK_Minus: case VK_Del: nOr=11; break; default: nOr=0; } return nOr; } static void Joysticks (void) { int i,tmp,tmp2; MouseJoyState[0]|=0x7F7F; MouseJoyState[1]|=0x7F7F; Mouse_Check (); JoystickJoyState[0]|=0x7F7F; JoystickJoyState[1]|=0x7F7F; Joy_Check (); JoyState[1]=(MouseJoyState[0] & JoystickJoyState[0]); JoyState[0]=(MouseJoyState[1] & JoystickJoyState[1]); if (!keyboardmode) { if (keybstatus[KEY_BUTTONA]) JoyState[0]&=(swapbuttons&2)? 0xFFBF:0xBFFF; if (keybstatus[KEY_BUTTONB]) JoyState[0]&=(swapbuttons&2)? 0xBFFF:0xFFBF; if (keybstatus[KEY_DOWN]) JoyState[0]&=0xFBFF; if (keybstatus[KEY_UP]) JoyState[0]&=0xFEFF; if (keybstatus[KEY_LEFT]) JoyState[0]&=0xF7FF; if (keybstatus[KEY_RIGHT]) JoyState[0]&=0xFDFF; for (i=VK_1;i<=VK_Equal;++i) if (keybstatus[i]) { tmp=numkeypressed(i); JoyState[0]=(JoyState[0]&0xFFF0)|tmp; } if (keybstatus[KEY_BUTTONC]) JoyState[0]=(JoyState[0]&0xFFF0)|12; if (keybstatus[KEY_BUTTOND]) JoyState[0]=(JoyState[0]&0xFFF0)|13; for (i=VK_Home;i<=VK_PageUp;++i) if (keybstatus[i]) { tmp=numkeypressed((keypadmode)? (i-VK_Home+VK_End) : i); JoyState[1]=(JoyState[1]&0xFFF0)|tmp; } for (i=VK_Left;i<=VK_Right;++i) if (keybstatus[i]) { tmp=numkeypressed(i); JoyState[1]=(JoyState[1]&0xFFF0)|tmp; } for (i=VK_End;i<=VK_PageDown;++i) if (keybstatus[i]) { tmp=numkeypressed((keypadmode)? (i-VK_End+VK_Home) : i); JoyState[1]=(JoyState[1]&0xFFF0)|tmp; } if (keybstatus[VK_Insert]) { tmp=numkeypressed((keypadmode)? VK_Del : VK_Insert); JoyState[1]=(JoyState[1]&0xFFF0)|tmp; } if (keybstatus[VK_Del]) { tmp=numkeypressed((keypadmode)? VK_Insert : VK_Del); JoyState[1]=(JoyState[1]&0xFFF0)|tmp; } if (keybstatus[VK_Enter+128]) { tmp=numkeypressed(VK_Enter); JoyState[1]=(JoyState[1]&0xFFF0)|tmp; } if (keybstatus[VK_PlusNumPad]) JoyState[1]=(JoyState[1]&0xFFF0)|13; if (keybstatus[VK_MinusNumPad]) JoyState[1]=(JoyState[1]&0xFFF0)|12; } switch (expansionmode) { case 1: /* emulate roller controller with mouse */ case 2: /* emulate RC with joystick */ if ((JoyState[1]&0x0F)==12 || (JoyState[1]&0x0F)==13) JoyState[1]|=0x0F; if ((JoyState[0]&0x0F)==12 || (JoyState[0]&0x0F)==13) JoyState[0]|=0x0F; tmp=JoyState[1]; JoyState[1]=(JoyState[0]&0x707F)|0x0F00; JoyState[0]=(tmp&0x7F7F); if ((JoyState[1]&0xF)!=0xF) JoyState[0]=(JoyState[0]&0xFFF0)|(JoyState[1]&0x0F); JoyState[1]=(JoyState[1]&0xFFF0)|(JoyState[0]&0x0F); break; case 3: /* emulate driving module with joystick */ case 4: /* emulate driving module with mouse */ if ((JoyState[1]&0x0F)==12 || (JoyState[1]&0x0F)==13) JoyState[1]|=0x0F; if ((JoyState[0]&0x0F)==12 || (JoyState[0]&0x0F)==13) JoyState[0]|=0x0F; if ((JoyState[1]&0xF)!=0xF) JoyState[0]=(JoyState[0]&0xFFF0)|(JoyState[1]&0x0F); if ((JoyState[1]&0x0100)==0) JoyState[1]&=0xBFFF; else JoyState[1]|=0x4000; JoyState[1]|=0x0F7F; tmp=JoyState[1]; JoyState[1]=JoyState[0]; JoyState[0]=tmp|0x0040; break; default: switch (joystick) { case 1: /* Joystick 1=Joystick 2 */ tmp=JoyState[0]&0x0F; tmp2=JoyState[1]&0x0F; if (tmp==12 || tmp==13) JoyState[1]=(JoyState[1]&0xFFF0)|(JoyState[0]&0xF); else if (tmp2==12 || tmp2==13) JoyState[0]=(JoyState[0]&0xFFF0)|(JoyState[1]&0xF); else if (tmp2!=15) { JoyState[0]=(JoyState[0]&0xFFF0)|(JoyState[1]&0x0F); JoyState[1]|=15; } JoyState[0]&=(JoyState[1]|0xF); JoyState[1]&=(JoyState[0]|0xF); break; case 2: /* Joystick 1=keyb, Joystick 2=joystick */ break; case 3: /* Joystick 1=joystick, Joystick 2=keyb */ tmp=JoyState[0]; JoyState[0]=JoyState[1]; JoyState[1]=tmp; break; } break; } } /****************************************************************************/ /*** Parse keyboard events ***/ /****************************************************************************/ extern byte *RAM; void Keyboard (void) { int tmp; /* Check if reset combination is pressed */ if (AltPressed()) { if (keybstatus[VK_F12]) ResetColeco (0); if (keybstatus[VK_F11]) ResetColeco (1); } /* Update keyboard buffer */ do { tmp=LocalGetKeyboardChar (); if (tmp) AddToKeyboardBuffer (tmp); } while (tmp); /* Check mouse and joystick events */ Joysticks (); /* Check if video mode should be switched */ if (SwitchVideoMode) { SwitchVideoMode=0; AutoText80=0; if (Text80) ResetText80(); else InitText80(); } /* Check is PAUSE is pressed */ if (PausePressed) { StopSound (); tmp=0; if (PausePressed==2) { tmp=1; VGA_SetBkColour (1); inportb (0x3BA); inportb (0x3DA); outportb (0x3C0,0); } while (PausePressed); if (tmp) { VGA_SetBkColour (VDP.BGColour); inportb (0x3BA); inportb (0x3DA); outportb (0x3C0,0x20); } ResumeSound (); if (syncemu) OldTimer=ReadTimer (); } /* Check if a screen shot should be taken */ if (makeshot) { sound (440); WriteBitmap (szBitmapFile,8,17,WIDTH,256,192, DisplayBuf+(WIDTH-256)/2+(HEIGHT-192)*WIDTH,VGA_Palette); NextBitmapFile (); makeshot--; nosound (); } if (makesnap) { sound (220); SaveSnapshotFile (szSnapshotFile); NextSnapshotFile (); nosound (); makesnap--; } #ifdef DEBUG if (dumpram) { FILE *f; char buf[20]; static int dumpram_count=0; sprintf (buf,"RAM.%03d",dumpram_count); dumpram_count++; if (dumpram_count>999) dumpram_count=0; f=fopen (buf,"wb"); for (tmp=0;tmp<256;++tmp) fwrite (AddrTabl[tmp],1,256,f); fclose (f); dumpram--; } #endif /* Check if OptionsDialogue() should be called */ if (calloptions) { in_options_dialogue=1; calloptions=0; StopSound (); VGA_Reset (); fflush (stdin); OptionsDialogue (); VGA_Init (); if (Text80) InitText80(); in_options_dialogue=0; ResumeSound (); RefreshScreen (1); if (syncemu) OldTimer=ReadTimer(); } } /****************************************************************************/ /** Interrupt routines **/ /****************************************************************************/ /* Gets called 50 times per second */ int CheckScreenRefresh (void) { static int skipped=0; if (syncemu) { NewTimer=ReadTimer (); OldTimer+=1192380/IFreq; if ((OldTimer-NewTimer)>0) { do NewTimer=ReadTimer (); while ((NewTimer-OldTimer)<0); skipped=0; return 1; } else if (++skipped>=UPeriod) { OldTimer=ReadTimer (); skipped=0; return 1; } else return 0; } return 2; } /****************************************************************************/ /** Screen refresh drivers **/ /****************************************************************************/ #define USE_LOOKUP_TABLE /* Use font2screen for faster refresh */ #define _8BPP /* We have an 8 bpp video device */ #include "Common.h"