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