1 /** ADAMEm: Coleco ADAM emulator ********************************************/
2 /**                                                                        **/
3 /**                                SVGALib.c                               **/
4 /**                                                                        **/
5 /** This file contains the SVGALib specific routines. It does not include  **/
6 /** the sound emulation code                                               **/
7 /**                                                                        **/
8 /** Copyright (C) Marcel de Kogel 1996,1997,1998,1999                      **/
9 /**     You are not allowed to distribute this software commercially       **/
10 /**     Please, notify me, if you make any changes to this file            **/
11 /****************************************************************************/
12 
13 #include "Coleco.h"
14 #include "SVGALib.h"
15 #include "Bitmap.h"
16 #include "Unix.h"
17 
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <signal.h>
22 #include <sys/time.h>
23 #include <asm/io.h>
24 #include <linux/keyboard.h>
25 #include <vga.h>
26 #include <vgakeyboard.h>
27 #include <termio.h>
28 
29 /* Title for -help output */
30 char Title[]="ADAMEm Linux/SVGALib 1.0";
31 
32 /* Key mapping */
33 static int KEY_LEFT,KEY_RIGHT,KEY_UP,KEY_DOWN,
34            KEY_BUTTONA,KEY_BUTTONB,KEY_BUTTONC,KEY_BUTTOND;
35 static byte VGA_Palette[17];      /* Coleco Palette                         */
36 static byte PalBuf[16],Pal0;      /* Palette buffer                         */
37 static int default_mouse_sens=200;/* Default mouse sensitivity              */
38 static int keyboardmode;          /* 0=joystick, 1=keyboard                 */
39 static word MouseJoyState[2];     /* Current mouse status                   */
40 static word JoystickJoyState[2];  /* Current joystick status                */
41 static unsigned font2screen[16*16*16];
42                                   /* Used by screen refresh driver          */
43 static int makeshot=0;            /* 1 if screen shot should be taken       */
44 static int makesnap=0;            /* 1 if snapshot should be written        */
45 static int OldTimer=0;            /* Last value of timer                    */
46 static int NewTimer=0;            /* New value of timer                     */
47 static int calloptions=0;         /* If 1, OptionsDialogue() is called      */
48 static struct termios termold;    /* Original terminal settings             */
49 
50 byte DisplayBuf[WIDTH*(HEIGHT+16)];    /* Screen buffer                          */
51 char szBitmapFile[256];           /* Next screen shot file                  */
52 char szSnapshotFile[256];         /* Next snapshot file                     */
53 char szJoystickFileName[256];     /* File holding joystick information      */
54 char *szKeys="696A676C381D2A2C";  /* Key scancodes                          */
55 int  mouse_sens=200;              /* Mouse sensitivity                      */
56 int  keypadmode=0;                /* 1 if keypad should be reversed         */
57 int  joystick=1;                  /* Joystick support                       */
58 int  calibrate=0;                 /* Set to 1 to force joystick calibration */
59 int  swapbuttons=0;               /* 1=joystick, 2=keyboard, 4=mouse        */
60 int  expansionmode=0;             /* Expansion module emulated              */
61 int  useoverscan=1;               /* Overscan colour support                */
62 int  videomode=0;                 /* 0=320x200   2=320x240                  */
63 int  syncemu=1;                   /* 0 if emulation shouldn't be synced     */
64 int  chipset=1;                   /* If 0, do not detect SVGA               */
65 
outportb(word _port,byte _data)66 static inline volatile void outportb (word _port,byte _data)
67 {
68  outb (_data,_port);
69 }
70 
outportw(word _port,word _data)71 static inline volatile void outportw (word _port,word _data)
72 {
73  outw (_data,_port);
74 }
75 
inportb(word _port)76 static inline volatile byte inportb (word _port)
77 {
78  return inb (_port);
79 }
80 
VGA_SetBkColour(unsigned char colour)81 static void VGA_SetBkColour (unsigned char colour)
82 {
83  static int currbkcol=-1;
84  if (currbkcol==colour)
85   return;
86  currbkcol=colour;
87  VGA_Palette[0]=VGA_Palette[3]=Coleco_Palette[currbkcol*3+0];
88  VGA_Palette[1]=VGA_Palette[4]=Coleco_Palette[currbkcol*3+1];
89  VGA_Palette[2]=VGA_Palette[5]=Coleco_Palette[currbkcol*3+2];
90  if (useoverscan)
91   vga_setpalette (0,VGA_Palette[0]/4,VGA_Palette[1]/4,VGA_Palette[2]/4);
92  vga_setpalette (1,VGA_Palette[3]/4,VGA_Palette[4]/4,VGA_Palette[5]/4);
93 }
94 
PutImage(void)95 static void PutImage (void)
96 {
97  char *p,*z;
98  int i,j;
99  p=vga_getgraphmem ();
100  z=DisplayBuf;
101  switch (videomode)
102  {
103   case 0:
104    p+=320*(200-192)/2+(320-256)/2;
105    for (i=0;i<192;i++,p+=320,z+=256)
106     for (j=0;j<256;j+=4)
107      *(unsigned*)(p+j)=*(unsigned*)(z+j);
108    break;
109   case 1:
110    p+=(320/4)*(240-192)/2+(320-256)/8;
111    for (i=0;i<192;++i,p+=320/4,z+=256)
112    {
113     outportw (0x3C4,0x102);
114     for (j=0;j<64;++j)
115      p[j]=z[j*4+0];
116     outportw (0x3C4,0x202);
117     for (j=0;j<64;++j)
118      p[j]=z[j*4+1];
119     outportw (0x3C4,0x402);
120     for (j=0;j<64;++j)
121      p[j]=z[j*4+2];
122     outportw (0x3C4,0x802);
123     for (j=0;j<64;++j)
124      p[j]=z[j*4+3];
125    }
126  }
127 }
128 
129 /****************************************************************************/
130 /** Keyboard routines                                                      **/
131 /****************************************************************************/
132 static int PausePressed=0;
133 static byte keybstatus[NR_KEYS];
134 
135 static byte keyboard_buffer[16];
136 static int keyboard_buffer_count=0;
LocalAddToKeyboardBuffer(byte ch)137 static void LocalAddToKeyboardBuffer (byte ch)
138 {
139  keyboard_buffer[keyboard_buffer_count]=ch;
140  keyboard_buffer_count=(keyboard_buffer_count+1)&15;
141  keyboard_buffer[keyboard_buffer_count]=0;
142 }
LocalGetKeyboardChar(void)143 static int LocalGetKeyboardChar (void)
144 {
145  int retval;
146  keyboard_buffer_count=(keyboard_buffer_count-1)&15;
147  retval=keyboard_buffer[keyboard_buffer_count];
148  keyboard_buffer[keyboard_buffer_count]=0;
149  return retval;
150 }
151 
152 static const byte scan2ascii[NR_KEYS] =
153 {
154  0,27,'1','2','3','4','5','6','7','8','9','0','-','=',8,
155  9,'q','w','e','r','t','y','u','i','o','p','[',']',13,
156  0,'a','s','d','f','g','h','j','k','l',';',39,'`',
157  0,92,'z','x','c','v','b','n','m',',','.','/',0,
158  '*',0,' ',0,129,130,131,132,133,134,144,145,0,0,
159  0,0,171,160,168,'-',163,128,161,'+',170,162,169,148,151,
160  0,0,0,0,0,0,0,0,0,0,0,0,
161  0,0,'/',0,0,0,146,160,150,163,161,147,162,149,148,151,
162  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
163 };
164 static const byte scan2ascii_shift[NR_KEYS] =
165 {
166  0,27,'!','@','#','$','%','^','&','*','(',')','_','+',184,
167  185,'Q','W','E','R','T','Y','U','I','O','P','{','}',13,
168  0,'A','S','D','F','G','H','J','K','L',':',34,'~',
169  0,'|','Z','X','C','V','B','N','M','<','>','?',0,
170  '*',0,' ',0,137,138,139,140,141,142,152,153,0,0,
171  0,0,0,0,0,'-',0,0,0,'+',0,0,0,156,159,
172  0,0,0,0,0,0,0,0,0,0,0,0,
173  0,0,'/',0,0,0,154,0,158,0,0,155,0,157,156,159,
174  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
175 };
176 static const byte scan2ascii_ctrl[NR_KEYS] =
177 {
178  0,27,0,255,0,0,0,30,0,0,0,0,31,0,127,
179  0,17,23,5,18,20,25,21,9,15,16,27,29,13,
180  0,1,19,4,6,7,8,10,11,12,0,0,0,
181  0,28,26,24,3,22,2,14,13,0,0,0,0,
182  0,0,32,0,0,0,0,0,0,0,0,0,0,0,
183  0,0,0,164,0,0,167,0,165,0,0,166,0,0,0,
184  0,0,0,0,0,0,0,0,0,0,0,0,
185  0,0,0,0,0,0,0,164,0,167,165,0,166,0,0,0,
186  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
187 };
AltPressed(void)188 static inline int AltPressed (void)
189 {
190  return keybstatus[SCANCODE_LEFTALT] || keybstatus[SCANCODE_RIGHTALT];
191 }
CtrlPressed(void)192 static inline int CtrlPressed (void)
193 {
194  return keybstatus[SCANCODE_LEFTCONTROL] || keybstatus[SCANCODE_RIGHTCONTROL];
195 }
keyb_handler(int code,int newstatus)196 static void keyb_handler (int code,int newstatus)
197 {
198  static int CapsLock=0;
199  if (code<0 || code>=NR_KEYS)
200   return;
201  if (newstatus) newstatus=1;
202  if (!newstatus)
203   keybstatus[code]=0;
204  else
205  {
206   if (!keybstatus[code])
207   {
208    keybstatus[code]=1;
209    if (CtrlPressed() &&
210        (code==SCANCODE_F11 || code==SCANCODE_F12))
211    {
212     if (code==SCANCODE_F11)
213      PausePressed=2;
214     else
215      PausePressed=1;
216    }
217    else
218     PausePressed=0;
219    switch (code)
220    {
221     case SCANCODE_INSERT:
222      if (!keyboardmode || AltPressed())
223       joystick=1;
224      break;
225     case SCANCODE_HOME:
226      if (!keyboardmode || AltPressed())
227       joystick=2;
228      break;
229     case SCANCODE_PAGEUP:
230      if (!keyboardmode || AltPressed())
231       joystick=3;
232      break;
233     case SCANCODE_REMOVE:
234      if (!keyboardmode || AltPressed())
235       swapbuttons^=1;
236      break;
237     case SCANCODE_END:
238      if (!keyboardmode || AltPressed())
239       swapbuttons^=2;
240      break;
241     case SCANCODE_PAGEDOWN:
242      if (!keyboardmode || AltPressed())
243       swapbuttons^=4;
244      break;
245     case SCANCODE_CAPSLOCK:
246      CapsLock^=1;
247      break;
248     case SCANCODE_F1:
249      if (!keyboardmode || AltPressed())
250       ToggleSoundChannel (0);
251      break;
252     case SCANCODE_F2:
253      if (!keyboardmode || AltPressed())
254       ToggleSoundChannel (1);
255      break;
256     case SCANCODE_F3:
257      if (!keyboardmode || AltPressed())
258       ToggleSoundChannel (2);
259      break;
260     case SCANCODE_F4:
261      if (!keyboardmode || AltPressed())
262       ToggleSoundChannel (3);
263      break;
264     case SCANCODE_F5:
265      if (!keyboardmode || AltPressed())
266       ToggleSound ();
267      break;
268     case SCANCODE_F11:
269      if (!PausePressed && !AltPressed())
270       DecreaseSoundVolume ();
271      break;
272     case SCANCODE_F12:
273      if (!PausePressed && !AltPressed())
274       IncreaseSoundVolume ();
275      break;
276     case SCANCODE_F10:
277      Z80_Running=0;
278      break;
279     case SCANCODE_F8:
280      if (!keyboardmode || AltPressed())
281       makeshot=1;
282      break;
283     case SCANCODE_F7:
284      if (!keyboardmode || AltPressed())
285       makesnap=1;
286      break;
287     case SCANCODE_F9:
288 #ifdef DEBUG
289      if (keybstatus[SCANCODE_LEFTSHIFT] || keybstatus[SCANCODE_RIGHTSHIFT])
290      {
291       Trace=!Trace;
292       break;
293      }
294 #endif
295      if (EmuMode)
296       if (CtrlPressed())
297        calloptions=1;
298       else
299        keyboardmode=(keyboardmode)? 0:1;
300      break;
301    }
302   }
303   if (keyboardmode && !AltPressed())  /* Modify keyboard buffer             */
304   {
305    /* Check for HOME+Cursor key and Cursor key combinations */
306    if (code==SCANCODE_KEYPAD5)
307    {
308     if (keybstatus[SCANCODE_CURSORLEFT] ||
309         keybstatus[SCANCODE_CURSORBLOCKLEFT])
310     { code=175; goto put_char_in_buf; }
311     if (keybstatus[SCANCODE_CURSORRIGHT] ||
312         keybstatus[SCANCODE_CURSORBLOCKRIGHT])
313     { code=173; goto put_char_in_buf; }
314     if (keybstatus[SCANCODE_CURSORUP] ||
315         keybstatus[SCANCODE_CURSORBLOCKUP])
316     { code=172; goto put_char_in_buf; }
317     if (keybstatus[SCANCODE_CURSORDOWN] ||
318         keybstatus[SCANCODE_CURSORBLOCKDOWN])
319     { code=170; goto put_char_in_buf; }
320    }
321    if (keybstatus[SCANCODE_KEYPAD5])
322    {
323     if (code==SCANCODE_CURSORLEFT) { code=175; goto put_char_in_buf; }
324     if (code==SCANCODE_CURSORRIGHT) { code=173; goto put_char_in_buf; }
325     if (code==SCANCODE_CURSORUP) { code=172; goto put_char_in_buf; }
326     if (code==SCANCODE_CURSORDOWN) { code=170; goto put_char_in_buf; }
327    }
328    if (code==SCANCODE_CURSORUP || code==SCANCODE_CURSORBLOCKUP)
329    {
330     if (keybstatus[SCANCODE_CURSORRIGHT] ||
331         keybstatus[SCANCODE_CURSORBLOCKRIGHT])
332     { code=168; goto put_char_in_buf; }
333     if (keybstatus[SCANCODE_CURSORLEFT] ||
334         keybstatus[SCANCODE_CURSORBLOCKLEFT])
335     { code=171; goto put_char_in_buf; }
336    }
337    if (code==SCANCODE_CURSORRIGHT || code==SCANCODE_CURSORBLOCKRIGHT)
338    {
339     if (keybstatus[SCANCODE_CURSORUP] ||
340         keybstatus[SCANCODE_CURSORBLOCKUP])
341     { code=168; goto put_char_in_buf; }
342     if (keybstatus[SCANCODE_CURSORDOWN] ||
343         keybstatus[SCANCODE_CURSORBLOCKDOWN])
344     { code=169; goto put_char_in_buf; }
345    }
346    if (code==SCANCODE_CURSORDOWN || code==SCANCODE_CURSORBLOCKDOWN)
347    {
348     if (keybstatus[SCANCODE_CURSORRIGHT] ||
349         keybstatus[SCANCODE_CURSORBLOCKRIGHT])
350     { code=169; goto put_char_in_buf; }
351     if (keybstatus[SCANCODE_CURSORLEFT] ||
352         keybstatus[SCANCODE_CURSORBLOCKLEFT])
353     { code=170; goto put_char_in_buf; }
354    }
355    if (code==SCANCODE_CURSORLEFT)
356    {
357     if (keybstatus[SCANCODE_CURSORUP] ||
358         keybstatus[SCANCODE_CURSORBLOCKUP])
359     { code=171; goto put_char_in_buf; }
360     if (keybstatus[SCANCODE_CURSORDOWN] ||
361         keybstatus[SCANCODE_CURSORBLOCKDOWN])
362     { code=170; goto put_char_in_buf; }
363    }
364    if (keybstatus[SCANCODE_LEFTCONTROL] ||
365        keybstatus[SCANCODE_RIGHTCONTROL])
366     code=scan2ascii_ctrl[code];
367    else if (keybstatus[SCANCODE_LEFTSHIFT] ||
368             keybstatus[SCANCODE_RIGHTSHIFT])
369     code=scan2ascii_shift[code];
370    else
371     code=scan2ascii[code];
372 put_char_in_buf:
373    if (CapsLock)
374    {
375     if (code>='a' && code<='z') code+='A'-'a';
376     else if (code>='A' && code<='Z') code+='a'-'A';
377    }
378    if (code) LocalAddToKeyboardBuffer (code);
379   }
380  }
381 }
382 
383 /****************************************************************************/
384 /** Mouse routines                                                         **/
385 /****************************************************************************/
386 static int mouse_buttons=0;       /* mouse buttons pressed                  */
387 static int mouse_xpos=500;        /* horizontal position (0 - 1000)         */
388 static int mouse_ypos=500;        /* vertical position (0 - 1000)           */
389 static int mouse_x=0;             /* horizontal position (-500 - 500)       */
390 static int mouse_y=0;             /* vertical position (-500 - 500)         */
391 static int got_mouse=0;           /* 1 if mouse was properly initialised    */
392 
Mouse_SetJoyState()393 static void Mouse_SetJoyState ()
394 {
395  if (mouse_buttons&1)
396   MouseJoyState[0]&=0xBFFF;
397  if (mouse_buttons&2)
398   MouseJoyState[0]&=0xFFBF;
399  if (mouse_buttons&4)
400   MouseJoyState[1]&=0xBFFF;
401  if (mouse_buttons&8)
402   MouseJoyState[1]&=0xFFBF;
403  SpinnerPosition[0]=(default_mouse_sens*mouse_x*(abs(mouse_x)+mouse_sens))/
404                     (mouse_sens*mouse_sens);
405  SpinnerPosition[1]=(default_mouse_sens*mouse_y*(abs(mouse_y)+mouse_sens))/
406                     (mouse_sens*mouse_sens);
407 }
408 
Mouse_GetPosition(void)409 static void Mouse_GetPosition (void)
410 {
411 }
412 
Mouse_SetPosition(int x,int y)413 static void Mouse_SetPosition (int x,int y)
414 {
415 }
416 
Mouse_SetHorizontalRange(int x,int y)417 static void Mouse_SetHorizontalRange (int x,int y)
418 {
419 }
420 
Mouse_SetVerticalRange(int x,int y)421 static void Mouse_SetVerticalRange (int x,int y)
422 {
423 }
424 
Mouse_Check(void)425 static void Mouse_Check (void)
426 {
427  int tmp;
428  if (!got_mouse)
429   return;
430  Mouse_GetPosition ();
431  mouse_x=mouse_xpos-500;
432  mouse_y=mouse_ypos-500;
433  tmp=mouse_buttons;
434  if (mouse_x || mouse_y)
435   Mouse_SetPosition (500,500);
436  switch (expansionmode)
437  {
438   case 4:                         /* emulate driving module                 */
439    if (mouse_buttons&7)
440     MouseJoyState[0]&=0xFEFF;
441    mouse_x/=4;
442    mouse_y=0;
443    mouse_buttons=0;
444    break;
445   case 5:                         /* emulate SA speed roller on both ports  */
446    mouse_x/=4;
447    mouse_y=mouse_x;
448    mouse_buttons=0;
449    break;
450   case 6:                         /* emulate SA speed roller on port 1      */
451    mouse_x/=4;
452    mouse_y=0;
453    mouse_buttons=0;
454    break;
455   case 7:                         /* emulate SA speed roller on port 2      */
456    mouse_y=mouse_x/4;
457    mouse_x=0;
458    mouse_buttons=0;
459    break;
460  }
461  if (swapbuttons&4)
462   mouse_buttons=(mouse_buttons&(~3))|
463                 ((mouse_buttons&1)<<1)|
464                 ((mouse_buttons&2)>>1);
465  Mouse_SetJoyState ();
466  mouse_buttons=tmp;
467 }
468 
Mouse_Detect(void)469 static int Mouse_Detect (void)
470 {
471  if (Verbose) puts ("  Detecting mouse... "
472                     "Sorry, mouse support is not implemented yet");
473  return 0;
474 }
475 
Mouse_Init(void)476 static void Mouse_Init (void)
477 {
478  if (!got_mouse)
479  Mouse_SetHorizontalRange (0,1000);
480  Mouse_SetVerticalRange (0,1000);
481  Mouse_SetPosition (500,500);
482  return;
483 }
484 
Mouse_Exit(void)485 static void Mouse_Exit (void)
486 {
487 }
488 
489 /****************************************************************************/
490 /** Joystick routines                                                      **/
491 /****************************************************************************/
492 static int gotjoy=0;              /* 1 if joystick was properly initialised */
493 static joypos_t joycentre;        /* joystick centre position               */
494 static joypos_t joymin;           /* left-upper corner position             */
495 static joypos_t joymax;           /* right-lower corner position            */
496 static joypos_t joy_lowmargin;    /* start of 'dead' region                 */
497 static joypos_t joy_highmargin;   /* end of 'dead' region                   */
498 
Joy_Init(void)499 static int Joy_Init (void)
500 {
501  if (!InitJoystick(1))
502   return 0;
503  ReadJoystick (&joycentre);
504  gotjoy=1;
505  return 1;
506 }
507 
CalibrateJoystick(void)508 static void CalibrateJoystick (void)
509 {
510  FILE *joyfile=NULL;
511  if (!calibrate)
512   joyfile=fopen(szJoystickFileName,"rb");
513  if (!joyfile)
514  {
515   vga_flip ();
516   fprintf (stderr,"Move joystick to top left and press CR\n");
517   fflush (stdin); fgetc (stdin);
518   ReadJoystick (&joymin);
519   fprintf (stderr,"Move joystick to bottom right and press CR\n");
520   fflush (stdin); fgetc (stdin);
521   vga_flip ();
522   ReadJoystick (&joymax);
523   joyfile=fopen(szJoystickFileName,"wb");
524   if (joyfile)
525   {
526    fwrite (&joymin,sizeof(joymin),1,joyfile);
527    fwrite (&joymax,sizeof(joymax),1,joyfile);
528    fclose (joyfile);
529   }
530  }
531  else
532  {
533   fread (&joymin,sizeof(joymin),1,joyfile);
534   fread (&joymax,sizeof(joymax),1,joyfile);
535   fclose (joyfile);
536  }
537  joy_lowmargin.x=joycentre.x-(joycentre.x-joymin.x)/8;
538  joy_lowmargin.y=joycentre.y-(joycentre.y-joymin.y)/8;
539  joy_highmargin.x=joycentre.x+(joymax.x-joycentre.x)/8;
540  joy_highmargin.y=joycentre.y+(joymax.y-joycentre.y)/8;
541  /* prevent a divide by zero in JoySortOutAnalogue() */
542  if (joy_lowmargin.x-joymin.x==0)
543   joy_lowmargin.x++;
544  if (joymax.x-joy_highmargin.x==0)
545   joy_highmargin.x--;
546  if (joy_lowmargin.y-joymin.y==0)
547   joy_lowmargin.y++;
548  if (joymax.y-joy_highmargin.y==0)
549   joy_highmargin.y--;
550 }
551 
552 #define JOY_RANGE       128
JoySortOutAnalogue(joypos_t * jp)553 static void JoySortOutAnalogue (joypos_t *jp)
554 {
555  if (jp->x < joymin.x)
556   jp->x=-JOY_RANGE;
557  else
558   if (jp->x > joymax.x)
559    jp->x=JOY_RANGE;
560   else
561    if ((jp->x > joy_lowmargin.x) && (jp->x < joy_highmargin.x))
562     jp->x=0;
563    else
564     if (jp->x < joy_lowmargin.x)
565      jp->x=-JOY_RANGE+(jp->x-joymin.x)*JOY_RANGE/(joy_lowmargin.x-joymin.x);
566     else
567      jp->x=JOY_RANGE-(joymax.x-jp->x)*JOY_RANGE/(joymax.x-joy_highmargin.x);
568 
569  if (jp->y < joymin.y)
570   jp->y=-JOY_RANGE;
571  else
572   if (jp->y > joymax.y)
573    jp->y=JOY_RANGE;
574   else
575    if ((jp->y > joy_lowmargin.y) && (jp->y < joy_highmargin.y))
576     jp->y=0;
577    else
578     if (jp->y < joy_lowmargin.y)
579      jp->y=-JOY_RANGE+(jp->y-joymin.y)*JOY_RANGE/(joy_lowmargin.y-joymin.y);
580     else
581      jp->y=JOY_RANGE-(joymax.y-jp->y)*JOY_RANGE/(joymax.y-joy_highmargin.y);
582 }
583 
Joy_Check(void)584 static void Joy_Check (void)
585 {
586  joypos_t jp;
587  if (!gotjoy)
588   return;
589  ReadJoystick (&jp);
590  switch (expansionmode)
591  {
592   case 0:
593   case 5:
594   case 6:
595   case 7:
596    if (jp.x<(joycentre.x*3/4))
597     JoystickJoyState[0]&=0xF7FF;
598    else
599     if (jp.x>(joycentre.x*5/4))
600      JoystickJoyState[0]&=0xFDFF;
601    if (jp.y<(joycentre.y*3/4))
602     JoystickJoyState[0]&=0xFEFF;
603    else
604     if (jp.y>(joycentre.y*5/4))
605      JoystickJoyState[0]&=0xFBFF;
606    if (jp.buttons&1)
607     JoystickJoyState[0]&=(swapbuttons&1)? 0xFFBF:0xBFFF;
608    if (jp.buttons&2)
609     JoystickJoyState[0]&=(swapbuttons&1)? 0xBFFF:0xFFBF;
610    if (jp.buttons&4)
611     JoystickJoyState[0]=(JoyState[0]&0xFFF0)|12;
612    if (jp.buttons&8)
613     JoystickJoyState[0]=(JoyState[0]&0xFFF0)|13;
614    break;
615   case 2:
616    JoySortOutAnalogue (&jp);
617    mouse_x=jp.x;
618    mouse_y=jp.y;
619    mouse_buttons=0;
620    if (jp.buttons&1)
621     mouse_buttons|=(swapbuttons&1)? 2:1;
622    if (jp.buttons&2)
623     mouse_buttons|=(swapbuttons&1)? 1:2;
624    if (jp.buttons&4)
625     mouse_buttons|=4;
626    if (jp.buttons&8)
627     mouse_buttons|=8;
628    Mouse_SetJoyState ();
629    break;
630   case 3:
631    if (jp.y<(joycentre.y*3/4))
632     JoystickJoyState[0]&=0xFEFF;
633    JoySortOutAnalogue (&jp);
634    mouse_x=(jp.x/2);
635    mouse_y=0;
636    Mouse_SetJoyState ();
637    if (jp.buttons&1)
638     JoystickJoyState[1]&=(swapbuttons&1)? 0xFBFF:0xFEFF;
639    if (jp.buttons&2)
640     JoystickJoyState[1]&=(swapbuttons&1)? 0xFEFF:0xFBFF;
641    if (jp.buttons&4)
642     JoystickJoyState[1]&=0xF7FF;
643    if (jp.buttons&8)
644     JoystickJoyState[1]&=0xFDFF;
645    break;
646  }
647 }
648 
649 /****************************************************************************/
650 /** Deallocate all resources taken by InitMachine()                        **/
651 /****************************************************************************/
TrashMachine(void)652 void TrashMachine(void)
653 {
654  Mouse_Exit ();
655  keyboard_close ();
656  vga_setmode (TEXT);
657  tcsetattr (0,0,&termold);
658  TrashSound ();
659  TrashJoystick ();
660 }
661 
NextFile(char * s)662 static int NextFile (char *s)
663 {
664  char *p;
665  p=s+strlen(s)-1;
666  if (*p=='9')
667  {
668   *p='0';
669   --p;
670   if (*p=='9')
671   {
672    (*p)++;
673    if (*p=='0')
674     return 0;
675   }
676   else
677    (*p)++;
678  }
679  else
680   (*p)++;
681  return 1;
682 }
683 
NextBitmapFile(void)684 static int NextBitmapFile (void)
685 {
686  return NextFile (szBitmapFile);
687 }
688 
NextSnapshotFile(void)689 static int NextSnapshotFile (void)
690 {
691  return NextFile (szSnapshotFile);
692 }
693 
signal_fatal_handler(int s)694 static void signal_fatal_handler(int s)
695 {
696  printf("Signal %s (%d) received\n",strsignal(s),s);
697  signal (s,signal_fatal_handler);
698  TrashMachine ();
699  raise (SIGKILL);
700 }
701 
signal_quit_handler(int s)702 static void signal_quit_handler(int s)
703 {
704  signal (s,signal_quit_handler);
705  Z80_Running=0;
706 }
707 
708 static int signals_fatal[] =
709 {
710  SIGHUP,  SIGINT,
711  SIGILL,  SIGIOT,
712  SIGBUS,  SIGFPE,
713  SIGSEGV, SIGPIPE,
714  SIGXCPU, SIGXFSZ,
715  SIGPROF, SIGPWR,
716  0
717 };
718 
719 static int signals_quit[] =
720 {
721  SIGQUIT, SIGTRAP,
722  SIGALRM, SIGTERM,
723  SIGVTALRM,
724  0
725 };
726 
727 /****************************************************************************/
728 /** Allocate resources needed by Linux/SVGALib-dependent code              **/
729 /****************************************************************************/
InitMachine(void)730 int InitMachine(void)
731 {
732  int i,j,c;
733  FILE *bitmapfile,*snapshotfile;
734  memset (VGA_Palette,0,sizeof(VGA_Palette));
735  memcpy (VGA_Palette+3,Coleco_Palette,16*3);
736  if (Verbose) printf ("Initialising Linux/SVGALib drivers...\n");
737  tcgetattr (0,&termold);
738  if (!chipset) vga_setchipset (VGA);
739  vga_init ();
740  if (Verbose) printf ("  Setting VGA mode... ");
741  switch (videomode)
742  {
743   case 1:  i=G320x240x256;
744            break;
745   default: i=G320x200x256;
746            videomode=0;
747            break;
748  }
749  i=vga_setmode (i);
750  if (i) { if (Verbose) puts ("FAILED"); return 0; }
751  if (videomode)
752  {
753   outportw (0x3C4,0xF02);
754   memset (vga_getgraphmem(),0,65536);
755  }
756  for (i=0;i<17;++i)
757   vga_setpalette (i,VGA_Palette[i*3+0]/4,
758                     VGA_Palette[i*3+1]/4,
759                     VGA_Palette[i*3+2]/4);
760  JoyState[0]=JoyState[1]=MouseJoyState[0]=MouseJoyState[1]=
761  JoystickJoyState[0]=JoystickJoyState[1]=0x7F7F;
762  memset (DisplayBuf,0,sizeof(DisplayBuf));
763  for (i=0;i<16;++i)
764   PalBuf[i]=i+1;
765  Pal0=2;
766  if (Verbose)
767   printf ("OK\n  Initialising conversion buffer... ");
768  for (i=0;i<16;++i)
769   for (j=0;j<16;++j)
770    for (c=0;c<16;++c)
771    {
772     unsigned a;
773     a=0;
774 #ifdef LSB_FIRST
775     if (c&0x08) a|=PalBuf[i]; else a|=PalBuf[j];
776     if (c&0x04) a|=(PalBuf[i]<<8); else a|=(PalBuf[j]<<8);
777     if (c&0x02) a|=(PalBuf[i]<<16); else a|=(PalBuf[j]<<16);
778     if (c&0x01) a|=(PalBuf[i]<<24); else a|=(PalBuf[j]<<24);
779 #else
780     if (c&0x01) a|=PalBuf[i]; else a|=PalBuf[j];
781     if (c&0x02) a|=(PalBuf[i]<<8); else a|=(PalBuf[j]<<8);
782     if (c&0x04) a|=(PalBuf[i]<<16); else a|=(PalBuf[j]<<16);
783     if (c&0x08) a|=(PalBuf[i]<<24); else a|=(PalBuf[j]<<24);
784 #endif
785     font2screen[i*16*16+j*16+c]=a;
786    }
787  if (Verbose) puts ("OK");
788  InitSound ();
789  if (expansionmode==2 || expansionmode==3 ||
790      (expansionmode!=1 && expansionmode!=4 && joystick))
791   Joy_Init ();
792  if (expansionmode==1 || expansionmode==4 ||
793      expansionmode==5 || expansionmode==6 ||
794      expansionmode==7)
795   i=Mouse_Detect ();
796  if (mouse_sens<=0 || mouse_sens>1000)
797   mouse_sens=default_mouse_sens;
798  switch (expansionmode)
799  {
800   case 2:
801   case 3:
802    if (!gotjoy)
803    {
804     expansionmode=0;
805     break;
806    }
807    CalibrateJoystick ();
808    break;
809   case 1:
810   case 4:
811   case 5:
812   case 6:
813   case 7:
814    if (!got_mouse)
815     expansionmode=0;
816    break;
817   default:
818    expansionmode=0;
819    default_mouse_sens*=5;
820    break;
821  }
822  if (syncemu)
823   OldTimer=ReadTimer ();
824  /* Parse keyboard mapping string */
825  sscanf (szKeys,"%02X%02X%02X%02X%02X%02X%02X%02X",
826          &KEY_LEFT,&KEY_RIGHT,&KEY_UP,&KEY_DOWN,
827          &KEY_BUTTONA,&KEY_BUTTONB,&KEY_BUTTONC,&KEY_BUTTOND);
828  while ((bitmapfile=fopen(szBitmapFile,"rb"))!=NULL)
829  {
830   fclose (bitmapfile);
831   if (!NextBitmapFile())
832    break;
833  }
834  while ((snapshotfile=fopen(szSnapshotFile,"rb"))!=NULL)
835  {
836   fclose (snapshotfile);
837   if (!NextSnapshotFile())
838    break;
839  }
840  if (Verbose)
841  {
842   printf ("  Next screenshot will be %s\n"
843           "  Next snapshot will be %s\n",
844           szBitmapFile,szSnapshotFile);
845  }
846  if (Verbose) printf ("  Initialising keyboard... ");
847  if (keyboard_init()) { if (Verbose) puts ("FAILED"); return 0; }
848  keyboard_translatekeys (DONT_CATCH_CTRLC);
849  keyboard_seteventhandler (keyb_handler);
850  if (Verbose) puts ("OK");
851  VGA_SetBkColour (0);
852  Mouse_Init ();
853  keyboardmode=(EmuMode)? 1:0;
854  for (i=0;signals_fatal[i];++i) signal (i,signal_fatal_handler);
855  for (i=0;signals_quit[i];++i) signal (i,signal_quit_handler);
856  return 1;
857 }
858 
859 /****************************************************************************/
860 /** Routines to modify the Coleco gamport status                           **/
861 /****************************************************************************/
numkeypressed(int nScanCode)862 static int numkeypressed (int nScanCode)
863 {
864  int nOr;
865  switch (nScanCode)
866  {
867   case SCANCODE_1:
868   case SCANCODE_KEYPAD1:
869    nOr=1;
870    break;
871   case SCANCODE_2:
872   case SCANCODE_KEYPAD2:
873    nOr=2;
874    break;
875   case SCANCODE_3:
876   case SCANCODE_KEYPAD3:
877    nOr=3;
878    break;
879   case SCANCODE_4:
880   case SCANCODE_KEYPAD4:
881    nOr=4;
882    break;
883   case SCANCODE_5:
884   case SCANCODE_KEYPAD5:
885    nOr=5;
886    break;
887   case SCANCODE_6:
888   case SCANCODE_KEYPAD6:
889    nOr=6;
890    break;
891   case SCANCODE_7:
892   case SCANCODE_KEYPAD7:
893    nOr=7;
894    break;
895   case SCANCODE_8:
896   case SCANCODE_KEYPAD8:
897    nOr=8;
898    break;
899   case SCANCODE_9:
900   case SCANCODE_KEYPAD9:
901    nOr=9;
902    break;
903   case SCANCODE_EQUAL:
904   case SCANCODE_KEYPADENTER:
905    nOr=10;
906    break;
907   case SCANCODE_MINUS:
908   case SCANCODE_KEYPADPERIOD:
909    nOr=11;
910    break;
911   default:
912    nOr=0;
913  }
914  return nOr;
915 }
916 
Joysticks(void)917 static void Joysticks (void)
918 {
919  int i,tmp,tmp2;
920  MouseJoyState[0]|=0x7F7F;
921  MouseJoyState[1]|=0x7F7F;
922  Mouse_Check ();
923  JoystickJoyState[0]|=0x7F7F;
924  JoystickJoyState[1]|=0x7F7F;
925  Joy_Check ();
926  JoyState[1]=(MouseJoyState[0] & JoystickJoyState[0]);
927  JoyState[0]=(MouseJoyState[1] & JoystickJoyState[1]);
928  if (!keyboardmode)
929  {
930   if (keybstatus[KEY_BUTTONA])
931    JoyState[0]&=(swapbuttons&2)? 0xFFBF:0xBFFF;
932   if (keybstatus[KEY_BUTTONB])
933    JoyState[0]&=(swapbuttons&2)? 0xBFFF:0xFFBF;
934   if (keybstatus[KEY_DOWN])
935    JoyState[0]&=0xFBFF;
936   if (keybstatus[KEY_UP])
937    JoyState[0]&=0xFEFF;
938   if (keybstatus[KEY_LEFT])
939    JoyState[0]&=0xF7FF;
940   if (keybstatus[KEY_RIGHT])
941    JoyState[0]&=0xFDFF;
942   for (i=SCANCODE_1;i<=SCANCODE_EQUAL;++i)
943    if (keybstatus[i])
944    {
945     tmp=numkeypressed(i);
946     JoyState[0]=(JoyState[0]&0xFFF0)|tmp;
947    }
948   if (keybstatus[KEY_BUTTONC])
949    JoyState[0]=(JoyState[0]&0xFFF0)|12;
950   if (keybstatus[KEY_BUTTOND])
951    JoyState[0]=(JoyState[0]&0xFFF0)|13;
952   for (i=SCANCODE_KEYPAD7;i<=SCANCODE_KEYPAD9;++i)
953    if (keybstatus[i])
954    {
955     tmp=numkeypressed((keypadmode)? (i-SCANCODE_KEYPAD7+SCANCODE_KEYPAD1) : i);
956     JoyState[1]=(JoyState[1]&0xFFF0)|tmp;
957    }
958   for (i=SCANCODE_KEYPAD4;i<=SCANCODE_KEYPAD6;++i)
959    if (keybstatus[i])
960    {
961     tmp=numkeypressed(i);
962     JoyState[1]=(JoyState[1]&0xFFF0)|tmp;
963    }
964   for (i=SCANCODE_KEYPAD1;i<=SCANCODE_KEYPAD3;++i)
965    if (keybstatus[i])
966    {
967     tmp=numkeypressed((keypadmode)? (i-SCANCODE_KEYPAD1+SCANCODE_KEYPAD7) : i);
968     JoyState[1]=(JoyState[1]&0xFFF0)|tmp;
969    }
970   if (keybstatus[SCANCODE_KEYPAD0])
971   {
972    tmp=numkeypressed((keypadmode)? SCANCODE_KEYPADPERIOD : SCANCODE_KEYPAD0);
973    JoyState[1]=(JoyState[1]&0xFFF0)|tmp;
974   }
975   if (keybstatus[SCANCODE_KEYPADPERIOD])
976   {
977    tmp=numkeypressed((keypadmode)? SCANCODE_KEYPAD0 : SCANCODE_KEYPADPERIOD);
978    JoyState[1]=(JoyState[1]&0xFFF0)|tmp;
979   }
980   if (keybstatus[SCANCODE_KEYPADENTER])
981   {
982    tmp=numkeypressed(SCANCODE_KEYPADENTER);
983    JoyState[1]=(JoyState[1]&0xFFF0)|tmp;
984   }
985   if (keybstatus[SCANCODE_KEYPADPLUS])
986    JoyState[1]=(JoyState[1]&0xFFF0)|13;
987   if (keybstatus[SCANCODE_KEYPADMINUS])
988    JoyState[1]=(JoyState[1]&0xFFF0)|12;
989  }
990  switch (expansionmode)
991  {
992   case 1:                         /* emulate roller controller with mouse   */
993   case 2:                         /* emulate RC with joystick               */
994    if ((JoyState[1]&0x0F)==12 || (JoyState[1]&0x0F)==13)
995     JoyState[1]|=0x0F;
996    if ((JoyState[0]&0x0F)==12 || (JoyState[0]&0x0F)==13)
997     JoyState[0]|=0x0F;
998    tmp=JoyState[1];
999    JoyState[1]=(JoyState[0]&0x707F)|0x0F00;
1000    JoyState[0]=(tmp&0x7F7F);
1001    if ((JoyState[1]&0xF)!=0xF)
1002     JoyState[0]=(JoyState[0]&0xFFF0)|(JoyState[1]&0x0F);
1003    JoyState[1]=(JoyState[1]&0xFFF0)|(JoyState[0]&0x0F);
1004    break;
1005   case 3:                         /* emulate driving module with joystick   */
1006   case 4:                         /* emulate driving module with mouse      */
1007    if ((JoyState[1]&0x0F)==12 || (JoyState[1]&0x0F)==13)
1008     JoyState[1]|=0x0F;
1009    if ((JoyState[0]&0x0F)==12 || (JoyState[0]&0x0F)==13)
1010     JoyState[0]|=0x0F;
1011    if ((JoyState[1]&0xF)!=0xF)
1012     JoyState[0]=(JoyState[0]&0xFFF0)|(JoyState[1]&0x0F);
1013    if ((JoyState[1]&0x0100)==0)
1014     JoyState[1]&=0xBFFF;
1015    else
1016     JoyState[1]|=0x4000;
1017    JoyState[1]|=0x0F7F;
1018    tmp=JoyState[1];
1019    JoyState[1]=JoyState[0];
1020    JoyState[0]=tmp|0x0040;
1021    break;
1022   default:
1023    switch (joystick)
1024    {
1025     case 1:                       /* Joystick 1=Joystick 2                  */
1026      tmp=JoyState[0]&0x0F;
1027      tmp2=JoyState[1]&0x0F;
1028      if (tmp==12 || tmp==13)
1029       JoyState[1]=(JoyState[1]&0xFFF0)|(JoyState[0]&0xF);
1030      else
1031       if (tmp2==12 || tmp2==13)
1032        JoyState[0]=(JoyState[0]&0xFFF0)|(JoyState[1]&0xF);
1033       else
1034        if (tmp2!=15)
1035        {
1036         JoyState[0]=(JoyState[0]&0xFFF0)|(JoyState[1]&0x0F);
1037         JoyState[1]|=15;
1038        }
1039      JoyState[0]&=(JoyState[1]|0xF);
1040      JoyState[1]&=(JoyState[0]|0xF);
1041      break;
1042     case 2:                       /* Joystick 1=keyb, Joystick 2=joystick   */
1043      break;
1044     case 3:                       /* Joystick 1=joystick, Joystick 2=keyb   */
1045      tmp=JoyState[0];
1046      JoyState[0]=JoyState[1];
1047      JoyState[1]=tmp;
1048      break;
1049    }
1050    break;
1051  }
1052 }
1053 
1054 /****************************************************************************/
1055 /*** Parse keyboard events                                                ***/
1056 /****************************************************************************/
Keyboard(void)1057 void Keyboard (void)
1058 {
1059  int tmp;
1060  keyboard_update ();
1061  /* Check if reset combination is pressed */
1062  if (AltPressed())
1063  {
1064   if (keybstatus[SCANCODE_F12]) ResetColeco (0);
1065   if (keybstatus[SCANCODE_F11]) ResetColeco (1);
1066  }
1067  /* Update keyboard buffer */
1068  do
1069  {
1070   tmp=LocalGetKeyboardChar ();
1071   if (tmp) AddToKeyboardBuffer (tmp);
1072  }
1073  while (tmp);
1074  /* Check mouse and joystick events */
1075  Joysticks ();
1076  /* Check is PAUSE is pressed */
1077  if (PausePressed)
1078  {
1079   StopSound ();
1080   tmp=0;
1081   if (PausePressed==2)
1082   {
1083    tmp=1;
1084    VGA_SetBkColour (1);
1085    inportb (0x3BA);
1086    inportb (0x3DA);
1087    outportb (0x3C0,0);
1088   }
1089   while (PausePressed) keyboard_update();
1090   if (tmp)
1091   {
1092    VGA_SetBkColour (PalBuf[0]-1);
1093    inportb (0x3BA);
1094    inportb (0x3DA);
1095    outportb (0x3C0,0x20);
1096   }
1097   ResumeSound ();
1098   if (syncemu)
1099    OldTimer=ReadTimer ();
1100  }
1101  /* Check if a screen shot should be taken */
1102  if (makeshot)
1103  {
1104   WriteBitmap (szBitmapFile,8,17,WIDTH,256,192,
1105                DisplayBuf+(WIDTH-256)/2+(HEIGHT-192)*WIDTH,VGA_Palette);
1106   NextBitmapFile ();
1107   makeshot--;
1108  }
1109  if (makesnap)
1110  {
1111   SaveSnapshotFile (szSnapshotFile);
1112   NextSnapshotFile ();
1113   makesnap--;
1114  }
1115  /* Check if OptionsDialogue() should be called */
1116  if (calloptions)
1117  {
1118   struct termios term;
1119   calloptions=0;
1120   StopSound ();
1121   vga_flip ();
1122   keyboard_close ();
1123   tcgetattr (0,&term);
1124   tcsetattr (0,0,&termold);
1125   fflush (stdin);
1126   OptionsDialogue ();
1127   tcsetattr (0,0,&term);
1128   keyboard_init ();
1129   keyboard_translatekeys (DONT_CATCH_CTRLC);
1130   keyboard_seteventhandler (keyb_handler);
1131   vga_flip ();
1132   ResumeSound ();
1133   if (syncemu) OldTimer=ReadTimer();
1134  }
1135 }
1136 
1137 /****************************************************************************/
1138 /** Interrupt routines                                                     **/
1139 /****************************************************************************/
1140 /* Gets called 50 times per second */
CheckScreenRefresh(void)1141 int CheckScreenRefresh (void)
1142 {
1143  static int skipped=0;
1144  if (syncemu)
1145  {
1146   NewTimer=ReadTimer ();
1147   OldTimer+=1000000/IFreq;
1148   if ((OldTimer-NewTimer)>0)
1149   {
1150    do
1151     NewTimer=ReadTimer ();
1152    while ((NewTimer-OldTimer)<0);
1153    skipped=0;
1154    return 1;
1155   }
1156   else
1157    if (++skipped>=UPeriod)
1158    {
1159     OldTimer=ReadTimer ();
1160     skipped=0;
1161     return 1;
1162    }
1163    else
1164     return 0;
1165  }
1166  return 2;
1167 }
1168 
1169 /****************************************************************************/
1170 /** Screen refresh drivers                                                 **/
1171 /****************************************************************************/
1172 #define USE_LOOKUP_TABLE              /* Use font2screen for faster refresh */
1173 #define _8BPP                         /* We have an 8 bpp video device      */
1174 
1175 #include "Common.h"
1176