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