|
|
1.1 root 1: /*
1.1.1.6 root 2: Hatari - ikbd.c
3:
4: This file is distributed under the GNU Public License, version 2 or at
5: your option any later version. Read the file gpl.txt for details.
1.1 root 6:
1.1.1.12 root 7: The keyboard processor(6301) handles any joystick/mouse task and sends bytes
8: to the ACIA(6850). When a byte arrives in the ACIA (which takes just over
9: 7000 CPU cycles) an MFP interrupt is flagged. The CPU can now read the byte
10: from the ACIA by reading address $fffc02.
11: An annoying bug can be found in Dungeon Master. This, when run, turns off the
12: mouse input - but of course then you are unable to play the game! A bodge
13: flag has been added so we need to be told twice to turn off the mouse input
14: (although I think this causes errors in other games...).
15: Also, the ACIA_CYCLES time is very important for games such as Carrier
16: Command. The keyboard handler in this game has a bug in it, which corrupts
17: its own registers if more than one byte is queued up. This value was found by
18: a test program on a real ST and has correctly emulated the behaviour.
19: */
1.1.1.14 root 20: const char IKBD_fileid[] = "Hatari ikbd.c : " __DATE__ " " __TIME__;
1.1.1.12 root 21:
22: /* 2007/09/29 [NP] Use the new int.c to add interrupts with INT_CPU_CYCLE / INT_MFP_CYCLE. */
23: /* 2007/12/09 [NP] If reset is written to ACIA control register, we must call ACIA_Reset to reset */
24: /* RX/TX status. Reading the control register fffc00 just after a reset should */
25: /* return the value 0x02 (used in Transbeauce 2 demo loader). */
1.1.1.13 root 26: /* 2008/07/06 [NP] Add support for executing 8 bit code sent to the 6301 processor. */
27: /* Instead of implementing a full 6301 emulator, we compute a checksum for each */
28: /* program sent to the 6301 RAM. If the checksum is recognized, we call some */
29: /* functions to emulate the behaviour of the 6301 in that case. */
30: /* When the 6301 is in 'Execute' mode (command 0x22), we must stop the normal */
31: /* reporting of key/mouse/joystick and use our custom handlers for each read or */
32: /* write to $fffc02. */
33: /* After a reset command, returns $F1 after $F0 (needed by Dragonnels Demo). */
34: /* This fixes the Transbeauce 2 demo menu, the Dragonnels demo menu and the */
35: /* Froggies Over The Fence demo menu (yeah ! enjoy this master piece of demo !). */
1.1.1.17! root 36: /* 2011/05/11 [NP] Add proper support for emulating TX buffer empty/full in status register bit 1 */
! 37: /* when writing to $fffc02 (using an internal timer). */
! 38: /* 2011/07/14 [NP] Don't clear bytes in transit when ACIA_Reset is called ; if a byte is sent to */
! 39: /* the ikbd it should not be cancelled ? FIXME : this would need more tests on a */
! 40: /* real ST (fix Froggies Over The Fence's menu when selecting a demo). */
1.1.1.13 root 41:
1.1.1.6 root 42:
43: #include <time.h>
1.1 root 44:
45: #include "main.h"
46: #include "ikbd.h"
1.1.1.16 root 47: #include "cycInt.h"
1.1.1.10 root 48: #include "ioMem.h"
1.1 root 49: #include "joy.h"
50: #include "m68000.h"
51: #include "memorySnapShot.h"
52: #include "mfp.h"
1.1.1.17! root 53: #include "screen.h"
1.1 root 54: #include "video.h"
1.1.1.13 root 55: #include "utils.h"
1.1.1.10 root 56:
1.1 root 57:
58: #define DBL_CLICK_HISTORY 0x07 /* Number of frames since last click to see if need to send one or two clicks */
1.1.1.9 root 59: #define ACIA_CYCLES 7200 /* Cycles (Multiple of 4) between sent to ACIA from keyboard along serial line - 500Hz/64, (approx' 6920-7200cycles from test program) */
1.1 root 60:
1.1.1.13 root 61: #define IKBD_RESET_CYCLES 223500 /* Cycles after RESET before complete */
1.1 root 62:
63: #define ABS_X_ONRESET 0 /* Initial XY for absolute mouse position after RESET command */
64: #define ABS_Y_ONRESET 0
65: #define ABS_MAX_X_ONRESET 320 /* Initial absolute mouse limits after RESET command */
66: #define ABS_MAY_Y_ONRESET 200 /* These values are never actually used as user MUST call 'IKBD_Cmd_AbsMouseMode' before ever using them */
67:
1.1.1.10 root 68: #define ABS_PREVBUTTONS (0x02|0x8) /* Don't report any buttons up on first call to 'IKBD_Cmd_ReadAbsMousePos' */
1.1 root 69:
70:
71: /* Keyboard state */
72: KEYBOARD Keyboard;
73:
74: /* Keyboard processor */
75: KEYBOARD_PROCESSOR KeyboardProcessor; /* Keyboard processor details */
1.1.1.11 root 76:
77: /* Pattern of mouse button up/down in ST frames (run off a double-click message) */
1.1.1.17! root 78: static const Uint8 DoubleClickPattern[] =
1.1.1.12 root 79: {
80: BUTTON_MOUSE,BUTTON_MOUSE,BUTTON_MOUSE,BUTTON_MOUSE,
81: 0,0,0,0,BUTTON_MOUSE,BUTTON_MOUSE,BUTTON_MOUSE,BUTTON_MOUSE
82: };
1.1.1.6 root 83:
1.1.1.13 root 84: static bool bMouseDisabled, bJoystickDisabled;
85: static bool bDuringResetCriticalTime, bBothMouseAndJoy;
1.1.1.14 root 86: static bool bMouseEnabledDuringReset;
1.1 root 87:
88: /* ACIA */
1.1.1.10 root 89: static Uint8 ACIAControlRegister = 0;
90: static Uint8 ACIAStatusRegister = ACIA_STATUS_REGISTER__TX_BUFFER_EMPTY; /* Pass when read 0xfffc00 */
1.1.1.13 root 91: static Uint8 ACIAByte; /* When a byte has arrived at the ACIA (from the keyboard) it is stored here */
1.1.1.17! root 92: static Uint8 ACIATxDataRegister; /* When a byte must be sent by the ACIA (to the keyboard) it is stored here */
1.1.1.15 root 93: static bool bByteInTransitToACIA = false; /* Is a byte being sent to the ACIA from the keyboard? */
1.1.1.17! root 94: static bool bByteInTransitFromACIA = false; /* Is a byte being sent from the ACIA to the keyboard? */
1.1 root 95:
96: /*
97: 6850 ACIA (Asynchronous Communications Inferface Apdater)
98: Page 41, ST Internals. Also ST Update Magazine, February 1989 (I glad I kept that!)
99:
100: Pins:-
101: Vss
102: RX DATA Receive Data
103: RX CLK Receive Clock
104: TX CLK Transmitter Clock
105: RTS Request To Send
106: TX DATA Transmitter Data
107: IRQ Interrupt Request
108: CS 0,1,2 Chip Select
109: RS Register Select
110: Vcc Voltage
111: R/W Read/Write
112: E Enable
113: D0-D7 Data
114: DCD Data Carrier Detect
115: CTS Clear To Send
116:
117: Registers:-
118: 0xfffc00 Keyboard ACIA Control (write)/Status(read)
119: 0xfffc02 Keyboard ACIA Data
120: 0xfffc04 MIDI ACIA Control (write)/Status(read)
121: 0xfffc06 MIDI ACIA Data
122:
123: Control Register (0xfffc00 write):-
124: Bits 0,1 - These bits determine by which factor the transmitter and receiver
125: clock will be divided. These bits also are joined with a master reset
126: function. The 6850 has no separate reset line, so it must be
127: accomplished though software.
128: 0 0 RXCLK/TXCLK without division
129: 0 1 RXCLK/TXCLK by 16 (MIDI)
130: 1 0 RXCLK/TXCLK by 64 (Keyboard)
131: 1 1 Master RESET
132: Bits 2,3,4 - These so-called Word Select bits tell whether 7 or 8 data-bits are
133: involved; whether 1 or 2 stop-bits are transferred; and the type of parity
134: Bits 5,6 - These Transmitter Control bits set the RTS output pin, and allow or prevent
135: an interrupt through the ACIA when the send register is emptied. Also, BREAK signals
136: can be sent over the serial output by this line. A BREAK signal is nothing more than
137: a long seqence of null bits
138: 0 0 RTS low, transmitter IRQ disabled
139: 0 1 RTS low, transmitter IRQ enabled
140: 1 0 RTS high, transmitter IRQ disabled
141: 1 1 RTS low, transmitter IRQ disabled, BREAK sent
142: Bit 7 - The Receiver Interrupt Enable bit determines whether the receiver interrupt
143: will be on. An interrupt can be caused by the DCD line chaning from low to high, or
144: by the receiver data buffer filling. Besides that, an interrupt can occur from an
145: OVERRUN ( a received character isn't properly read from the processior).
146: 0 Interrupt disabled
147: 1 Interrupt enabled
148:
149: Status Register (0xfffc00 read):-
150: Bit 0 - When this bit is high, the RX data register is full. The byte must be read
151: before a new character is received (otherwise an OVERRUN happens)
152: Bit 1 - This bit reflects the status of the TX data buffer. An empty register
153: set the bit.
154: Bit 2 - A low-high change in pin DCD sets bit 2. If the receiver interrupt is allowable, the IRQ
155: is cancelled. The bit is cleared when the status register and the receiver register are
156: read. This also cancels the IRQ. Bit 2 register remains highis the signal on the DCD pin
157: is still high; Bit 2 register low if DCD becomes low.
158: Bit 3 - This line shows the status of CTS. This signal cannot be altered by a mater reset,
159: or by ACIA programming.
160: Bit 4 - Shows 'Frame Errors'. Frame errors are when no stop-bit is recognized in receiver
161: switching. It can be set with every new character.
162: Bit 5 - This bit display the previously mentioned OVERRUN condition. Bit 5 is reset when the
163: RX buffer is read.
164: Bit 6 - This bit recognizes whether the parity of a received character is correct. The bit is
165: set on an error.
166: Bit 7 - This signals the state of the IRQ pins; this bit make it possible to switch several
167: IRQ lines on one interrupt input. In cases where an interrupt is program-generated, bit 7
168: can tell which IC cut off the interrupt.
1.1.1.7 root 169:
1.1 root 170: ST ACIA:-
171: Note CTS,DCD and RTS are not connected! Phew!
172: The keyboard ACIA are address 0xfffc000 and 0xfffc02.
1.1.1.17! root 173: Default parameters are :- 8-bit word, 1 stopbit, no parity, 7812.5 baud; 500KHz/64 (keyboard clock div)
1.1 root 174: Default MIDI parameters are are above but :- 31250 baud; 500KHz/16 (MIDI clock div)
175: */
176:
1.1.1.2 root 177: /* List of possible keyboard commands, others are seen as NOPs by keyboard processor */
1.1.1.13 root 178: static void IKBD_Cmd_Reset(void);
179: static void IKBD_Cmd_MouseAction(void);
180: static void IKBD_Cmd_RelMouseMode(void);
181: static void IKBD_Cmd_AbsMouseMode(void);
182: static void IKBD_Cmd_MouseCursorKeycodes(void);
183: static void IKBD_Cmd_SetMouseThreshold(void);
184: static void IKBD_Cmd_SetMouseScale(void);
185: static void IKBD_Cmd_ReadAbsMousePos(void);
186: static void IKBD_Cmd_SetInternalMousePos(void);
187: static void IKBD_Cmd_SetYAxisDown(void);
188: static void IKBD_Cmd_SetYAxisUp(void);
189: static void IKBD_Cmd_StartKeyboardTransfer(void);
190: static void IKBD_Cmd_TurnMouseOff(void);
191: static void IKBD_Cmd_StopKeyboardTransfer(void);
192: static void IKBD_Cmd_ReturnJoystickAuto(void);
193: static void IKBD_Cmd_StopJoystick(void);
194: static void IKBD_Cmd_ReturnJoystick(void);
195: static void IKBD_Cmd_SetJoystickDuration(void);
196: static void IKBD_Cmd_SetJoystickFireDuration(void);
197: static void IKBD_Cmd_SetCursorForJoystick(void);
198: static void IKBD_Cmd_DisableJoysticks(void);
199: static void IKBD_Cmd_SetClock(void);
200: static void IKBD_Cmd_ReadClock(void);
201: static void IKBD_Cmd_LoadMemory(void);
202: static void IKBD_Cmd_ReadMemory(void);
203: static void IKBD_Cmd_Execute(void);
204: static void IKBD_Cmd_ReportMouseAction(void);
205: static void IKBD_Cmd_ReportMouseMode(void);
206: static void IKBD_Cmd_ReportMouseThreshold(void);
207: static void IKBD_Cmd_ReportMouseScale(void);
208: static void IKBD_Cmd_ReportMouseVertical(void);
209: static void IKBD_Cmd_ReportMouseAvailability(void);
210: static void IKBD_Cmd_ReportJoystickMode(void);
211: static void IKBD_Cmd_ReportJoystickAvailability(void);
212:
1.1.1.17! root 213: /* Keyboard Command */
! 214: static const struct {
! 215: Uint8 Command;
! 216: Uint8 NumParameters;
! 217: void (*pCallFunction)(void);
! 218: } KeyboardCommands[] =
1.1.1.12 root 219: {
220: /* Known messages, counts include command byte */
221: { 0x80,2, IKBD_Cmd_Reset },
222: { 0x07,2, IKBD_Cmd_MouseAction },
223: { 0x08,1, IKBD_Cmd_RelMouseMode },
224: { 0x09,5, IKBD_Cmd_AbsMouseMode },
225: { 0x0A,3, IKBD_Cmd_MouseCursorKeycodes },
226: { 0x0B,3, IKBD_Cmd_SetMouseThreshold },
227: { 0x0C,3, IKBD_Cmd_SetMouseScale },
228: { 0x0D,1, IKBD_Cmd_ReadAbsMousePos },
229: { 0x0E,6, IKBD_Cmd_SetInternalMousePos },
230: { 0x0F,1, IKBD_Cmd_SetYAxisDown },
231: { 0x10,1, IKBD_Cmd_SetYAxisUp },
232: { 0x11,1, IKBD_Cmd_StartKeyboardTransfer },
233: { 0x12,1, IKBD_Cmd_TurnMouseOff },
234: { 0x13,1, IKBD_Cmd_StopKeyboardTransfer },
235: { 0x14,1, IKBD_Cmd_ReturnJoystickAuto },
236: { 0x15,1, IKBD_Cmd_StopJoystick },
237: { 0x16,1, IKBD_Cmd_ReturnJoystick },
238: { 0x17,2, IKBD_Cmd_SetJoystickDuration },
239: { 0x18,1, IKBD_Cmd_SetJoystickFireDuration },
240: { 0x19,7, IKBD_Cmd_SetCursorForJoystick },
241: { 0x1A,1, IKBD_Cmd_DisableJoysticks },
242: { 0x1B,7, IKBD_Cmd_SetClock },
243: { 0x1C,1, IKBD_Cmd_ReadClock },
244: { 0x20,4, IKBD_Cmd_LoadMemory },
245: { 0x21,3, IKBD_Cmd_ReadMemory },
246: { 0x22,3, IKBD_Cmd_Execute },
247:
1.1.1.13 root 248: /* Report message (top bit set) */
249: { 0x87,1, IKBD_Cmd_ReportMouseAction },
250: { 0x88,1, IKBD_Cmd_ReportMouseMode },
251: { 0x89,1, IKBD_Cmd_ReportMouseMode },
252: { 0x8A,1, IKBD_Cmd_ReportMouseMode },
253: { 0x8B,1, IKBD_Cmd_ReportMouseThreshold },
254: { 0x8C,1, IKBD_Cmd_ReportMouseScale },
255: { 0x8F,1, IKBD_Cmd_ReportMouseVertical },
256: { 0x90,1, IKBD_Cmd_ReportMouseVertical },
257: { 0x92,1, IKBD_Cmd_ReportMouseAvailability },
258: { 0x94,1, IKBD_Cmd_ReportJoystickMode },
259: { 0x95,1, IKBD_Cmd_ReportJoystickMode },
260: { 0x99,1, IKBD_Cmd_ReportJoystickMode },
261: { 0x9A,1, IKBD_Cmd_ReportJoystickAvailability },
1.1 root 262:
1.1.1.12 root 263: { 0xFF,0, NULL } /* Term */
1.1 root 264: };
265:
1.1.1.2 root 266:
1.1.1.13 root 267: static void IKBD_SendByteToKeyboardProcessor(Uint16 bl);
268: static Uint16 IKBD_GetByteFromACIA(void);
269: static void IKBD_SendByteToACIA(int nAciaCycles);
270: static void IKBD_AddKeyToKeyboardBuffer(Uint8 Data);
271: static void IKBD_AddKeyToKeyboardBufferWithDelay(Uint8 Data, int nAciaCycles);
272: static void IKBD_AddKeyToKeyboardBuffer_Real(Uint8 Data, int nAciaCycles);
273:
274:
275: /* Belows part is used to emulate the behaviour of custom 6301 programs */
276: /* sent to the ikbd RAM. */
277:
278: static void IKBD_LoadMemoryByte ( Uint8 aciabyte );
279:
280: static void IKBD_CustomCodeHandler_CommonBoot ( Uint8 aciabyte );
281:
282: static void IKBD_CustomCodeHandler_FroggiesMenu_Read ( void );
283: static void IKBD_CustomCodeHandler_FroggiesMenu_Write ( Uint8 aciabyte );
284: static void IKBD_CustomCodeHandler_Transbeauce2Menu_Read ( void );
285: static void IKBD_CustomCodeHandler_Transbeauce2Menu_Write ( Uint8 aciabyte );
286: static void IKBD_CustomCodeHandler_DragonnelsMenu_Read ( void );
287: static void IKBD_CustomCodeHandler_DragonnelsMenu_Write ( Uint8 aciabyte );
1.1.1.17! root 288: static void IKBD_CustomCodeHandler_ChaosAD_Read ( void );
! 289: static void IKBD_CustomCodeHandler_ChaosAD_Write ( Uint8 aciabyte );
1.1.1.13 root 290:
291:
1.1.1.17! root 292: static int MemoryLoadNbBytesTotal = 0; /* total number of bytes to send with the command 0x20 */
! 293: static int MemoryLoadNbBytesLeft = 0; /* number of bytes that remain to be sent */
! 294: static Uint32 MemoryLoadCrc = 0xffffffff; /* CRC of the bytes sent to the ikbd */
! 295: static int MemoryExeNbBytes = 0; /* current number of bytes sent to the ikbd when IKBD_ExeMode is true */
1.1.1.13 root 296:
1.1.1.17! root 297: static void (*pIKBD_CustomCodeHandler_Read) ( void );
! 298: static void (*pIKBD_CustomCodeHandler_Write) ( Uint8 );
! 299: static bool IKBD_ExeMode = false;
! 300:
! 301: static Uint8 ScanCodeState[ 128 ]; /* state of each key : 0=released 1=pressed */
1.1.1.13 root 302:
303: /* This array contains all known custom 6301 programs, with their CRC */
1.1.1.17! root 304: static const struct
1.1.1.13 root 305: {
306: Uint32 LoadMemCrc; /* CRC of the bytes sent using the command 0x20 */
307: void (*ExeBootHandler) ( Uint8 ); /* function handling write to $fffc02 during the 'boot' mode */
308: int MainProgNbBytes; /* number of bytes of the main 6301 program */
309: Uint32 MainProgCrc; /* CRC of the main 6301 program */
310: void (*ExeMainHandler_Read) ( void );/* function handling read to $fffc02 in the main 6301 program */
311: void (*ExeMainHandler_Write) ( Uint8 ); /* funciton handling write to $fffc02 in the main 6301 program */
312: const char *Name;
313: }
314: CustomCodeDefinitions[] =
315: {
316: {
317: 0x2efb11b1 ,
318: IKBD_CustomCodeHandler_CommonBoot ,
319: 167,
320: 0xe7110b6d ,
321: IKBD_CustomCodeHandler_FroggiesMenu_Read ,
322: IKBD_CustomCodeHandler_FroggiesMenu_Write ,
323: "Froggies Over The Fence Main Menu"
324: } ,
325: {
326: 0xadb6b503 ,
327: IKBD_CustomCodeHandler_CommonBoot ,
328: 165,
329: 0x5617c33c ,
330: IKBD_CustomCodeHandler_Transbeauce2Menu_Read ,
331: IKBD_CustomCodeHandler_Transbeauce2Menu_Write ,
332: "Transbeauce 2 Main Menu"
333: } ,
334: {
335: 0x33c23cdf ,
336: IKBD_CustomCodeHandler_CommonBoot ,
337: 83 ,
338: 0xdf3e5a88 ,
339: IKBD_CustomCodeHandler_DragonnelsMenu_Read ,
340: IKBD_CustomCodeHandler_DragonnelsMenu_Write ,
341: "Dragonnels Main Menu"
1.1.1.17! root 342: },
! 343: {
! 344: 0x9ad7fcdf ,
! 345: IKBD_CustomCodeHandler_CommonBoot ,
! 346: 109 ,
! 347: 0xa11d8be5 ,
! 348: IKBD_CustomCodeHandler_ChaosAD_Read ,
! 349: IKBD_CustomCodeHandler_ChaosAD_Write ,
! 350: "Chaos A.D."
1.1.1.13 root 351: }
352: };
353:
354:
355:
1.1.1.2 root 356: /*-----------------------------------------------------------------------*/
1.1.1.12 root 357: /**
358: * Reset the ACIA
359: */
360: void ACIA_Reset(void)
361: {
1.1.1.17! root 362: LOG_TRACE(TRACE_IKBD_EXEC, "ikbd acia reset\n");
! 363:
! 364: /* [NP] 2011/07/14 FIXME : Acia reset should not clear bytes in transit ? */
! 365: /* Else, "Froggies Over The Fence" doesn't exit the custom ikbd mode */
! 366: #if 0
1.1.1.15 root 367: bByteInTransitToACIA = false;
1.1.1.17! root 368: bByteInTransitFromACIA = false;
! 369: #endif
1.1.1.12 root 370: ACIAControlRegister = 0;
371: ACIAStatusRegister = ACIA_STATUS_REGISTER__TX_BUFFER_EMPTY;
372: }
373:
374:
375: /*-----------------------------------------------------------------------*/
376: /**
377: * Reset the IKBD processor
378: */
1.1.1.13 root 379:
380: /* Cancel execution of any program that was uploaded to the 6301's RAM */
381: /* This function is also called when performing a 68000 'reset' ; in that */
382: /* case we need to return $F0 and $F1. */
383:
384: void IKBD_Reset_ExeMode ( void )
1.1 root 385: {
1.1.1.15 root 386: LOG_TRACE(TRACE_IKBD_EXEC, "ikbd custom exe off\n");
1.1.1.13 root 387:
388: /* Reset any custom code run with the Execute command 0x22 */
389: MemoryLoadNbBytesLeft = 0;
390: pIKBD_CustomCodeHandler_Read = NULL;
391: pIKBD_CustomCodeHandler_Write = NULL;
1.1.1.15 root 392: IKBD_ExeMode = false;
1.1.1.13 root 393:
394: Keyboard.BufferHead = Keyboard.BufferTail = 0; /* flush all queued bytes that would be read in $fffc02 */
1.1.1.15 root 395: bByteInTransitToACIA = false;
1.1.1.17! root 396: bByteInTransitFromACIA = false;
1.1.1.15 root 397: // IKBD_AddKeyToKeyboardBuffer(0xF0); /* Assume OK, return correct code */
1.1.1.13 root 398: IKBD_AddKeyToKeyboardBuffer(0xF1); /* [NP] Dragonnels demo needs this */
399: }
400:
401:
402: void IKBD_Reset(bool bCold)
403: {
404: int i;
405:
406:
1.1.1.12 root 407: /* Reset internal keyboard processor details */
408: if (bCold)
409: {
1.1.1.15 root 410: KeyboardProcessor.bReset = false;
1.1.1.16 root 411: if (CycInt_InterruptActive(INTERRUPT_IKBD_RESETTIMER))
412: CycInt_RemovePendingInterrupt(INTERRUPT_IKBD_RESETTIMER);
1.1.1.12 root 413: }
414:
415: KeyboardProcessor.MouseMode = AUTOMODE_MOUSEREL;
416: KeyboardProcessor.JoystickMode = AUTOMODE_JOYSTICK;
417:
418: KeyboardProcessor.Abs.X = ABS_X_ONRESET;
419: KeyboardProcessor.Abs.Y = ABS_Y_ONRESET;
420: KeyboardProcessor.Abs.MaxX = ABS_MAX_X_ONRESET;
421: KeyboardProcessor.Abs.MaxY = ABS_MAY_Y_ONRESET;
422: KeyboardProcessor.Abs.PrevReadAbsMouseButtons = ABS_PREVBUTTONS;
423:
424: KeyboardProcessor.Mouse.DeltaX = KeyboardProcessor.Mouse.DeltaY = 0;
425: KeyboardProcessor.Mouse.XScale = KeyboardProcessor.Mouse.YScale = 0;
426: KeyboardProcessor.Mouse.XThreshold = KeyboardProcessor.Mouse.YThreshold = 1;
427: KeyboardProcessor.Mouse.YAxis = 1; /* Y origin at top */
428: KeyboardProcessor.Mouse.Action = 0;
429:
430: KeyboardProcessor.Joy.PrevJoyData[0] = KeyboardProcessor.Joy.PrevJoyData[1] = 0;
431:
1.1.1.13 root 432: for ( i=0 ; i<128 ; i++ )
433: ScanCodeState[ i ] = 0; /* key is released */
434:
1.1.1.12 root 435: /* Reset our ACIA status */
436: ACIA_Reset();
437: /* And our keyboard states and clear key state table */
438: Keyboard.BufferHead = Keyboard.BufferTail = 0;
439: Keyboard.nBytesInInputBuffer = 0;
440: memset(Keyboard.KeyStates, 0, sizeof(Keyboard.KeyStates));
441: Keyboard.bLButtonDown = BUTTON_NULL;
442: Keyboard.bRButtonDown = BUTTON_NULL;
443: Keyboard.bOldLButtonDown = Keyboard.bOldRButtonDown = BUTTON_NULL;
444: Keyboard.LButtonDblClk = Keyboard.RButtonDblClk = 0;
445: Keyboard.LButtonHistory = Keyboard.RButtonHistory = 0;
446:
1.1.1.13 root 447: /* Store bool for when disable mouse or joystick */
1.1.1.15 root 448: bMouseDisabled = bJoystickDisabled = false;
1.1.1.12 root 449: /* do emulate hardware 'quirk' where if disable both with 'x' time
450: * of a RESET command they are ignored! */
1.1.1.15 root 451: bDuringResetCriticalTime = bBothMouseAndJoy = false;
452: bMouseEnabledDuringReset = false;
1.1.1.13 root 453:
454: /* Remove any custom handlers used to emulate code loaded to the 6301's RAM */
455: IKBD_Reset_ExeMode ();
1.1.1.14 root 456:
457: /* Add auto-update function to the queue */
1.1.1.16 root 458: CycInt_AddRelativeInterrupt(150000, INT_CPU_CYCLE, INTERRUPT_IKBD_AUTOSEND);
1.1 root 459: }
460:
1.1.1.2 root 461:
462: /*-----------------------------------------------------------------------*/
1.1.1.12 root 463: /**
464: * Save/Restore snapshot of local variables
465: * ('MemorySnapShot_Store' handles type)
466: */
1.1.1.13 root 467: void IKBD_MemorySnapShot_Capture(bool bSave)
1.1 root 468: {
1.1.1.13 root 469: unsigned int i;
470:
1.1.1.12 root 471: /* Save/Restore details */
472: MemorySnapShot_Store(&Keyboard, sizeof(Keyboard));
473: MemorySnapShot_Store(&KeyboardProcessor, sizeof(KeyboardProcessor));
474: MemorySnapShot_Store(&ACIAControlRegister, sizeof(ACIAControlRegister));
475: MemorySnapShot_Store(&ACIAStatusRegister, sizeof(ACIAStatusRegister));
476: MemorySnapShot_Store(&ACIAByte, sizeof(ACIAByte));
1.1.1.17! root 477: MemorySnapShot_Store(&ACIATxDataRegister, sizeof(ACIATxDataRegister));
1.1.1.12 root 478: MemorySnapShot_Store(&bByteInTransitToACIA, sizeof(bByteInTransitToACIA));
1.1.1.17! root 479: MemorySnapShot_Store(&bByteInTransitFromACIA, sizeof(bByteInTransitFromACIA));
1.1.1.12 root 480: MemorySnapShot_Store(&bMouseDisabled, sizeof(bMouseDisabled));
481: MemorySnapShot_Store(&bJoystickDisabled, sizeof(bJoystickDisabled));
482: MemorySnapShot_Store(&bDuringResetCriticalTime, sizeof(bDuringResetCriticalTime));
483: MemorySnapShot_Store(&bBothMouseAndJoy, sizeof(bBothMouseAndJoy));
1.1.1.14 root 484: MemorySnapShot_Store(&bMouseEnabledDuringReset, sizeof(bMouseEnabledDuringReset));
1.1.1.13 root 485:
486: /* restore custom 6301 program if needed */
487: MemorySnapShot_Store(&IKBD_ExeMode, sizeof(IKBD_ExeMode));
488: MemorySnapShot_Store(&MemoryLoadCrc, sizeof(MemoryLoadCrc));
1.1.1.15 root 489: if ((bSave == false) && (IKBD_ExeMode == true)) /* restoring a snapshot with active 6301 emulation */
1.1.1.13 root 490: {
491: for ( i = 0 ; i < sizeof ( CustomCodeDefinitions ) / sizeof ( CustomCodeDefinitions[0] ); i++ )
492: if ( CustomCodeDefinitions[ i ].MainProgCrc == MemoryLoadCrc )
493: {
494: pIKBD_CustomCodeHandler_Read = CustomCodeDefinitions[ i ].ExeMainHandler_Read;
495: pIKBD_CustomCodeHandler_Write = CustomCodeDefinitions[ i ].ExeMainHandler_Write;
496: Keyboard.BufferHead = Keyboard.BufferTail = 0; /* flush all queued bytes that would be read in $fffc02 */
497: // (*pIKBD_CustomCodeHandler_Read) (); /* initialize ACIAByte */
498: ACIAByte = 0; /* initialize ACIAByte, don't call IKBD_AddKeyToKeyboardBuffer_Real now */
499: break;
500: }
501:
502: if ( i >= sizeof ( CustomCodeDefinitions ) / sizeof ( CustomCodeDefinitions[0] ) ) /* not found (should not happen) */
1.1.1.15 root 503: IKBD_ExeMode = false; /* turn off exe mode */
1.1.1.13 root 504: }
1.1 root 505: }
506:
1.1.1.2 root 507:
508: /*-----------------------------------------------------------------------*/
1.1.1.12 root 509: /**
510: * Calculate out 'delta' that mouse has moved by each frame, and add this to our internal keyboard position
511: */
1.1.1.8 root 512: static void IKBD_UpdateInternalMousePosition(void)
1.1 root 513: {
514:
1.1.1.12 root 515: KeyboardProcessor.Mouse.DeltaX = KeyboardProcessor.Mouse.dx;
516: KeyboardProcessor.Mouse.DeltaY = KeyboardProcessor.Mouse.dy;
517: KeyboardProcessor.Mouse.dx = 0;
518: KeyboardProcessor.Mouse.dy = 0;
519:
520: /* Update internal mouse coords - Y axis moves according to YAxis setting(up/down) */
521: /* Limit to Max X/Y(inclusive) */
522: KeyboardProcessor.Abs.X += KeyboardProcessor.Mouse.DeltaX;
523: if (KeyboardProcessor.Abs.X < 0)
524: KeyboardProcessor.Abs.X = 0;
525: if (KeyboardProcessor.Abs.X > KeyboardProcessor.Abs.MaxX)
526: KeyboardProcessor.Abs.X = KeyboardProcessor.Abs.MaxX;
527:
528: KeyboardProcessor.Abs.Y += KeyboardProcessor.Mouse.DeltaY*KeyboardProcessor.Mouse.YAxis; /* Needed '+' for Falcon... */
529: if (KeyboardProcessor.Abs.Y < 0)
530: KeyboardProcessor.Abs.Y = 0;
531: if (KeyboardProcessor.Abs.Y > KeyboardProcessor.Abs.MaxY)
532: KeyboardProcessor.Abs.Y = KeyboardProcessor.Abs.MaxY;
1.1.1.4 root 533:
1.1 root 534: }
535:
1.1.1.2 root 536:
537: /*-----------------------------------------------------------------------*/
1.1.1.12 root 538: /**
539: * When running in maximum speed the emulation will not see 'double-clicks'
540: * of the mouse as it is running so fast. In this case, we check for a
541: * double-click and pass the 'up'/'down' messages in emulation time to
542: * simulate the double-click effect!
543: */
1.1.1.8 root 544: static void IKBD_CheckForDoubleClicks(void)
1.1 root 545: {
1.1.1.12 root 546: /*
547: Things get a little complicated when running max speed as a normal
548: double-click is a load of 1's, followed by 0's, 1's and 0's - But the
549: ST does not see this as a double click as the space in 'ST' time
550: between changes is so great.
551: Now, when we see a real double-click in max speed we actually send
552: the down/up/down/up in ST time. To get this correct (and not send
553: three clicks) we look in a history buffer and start at an index which
554: gives the correct number of clicks! Phew!
555: */
556:
557: /* Handle double clicks!!! */
558: if (Keyboard.LButtonDblClk)
559: {
560: if (Keyboard.LButtonDblClk == 1) /* First pressed! */
561: {
562: if ((Keyboard.LButtonHistory&0x3f) == 0) /* If not pressed button in long time do full dbl-click pattern */
563: Keyboard.LButtonDblClk = 1;
564: else
565: {
566: Keyboard.LButtonDblClk = 4; /* Otherwise, check where to begin to give 1111000011110000 pattern */
567: if ((Keyboard.LButtonHistory&0x7) == 0)
568: Keyboard.LButtonDblClk = 8;
569: else if ((Keyboard.LButtonHistory&0x3) == 0)
570: Keyboard.LButtonDblClk = 7;
571: else if ((Keyboard.LButtonHistory&0x1) == 0)
572: Keyboard.LButtonDblClk = 6;
573: }
574: }
575:
576: Keyboard.bLButtonDown = DoubleClickPattern[Keyboard.LButtonDblClk];
577: Keyboard.LButtonDblClk++;
578: if (Keyboard.LButtonDblClk >= 13) /* Check for end of sequence */
579: {
580: Keyboard.LButtonDblClk = 0;
1.1.1.15 root 581: Keyboard.bLButtonDown = false;
1.1.1.12 root 582: }
583: }
584: if (Keyboard.RButtonDblClk)
585: {
586: if (Keyboard.RButtonDblClk == 1) /* First pressed! */
587: {
588: if ((Keyboard.RButtonHistory&0x3f) == 0) /* If not pressed button in long time do full dbl-click pattern */
589: Keyboard.RButtonDblClk = 1;
590: else
591: {
592: Keyboard.RButtonDblClk = 4; /* Otherwise, check where to begin to give 1111000011110000 pattern */
593: if ((Keyboard.RButtonHistory&0x7) == 0)
594: Keyboard.RButtonDblClk = 8;
595: else if ((Keyboard.RButtonHistory&0x3) == 0)
596: Keyboard.RButtonDblClk = 7;
597: else if ((Keyboard.RButtonHistory&0x1) == 0)
598: Keyboard.RButtonDblClk = 6;
599: }
600: }
601:
602: Keyboard.bRButtonDown = DoubleClickPattern[Keyboard.RButtonDblClk];
603: Keyboard.RButtonDblClk++;
604: if (Keyboard.RButtonDblClk >= 13) /* Check for end of sequence */
605: {
606: Keyboard.RButtonDblClk = 0;
1.1.1.15 root 607: Keyboard.bRButtonDown = false;
1.1.1.12 root 608: }
609: }
610:
611: /* Store presses into history */
612: Keyboard.LButtonHistory = (Keyboard.LButtonHistory<<1);
613: if (Keyboard.bLButtonDown)
614: Keyboard.LButtonHistory |= 0x1;
615: Keyboard.RButtonHistory = (Keyboard.RButtonHistory<<1);
616: if (Keyboard.bRButtonDown)
617: Keyboard.RButtonHistory |= 0x1;
618: }
619:
620:
621: /*-----------------------------------------------------------------------*/
622: /**
1.1.1.13 root 623: * Convert button to bool value
1.1.1.12 root 624: */
1.1.1.13 root 625: static bool IKBD_ButtonBool(int Button)
1.1 root 626: {
1.1.1.12 root 627: /* Button pressed? */
628: if (Button)
1.1.1.15 root 629: return true;
630: return false;
1.1 root 631: }
632:
1.1.1.2 root 633:
634: /*-----------------------------------------------------------------------*/
1.1.1.12 root 635: /**
1.1.1.15 root 636: * Return true if buttons match, use this as buttons are a mask and not boolean
1.1.1.12 root 637: */
1.1.1.13 root 638: static bool IKBD_ButtonsEqual(int Button1,int Button2)
1.1 root 639: {
1.1.1.13 root 640: /* Return bool compare */
1.1.1.12 root 641: return (IKBD_ButtonBool(Button1) == IKBD_ButtonBool(Button2));
1.1 root 642: }
643:
1.1.1.2 root 644:
645: /*-----------------------------------------------------------------------*/
1.1.1.12 root 646: /**
1.1.1.13 root 647: * According to if the mouse is enabled or not the joystick 1 fire
648: * button/right mouse button will become the same button. That means
649: * pressing one will also press the other and vice-versa.
650: * If both mouse and joystick are enabled, report it as a mouse button
651: * (needed by the game Big Run for example).
1.1.1.12 root 652: */
1.1.1.8 root 653: static void IKBD_DuplicateMouseFireButtons(void)
1.1 root 654: {
1.1.1.12 root 655: /* If mouse is off then joystick fire button goes to joystick */
1.1.1.14 root 656: if (KeyboardProcessor.MouseMode == AUTOMODE_OFF)
1.1.1.12 root 657: {
658: /* If pressed right mouse button, should go to joystick 1 */
659: if (Keyboard.bRButtonDown&BUTTON_MOUSE)
660: KeyboardProcessor.Joy.JoyData[1] |= 0x80;
661: /* And left mouse button, should go to joystick 0 */
662: if (Keyboard.bLButtonDown&BUTTON_MOUSE)
663: KeyboardProcessor.Joy.JoyData[0] |= 0x80;
664: }
1.1.1.13 root 665: /* If mouse is on, joystick 1 fire button goes to the mouse instead */
1.1.1.12 root 666: else
667: {
668: /* Is fire button pressed? */
669: if (KeyboardProcessor.Joy.JoyData[1]&0x80)
670: {
671: KeyboardProcessor.Joy.JoyData[1] &= 0x7f; /* Clear fire button bit */
672: Keyboard.bRButtonDown |= BUTTON_JOYSTICK; /* Mimick on mouse right button */
673: }
674: else
675: Keyboard.bRButtonDown &= ~BUTTON_JOYSTICK;
676: }
1.1 root 677: }
678:
1.1.1.2 root 679:
680: /*-----------------------------------------------------------------------*/
1.1.1.12 root 681: /**
682: * Send 'relative' mouse position
683: */
1.1.1.8 root 684: static void IKBD_SendRelMousePacket(void)
1.1 root 685: {
1.1.1.12 root 686: int ByteRelX,ByteRelY;
687: Uint8 Header;
1.1 root 688:
1.1.1.12 root 689: if ( (KeyboardProcessor.Mouse.DeltaX!=0) || (KeyboardProcessor.Mouse.DeltaY!=0)
690: || (!IKBD_ButtonsEqual(Keyboard.bOldLButtonDown,Keyboard.bLButtonDown)) || (!IKBD_ButtonsEqual(Keyboard.bOldRButtonDown,Keyboard.bRButtonDown)) )
691: {
692: /* Send packet to keyboard process */
1.1.1.15 root 693: while (true)
1.1.1.12 root 694: {
695: ByteRelX = KeyboardProcessor.Mouse.DeltaX;
696: if (ByteRelX>127) ByteRelX = 127;
697: if (ByteRelX<-128) ByteRelX = -128;
698: ByteRelY = KeyboardProcessor.Mouse.DeltaY;
699: if (ByteRelY>127) ByteRelY = 127;
700: if (ByteRelY<-128) ByteRelY = -128;
701:
702: Header = 0xf8;
703: if (Keyboard.bLButtonDown)
704: Header |= 0x02;
705: if (Keyboard.bRButtonDown)
706: Header |= 0x01;
707: IKBD_AddKeyToKeyboardBuffer(Header);
708: IKBD_AddKeyToKeyboardBuffer(ByteRelX);
709: IKBD_AddKeyToKeyboardBuffer(ByteRelY*KeyboardProcessor.Mouse.YAxis);
710:
711: KeyboardProcessor.Mouse.DeltaX -= ByteRelX;
712: KeyboardProcessor.Mouse.DeltaY -= ByteRelY;
713:
714: if ( (KeyboardProcessor.Mouse.DeltaX==0) && (KeyboardProcessor.Mouse.DeltaY==0) )
715: break;
716:
717: /* Store buttons for next time around */
718: Keyboard.bOldLButtonDown = Keyboard.bLButtonDown;
719: Keyboard.bOldRButtonDown = Keyboard.bRButtonDown;
720: }
721: }
1.1 root 722: }
723:
1.1.1.2 root 724:
1.1.1.13 root 725: /**
726: * Get joystick data
727: */
728: static void IKBD_GetJoystickData(void)
729: {
730: /* Joystick 1 */
731: KeyboardProcessor.Joy.JoyData[1] = Joy_GetStickData(1);
732:
733: /* If mouse is on, joystick 0 is not connected */
734: if (KeyboardProcessor.MouseMode==AUTOMODE_OFF
735: || (bBothMouseAndJoy && KeyboardProcessor.MouseMode==AUTOMODE_MOUSEREL))
736: KeyboardProcessor.Joy.JoyData[0] = Joy_GetStickData(0);
737: else
738: KeyboardProcessor.Joy.JoyData[0] = 0x00;
739: }
740:
741:
1.1.1.2 root 742: /*-----------------------------------------------------------------------*/
1.1.1.12 root 743: /**
744: * Send 'joysticks' bit masks
745: */
1.1.1.8 root 746: static void IKBD_SelAutoJoysticks(void)
1.1 root 747: {
1.1.1.12 root 748: Uint8 JoyData;
1.1 root 749:
1.1.1.12 root 750: /* Did joystick 0/mouse change? */
751: JoyData = KeyboardProcessor.Joy.JoyData[0];
752: if (JoyData!=KeyboardProcessor.Joy.PrevJoyData[0])
753: {
754: IKBD_AddKeyToKeyboardBuffer(0xFE); /* Joystick 0/Mouse */
755: IKBD_AddKeyToKeyboardBuffer(JoyData);
756:
757: KeyboardProcessor.Joy.PrevJoyData[0] = JoyData;
758: }
759:
760: /* Did joystick 1(default) change? */
761: JoyData = KeyboardProcessor.Joy.JoyData[1];
762: if (JoyData!=KeyboardProcessor.Joy.PrevJoyData[1])
763: {
764: IKBD_AddKeyToKeyboardBuffer(0xFF); /* Joystick 1 */
765: IKBD_AddKeyToKeyboardBuffer(JoyData);
766:
767: KeyboardProcessor.Joy.PrevJoyData[1] = JoyData;
768: }
1.1 root 769: }
770:
771: /*-----------------------------------------------------------------------*/
1.1.1.12 root 772: /**
773: * Send packets which are generated from the mouse action settings
774: * If relative mode is on, still generate these packets
775: */
1.1.1.8 root 776: static void IKBD_SendOnMouseAction(void)
1.1 root 777: {
1.1.1.15 root 778: bool bReportPosition = false;
1.1 root 779:
1.1.1.12 root 780: /* Report buttons as keys? Do in relative/absolute mode */
781: if (KeyboardProcessor.Mouse.Action&0x4)
782: {
783: /* Left button? */
784: if ( (IKBD_ButtonBool(Keyboard.bLButtonDown) && (!IKBD_ButtonBool(Keyboard.bOldLButtonDown))) )
785: IKBD_AddKeyToKeyboardBuffer(0x74); /* Left */
786: else if ( (IKBD_ButtonBool(Keyboard.bOldLButtonDown) && (!IKBD_ButtonBool(Keyboard.bLButtonDown))) )
787: IKBD_AddKeyToKeyboardBuffer(0x74|0x80);
788: /* Right button? */
789: if ( (IKBD_ButtonBool(Keyboard.bRButtonDown) && (!IKBD_ButtonBool(Keyboard.bOldRButtonDown))) )
790: IKBD_AddKeyToKeyboardBuffer(0x75); /* Right */
791: else if ( (IKBD_ButtonBool(Keyboard.bOldRButtonDown) && (!IKBD_ButtonBool(Keyboard.bRButtonDown))) )
792: IKBD_AddKeyToKeyboardBuffer(0x75|0x80);
793:
794: /* Ignore bottom two bits, so return now */
795: return;
796: }
797:
798: /* Check MouseAction - report position on press/release */
799: /* MUST do this before update relative positions as buttons get reset */
800: if (KeyboardProcessor.Mouse.Action&0x3)
801: {
802: /* Check for 'press'? */
803: if (KeyboardProcessor.Mouse.Action&0x1)
804: {
805: /* Did 'press' mouse buttons? */
806: if ( (IKBD_ButtonBool(Keyboard.bLButtonDown) && (!IKBD_ButtonBool(Keyboard.bOldLButtonDown))) )
807: {
1.1.1.15 root 808: bReportPosition = true;
1.1.1.12 root 809: KeyboardProcessor.Abs.PrevReadAbsMouseButtons &= ~0x04;
810: KeyboardProcessor.Abs.PrevReadAbsMouseButtons |= 0x02;
811: }
812: if ( (IKBD_ButtonBool(Keyboard.bRButtonDown) && (!IKBD_ButtonBool(Keyboard.bOldRButtonDown))) )
813: {
1.1.1.15 root 814: bReportPosition = true;
1.1.1.12 root 815: KeyboardProcessor.Abs.PrevReadAbsMouseButtons &= ~0x01;
816: KeyboardProcessor.Abs.PrevReadAbsMouseButtons |= 0x08;
817: }
818: }
819: /* Check for 'release'? */
820: if (KeyboardProcessor.Mouse.Action&0x2)
821: {
822: /* Did 'release' mouse buttons? */
823: if ( (IKBD_ButtonBool(Keyboard.bOldLButtonDown) && (!IKBD_ButtonBool(Keyboard.bLButtonDown))) )
824: {
1.1.1.15 root 825: bReportPosition = true;
1.1.1.12 root 826: KeyboardProcessor.Abs.PrevReadAbsMouseButtons &= ~0x08;
827: KeyboardProcessor.Abs.PrevReadAbsMouseButtons |= 0x01;
828: }
829: if ( (IKBD_ButtonBool(Keyboard.bOldRButtonDown) && (!IKBD_ButtonBool(Keyboard.bRButtonDown))) )
830: {
1.1.1.15 root 831: bReportPosition = true;
1.1.1.12 root 832: KeyboardProcessor.Abs.PrevReadAbsMouseButtons &= ~0x02;
833: KeyboardProcessor.Abs.PrevReadAbsMouseButtons |= 0x04;
834: }
835: }
836:
837: /* Do need to report? */
838: if (bReportPosition)
839: {
840: /* Only report if mouse in absolute mode */
841: if (KeyboardProcessor.MouseMode==AUTOMODE_MOUSEABS)
842: {
1.1.1.15 root 843: LOG_TRACE(TRACE_IKBD_ALL, "Report ABS on MouseAction\n");
1.1.1.12 root 844: IKBD_Cmd_ReadAbsMousePos();
845: }
846: }
847: }
848: }
849:
850:
851: /*-----------------------------------------------------------------------*/
852: /**
853: * Send mouse movements as cursor keys
854: */
1.1.1.8 root 855: static void IKBD_SendCursorMousePacket(void)
1.1 root 856: {
1.1.1.12 root 857: int i=0;
1.1 root 858:
1.1.1.12 root 859: /* Run each 'Delta' as cursor presses */
860: /* Limit to '10' loops as host mouse cursor might have a VERY poor quality. */
861: /* Eg, a single mouse movement on and ST gives delta's of '1', mostly, */
862: /* but host mouse might go as high as 20+! */
863: while ( (i<10) && ((KeyboardProcessor.Mouse.DeltaX!=0) || (KeyboardProcessor.Mouse.DeltaY!=0)
864: || (!IKBD_ButtonsEqual(Keyboard.bOldLButtonDown,Keyboard.bLButtonDown)) || (!IKBD_ButtonsEqual(Keyboard.bOldRButtonDown,Keyboard.bRButtonDown))) )
865: {
866: /* Left? */
867: if (KeyboardProcessor.Mouse.DeltaX<0)
868: {
869: IKBD_AddKeyToKeyboardBuffer(75); /* Left cursor */
870: IKBD_AddKeyToKeyboardBuffer(75|0x80);
871: KeyboardProcessor.Mouse.DeltaX++;
872: }
873: /* Right? */
874: if (KeyboardProcessor.Mouse.DeltaX>0)
875: {
876: IKBD_AddKeyToKeyboardBuffer(77); /* Right cursor */
877: IKBD_AddKeyToKeyboardBuffer(77|0x80);
878: KeyboardProcessor.Mouse.DeltaX--;
879: }
880: /* Up? */
881: if (KeyboardProcessor.Mouse.DeltaY<0)
882: {
883: IKBD_AddKeyToKeyboardBuffer(72); /* Up cursor */
884: IKBD_AddKeyToKeyboardBuffer(72|0x80);
885: KeyboardProcessor.Mouse.DeltaY++;
886: }
887: /* Down? */
888: if (KeyboardProcessor.Mouse.DeltaY>0)
889: {
890: IKBD_AddKeyToKeyboardBuffer(80); /* Down cursor */
891: IKBD_AddKeyToKeyboardBuffer(80|0x80);
892: KeyboardProcessor.Mouse.DeltaY--;
893: }
894:
895: /* Left button? */
896: if ( (IKBD_ButtonBool(Keyboard.bLButtonDown) && (!IKBD_ButtonBool(Keyboard.bOldLButtonDown))) )
897: IKBD_AddKeyToKeyboardBuffer(0x74); /* Left */
898: else if ( (IKBD_ButtonBool(Keyboard.bOldLButtonDown) && (!IKBD_ButtonBool(Keyboard.bLButtonDown))) )
899: IKBD_AddKeyToKeyboardBuffer(0x74|0x80);
900: /* Right button? */
901: if ( (IKBD_ButtonBool(Keyboard.bRButtonDown) && (!IKBD_ButtonBool(Keyboard.bOldRButtonDown))) )
902: IKBD_AddKeyToKeyboardBuffer(0x75); /* Right */
903: else if ( (IKBD_ButtonBool(Keyboard.bOldRButtonDown) && (!IKBD_ButtonBool(Keyboard.bRButtonDown))) )
904: IKBD_AddKeyToKeyboardBuffer(0x75|0x80);
905:
906: Keyboard.bOldLButtonDown = Keyboard.bLButtonDown;
907: Keyboard.bOldRButtonDown = Keyboard.bRButtonDown;
908:
909: /* Count, so exit if try too many times! */
910: i++;
911: }
1.1 root 912: }
913:
1.1.1.2 root 914:
915: /*-----------------------------------------------------------------------*/
1.1.1.12 root 916: /**
917: * Return packets from keyboard for auto, rel mouse, joystick etc...
918: */
1.1.1.14 root 919: static void IKBD_SendAutoKeyboardCommands(void)
1.1 root 920: {
1.1.1.12 root 921: /* Don't do anything until processor is first reset */
922: if (!KeyboardProcessor.bReset)
923: return;
924:
925: /* Read joysticks for this frame */
1.1.1.13 root 926: IKBD_GetJoystickData();
1.1.1.12 root 927:
928: /* Check for double-clicks in maximum speed mode */
929: IKBD_CheckForDoubleClicks();
930:
931: /* Handle Joystick/Mouse fire buttons */
932: IKBD_DuplicateMouseFireButtons();
933:
934: /* Send any packets which are to be reported by mouse action */
935: IKBD_SendOnMouseAction();
936:
937: /* Update internal mouse absolute position by find 'delta' of mouse movement */
938: IKBD_UpdateInternalMousePosition();
939:
940: /* Send automatic joystick packets */
941: if (KeyboardProcessor.JoystickMode==AUTOMODE_JOYSTICK)
942: IKBD_SelAutoJoysticks();
943: /* Send automatic relative mouse positions(absolute are not send automatically) */
944: if (KeyboardProcessor.MouseMode==AUTOMODE_MOUSEREL)
945: IKBD_SendRelMousePacket();
946: /* Send cursor key directions for movements */
947: else if (KeyboardProcessor.MouseMode==AUTOMODE_MOUSECURSOR)
948: IKBD_SendCursorMousePacket();
949:
950: /* Store buttons for next time around */
951: Keyboard.bOldLButtonDown = Keyboard.bLButtonDown;
952: Keyboard.bOldRButtonDown = Keyboard.bRButtonDown;
953:
954: /* Send joystick button '2' as 'Space bar' key - MUST do here so does not get mixed up in middle of joystick packets! */
955: if (JoystickSpaceBar)
956: {
957: /* As we simulating space bar? */
958: if (JoystickSpaceBar==JOYSTICK_SPACE_DOWN)
959: {
1.1.1.15 root 960: IKBD_PressSTKey(57, true); /* Press */
1.1.1.12 root 961: JoystickSpaceBar = JOYSTICK_SPACE_UP;
962: }
963: else //if (JoystickSpaceBar==JOYSTICK_SPACE_UP) {
964: {
1.1.1.15 root 965: IKBD_PressSTKey(57, false); /* Release */
966: JoystickSpaceBar = false; /* Complete */
1.1.1.12 root 967: }
968: }
1.1 root 969: }
970:
1.1.1.2 root 971:
972: /*-----------------------------------------------------------------------*/
1.1.1.12 root 973: /**
1.1.1.14 root 974: * This function is called regularly to automatically send keyboard, mouse
975: * and joystick updates.
976: */
977: void IKBD_InterruptHandler_AutoSend(void)
978: {
979: /* Handle user events and other messages, (like quit message) */
980: Main_EventHandler();
981:
1.1.1.17! root 982: /* Remove this interrupt from list and re-order.
! 983: * (needs to be done after UI event handling so
! 984: * that snapshots saved from UI and restored from
! 985: * command line don't miss the AUTOSEND interrupt)
! 986: */
! 987: CycInt_AcknowledgeInterrupt();
! 988:
1.1.1.14 root 989: /* Did user try to quit? */
990: if (bQuitProgram)
991: {
992: /* Pass NULL interrupt function to quit cleanly */
1.1.1.16 root 993: CycInt_AddAbsoluteInterrupt(4, INT_CPU_CYCLE, INTERRUPT_NULL);
1.1.1.14 root 994: /* Assure that CPU core shuts down */
995: M68000_SetSpecial(SPCFLAG_BRK);
996: return;
997: }
998:
999: /* Trigger this auto-update function again after a while */
1.1.1.16 root 1000: CycInt_AddRelativeInterrupt(150000, INT_CPU_CYCLE, INTERRUPT_IKBD_AUTOSEND);
1.1.1.14 root 1001:
1002: /* We don't send keyboard data automatically within the first few
1003: * VBLs to avoid that TOS gets confused during its boot time */
1004: if (nVBLs > 20)
1005: {
1006: /* Send automatic keyboard packets for mouse, joysticks etc... */
1007: IKBD_SendAutoKeyboardCommands();
1008: }
1009: }
1010:
1011:
1012: /*-----------------------------------------------------------------------*/
1013: /**
1.1.1.12 root 1014: * On ST if disable Mouse AND Joystick with a set time of a RESET command they are
1015: * actually turned back on! (A number of games do this so can get mouse and joystick
1016: * packets at the same time)
1017: */
1.1.1.8 root 1018: static void IKBD_CheckResetDisableBug(void)
1.1 root 1019: {
1.1.1.12 root 1020: /* Have disabled BOTH mouse and joystick? */
1021: if (bMouseDisabled && bJoystickDisabled)
1022: {
1023: /* And in critical time? */
1024: if (bDuringResetCriticalTime)
1025: {
1026: /* Emulate relative mouse and joystick reports being turned back on */
1027: KeyboardProcessor.MouseMode = AUTOMODE_MOUSEREL;
1028: KeyboardProcessor.JoystickMode = AUTOMODE_JOYSTICK;
1.1.1.15 root 1029: bBothMouseAndJoy = true;
1.1.1.6 root 1030:
1.1.1.15 root 1031: LOG_TRACE(TRACE_IKBD_ALL, "IKBD Mouse+Joystick disabled "
1032: "during RESET. Revert.\n");
1.1.1.12 root 1033: }
1034: }
1.1 root 1035: }
1036:
1.1.1.2 root 1037:
1038: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1039: /**
1040: * Start timer after keyboard RESET command to emulate 'quirk'
1041: * If some IKBD commands are sent during time after a RESET they may be ignored
1042: */
1.1 root 1043: void IKBD_InterruptHandler_ResetTimer(void)
1044: {
1.1.1.12 root 1045: /* Remove this interrupt from list and re-order */
1.1.1.16 root 1046: CycInt_AcknowledgeInterrupt();
1.1 root 1047:
1.1.1.12 root 1048: /* Turn processor on; can now process commands */
1.1.1.15 root 1049: KeyboardProcessor.bReset = true;
1.1.1.9 root 1050:
1.1.1.12 root 1051: /* Critical timer is over */
1.1.1.15 root 1052: bDuringResetCriticalTime = false;
1053: bMouseEnabledDuringReset = false;
1.1 root 1054: }
1055:
1056:
1057:
1.1.1.2 root 1058: /*-----------------------------------------------------------------------*/
1.1 root 1059: /*
1060: List of keyboard commands
1061: */
1062:
1063:
1.1.1.2 root 1064: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1065: /**
1066: * RESET
1067: *
1068: * 0x80
1069: * 0x01
1070: *
1.1.1.15 root 1071: * Performs self test and checks for stuck (closed) keys, if OK returns 0xF0 or
1072: * 0xF1. Otherwise returns break codes for keys (not emulated).
1.1.1.12 root 1073: */
1.1.1.13 root 1074: static void IKBD_Cmd_Reset(void)
1.1 root 1075: {
1.1.1.15 root 1076: LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_Reset. VBLs=%i framecyc=%i\n",
1077: nVBLs, Cycles_GetCounter(CYCLES_COUNTER_VIDEO));
1.1.1.14 root 1078:
1.1.1.12 root 1079: /* Check for error series of bytes, eg 0x80,0x01 */
1080: if (Keyboard.InputBuffer[1] == 0x01)
1081: {
1082: /* Set defaults */
1083: KeyboardProcessor.MouseMode = AUTOMODE_MOUSEREL;
1084: KeyboardProcessor.JoystickMode = AUTOMODE_JOYSTICK;
1085: KeyboardProcessor.Abs.X = ABS_X_ONRESET;
1086: KeyboardProcessor.Abs.Y = ABS_Y_ONRESET;
1087: KeyboardProcessor.Abs.MaxX = ABS_MAX_X_ONRESET;
1088: KeyboardProcessor.Abs.MaxY = ABS_MAY_Y_ONRESET;
1089: KeyboardProcessor.Abs.PrevReadAbsMouseButtons = ABS_PREVBUTTONS;
1090:
1.1.1.15 root 1091: /* flush all queued bytes that would be read in $fffc02 */
1092: Keyboard.BufferHead = Keyboard.BufferTail = 0;
1093:
1094: /* This command returns either the byte 0xf0 or 0xf1 (depending
1095: * on the version of the IKBD ROM) when the reset has been
1096: * successful. Some notes:
1097: * - Dragonnels demo requires 0xf1 so we use only this value
1098: * right now.
1099: * - Lotus Turbo Esprit 2 requires at least a delay of 50000
1100: * cycles or it will crash during start up.
1101: */
1102: IKBD_AddKeyToKeyboardBufferWithDelay(0xf1, 50000);
1.1.1.12 root 1103:
1104: /* Start timer - some commands are send during this time they may be ignored (see real ST!) */
1.1.1.16 root 1105: CycInt_AddRelativeInterrupt(IKBD_RESET_CYCLES, INT_CPU_CYCLE, INTERRUPT_IKBD_RESETTIMER);
1.1.1.12 root 1106:
1107: /* Set this 'critical' flag, gets reset when timer expires */
1.1.1.15 root 1108: bDuringResetCriticalTime = true;
1109: bMouseDisabled = bJoystickDisabled = false;
1110: bBothMouseAndJoy = false;
1111: bMouseEnabledDuringReset = false;
1.1.1.14 root 1112:
1.1.1.15 root 1113: LOG_TRACE(TRACE_IKBD_ALL, "IKBD reset done.\n");
1.1.1.12 root 1114: }
1115: /* else if not 0x80,0x01 just ignore */
1.1 root 1116: }
1117:
1.1.1.2 root 1118:
1119: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1120: /**
1121: * SET MOUSE BUTTON ACTION
1122: *
1123: * 0x07
1124: * %00000mss ; mouse button action
1125: * ; (m is presumed =1 when in MOUSE KEYCODE mode)
1126: * ; mss=0xy, mouse button press or release causes mouse
1127: * ; position report
1128: * ; where y=1, mouse key press causes absolute report
1129: * ; and x=1, mouse key release causes absolute report
1130: * ; mss=100, mouse buttons act like keys
1131: */
1.1.1.13 root 1132: static void IKBD_Cmd_MouseAction(void)
1.1 root 1133: {
1.1.1.12 root 1134: KeyboardProcessor.Mouse.Action = Keyboard.InputBuffer[1];
1135: KeyboardProcessor.Abs.PrevReadAbsMouseButtons = ABS_PREVBUTTONS;
1.1.1.13 root 1136:
1.1.1.15 root 1137: LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_MouseAction %d\n",
1138: (unsigned int)KeyboardProcessor.Mouse.Action);
1.1 root 1139: }
1140:
1.1.1.2 root 1141:
1142: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1143: /**
1144: * SET RELATIVE MOUSE POSITION REPORTING
1145: *
1146: * 0x08
1147: */
1.1.1.13 root 1148: static void IKBD_Cmd_RelMouseMode(void)
1.1 root 1149: {
1.1.1.12 root 1150: KeyboardProcessor.MouseMode = AUTOMODE_MOUSEREL;
1.1.1.13 root 1151:
1.1.1.14 root 1152: /* Some games (like Barbarian by Psygnosis) enable both, mouse and
1153: * joystick directly after a reset. This causes the IKBD to send both
1154: * type of packets. To emulate this feature, we've got to remember
1155: * that the mouse has been enabled during reset. */
1156: if (bDuringResetCriticalTime)
1.1.1.15 root 1157: bMouseEnabledDuringReset = true;
1.1.1.14 root 1158:
1.1.1.15 root 1159: LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_RelMouseMode\n");
1.1 root 1160: }
1161:
1.1.1.2 root 1162:
1163: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1164: /**
1165: * SET ABSOLUTE MOUSE POSITIONING
1166: *
1167: * 0x09
1168: * XMSB ;X maximum (in scaled mouse clicks)
1169: * XLSB
1170: * YMSB ;Y maximum (in scaled mouse clicks)
1171: * YLSB
1172: */
1.1.1.13 root 1173: static void IKBD_Cmd_AbsMouseMode(void)
1.1 root 1174: {
1.1.1.12 root 1175: /* These maximums are 'inclusive' */
1176: KeyboardProcessor.MouseMode = AUTOMODE_MOUSEABS;
1177: KeyboardProcessor.Abs.MaxX = (((unsigned int)Keyboard.InputBuffer[1])<<8) | (unsigned int)Keyboard.InputBuffer[2];
1178: KeyboardProcessor.Abs.MaxY = (((unsigned int)Keyboard.InputBuffer[3])<<8) | (unsigned int)Keyboard.InputBuffer[4];
1.1.1.13 root 1179:
1.1.1.15 root 1180: LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_AbsMouseMode %d,%d\n",
1181: KeyboardProcessor.Abs.MaxX, KeyboardProcessor.Abs.MaxY);
1.1 root 1182: }
1183:
1.1.1.2 root 1184:
1185: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1186: /**
1187: * SET MOUSE KEYCODE MODE
1188: *
1189: * 0x0A
1190: * deltax ; distance in X clicks to return (LEFT) or (RIGHT)
1191: * deltay ; distance in Y clicks to return (UP) or (DOWN)
1192: */
1.1.1.13 root 1193: static void IKBD_Cmd_MouseCursorKeycodes(void)
1.1 root 1194: {
1.1.1.12 root 1195: KeyboardProcessor.MouseMode = AUTOMODE_MOUSECURSOR;
1196: KeyboardProcessor.Mouse.KeyCodeDeltaX = Keyboard.InputBuffer[1];
1197: KeyboardProcessor.Mouse.KeyCodeDeltaY = Keyboard.InputBuffer[2];
1.1.1.13 root 1198:
1.1.1.15 root 1199: LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_MouseCursorKeycodes %d,%d\n",
1200: (int)KeyboardProcessor.Mouse.KeyCodeDeltaX,
1201: (int)KeyboardProcessor.Mouse.KeyCodeDeltaY);
1.1 root 1202: }
1203:
1.1.1.2 root 1204:
1205: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1206: /**
1207: * SET MOUSE THRESHOLD
1208: *
1209: * 0x0B
1210: * X ; x threshold in mouse ticks (positive integers)
1211: * Y ; y threshold in mouse ticks (positive integers)
1212: */
1.1.1.13 root 1213: static void IKBD_Cmd_SetMouseThreshold(void)
1.1 root 1214: {
1.1.1.12 root 1215: KeyboardProcessor.Mouse.XThreshold = (unsigned int)Keyboard.InputBuffer[1];
1216: KeyboardProcessor.Mouse.YThreshold = (unsigned int)Keyboard.InputBuffer[2];
1.1.1.13 root 1217:
1.1.1.15 root 1218: LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_SetMouseThreshold %d,%d\n",
1219: KeyboardProcessor.Mouse.XThreshold, KeyboardProcessor.Mouse.YThreshold);
1.1 root 1220: }
1221:
1.1.1.2 root 1222:
1223: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1224: /**
1225: * SET MOUSE SCALE
1226: *
1227: * 0x0C
1228: * X ; horizontal mouse ticks per internel X
1229: * Y ; vertical mouse ticks per internel Y
1230: */
1.1.1.13 root 1231: static void IKBD_Cmd_SetMouseScale(void)
1.1 root 1232: {
1.1.1.12 root 1233: KeyboardProcessor.Mouse.XScale = (unsigned int)Keyboard.InputBuffer[1];
1234: KeyboardProcessor.Mouse.YScale = (unsigned int)Keyboard.InputBuffer[2];
1.1.1.13 root 1235:
1.1.1.15 root 1236: LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_SetMouseScale %d,%d\n",
1237: KeyboardProcessor.Mouse.XScale, KeyboardProcessor.Mouse.YScale);
1.1 root 1238: }
1239:
1240:
1.1.1.12 root 1241: /*-----------------------------------------------------------------------*/
1242: /**
1243: * INTERROGATE MOUSE POSITION
1244: *
1245: * 0x0D
1246: * Returns: 0xF7 ; absolute mouse position header
1247: * BUTTONS
1248: * 0000dcba
1249: * where a is right button down since last interrogation
1250: * b is right button up since last
1251: * c is left button down since last
1252: * d is left button up since last
1253: * XMSB ; X coordinate
1254: * XLSB
1255: * YMSB ; Y coordinate
1256: * YLSB
1257: */
1.1.1.13 root 1258: static void IKBD_Cmd_ReadAbsMousePos(void)
1.1 root 1259: {
1.1.1.12 root 1260: Uint8 Buttons,PrevButtons;
1.1 root 1261:
1.1.1.12 root 1262: /* Test buttons */
1263: Buttons = 0;
1264: /* Set buttons to show if up/down */
1265: if (Keyboard.bRButtonDown)
1266: Buttons |= 0x01;
1267: else
1268: Buttons |= 0x02;
1269: if (Keyboard.bLButtonDown)
1270: Buttons |= 0x04;
1271: else
1272: Buttons |= 0x08;
1273: /* Mask off it didn't send last time */
1274: PrevButtons = KeyboardProcessor.Abs.PrevReadAbsMouseButtons;
1275: KeyboardProcessor.Abs.PrevReadAbsMouseButtons = Buttons;
1276: Buttons &= ~PrevButtons;
1277:
1278: /* And send packet */
1.1.1.13 root 1279: IKBD_AddKeyToKeyboardBufferWithDelay(0xf7, 18000);
1.1.1.12 root 1280: IKBD_AddKeyToKeyboardBuffer(Buttons);
1281: IKBD_AddKeyToKeyboardBuffer((unsigned int)KeyboardProcessor.Abs.X>>8);
1282: IKBD_AddKeyToKeyboardBuffer((unsigned int)KeyboardProcessor.Abs.X&0xff);
1283: IKBD_AddKeyToKeyboardBuffer((unsigned int)KeyboardProcessor.Abs.Y>>8);
1284: IKBD_AddKeyToKeyboardBuffer((unsigned int)KeyboardProcessor.Abs.Y&0xff);
1285:
1.1.1.15 root 1286: LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_ReadAbsMousePos %d,%d 0x%X\n",
1287: KeyboardProcessor.Abs.X, KeyboardProcessor.Abs.Y, Buttons);
1.1 root 1288: }
1289:
1290:
1.1.1.12 root 1291: /*-----------------------------------------------------------------------*/
1292: /**
1293: * LOAD MOUSE POSITION
1294: *
1295: * 0x0E
1296: * 0x00 ; filler
1297: * XMSB ; X coordinate
1298: * XLSB ; (in scaled coordinate system)
1299: * YMSB ; Y coordinate
1300: * YLSB
1301: */
1.1.1.13 root 1302: static void IKBD_Cmd_SetInternalMousePos(void)
1.1.1.7 root 1303: {
1.1.1.12 root 1304: /* Setting these do not clip internal position(this happens on next update) */
1305: KeyboardProcessor.Abs.X = (((unsigned int)Keyboard.InputBuffer[2])<<8) | (unsigned int)Keyboard.InputBuffer[3];
1306: KeyboardProcessor.Abs.Y = (((unsigned int)Keyboard.InputBuffer[4])<<8) | (unsigned int)Keyboard.InputBuffer[5];
1.1.1.13 root 1307:
1.1.1.15 root 1308: LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_SetInternalMousePos %d,%d\n",
1309: KeyboardProcessor.Abs.X, KeyboardProcessor.Abs.Y);
1.1 root 1310: }
1311:
1.1.1.2 root 1312:
1313: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1314: /**
1315: * SET Y=0 AT BOTTOM
1316: *
1317: * 0x0F
1318: */
1.1.1.13 root 1319: static void IKBD_Cmd_SetYAxisDown(void)
1.1 root 1320: {
1.1.1.12 root 1321: KeyboardProcessor.Mouse.YAxis = -1;
1.1.1.13 root 1322:
1.1.1.15 root 1323: LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_SetYAxisDown\n");
1.1 root 1324: }
1325:
1.1.1.2 root 1326:
1327: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1328: /**
1329: * SET Y=0 AT TOP
1330: *
1331: * 0x10
1332: */
1.1.1.13 root 1333: static void IKBD_Cmd_SetYAxisUp(void)
1.1 root 1334: {
1.1.1.12 root 1335: KeyboardProcessor.Mouse.YAxis = 1;
1.1.1.13 root 1336:
1.1.1.15 root 1337: LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_SetYAxisUp\n");
1.1 root 1338: }
1339:
1.1.1.2 root 1340:
1341: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1342: /**
1343: * RESUME
1344: *
1345: * 0x11
1346: */
1.1.1.13 root 1347: static void IKBD_Cmd_StartKeyboardTransfer(void)
1.1 root 1348: {
1.1.1.15 root 1349: LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_StartKeyboardTransfer\n");
1.1 root 1350: }
1351:
1.1.1.2 root 1352:
1353: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1354: /**
1355: * DISABLE MOUSE
1356: *
1357: * 0x12
1358: */
1.1.1.13 root 1359: static void IKBD_Cmd_TurnMouseOff(void)
1.1 root 1360: {
1.1.1.12 root 1361: KeyboardProcessor.MouseMode = AUTOMODE_OFF;
1.1.1.15 root 1362: bMouseDisabled = true;
1.1.1.13 root 1363:
1.1.1.15 root 1364: LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_TurnMouseOff\n");
1.1 root 1365:
1.1.1.12 root 1366: IKBD_CheckResetDisableBug();
1.1 root 1367: }
1368:
1.1.1.2 root 1369:
1370: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1371: /**
1372: * PAUSE OUTPUT
1373: *
1374: * 0x13
1375: */
1.1.1.13 root 1376: static void IKBD_Cmd_StopKeyboardTransfer(void)
1.1 root 1377: {
1.1.1.15 root 1378: LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_StopKeyboardTransfer\n");
1.1 root 1379: }
1380:
1.1.1.2 root 1381:
1382: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1383: /**
1384: * SET JOYSTICK EVENT REPORTING
1385: *
1386: * 0x14
1387: */
1.1.1.13 root 1388: static void IKBD_Cmd_ReturnJoystickAuto(void)
1.1 root 1389: {
1.1.1.15 root 1390: LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_ReturnJoystickAuto\n");
1.1.1.14 root 1391:
1.1.1.12 root 1392: KeyboardProcessor.JoystickMode = AUTOMODE_JOYSTICK;
1393: KeyboardProcessor.MouseMode = AUTOMODE_OFF;
1.1.1.6 root 1394:
1.1.1.14 root 1395: /* If mouse was also enabled within time of a reset it isn't disabled now!
1396: * (Used by the game Barbarian 1 by Psygnosis for example) */
1397: if (bMouseEnabledDuringReset)
1.1.1.12 root 1398: {
1399: KeyboardProcessor.MouseMode = AUTOMODE_MOUSEREL;
1.1.1.15 root 1400: bBothMouseAndJoy = true;
1401: LOG_TRACE(TRACE_IKBD_ALL, "IKBD joystick and mouse "
1402: "enabled during RESET. Mouse not disabled!\n");
1.1.1.12 root 1403: }
1.1.1.6 root 1404:
1.1.1.13 root 1405: /* This command resets the internally previously stored joystick states */
1406: KeyboardProcessor.Joy.PrevJoyData[0] = KeyboardProcessor.Joy.PrevJoyData[1] = 0;
1407:
1408: /* This is a hack for the STE Utopos (=> v1.50) and Falcon Double Bubble
1409: * 2000 games. They expect the joystick data to be sent within a certain
1410: * amount of time after this command, without checking the ACIA control
1411: * register first.
1412: */
1413: IKBD_GetJoystickData();
1414: IKBD_SelAutoJoysticks();
1.1 root 1415: }
1416:
1.1.1.2 root 1417:
1418: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1419: /**
1420: * SET JOYSTICK INTERROGATION MODE
1421: *
1422: * 0x15
1423: */
1.1.1.13 root 1424: static void IKBD_Cmd_StopJoystick(void)
1.1 root 1425: {
1.1.1.12 root 1426: KeyboardProcessor.JoystickMode = AUTOMODE_OFF;
1.1.1.15 root 1427: LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_StopJoystick\n");
1.1 root 1428: }
1429:
1.1.1.2 root 1430:
1431: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1432: /**
1433: * JOYSTICK INTERROGATE
1434: *
1435: * 0x16
1436: */
1.1.1.13 root 1437: static void IKBD_Cmd_ReturnJoystick(void)
1.1 root 1438: {
1.1.1.17! root 1439: /* The game "Downfall" continually issues this command during the
! 1440: * title screen - faster than processing the 3 bytes from the ACIA,
! 1441: * so it floods our Keyboard.Buffer ... in the end, we can not put the
! 1442: * whole packet into the buffer anymore, and the game hangs due to
! 1443: * these incomplete answers. To avoid this situation, only execute
! 1444: * this command if there is enough space left in our Keyboard.Buffer! */
! 1445: if (((Keyboard.BufferHead-1-Keyboard.BufferTail)&KEYBOARD_BUFFER_MASK) < 3)
! 1446: {
! 1447: LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_ReturnJoystick ignored - buffer is full!\n");
! 1448: return;
! 1449: }
! 1450:
! 1451: LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_ReturnJoystick\n");
! 1452:
1.1.1.13 root 1453: IKBD_AddKeyToKeyboardBufferWithDelay(0xFD, 35000);
1.1.1.12 root 1454: IKBD_AddKeyToKeyboardBuffer(Joy_GetStickData(0));
1455: IKBD_AddKeyToKeyboardBuffer(Joy_GetStickData(1));
1.1 root 1456: }
1457:
1.1.1.2 root 1458:
1459: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1460: /**
1461: * SET JOYSTICK MONITORING
1462: *
1463: * 0x17
1464: * rate ; time between samples in hundreths of a second
1465: * Returns: (in packets of two as long as in mode)
1466: * %000000xy where y is JOYSTICK1 Fire button
1467: * and x is JOYSTICK0 Fire button
1468: * %nnnnmmmm where m is JOYSTICK1 state
1469: * and n is JOYSTICK0 state
1470: */
1.1.1.13 root 1471: static void IKBD_Cmd_SetJoystickDuration(void)
1.1 root 1472: {
1.1.1.15 root 1473: LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_SetJoystickDuration\n");
1.1 root 1474: }
1475:
1.1.1.2 root 1476:
1477: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1478: /**
1479: * SET FIRE BUTTON MONITORING
1480: *
1481: * 0x18
1482: * Returns: (as long as in mode)
1483: * %bbbbbbbb ; state of the JOYSTICK1 fire button packed
1484: * ; 8 bits per byte, the first sample if the MSB
1485: */
1.1.1.13 root 1486: static void IKBD_Cmd_SetJoystickFireDuration(void)
1.1 root 1487: {
1.1.1.15 root 1488: LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_SetJoystickFireDuration\n");
1.1 root 1489: }
1490:
1.1.1.2 root 1491:
1492: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1493: /**
1494: * SET JOYSTICK KEYCODE MODE
1495: *
1496: * 0x19
1497: * RX ; length of time (in tenths of seconds) until
1498: * ; horizontal velocity breakpoint is reached
1499: * RY ; length of time (in tenths of seconds) until
1500: * ; vertical velocity breakpoint is reached
1501: * TX ; length (in tenths of seconds) of joystick closure
1502: * ; until horizontal cursor key is generated before RX
1503: * ; has elapsed
1504: * TY ; length (in tenths of seconds) of joystick closure
1505: * ; until vertical cursor key is generated before RY
1506: * ; has elapsed
1507: * VX ; length (in tenths of seconds) of joystick closure
1508: * ; until horizontal cursor keystokes are generated after RX
1509: * ; has elapsed
1510: * VY ; length (in tenths of seconds) of joystick closure
1511: * ; until vertical cursor keystokes are generated after RY
1512: * ; has elapsed
1513: */
1.1.1.13 root 1514: static void IKBD_Cmd_SetCursorForJoystick(void)
1.1 root 1515: {
1.1.1.15 root 1516: LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_SetCursorForJoystick\n");
1.1 root 1517: }
1518:
1.1.1.2 root 1519:
1520: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1521: /**
1522: * DISABLE JOYSTICKS
1523: *
1524: * 0x1A
1525: */
1.1.1.13 root 1526: static void IKBD_Cmd_DisableJoysticks(void)
1.1 root 1527: {
1.1.1.12 root 1528: KeyboardProcessor.JoystickMode = AUTOMODE_OFF;
1.1.1.15 root 1529: bJoystickDisabled = true;
1.1.1.13 root 1530:
1.1.1.15 root 1531: LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_DisableJoysticks\n");
1.1 root 1532:
1.1.1.12 root 1533: IKBD_CheckResetDisableBug();
1.1 root 1534: }
1535:
1.1.1.2 root 1536:
1537: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1538: /**
1539: * TIME-OF-DAY CLOCK SET
1540: *
1541: * 0x1B
1542: * YY ; year (2 least significant digits)
1543: * MM ; month
1544: * DD ; day
1545: * hh ; hour
1546: * mm ; minute
1547: * ss ; second
1548: */
1.1.1.13 root 1549: static void IKBD_Cmd_SetClock(void)
1.1 root 1550: {
1.1.1.15 root 1551: LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_SetClock\n");
1.1.1.13 root 1552: }
1553:
1554:
1555: /*-----------------------------------------------------------------------*/
1556: /**
1.1.1.17! root 1557: * Convert value to 2-digit BCD.
! 1558: * Note: TOS 2.0x requires BCD conversion with overflow, so the decade
! 1559: * is not calculated modulo 10, or it will end up in the year 2039
! 1560: * instead...
1.1.1.13 root 1561: */
1.1.1.17! root 1562: static Uint8 IKBD_ConvertToBCD(Uint16 Value)
1.1.1.13 root 1563: {
1.1.1.17! root 1564: return ((Value/10)<<4) | (Value%10);
1.1 root 1565: }
1566:
1.1.1.2 root 1567:
1568: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1569: /**
1570: * INTERROGATE TIME-OF-DAT CLOCK
1571: *
1572: * 0x1C
1573: * Returns:
1574: * 0xFC ; time-of-day event header
1575: * YY ; year (2 least significant digits)
1576: * MM ; month
1577: * DD ; day
1578: * hh ; hour
1579: * mm ; minute
1580: * ss ; second
1581: */
1.1.1.13 root 1582: static void IKBD_Cmd_ReadClock(void)
1.1 root 1583: {
1.1.1.12 root 1584: struct tm *SystemTime;
1585: time_t nTimeTicks;
1.1 root 1586:
1.1.1.12 root 1587: /* Get system time */
1588: nTimeTicks = time(NULL);
1589: SystemTime = localtime(&nTimeTicks);
1590:
1591: /* Return packet */
1.1.1.13 root 1592: IKBD_AddKeyToKeyboardBufferWithDelay(0xFC, 32000);
1.1.1.12 root 1593: /* Return time-of-day clock as yy-mm-dd-hh-mm-ss as BCD */
1.1.1.13 root 1594: IKBD_AddKeyToKeyboardBuffer(IKBD_ConvertToBCD(SystemTime->tm_year)); /* yy - year (2 least significant digits) */
1595: IKBD_AddKeyToKeyboardBuffer(IKBD_ConvertToBCD(SystemTime->tm_mon+1)); /* mm - Month */
1596: IKBD_AddKeyToKeyboardBuffer(IKBD_ConvertToBCD(SystemTime->tm_mday)); /* dd - Day */
1597: IKBD_AddKeyToKeyboardBuffer(IKBD_ConvertToBCD(SystemTime->tm_hour)); /* hh - Hour */
1598: IKBD_AddKeyToKeyboardBuffer(IKBD_ConvertToBCD(SystemTime->tm_min)); /* mm - Minute */
1599: IKBD_AddKeyToKeyboardBuffer(IKBD_ConvertToBCD(SystemTime->tm_sec)); /* ss - Second */
1600:
1.1.1.15 root 1601: LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_ReadClock\n");
1.1 root 1602: }
1603:
1.1.1.2 root 1604:
1605: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1606: /**
1607: * MEMORY LOAD
1608: *
1609: * 0x20
1610: * ADRMSB ; address in controller
1611: * ADRLSB ; memory to be loaded
1612: * NUM ; number of bytes (0-128)
1613: * { data }
1614: */
1.1.1.13 root 1615: static void IKBD_Cmd_LoadMemory(void)
1.1 root 1616: {
1.1.1.15 root 1617: LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_LoadMemory addr 0x%x count %d\n",
1618: (Keyboard.InputBuffer[1] << 8) + Keyboard.InputBuffer[2], Keyboard.InputBuffer[3]);
1.1.1.13 root 1619:
1620: MemoryLoadNbBytesTotal = Keyboard.InputBuffer[3];
1621: MemoryLoadNbBytesLeft = MemoryLoadNbBytesTotal;
1622: crc32_reset ( &MemoryLoadCrc );
1.1 root 1623: }
1624:
1.1.1.2 root 1625:
1626: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1627: /**
1628: * MEMORY READ
1629: *
1630: * 0x21
1631: * ADRMSB ; address in controller
1632: * ADRLSB ; memory to be read
1633: * Returns:
1634: * 0xF6 ; status header
1635: * 0x20 ; memory access
1636: * { data } ; 6 data bytes starting at ADR
1637: */
1.1.1.13 root 1638: static void IKBD_Cmd_ReadMemory(void)
1.1 root 1639: {
1.1.1.15 root 1640: LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_ReadMemory\n");
1.1 root 1641: }
1642:
1.1.1.2 root 1643:
1644: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1645: /**
1646: * CONTROLLER EXECUTE
1647: *
1648: * 0x22
1649: * ADRMSB ; address of subroutine in
1650: * ADRLSB ; controller memory to be called
1651: */
1.1.1.13 root 1652: static void IKBD_Cmd_Execute(void)
1653: {
1.1.1.17! root 1654: LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_Execute addr 0x%x\n",
! 1655: (Keyboard.InputBuffer[1] << 8) + Keyboard.InputBuffer[2]);
1.1.1.13 root 1656:
1657: if ( pIKBD_CustomCodeHandler_Write )
1658: {
1.1.1.15 root 1659: LOG_TRACE(TRACE_IKBD_EXEC, "ikbd execute addr 0x%x using custom handler\n",
1660: (Keyboard.InputBuffer[1] << 8) + Keyboard.InputBuffer[2]);
1.1.1.13 root 1661:
1.1.1.15 root 1662: IKBD_ExeMode = true; /* turn 6301's custom mode ON */
1.1.1.13 root 1663: }
1664: else /* unknown code uploaded to ikbd RAM */
1665: {
1.1.1.15 root 1666: LOG_TRACE(TRACE_IKBD_EXEC, "ikbd execute addr 0x%x ignored, no custom handler found\n",
1667: (Keyboard.InputBuffer[1] << 8) + Keyboard.InputBuffer[2]);
1.1.1.13 root 1668: }
1669: }
1670:
1671:
1672: /*-----------------------------------------------------------------------*/
1673: /**
1674: * REPORT MOUSE BUTTON ACTION
1675: *
1676: * 0x87
1677: */
1678: static void IKBD_Cmd_ReportMouseAction(void)
1679: {
1.1.1.15 root 1680: LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_ReportMouseAction\n");
1.1.1.13 root 1681:
1682: IKBD_AddKeyToKeyboardBufferWithDelay(0xf6, 30000);
1683: IKBD_AddKeyToKeyboardBuffer(7);
1684: IKBD_AddKeyToKeyboardBuffer(KeyboardProcessor.Mouse.Action);
1685: IKBD_AddKeyToKeyboardBuffer(0);
1686: IKBD_AddKeyToKeyboardBuffer(0);
1687: IKBD_AddKeyToKeyboardBuffer(0);
1688: IKBD_AddKeyToKeyboardBuffer(0);
1689: IKBD_AddKeyToKeyboardBuffer(0);
1690: }
1691:
1692:
1693: /*-----------------------------------------------------------------------*/
1694: /**
1695: * REPORT MOUSE MODE
1696: *
1697: * 0x88 or 0x89 or 0x8A
1698: */
1699: static void IKBD_Cmd_ReportMouseMode(void)
1700: {
1.1.1.15 root 1701: LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_ReportMouseMode\n");
1.1.1.13 root 1702:
1703: IKBD_AddKeyToKeyboardBufferWithDelay(0xf6, 30000);
1704: switch (KeyboardProcessor.MouseMode)
1705: {
1706: case AUTOMODE_MOUSEREL:
1707: IKBD_AddKeyToKeyboardBuffer(8);
1708: IKBD_AddKeyToKeyboardBuffer(0);
1709: IKBD_AddKeyToKeyboardBuffer(0);
1710: IKBD_AddKeyToKeyboardBuffer(0);
1711: IKBD_AddKeyToKeyboardBuffer(0);
1712: IKBD_AddKeyToKeyboardBuffer(0);
1713: IKBD_AddKeyToKeyboardBuffer(0);
1714: break;
1715: case AUTOMODE_MOUSEABS:
1716: IKBD_AddKeyToKeyboardBuffer(9);
1717: IKBD_AddKeyToKeyboardBuffer(KeyboardProcessor.Abs.MaxX >> 8);
1718: IKBD_AddKeyToKeyboardBuffer(KeyboardProcessor.Abs.MaxX);
1719: IKBD_AddKeyToKeyboardBuffer(KeyboardProcessor.Abs.MaxY >> 8);
1720: IKBD_AddKeyToKeyboardBuffer(KeyboardProcessor.Abs.MaxY);
1721: IKBD_AddKeyToKeyboardBuffer(0);
1722: IKBD_AddKeyToKeyboardBuffer(0);
1723: break;
1724: case AUTOMODE_MOUSECURSOR:
1725: IKBD_AddKeyToKeyboardBuffer(10);
1726: IKBD_AddKeyToKeyboardBuffer(KeyboardProcessor.Mouse.KeyCodeDeltaX);
1727: IKBD_AddKeyToKeyboardBuffer(KeyboardProcessor.Mouse.KeyCodeDeltaY);
1728: IKBD_AddKeyToKeyboardBuffer(0);
1729: IKBD_AddKeyToKeyboardBuffer(0);
1730: IKBD_AddKeyToKeyboardBuffer(0);
1731: IKBD_AddKeyToKeyboardBuffer(0);
1732: break;
1733: }
1734: }
1735:
1736:
1737: /*-----------------------------------------------------------------------*/
1738: /**
1739: * REPORT MOUSE THRESHOLD
1740: *
1741: * 0x8B
1742: */
1743: static void IKBD_Cmd_ReportMouseThreshold(void)
1744: {
1.1.1.15 root 1745: LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_ReportMouseThreshold\n");
1.1.1.13 root 1746:
1747: IKBD_AddKeyToKeyboardBufferWithDelay(0xf6, 30000);
1748: IKBD_AddKeyToKeyboardBuffer(0x0B);
1749: IKBD_AddKeyToKeyboardBuffer(KeyboardProcessor.Mouse.XThreshold);
1750: IKBD_AddKeyToKeyboardBuffer(KeyboardProcessor.Mouse.YThreshold);
1751: IKBD_AddKeyToKeyboardBuffer(0);
1752: IKBD_AddKeyToKeyboardBuffer(0);
1753: IKBD_AddKeyToKeyboardBuffer(0);
1754: IKBD_AddKeyToKeyboardBuffer(0);
1755: }
1756:
1757:
1758: /*-----------------------------------------------------------------------*/
1759: /**
1760: * REPORT MOUSE SCALE
1761: *
1762: * 0x8C
1763: */
1764: static void IKBD_Cmd_ReportMouseScale(void)
1765: {
1.1.1.15 root 1766: LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_ReportMouseScale\n");
1.1.1.13 root 1767:
1768: IKBD_AddKeyToKeyboardBufferWithDelay(0xf6, 30000);
1769: IKBD_AddKeyToKeyboardBuffer(0x0C);
1770: IKBD_AddKeyToKeyboardBuffer(KeyboardProcessor.Mouse.XScale);
1771: IKBD_AddKeyToKeyboardBuffer(KeyboardProcessor.Mouse.YScale);
1772: IKBD_AddKeyToKeyboardBuffer(0);
1773: IKBD_AddKeyToKeyboardBuffer(0);
1774: IKBD_AddKeyToKeyboardBuffer(0);
1775: IKBD_AddKeyToKeyboardBuffer(0);
1776: }
1777:
1778:
1779: /*-----------------------------------------------------------------------*/
1780: /**
1781: * REPORT MOUSE VERTICAL COORDINATES
1782: *
1783: * 0x8F and 0x90
1784: */
1785: static void IKBD_Cmd_ReportMouseVertical(void)
1786: {
1.1.1.15 root 1787: LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_ReportMouseVertical\n");
1.1.1.13 root 1788:
1789: IKBD_AddKeyToKeyboardBufferWithDelay(0xf6, 30000);
1790: if (KeyboardProcessor.Mouse.YAxis == -1)
1791: IKBD_AddKeyToKeyboardBuffer(0x0F);
1792: else
1793: IKBD_AddKeyToKeyboardBuffer(0x10);
1794: IKBD_AddKeyToKeyboardBuffer(0);
1795: IKBD_AddKeyToKeyboardBuffer(0);
1796: IKBD_AddKeyToKeyboardBuffer(0);
1797: IKBD_AddKeyToKeyboardBuffer(0);
1798: IKBD_AddKeyToKeyboardBuffer(0);
1799: IKBD_AddKeyToKeyboardBuffer(0);
1800: }
1801:
1802:
1803: /*-----------------------------------------------------------------------*/
1804: /**
1805: * REPORT MOUSE AVAILABILITY
1806: *
1807: * 0x92
1808: */
1809: static void IKBD_Cmd_ReportMouseAvailability(void)
1810: {
1.1.1.15 root 1811: LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_ReportMouseAvailability\n");
1.1.1.13 root 1812:
1813: IKBD_AddKeyToKeyboardBufferWithDelay(0xf6, 30000);
1814: if (KeyboardProcessor.MouseMode == AUTOMODE_OFF)
1815: IKBD_AddKeyToKeyboardBuffer(0x12);
1816: else
1817: IKBD_AddKeyToKeyboardBuffer(0x00);
1818: IKBD_AddKeyToKeyboardBuffer(0);
1819: IKBD_AddKeyToKeyboardBuffer(0);
1820: IKBD_AddKeyToKeyboardBuffer(0);
1821: IKBD_AddKeyToKeyboardBuffer(0);
1822: IKBD_AddKeyToKeyboardBuffer(0);
1823: IKBD_AddKeyToKeyboardBuffer(0);
1824: }
1825:
1826:
1827: /*-----------------------------------------------------------------------*/
1828: /**
1829: * REPORT JOYSTICK MODE
1830: *
1831: * 0x94 or 0x95 or 0x99
1832: */
1833: static void IKBD_Cmd_ReportJoystickMode(void)
1.1 root 1834: {
1.1.1.15 root 1835: LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_ReportJoystickMode\n");
1.1.1.13 root 1836:
1837: IKBD_AddKeyToKeyboardBufferWithDelay(0xf6, 30000);
1838: switch (KeyboardProcessor.JoystickMode)
1839: {
1840: case AUTOMODE_JOYSTICK:
1841: IKBD_AddKeyToKeyboardBuffer(0x14);
1842: IKBD_AddKeyToKeyboardBuffer(0);
1843: IKBD_AddKeyToKeyboardBuffer(0);
1844: IKBD_AddKeyToKeyboardBuffer(0);
1845: IKBD_AddKeyToKeyboardBuffer(0);
1846: IKBD_AddKeyToKeyboardBuffer(0);
1847: IKBD_AddKeyToKeyboardBuffer(0);
1848: break;
1849: default: /* TODO: Joystick keycodes mode not supported yet! */
1850: IKBD_AddKeyToKeyboardBuffer(0x15);
1851: IKBD_AddKeyToKeyboardBuffer(0);
1852: IKBD_AddKeyToKeyboardBuffer(0);
1853: IKBD_AddKeyToKeyboardBuffer(0);
1854: IKBD_AddKeyToKeyboardBuffer(0);
1855: IKBD_AddKeyToKeyboardBuffer(0);
1856: IKBD_AddKeyToKeyboardBuffer(0);
1857: break;
1858: }
1859: }
1860:
1861:
1862: /*-----------------------------------------------------------------------*/
1863: /**
1864: * REPORT JOYSTICK AVAILABILITY
1865: *
1866: * 0x9A
1867: */
1868: static void IKBD_Cmd_ReportJoystickAvailability(void)
1869: {
1.1.1.15 root 1870: LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_ReportJoystickAvailability\n");
1.1.1.13 root 1871:
1872: IKBD_AddKeyToKeyboardBufferWithDelay(0xf6, 30000);
1873: if (KeyboardProcessor.JoystickMode == AUTOMODE_OFF)
1874: IKBD_AddKeyToKeyboardBuffer(0x1A);
1875: else
1876: IKBD_AddKeyToKeyboardBuffer(0x00);
1877: IKBD_AddKeyToKeyboardBuffer(0);
1878: IKBD_AddKeyToKeyboardBuffer(0);
1879: IKBD_AddKeyToKeyboardBuffer(0);
1880: IKBD_AddKeyToKeyboardBuffer(0);
1881: IKBD_AddKeyToKeyboardBuffer(0);
1882: IKBD_AddKeyToKeyboardBuffer(0);
1.1 root 1883: }
1884:
1885:
1.1.1.2 root 1886: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1887: /**
1888: * Send data to keyboard processor via ACIA by writing to address 0xfffc02.
1889: * For our emulation we bypass the ACIA (I've yet to see anything check for this)
1890: * and add the byte directly into the keyboard input buffer.
1891: */
1.1.1.11 root 1892: static void IKBD_RunKeyboardCommand(Uint16 aciabyte)
1.1 root 1893: {
1.1.1.12 root 1894: int i=0;
1.1 root 1895:
1.1.1.12 root 1896: /* Write into our keyboard input buffer */
1897: Keyboard.InputBuffer[Keyboard.nBytesInInputBuffer++] = aciabyte;
1.1 root 1898:
1.1.1.12 root 1899: /* Now check bytes to see if we have a valid/in-valid command string set */
1900: while (KeyboardCommands[i].Command!=0xff)
1901: {
1902: /* Found command? */
1903: if (KeyboardCommands[i].Command==Keyboard.InputBuffer[0])
1904: {
1905: /* Is string complete, then can execute? */
1906: if (KeyboardCommands[i].NumParameters==Keyboard.nBytesInInputBuffer)
1907: {
1908: CALL_VAR(KeyboardCommands[i].pCallFunction);
1909: Keyboard.nBytesInInputBuffer = 0;
1910: }
1.1 root 1911:
1.1.1.12 root 1912: return;
1913: }
1.1.1.7 root 1914:
1.1.1.12 root 1915: i++;
1916: }
1.1 root 1917:
1.1.1.12 root 1918: /* Command not known, reset buffer(IKBD assumes a NOP) */
1919: Keyboard.nBytesInInputBuffer = 0;
1.1 root 1920: }
1921:
1.1.1.2 root 1922:
1923: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1924: /**
1925: * Send byte to our keyboard processor, and execute
1926: */
1.1.1.13 root 1927: static void IKBD_SendByteToKeyboardProcessor(Uint16 bl)
1.1 root 1928: {
1.1.1.13 root 1929: /* If IKBD is executing custom code, send the byte to the function handling this code */
1930: if ( IKBD_ExeMode && pIKBD_CustomCodeHandler_Write )
1931: {
1932: (*pIKBD_CustomCodeHandler_Write) ( (Uint8) bl );
1933: return;
1934: }
1935:
1936: if ( MemoryLoadNbBytesLeft == 0 ) /* No pending MemoryLoad command */
1937: IKBD_RunKeyboardCommand ( bl ); /* check for known commands */
1938:
1939: else /* MemoryLoad command is not finished yet */
1940: IKBD_LoadMemoryByte ( (Uint8) bl ); /* process bytes sent to the ikbd RAM */
1.1 root 1941: }
1942:
1.1.1.2 root 1943:
1944: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1945: /**
1946: * The byte stored in the ACIA 'ACIAByte' has been read by the CPU by reading from
1947: * address $fffc02. We clear the status flag and set the GPIP register to signal read.
1948: */
1.1.1.11 root 1949: Uint16 IKBD_GetByteFromACIA(void)
1.1 root 1950: {
1.1.1.12 root 1951: /* ACIA is now reset */
1952: ACIAStatusRegister &= ~(ACIA_STATUS_REGISTER__RX_BUFFER_FULL | ACIA_STATUS_REGISTER__INTERRUPT_REQUEST | ACIA_STATUS_REGISTER__OVERRUN_ERROR);
1.1 root 1953:
1.1.1.12 root 1954: /* GPIP I4 - General Purpose Pin Keyboard/MIDI interrupt */
1955: MFP_GPIP |= 0x10;
1956: return ACIAByte; /* Return byte from keyboard */
1.1 root 1957: }
1958:
1.1.1.2 root 1959:
1960: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1961: /**
1.1.1.17! root 1962: * This interrupt handler is used to simulate a correct number of CPU cycles
! 1963: * when sending a byte from the ACIA to the ikdb or when receiving a byte
! 1964: * from the ikbd to the ACIA (because ACIA serial transfers are running
! 1965: * at 7812.5 bps, bytes should not be available immediatly as it would break
! 1966: * some programs)
! 1967: * - Byte received in the ACIA from the keyboard processor : store byte for read
! 1968: * from $fffc02 and schedule MFP interrupt to be triggered just a few cycles after.
! 1969: * - Byte sent from the ACIA to the keyboard processor : pass the byte to
! 1970: * IKBD_SendByteToKeyboardProcessor and set TX_BUFFER_EMPTY in status register.
1.1.1.12 root 1971: */
1.1 root 1972: void IKBD_InterruptHandler_ACIA(void)
1973: {
1.1.1.12 root 1974: /* Remove this interrupt from list and re-order */
1.1.1.16 root 1975: CycInt_AcknowledgeInterrupt();
1.1 root 1976:
1.1.1.17! root 1977: if ( bByteInTransitToACIA )
! 1978: {
! 1979: /* Copy keyboard byte, ready for read from $fffc02 */
! 1980: ACIAByte = Keyboard.Buffer[Keyboard.BufferHead++];
! 1981: Keyboard.BufferHead &= KEYBOARD_BUFFER_MASK;
! 1982:
! 1983: /* Did we get an over-run? Ie byte has arrived from keyboard processor BEFORE CPU has read previous one from ACIA */
! 1984: if (ACIAStatusRegister&ACIA_STATUS_REGISTER__RX_BUFFER_FULL)
! 1985: ACIAStatusRegister |= ACIA_STATUS_REGISTER__OVERRUN_ERROR; /* Set over-run */
! 1986:
! 1987: /* ACIA buffer is now full */
! 1988: ACIAStatusRegister |= ACIA_STATUS_REGISTER__RX_BUFFER_FULL;
! 1989: /* Signal interrupt pending */
! 1990: ACIAStatusRegister |= ACIA_STATUS_REGISTER__INTERRUPT_REQUEST;
! 1991:
! 1992: /* GPIP I4 - General Purpose Pin Keyboard/MIDI interrupt */
! 1993: /* NOTE: GPIP will remain low(0) until keyboard data is read from $fffc02. */
! 1994: MFP_GPIP &= ~0x10;
! 1995:
! 1996: /* There seems to be a small gap on a real ST between the point in time
! 1997: * the ACIA_STATUS_REGISTER__RX_BUFFER_FULL bit is set and the MFP
! 1998: * interrupt is triggered - for example the "V8 music system" demo
! 1999: * depends on this behaviour. To emulate this, we simply start another
! 2000: * Int which triggers the MFP interrupt later: */
! 2001: CycInt_AddRelativeInterrupt(18, INT_CPU_CYCLE, INTERRUPT_IKBD_MFP);
! 2002: }
! 2003:
! 2004: if ( bByteInTransitFromACIA )
! 2005: {
! 2006: IKBD_SendByteToKeyboardProcessor(ACIATxDataRegister); /* Pass the byte to the keyboard processor */
! 2007: ACIAStatusRegister |= ACIA_STATUS_REGISTER__TX_BUFFER_EMPTY; /* TX buffer is now empty */
! 2008: bByteInTransitFromACIA = false; /* ready to send another byte */
! 2009: }
1.1.1.13 root 2010: }
2011:
2012:
2013: /**
2014: * Start MFP interrupt after byte has been received in the ACIA.
2015: */
2016: void IKBD_InterruptHandler_MFP(void)
2017: {
2018: /* Remove this interrupt from list and re-order */
1.1.1.16 root 2019: CycInt_AcknowledgeInterrupt();
1.1.1.13 root 2020:
1.1.1.12 root 2021: /* Acknowledge in MFP circuit, pass bit,enable,pending */
2022: MFP_InputOnChannel(MFP_ACIA_BIT, MFP_IERB, &MFP_IPRB);
2023:
2024: /* Clear flag so can allow another byte to be sent along serial line */
1.1.1.15 root 2025: bByteInTransitToACIA = false;
1.1.1.13 root 2026:
1.1.1.12 root 2027: /* If another key is waiting, start sending from keyboard processor now */
2028: if (Keyboard.BufferHead!=Keyboard.BufferTail)
1.1.1.13 root 2029: IKBD_SendByteToACIA(ACIA_CYCLES);
1.1 root 2030: }
2031:
2032:
1.1.1.2 root 2033: /*-----------------------------------------------------------------------*/
1.1.1.12 root 2034: /**
2035: * Send a byte from the keyboard buffer to the ACIA. On a real ST this takes some time to send
2036: * so we must be as accurate in the timing as possible - bytes do not appear to the 68000 instantly!
2037: * We do this via an internal interrupt - neat!
2038: */
1.1.1.13 root 2039: static void IKBD_SendByteToACIA(int nAciaCycles)
1.1 root 2040: {
1.1.1.13 root 2041: /* Transmit byte from keyboard processor to ACIA.
2042: * This takes approx ACIA_CYCLES CPU clock cycles to complete */
1.1.1.12 root 2043: if (!bByteInTransitToACIA)
2044: {
2045: /* Send byte to ACIA */
1.1.1.16 root 2046: CycInt_AddRelativeInterrupt(nAciaCycles, INT_CPU_CYCLE, INTERRUPT_IKBD_ACIA);
1.1.1.12 root 2047: /* Set flag so only transmit one byte at a time */
1.1.1.15 root 2048: bByteInTransitToACIA = true;
1.1.1.12 root 2049: }
1.1 root 2050: }
2051:
1.1.1.2 root 2052:
2053: /*-----------------------------------------------------------------------*/
1.1.1.12 root 2054: /**
1.1.1.13 root 2055: * Add character to our internal keyboard buffer, with default ACIA_CYCLES
2056: * timing.
2057: */
2058: static void IKBD_AddKeyToKeyboardBuffer(Uint8 Data)
2059: {
2060: if ( IKBD_ExeMode ) /* if IKBD is executing custom code, don't add */
2061: return; /* anything to the buffer */
2062:
2063: IKBD_AddKeyToKeyboardBuffer_Real(Data, ACIA_CYCLES);
2064: }
2065:
2066:
2067: /**
2068: * Add character to our internal keyboard buffer, with additional delay.
2069: * This is required for some keyboard commands like ReadAbsMousePos (0x0d)
2070: * where it takes a little bit longer than the typical ACIA_CYCLES until
2071: * the first byte arrives from the IKBD (for example the "Unlimited bobs"
2072: * screen in the Dragonnels demo depends on this behaviour.
2073: */
2074: static void IKBD_AddKeyToKeyboardBufferWithDelay(Uint8 Data, int nAciaCycles)
2075: {
2076: if (IKBD_ExeMode) /* if IKBD is executing custom code, */
2077: return; /* don't add anything to the buffer */
2078:
2079: IKBD_AddKeyToKeyboardBuffer_Real(Data, nAciaCycles);
2080: }
2081:
2082:
2083: /**
2084: * Add character to our internal keyboard buffer. These bytes are then sent
2085: * one at a time to the ACIA. This is done via a delay to mimick the STs
2086: * internal workings, as this is needed for games such as Carrier Command.
1.1.1.12 root 2087: */
1.1.1.13 root 2088: static void IKBD_AddKeyToKeyboardBuffer_Real(Uint8 Data, int nAciaCycles)
1.1 root 2089: {
1.1.1.12 root 2090: /* Is keyboard initialised yet? Ignore any bytes until it is */
2091: if (!KeyboardProcessor.bReset)
2092: return;
2093:
2094: /* Check we have space to add byte */
2095: if (Keyboard.BufferHead!=((Keyboard.BufferTail+1)&KEYBOARD_BUFFER_MASK))
2096: {
2097: /* Add byte to our buffer */
2098: Keyboard.Buffer[Keyboard.BufferTail++] = Data;
2099: Keyboard.BufferTail &= KEYBOARD_BUFFER_MASK;
2100:
2101: /* We have character ready to transmit from the ACIA - see if can send it now */
1.1.1.13 root 2102: IKBD_SendByteToACIA(nAciaCycles);
1.1.1.12 root 2103: }
1.1.1.17! root 2104: else
! 2105: {
! 2106: Log_Printf(LOG_ERROR, "IKBD buffer is full!\n");
! 2107: }
1.1 root 2108: }
2109:
1.1.1.2 root 2110:
2111: /*-----------------------------------------------------------------------*/
1.1.1.12 root 2112: /**
2113: * When press/release key under host OS, execute this function.
2114: */
1.1.1.13 root 2115: void IKBD_PressSTKey(Uint8 ScanCode, bool bPress)
1.1 root 2116: {
1.1.1.13 root 2117: /* Store the state of each ST scancode : 1=pressed 0=released */
2118: if ( bPress ) ScanCodeState[ ScanCode & 0x7f ] = 1;
2119: else ScanCodeState[ ScanCode & 0x7f ] = 0;
2120:
1.1.1.12 root 2121: if (!bPress)
2122: ScanCode |= 0x80; /* Set top bit if released key */
2123: IKBD_AddKeyToKeyboardBuffer(ScanCode); /* And send to keyboard processor */
1.1 root 2124: }
1.1.1.10 root 2125:
2126:
2127: /*-----------------------------------------------------------------------*/
1.1.1.12 root 2128: /**
2129: * Handle read from keyboard control ACIA register (0xfffc00)
2130: */
1.1.1.10 root 2131: void IKBD_KeyboardControl_ReadByte(void)
2132: {
1.1.1.11 root 2133: /* ACIA registers need wait states - but the value seems to vary in certain cases */
2134: M68000_WaitState(8);
2135:
1.1.1.13 root 2136: IoMem[0xfffc00] = ACIAStatusRegister;
1.1.1.12 root 2137:
1.1.1.15 root 2138: if (LOG_TRACE_LEVEL(TRACE_IKBD_ACIA))
1.1.1.12 root 2139: {
1.1.1.15 root 2140: int FrameCycles, HblCounterVideo, LineCycles;
2141: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
2142: LOG_TRACE_PRINT("ikbd read fffc00 ctrl=0x%x video_cyc=%d %d@%d pc=%x instr_cycle %d\n",
2143: IoMem[0xfffc00], FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC(), CurrentInstrCycles);
1.1.1.12 root 2144: }
1.1.1.10 root 2145: }
2146:
2147: /*-----------------------------------------------------------------------*/
1.1.1.12 root 2148: /**
2149: * Handle read from keyboard data ACIA register (0xfffc02)
2150: */
1.1.1.10 root 2151: void IKBD_KeyboardData_ReadByte(void)
2152: {
1.1.1.11 root 2153: /* ACIA registers need wait states - but the value seems to vary in certain cases */
2154: M68000_WaitState(8);
2155:
1.1.1.13 root 2156: /* If IKBD is executing custom code, call the function to update the byte read in $fffc02 */
2157: if ( IKBD_ExeMode && pIKBD_CustomCodeHandler_Read )
2158: {
2159: (*pIKBD_CustomCodeHandler_Read) ();
2160: }
2161:
2162:
1.1.1.10 root 2163: IoMem[0xfffc02] = IKBD_GetByteFromACIA(); /* Return our byte from keyboard processor */
1.1.1.12 root 2164:
1.1.1.15 root 2165: if (LOG_TRACE_LEVEL(TRACE_IKBD_ACIA))
1.1.1.12 root 2166: {
1.1.1.15 root 2167: int FrameCycles, HblCounterVideo, LineCycles;
2168: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
2169: LOG_TRACE_PRINT("ikbd read fffc02 data=0x%x video_cyc=%d %d@%d pc=%x instr_cycle %d\n",
2170: IoMem[0xfffc02], FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC(), CurrentInstrCycles);
1.1.1.12 root 2171: }
1.1.1.10 root 2172: }
2173:
2174:
2175: /*-----------------------------------------------------------------------*/
1.1.1.12 root 2176: /**
2177: * Handle write to keyboard control ACIA register (0xfffc00)
2178: */
1.1.1.10 root 2179: void IKBD_KeyboardControl_WriteByte(void)
2180: {
1.1.1.11 root 2181: /* ACIA registers need wait states - but the value seems to vary in certain cases */
2182: M68000_WaitState(8);
2183:
1.1.1.15 root 2184: if (LOG_TRACE_LEVEL(TRACE_IKBD_ACIA))
1.1.1.12 root 2185: {
1.1.1.15 root 2186: int FrameCycles, HblCounterVideo, LineCycles;
2187: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
2188: LOG_TRACE_PRINT("ikbd write fffc00 ctrl=0x%x video_cyc=%d %d@%d pc=%x instr_cycle %d\n",
2189: IoMem[0xfffc00], FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC(), CurrentInstrCycles);
1.1.1.12 root 2190: }
2191:
2192: /* [NP] We only handle reset of the ACIA */
2193: if ( ( IoMem[0xfffc00] & 0x03 ) == 0x03 )
2194: ACIA_Reset();
2195:
1.1.1.10 root 2196: /* Nothing... */
2197: }
2198:
2199: /*-----------------------------------------------------------------------*/
1.1.1.12 root 2200: /**
2201: * Handle write to keyboard data ACIA register (0xfffc02)
2202: */
1.1.1.10 root 2203: void IKBD_KeyboardData_WriteByte(void)
2204: {
1.1.1.11 root 2205: /* ACIA registers need wait states - but the value seems to vary in certain cases */
2206: M68000_WaitState(8);
2207:
1.1.1.15 root 2208: if (LOG_TRACE_LEVEL(TRACE_IKBD_ACIA))
1.1.1.12 root 2209: {
1.1.1.15 root 2210: int FrameCycles, HblCounterVideo, LineCycles;
2211: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
2212: LOG_TRACE_PRINT("ikbd write fffc02 data=0x%x video_cyc=%d %d@%d pc=%x instr_cycle %d\n",
2213: IoMem[0xfffc02], FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC(), CurrentInstrCycles);
1.1.1.12 root 2214: }
2215:
1.1.1.13 root 2216:
1.1.1.17! root 2217: if ( bByteInTransitFromACIA == false ) /* we're not already transfering a byte to the ikbd */
! 2218: {
! 2219: // IKBD_SendByteToKeyboardProcessor(IoMem[0xfffc02]); /* Pass our byte to the keyboard processor */
! 2220: ACIATxDataRegister = IoMem[0xfffc02]; /* store the byte that we want to send to the ikbd */
! 2221:
! 2222: /* Delay the processing of the byte in IKBD_InterruptHandler_ACIA */
! 2223: /* The delay doesn't seem to be constant, so we add a small random number of max 40 cycles */
! 2224: /* (else some programs get stuck in an endless loop ('Pandemonium Demos' by Chaos) */
! 2225:
! 2226: // [NP] FIXME 2011/05/20 : if we use a delay of ACIA_CYCLES=7200, tos 1.02 and 1.04 are showing
! 2227: // a bug where addr $6122/$6124 are overwritten by the stack, preventing the desktop
! 2228: // to be restored at the correct resolution !
! 2229: // For now, use a delay of 1000 cycles ; need to do complete measures on a real ST for this
! 2230: //CycInt_AddRelativeInterrupt(ACIA_CYCLES+rand()%40, INT_CPU_CYCLE, INTERRUPT_IKBD_ACIA);
! 2231: // delay cycles <=1560 ok, > 1570 bad for tos 1.02/1.04
! 2232: CycInt_AddRelativeInterrupt(1000+rand()%40, INT_CPU_CYCLE, INTERRUPT_IKBD_ACIA);
! 2233:
! 2234: /* Some games like USS John Young / FOF54 actually check whether the
! 2235: * transmit-buffer-empty bit is really cleared after writing a data
! 2236: * byte to the IKBD, so we have to temporarily clear this bit, too,
! 2237: * although the byte is send immediately to our virtual IKBD. */
! 2238: ACIAStatusRegister &= ~ACIA_STATUS_REGISTER__TX_BUFFER_EMPTY; /* TX buffer is full */
! 2239:
! 2240: bByteInTransitFromACIA = true;
! 2241: }
1.1.1.10 root 2242: }
1.1.1.13 root 2243:
2244:
2245: /*************************************************************************/
2246: /**
2247: * Below part is for emulating custom 6301 program sent to the ikbd RAM
2248: * Specific read/write functions for each demo/game should be added here,
2249: * after being defined in the CustomCodeDefinitions[] array.
2250: *
2251: * The 6301 has 256 bytes of RAM, but only 128 bytes are available to
2252: * put a program (from $80 to $ff).
2253: *
2254: * Executing a program in the 6301 is a 2 steps process :
2255: * 1) a very small program is sent to the RAM using the 0x20 command.
2256: * This is often loaded at address $b0.
2257: * This program will stop interruptions in the 6301 and will accept
2258: * a second small program that will relocate itself to $80.
2259: * 2) the relocated program at address $80 will accept a third (main)
2260: * program and will execute it once reception is complete.
2261: *
2262: * Writes during step 1 are handled with the ExeBootHandler matching the
2263: * LoadMemory CRC.
2264: * ExeBootHandler will compute a 2nd CRC for the writes corresponding to
2265: * the 2nd and 3rd programs sent to the 6301's RAM.
2266: *
2267: * If a match is found for this 2nd CRC, we will override default ikbd's behaviour
2268: * for reading/writing to $fffc02 with ExeMainHandler_Read / ExeMainHandler_Write
2269: * (once the Execute command 0x22 is received).
2270: *
1.1.1.15 root 2271: * When using custom program (ExeMode==true), we must ignore all keyboard/mouse/joystick
1.1.1.13 root 2272: * events sent to IKBD_AddKeyToKeyboardBuffer. Only our functions can add bytes
2273: * to the keyboard buffer.
2274: *
2275: * To exit 6301's execution mode, we can use the 68000 'reset' instruction.
2276: * Some 6301's programs also handle a write to $fffc02 as an exit signal.
2277: */
2278:
2279:
2280: /*-----------------------------------------------------------------------*/
2281: /**
2282: * Handle writes to $fffc02 when loading bytes in the ikbd RAM.
2283: * We compute a CRC of the bytes that are sent until MemoryLoadNbBytesLeft
2284: * reaches 0.
2285: * When all bytes are loaded, we look for a matching CRC ; if found, we
2286: * use the ExeBootHandler defined for this CRC to process the next writes
2287: * that will occur in $fffc02.
2288: * LoadMemory is often used to load a small boot code into the 6301's RAM.
2289: * This small program will be executed later using the command 0x22.
2290: */
2291:
2292: static void IKBD_LoadMemoryByte ( Uint8 aciabyte )
2293: {
2294: unsigned int i;
2295:
2296: crc32_add_byte ( &MemoryLoadCrc , aciabyte );
2297:
2298: MemoryLoadNbBytesLeft--;
2299: if ( MemoryLoadNbBytesLeft == 0 ) /* all bytes were received */
2300: {
2301: /* Search for a match amongst the known custom routines */
2302: for ( i = 0 ; i < sizeof ( CustomCodeDefinitions ) / sizeof ( CustomCodeDefinitions[0] ) ; i++ )
2303: if ( CustomCodeDefinitions[ i ].LoadMemCrc == MemoryLoadCrc )
2304: break;
2305:
2306: if ( i < sizeof ( CustomCodeDefinitions ) / sizeof ( CustomCodeDefinitions[0] ) ) /* found */
2307: {
1.1.1.15 root 2308: LOG_TRACE(TRACE_IKBD_EXEC, "ikbd loadmemory %d bytes crc=0x%x matches <%s>\n",
2309: MemoryLoadNbBytesTotal, MemoryLoadCrc, CustomCodeDefinitions[ i ].Name);
1.1.1.13 root 2310:
2311: crc32_reset ( &MemoryLoadCrc );
2312: MemoryExeNbBytes = 0;
2313: pIKBD_CustomCodeHandler_Read = NULL;
2314: pIKBD_CustomCodeHandler_Write = CustomCodeDefinitions[ i ].ExeBootHandler;
2315: }
2316:
2317: else /* unknown code uploaded to ikbd RAM */
2318: {
1.1.1.15 root 2319: LOG_TRACE(TRACE_IKBD_EXEC, "ikbd loadmemory %d bytes crc=0x%x : unknown code\n",
2320: MemoryLoadNbBytesTotal, MemoryLoadCrc);
1.1.1.13 root 2321:
2322: pIKBD_CustomCodeHandler_Read = NULL;
2323: pIKBD_CustomCodeHandler_Write = NULL;
2324: }
2325: }
2326: }
2327:
2328:
2329:
2330: /*-----------------------------------------------------------------------*/
2331: /**
2332: * Handle writes to $fffc02 when executing custom code in the ikbd RAM.
2333: * This is used to send the small ikdb program that will handle keyboard/mouse/joystick
2334: * input.
2335: * We compute a CRC of the bytes that are sent until we found a match
2336: * with a known custom ikbd program.
2337: */
2338:
2339: static void IKBD_CustomCodeHandler_CommonBoot ( Uint8 aciabyte )
2340: {
2341: unsigned int i;
2342:
2343: crc32_add_byte ( &MemoryLoadCrc , aciabyte );
2344: MemoryExeNbBytes++;
2345:
1.1.1.15 root 2346: LOG_TRACE(TRACE_IKBD_EXEC, "ikbd custom exe common boot write 0x%02x count %d crc=0x%x\n",
2347: aciabyte, MemoryExeNbBytes, MemoryLoadCrc);
1.1.1.13 root 2348:
2349: /* Search for a match amongst the known custom routines */
2350: for ( i = 0 ; i < sizeof ( CustomCodeDefinitions ) / sizeof ( CustomCodeDefinitions[0] ) ; i++ )
2351: if ( ( CustomCodeDefinitions[ i ].MainProgNbBytes == MemoryExeNbBytes )
2352: && ( CustomCodeDefinitions[ i ].MainProgCrc == MemoryLoadCrc ) )
2353: break;
2354:
2355: if ( i < sizeof ( CustomCodeDefinitions ) / sizeof ( CustomCodeDefinitions[0] ) ) /* found */
2356: {
1.1.1.15 root 2357: LOG_TRACE(TRACE_IKBD_EXEC, "ikbd custom exe common boot, uploaded code matches <%s>\n",
2358: CustomCodeDefinitions[i].Name);
1.1.1.13 root 2359:
2360: pIKBD_CustomCodeHandler_Read = CustomCodeDefinitions[ i ].ExeMainHandler_Read;
2361: pIKBD_CustomCodeHandler_Write = CustomCodeDefinitions[ i ].ExeMainHandler_Write;
2362:
2363: Keyboard.BufferHead = Keyboard.BufferTail = 0; /* flush all queued bytes that would be read in $fffc02 */
2364: (*pIKBD_CustomCodeHandler_Read) (); /* initialize ACIAByte */
2365: }
2366:
2367: /* If not found, we keep on accumulating bytes until we find a matching crc */
2368: }
2369:
2370:
2371:
2372: /*----------------------------------------------------------------------*/
2373: /* Froggies Over The Fence menu. */
2374: /* Returns 2 bytes with the mouse position, keyboard can be used too. */
2375: /* Writing 0xff to $fffc02 will cause the 6301 to exit custom exe mode. */
2376: /*----------------------------------------------------------------------*/
2377:
2378: static void IKBD_CustomCodeHandler_FroggiesMenu_Read ( void )
2379: {
2380: Uint8 res1 = 0;
2381: Uint8 res2 = 0;
2382:
2383: if ( KeyboardProcessor.Mouse.DeltaX < 0 ) res1 = 0x7a; /* mouse left */
2384: if ( KeyboardProcessor.Mouse.DeltaX > 0 ) res1 = 0x06; /* mouse right */
2385: if ( KeyboardProcessor.Mouse.DeltaY < 0 ) res2 = 0x7a; /* mouse up */
2386: if ( KeyboardProcessor.Mouse.DeltaY > 0 ) res2 = 0x06; /* mouse down */
2387: if ( Keyboard.bLButtonDown & BUTTON_MOUSE ) res1 |= 0x80; /* left mouse button */
2388:
2389: if ( ScanCodeState[ 0x4b ] ) res1 |= 0x7a; /* left */
2390: if ( ScanCodeState[ 0x4d ] ) res1 |= 0x06; /* right */
2391: if ( ScanCodeState[ 0x48 ] ) res2 |= 0x7a; /* up */
2392: if ( ScanCodeState[ 0x50 ] ) res2 |= 0x06; /* down */
2393: if ( ScanCodeState[ 0x70 ] ) res1 |= 0x80; /* keypad 0 */
2394:
2395: IKBD_AddKeyToKeyboardBuffer_Real(res1, ACIA_CYCLES);
2396: IKBD_AddKeyToKeyboardBuffer_Real(res2, ACIA_CYCLES);
2397: }
2398:
2399: static void IKBD_CustomCodeHandler_FroggiesMenu_Write ( Uint8 aciabyte )
2400: {
2401: /* When writing 0xff to $fffc02, Froggies ikbd's program will terminate itself */
2402: /* and leave Execution mode */
2403: if ( aciabyte == 0xff )
2404: IKBD_Reset_ExeMode ();
2405: }
2406:
2407:
2408:
2409: /*----------------------------------------------------------------------*/
2410: /* Transbeauce II menu. */
2411: /* Returns 1 byte with the joystick position, keyboard can be used too. */
2412: /*----------------------------------------------------------------------*/
2413:
2414: static void IKBD_CustomCodeHandler_Transbeauce2Menu_Read ( void )
2415: {
2416: Uint8 res = 0;
2417:
2418: /* keyboard emulation */
2419: if ( ScanCodeState[ 0x48 ] ) res |= 0x01; /* up */
2420: if ( ScanCodeState[ 0x50 ] ) res |= 0x02; /* down */
2421: if ( ScanCodeState[ 0x4b ] ) res |= 0x04; /* left */
2422: if ( ScanCodeState[ 0x4d ] ) res |= 0x08; /* right */
2423: if ( ScanCodeState[ 0x62 ] ) res |= 0x40; /* help */
2424: if ( ScanCodeState[ 0x39 ] ) res |= 0x80; /* space */
2425:
2426: /* joystick emulation (bit mapping is same as cursor above, with bit 7 = fire button */
2427: res |= ( Joy_GetStickData(1) & 0x8f ) ; /* keep bits 0-3 and 7 */
2428:
2429: IKBD_AddKeyToKeyboardBuffer_Real(res, ACIA_CYCLES);
2430: }
2431:
2432: static void IKBD_CustomCodeHandler_Transbeauce2Menu_Write ( Uint8 aciabyte )
2433: {
2434: /* Ignore write */
2435: }
2436:
2437:
2438:
2439: /*----------------------------------------------------------------------*/
2440: /* Dragonnels demo menu. */
2441: /* Returns 1 byte with the Y position of the mouse. */
2442: /*----------------------------------------------------------------------*/
2443:
2444: static void IKBD_CustomCodeHandler_DragonnelsMenu_Read ( void )
2445: {
2446: Uint8 res = 0;
2447:
2448: if ( KeyboardProcessor.Mouse.DeltaY < 0 ) res = 0xfc; /* mouse up */
2449: if ( KeyboardProcessor.Mouse.DeltaY > 0 ) res = 0x04; /* mouse down */
2450:
2451: if ( Keyboard.bLButtonDown & BUTTON_MOUSE ) res = 0x80; /* left mouse button */
2452:
2453: IKBD_AddKeyToKeyboardBuffer_Real(res, ACIA_CYCLES);
2454: }
2455:
2456: static void IKBD_CustomCodeHandler_DragonnelsMenu_Write ( Uint8 aciabyte )
2457: {
2458: /* Ignore write */
2459: }
2460:
1.1.1.17! root 2461:
! 2462:
! 2463: /*----------------------------------------------------------------------*/
! 2464: /* Chaos A.D. protection's decoder */
! 2465: /* This custom program reads bytes, decode them and send back the result*/
! 2466: /* to the 68000. */
! 2467: /* The program first returns $fe to indicate it's ready to receive the */
! 2468: /* encoded bytes. */
! 2469: /* The program then receives the 8 bytes used to decode the data and */
! 2470: /* store them in $f0 - $f7 (KeyBuffer is already initialized, so we */
! 2471: /* ignore those 8 bytes). */
! 2472: /* Then for any received byte a XOR is made with one of the byte in the */
! 2473: /* 8 bytes buffer, by incrementing an index in this buffer. */
! 2474: /* The decoded byte is written to addr $13 (TDR) to be received by ACIA */
! 2475: /*----------------------------------------------------------------------*/
! 2476:
! 2477: static void IKBD_CustomCodeHandler_ChaosAD_Read ( void )
! 2478: {
! 2479: static bool FirstCall = true;
! 2480:
! 2481: if ( FirstCall == true )
! 2482: IKBD_AddKeyToKeyboardBuffer_Real ( 0xfe , ACIA_CYCLES );
! 2483:
! 2484: FirstCall = false;
! 2485: }
! 2486:
! 2487: static void IKBD_CustomCodeHandler_ChaosAD_Write ( Uint8 aciabyte )
! 2488: {
! 2489: static int IgnoreNb = 8;
! 2490: Uint8 KeyBuffer[] = { 0xca , 0x0a , 0xbc , 0x00 , 0xde , 0xde , 0xfe , 0xca };
! 2491: static int Index = 0;
! 2492: static int Count = 0;
! 2493:
! 2494: /* We ignore the first 8 bytes we received (they're already in KeyBuffer) */
! 2495: if ( IgnoreNb > 0 )
! 2496: {
! 2497: IgnoreNb--;
! 2498: return;
! 2499: }
! 2500:
! 2501: if ( Count <= 6080 ) /* there're 6081 bytes to decode */
! 2502: {
! 2503: Count++;
! 2504:
! 2505: aciabyte ^= KeyBuffer[ Index ];
! 2506: Index++;
! 2507: Index &= 0x07;
! 2508:
! 2509: IKBD_AddKeyToKeyboardBuffer_Real ( aciabyte , ACIA_CYCLES );
! 2510: }
! 2511:
! 2512: else
! 2513: {
! 2514: /* When all bytes were decoded if 0x08 is written to $fffc02 */
! 2515: /* the program will terminate itself and leave Execution mode */
! 2516: if ( aciabyte == 0x08 )
! 2517: IKBD_Reset_ExeMode ();
! 2518: }
! 2519: }
! 2520:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.