|
|
1.1 root 1: /*
1.1.1.6 root 2: Hatari - ikbd.c
3:
1.1.1.20 root 4: This file is distributed under the GNU General Public License, version 2
5: or at your option any later version. Read the file gpl.txt for details.
1.1 root 6:
1.1.1.20 root 7: The keyboard processor(6301) handles any joystick/mouse/keyboard task
8: and sends bytes to the ACIA(6850).
9: The IKBD has a small ROM which is used to process various commands send
10: by the main CPU to the THE IKBD.
11: Due to lack of real HD6301 emulation, those commands are handled by
12: functionnaly equivalent code that tries to be as close as possible
13: to a real HD6301.
14:
15: For program using their own HD6301 code, we also use some custom
16: handlers to emulate the expected result.
1.1.1.12 root 17: */
1.1.1.20 root 18:
1.1.1.14 root 19: const char IKBD_fileid[] = "Hatari ikbd.c : " __DATE__ " " __TIME__;
1.1.1.12 root 20:
21: /* 2007/09/29 [NP] Use the new int.c to add interrupts with INT_CPU_CYCLE / INT_MFP_CYCLE. */
22: /* 2007/12/09 [NP] If reset is written to ACIA control register, we must call ACIA_Reset to reset */
23: /* RX/TX status. Reading the control register fffc00 just after a reset should */
24: /* return the value 0x02 (used in Transbeauce 2 demo loader). */
1.1.1.13 root 25: /* 2008/07/06 [NP] Add support for executing 8 bit code sent to the 6301 processor. */
26: /* Instead of implementing a full 6301 emulator, we compute a checksum for each */
27: /* program sent to the 6301 RAM. If the checksum is recognized, we call some */
28: /* functions to emulate the behaviour of the 6301 in that case. */
29: /* When the 6301 is in 'Execute' mode (command 0x22), we must stop the normal */
30: /* reporting of key/mouse/joystick and use our custom handlers for each read or */
31: /* write to $fffc02. */
32: /* After a reset command, returns $F1 after $F0 (needed by Dragonnels Demo). */
33: /* This fixes the Transbeauce 2 demo menu, the Dragonnels demo menu and the */
34: /* Froggies Over The Fence demo menu (yeah ! enjoy this master piece of demo !). */
1.1.1.17 root 35: /* 2011/05/11 [NP] Add proper support for emulating TX buffer empty/full in status register bit 1 */
36: /* when writing to $fffc02 (using an internal timer). */
37: /* 2011/07/14 [NP] Don't clear bytes in transit when ACIA_Reset is called ; if a byte is sent to */
38: /* the ikbd it should not be cancelled ? FIXME : this would need more tests on a */
39: /* real ST (fix Froggies Over The Fence's menu when selecting a demo). */
1.1.1.18 root 40: /* 2011/07/31 [NP] Don't clear bytes in transit in the ACIA when the IKBD is reset (fix Overdrive */
41: /* by Phalanx). */
42: /* 2011/12/27 [NP] When sending new bytes while a byte is already in transfer from ACIA to IKBD, */
43: /* don't restart the internal TX timer (fix 'Pandemonium Demos' Intro). */
44: /* eg : .loop : move.b d0,$fc02.w btst #1,$fc00.w beq.s .loop */
1.1.1.19 root 45: /* 2012/01/22 [NP] Enable both mouse and joystick reporting when commands 0x12 and 0x14 are */
46: /* received during the IKBD reset. */
47: /* 2012/02/26 [NP] Handle TX interrupt in the ACIA (eg by sending 0xb6 instead of 0x96 after */
48: /* resetting the ACIA) (fix the game 'Hades Nebula'). */
1.1.1.20 root 49: /* 2012/10/10 [NP] Use the new ACIA emulation in acia.c ; add support for the IKBD's SCI, which */
50: /* is similar to the ACIA, with fixed 8 data bits, 1 stop bit and no parity bit. */
51: /* 2012/12/23 [NP] Fix timings for the commands $16, $1C, $87-$9A. The first byte is returned */
52: /* between 'min' and 'max' cycles after receiving the full command. The delay */
53: /* is not fixed to simulate the slight variations measured on a real ST. */
54: /* 2012/12/24 [NP] Rewrite SetClock and ReadClock commands to behave like the real IKBD. */
55: /* Instead of using time()/localtime() to handle the clock, we now increment it */
56: /* on each VBL, taking care of the BCD data (overflows and such) like in the IKBD. */
57: /* (this new code is based on the HD6301 disassembly of the IKBD's ROM) */
58: /* 2013/01/02 [NP] - Use IKBD_OutputBuffer_CheckFreeCount to ensure there's enough room in the */
59: /* output buffer before sending an IKBD packet. If there's not enough bytes to */
60: /* transfer the whole packet, then the packet must be discarded. */
61: /* - Don't ignore a new RDR byte if the output buffer is not empty yet. The IKBD */
62: /* can handle new bytes asynchronously using some interrupt while still processing */
63: /* another command. New RDR is discarded only if the input buffer is full. */
64: /* 2013/01/13 [NP] For hardware and software reset, share the common code in IKBD_Boot_ROM(). */
1.1.1.21 root 65: /* 2014/07/06 [NP] Ignore command 0x13 IKBD_Cmd_StopKeyboardTransfer during ikbd's reset. This is */
66: /* required for the loader of 'Just Bugging' by ACF which sends 0x11 and 0x13 just */
67: /* after 0x80 0x01 (temporary fix, would need to be measured on a real STF to see */
68: /* if it's always ignored or just during a specific delay) */
1.1.1.23! root 69: /* 2015/10/10 [NP] When IKBD_Reset / IKBD_Boot_ROM are called, we should not restart the autosend */
! 70: /* handler INTERRUPT_IKBD_AUTOSEND if it's already set, else we can loose keyboard */
! 71: /* input if IKBD_Reset is called in a loop before any event could be processed */
! 72: /* (this could happen if a program called the 'RESET' instruction in a loop, then */
! 73: /* we lost the F12 key for example) (fix endless RESET when doing a warm reset */
! 74: /* (alt+r) during the 'Vodka Demo' by 'Equinox', only solution was to kill Hatari) */
1.1.1.6 root 75:
1.1 root 76:
77: #include "main.h"
1.1.1.23! root 78: #include "configuration.h"
1.1 root 79: #include "ikbd.h"
1.1.1.16 root 80: #include "cycInt.h"
1.1.1.10 root 81: #include "ioMem.h"
1.1 root 82: #include "joy.h"
83: #include "m68000.h"
84: #include "memorySnapShot.h"
85: #include "mfp.h"
1.1.1.17 root 86: #include "screen.h"
1.1 root 87: #include "video.h"
1.1.1.13 root 88: #include "utils.h"
1.1.1.20 root 89: #include "acia.h"
90: #include "clocks_timings.h"
1.1.1.10 root 91:
1.1 root 92:
93: #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 94: #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 95:
96: #define ABS_X_ONRESET 0 /* Initial XY for absolute mouse position after RESET command */
97: #define ABS_Y_ONRESET 0
98: #define ABS_MAX_X_ONRESET 320 /* Initial absolute mouse limits after RESET command */
99: #define ABS_MAY_Y_ONRESET 200 /* These values are never actually used as user MUST call 'IKBD_Cmd_AbsMouseMode' before ever using them */
100:
1.1.1.10 root 101: #define ABS_PREVBUTTONS (0x02|0x8) /* Don't report any buttons up on first call to 'IKBD_Cmd_ReadAbsMousePos' */
1.1 root 102:
1.1.1.20 root 103: #define IKBD_RESET_CYCLES 502000 /* Number of cycles (for a 68000 at 8 MHz) between sending the reset command and receiving $F1 */
104:
105: #define IKBD_ROM_VERSION 0xF1 /* On reset, the IKBD will return either 0xF0 or 0xF1, depending on the IKBD's ROM */
106: /* version. Only very early ST returned 0xF0, so we use 0xF1 which is the most common case.*/
107: /* Beside, some programs explicitly wait for 0xF1 after a reset (Dragonnels demo) */
108:
1.1 root 109:
110: /* Keyboard state */
111: KEYBOARD Keyboard;
112:
113: /* Keyboard processor */
114: KEYBOARD_PROCESSOR KeyboardProcessor; /* Keyboard processor details */
1.1.1.11 root 115:
116: /* Pattern of mouse button up/down in ST frames (run off a double-click message) */
1.1.1.17 root 117: static const Uint8 DoubleClickPattern[] =
1.1.1.12 root 118: {
119: BUTTON_MOUSE,BUTTON_MOUSE,BUTTON_MOUSE,BUTTON_MOUSE,
120: 0,0,0,0,BUTTON_MOUSE,BUTTON_MOUSE,BUTTON_MOUSE,BUTTON_MOUSE
121: };
1.1.1.6 root 122:
1.1.1.13 root 123: static bool bMouseDisabled, bJoystickDisabled;
124: static bool bDuringResetCriticalTime, bBothMouseAndJoy;
1.1.1.14 root 125: static bool bMouseEnabledDuringReset;
1.1 root 126:
1.1.1.19 root 127:
1.1.1.20 root 128:
1.1 root 129:
130: /*
1.1.1.20 root 131: HD6301 processor by Hitachi
132:
133: References :
134: - HD6301V1, HD63A01V1, HD63B01V1 CMOS MCU datasheet by Hitachi
135:
136: The HD6301 is connected to the ACIA through TX and RX pins.
137: Serial transfers are made with 8 bit word, 1 stop bit, no parity and 7812.5 baud
1.1 root 138:
1.1.1.20 root 139: The IKBD's ROM is using 2 buffers to handle input/output on the serial line
140: in an asynchronous way, by using the SCI's interrupt at address $FEE2. This means
141: the IKBD can execute a new command as soon as the current one is completed, as it is
142: the interrupt function that will handle sending bytes to the ACIA.
143:
144: Input buffer : 8 bytes, located at $CD-$D4 in the IKBD's RAM.
145: New bytes received in RDR are added to this buffer, until we have
146: enough bytes to obtain a valid command (with its potential parameters)
147: If the buffer already contains 8 bytes, new bytes are ignored (lost).
148: This buffer is emptied if a valid command was processed or if the first
149: byte in the buffer is not a valid command.
150:
151: Output buffer : 20 bytes as a ring buffer, located at $D9-$ED in the IKBD's RAM.
152: When the IKBD automatically reports events or when a command returns some bytes,
153: those 'n' bytes are added to the ring buffer.
154: If the ring buffer doesn't have enough space to store 'n' new bytes, the 'n' bytes
155: are ignored (lost).
156: Each time a byte is correctly sent in TDR, a new byte is processed, until the ring
157: buffer becomes empty.
1.1.1.19 root 158:
159:
160: Special behaviours during the IKBD reset :
161: If the following commands are received during the reset of the IKBD,
162: the IKBD will go in a special mode and report both mouse and joystick at the same time :
163: 0x08 0x14 relative mouse on , joysticks auto
164: 0x08 0x0b 0x14 relative mouse on , mouse threshold , joysticks auto (eg Barbarian 1 by Psygnosis)
165: 0x12 0x14 disable mouse , joysticks auto (eg Hammerfist)
166: 0x12 0x1a disable mouse , disable joysticks
167:
168: In that case mouse and joystick buttons will be reported in a "mouse report" packet
169: and joystick actions (except buttons) will be reported in a "joystick report" packet.
170:
1.1 root 171: */
172:
1.1.1.20 root 173:
174: static void IKBD_RunKeyboardCommand(Uint8 aciabyte);
175:
176:
1.1.1.2 root 177: /* List of possible keyboard commands, others are seen as NOPs by keyboard processor */
1.1.1.13 root 178: static void IKBD_Cmd_Reset(void);
179: static void IKBD_Cmd_MouseAction(void);
180: static void IKBD_Cmd_RelMouseMode(void);
181: static void IKBD_Cmd_AbsMouseMode(void);
182: static void IKBD_Cmd_MouseCursorKeycodes(void);
183: static void IKBD_Cmd_SetMouseThreshold(void);
184: static void IKBD_Cmd_SetMouseScale(void);
185: static void IKBD_Cmd_ReadAbsMousePos(void);
186: static void IKBD_Cmd_SetInternalMousePos(void);
187: static void IKBD_Cmd_SetYAxisDown(void);
188: static void IKBD_Cmd_SetYAxisUp(void);
189: static void IKBD_Cmd_StartKeyboardTransfer(void);
190: static void IKBD_Cmd_TurnMouseOff(void);
191: static void IKBD_Cmd_StopKeyboardTransfer(void);
192: static void IKBD_Cmd_ReturnJoystickAuto(void);
193: static void IKBD_Cmd_StopJoystick(void);
194: static void IKBD_Cmd_ReturnJoystick(void);
1.1.1.21 root 195: static void IKBD_Cmd_SetJoystickMonitoring(void);
1.1.1.13 root 196: static void IKBD_Cmd_SetJoystickFireDuration(void);
197: static void IKBD_Cmd_SetCursorForJoystick(void);
198: static void IKBD_Cmd_DisableJoysticks(void);
199: static void IKBD_Cmd_SetClock(void);
200: static void IKBD_Cmd_ReadClock(void);
201: static void IKBD_Cmd_LoadMemory(void);
202: static void IKBD_Cmd_ReadMemory(void);
203: static void IKBD_Cmd_Execute(void);
204: static void IKBD_Cmd_ReportMouseAction(void);
205: static void IKBD_Cmd_ReportMouseMode(void);
206: static void IKBD_Cmd_ReportMouseThreshold(void);
207: static void IKBD_Cmd_ReportMouseScale(void);
208: static void IKBD_Cmd_ReportMouseVertical(void);
209: static void IKBD_Cmd_ReportMouseAvailability(void);
210: static void IKBD_Cmd_ReportJoystickMode(void);
211: static void IKBD_Cmd_ReportJoystickAvailability(void);
212:
1.1.1.17 root 213: /* Keyboard Command */
214: static const struct {
215: Uint8 Command;
216: Uint8 NumParameters;
217: void (*pCallFunction)(void);
218: } KeyboardCommands[] =
1.1.1.12 root 219: {
220: /* Known messages, counts include command byte */
221: { 0x80,2, IKBD_Cmd_Reset },
222: { 0x07,2, IKBD_Cmd_MouseAction },
223: { 0x08,1, IKBD_Cmd_RelMouseMode },
224: { 0x09,5, IKBD_Cmd_AbsMouseMode },
225: { 0x0A,3, IKBD_Cmd_MouseCursorKeycodes },
226: { 0x0B,3, IKBD_Cmd_SetMouseThreshold },
227: { 0x0C,3, IKBD_Cmd_SetMouseScale },
228: { 0x0D,1, IKBD_Cmd_ReadAbsMousePos },
229: { 0x0E,6, IKBD_Cmd_SetInternalMousePos },
230: { 0x0F,1, IKBD_Cmd_SetYAxisDown },
231: { 0x10,1, IKBD_Cmd_SetYAxisUp },
232: { 0x11,1, IKBD_Cmd_StartKeyboardTransfer },
233: { 0x12,1, IKBD_Cmd_TurnMouseOff },
234: { 0x13,1, IKBD_Cmd_StopKeyboardTransfer },
235: { 0x14,1, IKBD_Cmd_ReturnJoystickAuto },
236: { 0x15,1, IKBD_Cmd_StopJoystick },
237: { 0x16,1, IKBD_Cmd_ReturnJoystick },
1.1.1.21 root 238: { 0x17,2, IKBD_Cmd_SetJoystickMonitoring },
1.1.1.12 root 239: { 0x18,1, IKBD_Cmd_SetJoystickFireDuration },
240: { 0x19,7, IKBD_Cmd_SetCursorForJoystick },
241: { 0x1A,1, IKBD_Cmd_DisableJoysticks },
242: { 0x1B,7, IKBD_Cmd_SetClock },
243: { 0x1C,1, IKBD_Cmd_ReadClock },
244: { 0x20,4, IKBD_Cmd_LoadMemory },
245: { 0x21,3, IKBD_Cmd_ReadMemory },
246: { 0x22,3, IKBD_Cmd_Execute },
247:
1.1.1.13 root 248: /* Report message (top bit set) */
249: { 0x87,1, IKBD_Cmd_ReportMouseAction },
250: { 0x88,1, IKBD_Cmd_ReportMouseMode },
251: { 0x89,1, IKBD_Cmd_ReportMouseMode },
252: { 0x8A,1, IKBD_Cmd_ReportMouseMode },
253: { 0x8B,1, IKBD_Cmd_ReportMouseThreshold },
254: { 0x8C,1, IKBD_Cmd_ReportMouseScale },
255: { 0x8F,1, IKBD_Cmd_ReportMouseVertical },
256: { 0x90,1, IKBD_Cmd_ReportMouseVertical },
257: { 0x92,1, IKBD_Cmd_ReportMouseAvailability },
258: { 0x94,1, IKBD_Cmd_ReportJoystickMode },
259: { 0x95,1, IKBD_Cmd_ReportJoystickMode },
260: { 0x99,1, IKBD_Cmd_ReportJoystickMode },
261: { 0x9A,1, IKBD_Cmd_ReportJoystickAvailability },
1.1 root 262:
1.1.1.12 root 263: { 0xFF,0, NULL } /* Term */
1.1 root 264: };
265:
1.1.1.2 root 266:
1.1.1.13 root 267:
268:
1.1.1.20 root 269: /*----------------------------------------------------------------------*/
270: /* Variables/defines/functions used to transfer data between the */
271: /* IKBD's SCI and the ACIA. */
272: /*----------------------------------------------------------------------*/
273:
274: #define IKBD_TRCSR_BIT_WU 0x01 /* Wake Up */
275: #define IKBD_TRCSR_BIT_TE 0x02 /* Transmit Enable */
276: #define IKBD_TRCSR_BIT_TIE 0x04 /* Transmit Interrupt Enable */
277: #define IKBD_TRCSR_BIT_RE 0x08 /* Receive Enable */
278: #define IKBD_TRCSR_BIT_RIE 0x10 /* Receive Interrupt Enable */
279: #define IKBD_TRCSR_BIT_TDRE 0x20 /* Transmit Data Register Empty */
280: #define IKBD_TRCSR_BIT_ORFE 0x40 /* Over Run Framing Error */
281: #define IKBD_TRCSR_BIT_RDRF 0x80 /* Receive Data Register Full */
282:
283:
284:
285: /* Possible states when handling TX/RX in the IKBD's Serial Communication Interface */
286: enum
287: {
288: IKBD_SCI_STATE_IDLE = 0,
289: IKBD_SCI_STATE_DATA_BIT,
290: IKBD_SCI_STATE_STOP_BIT
291: };
292:
293:
294: typedef struct {
295: /* IKBD's SCI internal registers */
296: Uint8 RMCR; /* reg 0x10 : Rate and Mode Control Register */
297: Uint8 TRCSR; /* reg 0x11 : Transmit/Receive Control and Status Register */
298: Uint8 TDR; /* reg 0x12 : Transmit Data Register */
299: Uint8 RDR; /* reg 0x13 : Receive Data Register */
300:
301: int SCI_TX_State;
302: Uint8 TSR; /* Transmit Shift Register */
303: Uint8 SCI_TX_Size; /* How many data bits left to transmit in TSR (8 .. 0) */
304: int SCI_TX_Delay; /* If >0, wait SCI_TX_Delay calls of IKBD_SCI_Set_Line_TX before */
305: /* transferring a new byte in TDR (to simulate the time needed by */
306: /* the IKBD to process a command and return the result) */
307:
308: int SCI_RX_State;
309: Uint8 RSR; /* Receive Shift Register */
310: Uint8 SCI_RX_Size; /* How many bits left to receive in RSR (8 .. 0) */
311:
312:
313: /* Date/Time is stored in the IKBD using 6 bytes in BCD format */
314: /* Clock is cleared on cold reset, but keeps its values on warm reset */
315: /* Original RAM location : $82=year $83=month $84=day $85=hour $86=minute $87=second */
316: Uint8 Clock[ 6 ];
317: Sint64 Clock_micro; /* Incremented every VBL to update Clock[] every second */
318:
319: } IKBD_STRUCT;
320:
321:
322: static IKBD_STRUCT IKBD;
323: static IKBD_STRUCT *pIKBD = &IKBD;
324:
325:
326:
327:
328: static void IKBD_Init_Pointers ( ACIA_STRUCT *pACIA_IKBD );
329: static void IKBD_Boot_ROM ( bool ClearAllRAM );
330:
331: static void IKBD_SCI_Get_Line_RX ( int rx_bit );
332: static Uint8 IKBD_SCI_Set_Line_TX ( void );
333:
334: static void IKBD_Process_RDR ( Uint8 RDR );
335: static void IKBD_Check_New_TDR ( void );
336:
337: static bool IKBD_OutputBuffer_CheckFreeCount ( int Nb );
338: static int IKBD_Delay_Random ( int min , int max );
339: static void IKBD_Cmd_Return_Byte ( Uint8 Data );
340: static void IKBD_Cmd_Return_Byte_Delay ( Uint8 Data , int Delay_Cycles );
341: static void IKBD_Send_Byte_Delay ( Uint8 Data , int Delay_Cycles );
342:
343: static bool IKBD_BCD_Check ( Uint8 val );
344: static Uint8 IKBD_BCD_Adjust ( Uint8 val );
345:
346:
347: /*-----------------------------------------------------------------------*/
348: /* Belows part is used to emulate the behaviour of custom 6301 programs */
349: /* sent to the IKBD's RAM. */
350: /*-----------------------------------------------------------------------*/
1.1.1.13 root 351:
352: static void IKBD_LoadMemoryByte ( Uint8 aciabyte );
353:
354: static void IKBD_CustomCodeHandler_CommonBoot ( Uint8 aciabyte );
355:
356: static void IKBD_CustomCodeHandler_FroggiesMenu_Read ( void );
357: static void IKBD_CustomCodeHandler_FroggiesMenu_Write ( Uint8 aciabyte );
358: static void IKBD_CustomCodeHandler_Transbeauce2Menu_Read ( void );
359: static void IKBD_CustomCodeHandler_Transbeauce2Menu_Write ( Uint8 aciabyte );
360: static void IKBD_CustomCodeHandler_DragonnelsMenu_Read ( void );
361: static void IKBD_CustomCodeHandler_DragonnelsMenu_Write ( Uint8 aciabyte );
1.1.1.17 root 362: static void IKBD_CustomCodeHandler_ChaosAD_Read ( void );
363: static void IKBD_CustomCodeHandler_ChaosAD_Write ( Uint8 aciabyte );
1.1.1.13 root 364:
365:
1.1.1.17 root 366: static int MemoryLoadNbBytesTotal = 0; /* total number of bytes to send with the command 0x20 */
367: static int MemoryLoadNbBytesLeft = 0; /* number of bytes that remain to be sent */
1.1.1.20 root 368: static Uint32 MemoryLoadCrc = 0xffffffff; /* CRC of the bytes sent to the IKBD */
369: static int MemoryExeNbBytes = 0; /* current number of bytes sent to the IKBD when IKBD_ExeMode is true */
1.1.1.13 root 370:
1.1.1.17 root 371: static void (*pIKBD_CustomCodeHandler_Read) ( void );
372: static void (*pIKBD_CustomCodeHandler_Write) ( Uint8 );
373: static bool IKBD_ExeMode = false;
374:
375: static Uint8 ScanCodeState[ 128 ]; /* state of each key : 0=released 1=pressed */
1.1.1.13 root 376:
377: /* This array contains all known custom 6301 programs, with their CRC */
1.1.1.17 root 378: static const struct
1.1.1.13 root 379: {
380: Uint32 LoadMemCrc; /* CRC of the bytes sent using the command 0x20 */
381: void (*ExeBootHandler) ( Uint8 ); /* function handling write to $fffc02 during the 'boot' mode */
382: int MainProgNbBytes; /* number of bytes of the main 6301 program */
383: Uint32 MainProgCrc; /* CRC of the main 6301 program */
384: void (*ExeMainHandler_Read) ( void );/* function handling read to $fffc02 in the main 6301 program */
1.1.1.20 root 385: void (*ExeMainHandler_Write) ( Uint8 ); /* function handling write to $fffc02 in the main 6301 program */
1.1.1.13 root 386: const char *Name;
387: }
388: CustomCodeDefinitions[] =
389: {
390: {
391: 0x2efb11b1 ,
392: IKBD_CustomCodeHandler_CommonBoot ,
393: 167,
394: 0xe7110b6d ,
395: IKBD_CustomCodeHandler_FroggiesMenu_Read ,
396: IKBD_CustomCodeHandler_FroggiesMenu_Write ,
397: "Froggies Over The Fence Main Menu"
398: } ,
399: {
400: 0xadb6b503 ,
401: IKBD_CustomCodeHandler_CommonBoot ,
402: 165,
403: 0x5617c33c ,
404: IKBD_CustomCodeHandler_Transbeauce2Menu_Read ,
405: IKBD_CustomCodeHandler_Transbeauce2Menu_Write ,
406: "Transbeauce 2 Main Menu"
407: } ,
408: {
409: 0x33c23cdf ,
410: IKBD_CustomCodeHandler_CommonBoot ,
411: 83 ,
412: 0xdf3e5a88 ,
413: IKBD_CustomCodeHandler_DragonnelsMenu_Read ,
414: IKBD_CustomCodeHandler_DragonnelsMenu_Write ,
415: "Dragonnels Main Menu"
1.1.1.17 root 416: },
417: {
418: 0x9ad7fcdf ,
419: IKBD_CustomCodeHandler_CommonBoot ,
420: 109 ,
421: 0xa11d8be5 ,
422: IKBD_CustomCodeHandler_ChaosAD_Read ,
423: IKBD_CustomCodeHandler_ChaosAD_Write ,
424: "Chaos A.D."
1.1.1.13 root 425: }
426: };
427:
428:
429:
1.1.1.20 root 430:
431:
1.1.1.2 root 432: /*-----------------------------------------------------------------------*/
1.1.1.12 root 433: /**
1.1.1.20 root 434: * Init the IKBD processor.
435: * Connect the IKBD RX/TX callback functions to the ACIA.
436: * This is called only once, when the emulator starts.
1.1.1.12 root 437: */
1.1.1.20 root 438: void IKBD_Init ( void )
1.1.1.12 root 439: {
1.1.1.20 root 440: LOG_TRACE ( TRACE_IKBD_ALL, "ikbd init\n" );
1.1.1.17 root 441:
1.1.1.20 root 442: /* Set the callback functions for RX/TX line */
443: IKBD_Init_Pointers ( pACIA_IKBD );
1.1.1.12 root 444: }
445:
446:
1.1.1.20 root 447:
1.1.1.12 root 448: /*-----------------------------------------------------------------------*/
449: /**
1.1.1.20 root 450: * Init some functions/memory pointers for the IKBD.
451: * This is called at Init and when restoring a memory snapshot.
1.1.1.12 root 452: */
1.1.1.20 root 453: static void IKBD_Init_Pointers ( ACIA_STRUCT *pACIA_IKBD )
454: {
455: pACIA_IKBD->Get_Line_RX = IKBD_SCI_Set_Line_TX; /* Connect ACIA's RX to IKBD SCI's TX */
456: pACIA_IKBD->Set_Line_TX = IKBD_SCI_Get_Line_RX; /* Connect ACIA's TX to IKBD SCI's RX */
457: }
1.1.1.13 root 458:
459:
460:
1.1.1.20 root 461: /*-----------------------------------------------------------------------*/
462: /**
463: * Reset the IKBD processor
464: */
1.1.1.13 root 465:
1.1.1.20 root 466: /* This function is called after a hardware reset of the IKBD.
467: * Cold reset is when the computer is turned off/on.
468: * Warm reset is when the reset button is pressed or the 68000
469: * RESET instruction is used.
470: * We clear the serial interface and we execute the function
471: * that emulates booting the ROM at 0xF000.
472: */
473: void IKBD_Reset ( bool bCold )
474: {
475: LOG_TRACE ( TRACE_IKBD_ALL , "ikbd reset mode=%s\n" , bCold?"cold":"warm" );
476:
477: /* Reset the SCI */
478: pIKBD->TRCSR = IKBD_TRCSR_BIT_TDRE;
479:
480: pIKBD->SCI_TX_State = IKBD_SCI_STATE_IDLE;
481: pIKBD->TSR = 0;
482: pIKBD->SCI_TX_Size = 0;
483: pIKBD->SCI_TX_Delay = 0;
484:
485: pIKBD->SCI_RX_State = IKBD_SCI_STATE_IDLE;
486: pIKBD->RSR = 0;
487: pIKBD->SCI_RX_Size = 0;
488:
489:
490: /* On cold reset, clear the whole RAM (including clock data) */
491: /* On warm reset, the clock data should be kept */
492: if ( bCold )
493: IKBD_Boot_ROM ( true );
494: else
495: IKBD_Boot_ROM ( false );
1.1.1.13 root 496: }
497:
498:
1.1.1.20 root 499:
500: /* This function emulates the boot code stored in the ROM at address $F000.
501: * This boot code is called either after a hardware reset, or when the
502: * reset command ($80 $01) is received.
503: * Depending on the conditions, we should clear the clock data or not (the
504: * real IKBD will test+clear RAM either in range $80-$FF or in range $89-$FF)
505: */
506: static void IKBD_Boot_ROM ( bool ClearAllRAM )
1.1.1.13 root 507: {
508: int i;
509:
510:
1.1.1.20 root 511: LOG_TRACE ( TRACE_IKBD_ALL , "ikbd boot rom clear_all=%s\n" , ClearAllRAM?"yes":"no" );
512:
513: /* Clear clock data when the 128 bytes of RAM are cleared */
514: if ( ClearAllRAM )
1.1.1.12 root 515: {
1.1.1.20 root 516: /* Clear clock data on cold reset */
517: for ( i=0 ; i<6 ; i++ )
518: pIKBD->Clock[ i ] = 0;
519: pIKBD->Clock_micro = 0;
1.1.1.12 root 520: }
521:
1.1.1.20 root 522: // pIKBD->Clock[ 0 ] = 0x99;
523: // pIKBD->Clock[ 1 ] = 0x12;
524: // pIKBD->Clock[ 2 ] = 0x31;
525: // pIKBD->Clock[ 3 ] = 0x23;
526: // pIKBD->Clock[ 4 ] = 0x59;
527: // pIKBD->Clock[ 5 ] = 0x57;
528:
529: /* Set default reporting mode for mouse/joysticks */
1.1.1.12 root 530: KeyboardProcessor.MouseMode = AUTOMODE_MOUSEREL;
531: KeyboardProcessor.JoystickMode = AUTOMODE_JOYSTICK;
532:
533: KeyboardProcessor.Abs.X = ABS_X_ONRESET;
534: KeyboardProcessor.Abs.Y = ABS_Y_ONRESET;
535: KeyboardProcessor.Abs.MaxX = ABS_MAX_X_ONRESET;
536: KeyboardProcessor.Abs.MaxY = ABS_MAY_Y_ONRESET;
537: KeyboardProcessor.Abs.PrevReadAbsMouseButtons = ABS_PREVBUTTONS;
538:
539: KeyboardProcessor.Mouse.DeltaX = KeyboardProcessor.Mouse.DeltaY = 0;
540: KeyboardProcessor.Mouse.XScale = KeyboardProcessor.Mouse.YScale = 0;
541: KeyboardProcessor.Mouse.XThreshold = KeyboardProcessor.Mouse.YThreshold = 1;
542: KeyboardProcessor.Mouse.YAxis = 1; /* Y origin at top */
543: KeyboardProcessor.Mouse.Action = 0;
544:
545: KeyboardProcessor.Joy.PrevJoyData[0] = KeyboardProcessor.Joy.PrevJoyData[1] = 0;
546:
1.1.1.13 root 547: for ( i=0 ; i<128 ; i++ )
548: ScanCodeState[ i ] = 0; /* key is released */
549:
1.1.1.20 root 550:
551: /* Reset our keyboard states and clear key state table */
1.1.1.12 root 552: Keyboard.BufferHead = Keyboard.BufferTail = 0;
1.1.1.20 root 553: Keyboard.NbBytesInOutputBuffer = 0;
1.1.1.12 root 554: Keyboard.nBytesInInputBuffer = 0;
1.1.1.21 root 555: Keyboard.PauseOutput = false;
1.1.1.20 root 556:
1.1.1.12 root 557: memset(Keyboard.KeyStates, 0, sizeof(Keyboard.KeyStates));
558: Keyboard.bLButtonDown = BUTTON_NULL;
559: Keyboard.bRButtonDown = BUTTON_NULL;
560: Keyboard.bOldLButtonDown = Keyboard.bOldRButtonDown = BUTTON_NULL;
561: Keyboard.LButtonDblClk = Keyboard.RButtonDblClk = 0;
562: Keyboard.LButtonHistory = Keyboard.RButtonHistory = 0;
563:
1.1.1.13 root 564: /* Store bool for when disable mouse or joystick */
1.1.1.15 root 565: bMouseDisabled = bJoystickDisabled = false;
1.1.1.12 root 566: /* do emulate hardware 'quirk' where if disable both with 'x' time
567: * of a RESET command they are ignored! */
1.1.1.20 root 568: bDuringResetCriticalTime = true;
569: bBothMouseAndJoy = false;
1.1.1.15 root 570: bMouseEnabledDuringReset = false;
1.1.1.13 root 571:
1.1.1.20 root 572:
1.1.1.13 root 573: /* Remove any custom handlers used to emulate code loaded to the 6301's RAM */
1.1.1.20 root 574: if ( IKBD_ExeMode == true )
575: {
576: LOG_TRACE ( TRACE_IKBD_ALL , "ikbd custom exe off\n" );
577:
578: MemoryLoadNbBytesLeft = 0;
579: pIKBD_CustomCodeHandler_Read = NULL;
580: pIKBD_CustomCodeHandler_Write = NULL;
581: IKBD_ExeMode = false;
582: }
583:
584:
585: /* During the boot, the IKBD will test all the keys to ensure no key */
586: /* is stuck. We use a timer to emulate the time needed for this part */
587: /* (eg Lotus Turbo Esprit 2 requires at least a delay of 50000 cycles */
588: /* or it will crash during start up) */
1.1.1.23! root 589: #ifdef OLD_CPU_SHIFT
1.1.1.20 root 590: CycInt_AddRelativeInterrupt( IKBD_RESET_CYCLES , INT_CPU_CYCLE , INTERRUPT_IKBD_RESETTIMER );
1.1.1.23! root 591: #else
! 592: CycInt_AddRelativeInterrupt( IKBD_RESET_CYCLES , INT_CPU8_CYCLE , INTERRUPT_IKBD_RESETTIMER );
! 593: #endif
1.1.1.20 root 594:
1.1.1.14 root 595:
596: /* Add auto-update function to the queue */
1.1.1.23! root 597: /* We add it only if it was not active, else this can lead to unresponsive keyboard/input */
! 598: /* when RESET instruction is called in a loop in less than 150000 cycles */
1.1.1.21 root 599: Keyboard.AutoSendCycles = 150000; /* approx every VBL */
1.1.1.23! root 600: if ( CycInt_InterruptActive ( INTERRUPT_IKBD_AUTOSEND ) == false )
! 601: #ifdef OLD_CPU_SHIFT
! 602: CycInt_AddRelativeInterrupt ( Keyboard.AutoSendCycles, INT_CPU_CYCLE, INTERRUPT_IKBD_AUTOSEND );
! 603: #else
! 604: CycInt_AddRelativeInterrupt ( Keyboard.AutoSendCycles, INT_CPU8_CYCLE, INTERRUPT_IKBD_AUTOSEND );
! 605: #endif
! 606:
1.1.1.20 root 607: LOG_TRACE ( TRACE_IKBD_ALL , "ikbd reset done, starting reset timer\n" );
608: }
609:
610:
611: /*-----------------------------------------------------------------------*/
612: /**
613: * This timer is started by IKBD_Boot_ROM to emulate the time needed
614: * to setup the IKBD in its default state after a reset.
615: * If some IKBD commands are received during the boot phase they may be ignored.
616: */
617: void IKBD_InterruptHandler_ResetTimer(void)
618: {
619: LOG_TRACE(TRACE_IKBD_ALL, "ikbd reset timer completed, resuming ikbd processing VBLs=%i framecyc=%i\n",
620: nVBLs, Cycles_GetCounter(CYCLES_COUNTER_VIDEO));
621:
622: /* Remove this interrupt from list and re-order */
623: CycInt_AcknowledgeInterrupt();
624:
625: /* Reset timer is over */
626: bDuringResetCriticalTime = false;
627: bMouseEnabledDuringReset = false;
628:
629: /* Return $F1 when IKBD's boot is complete */
630: IKBD_Cmd_Return_Byte_Delay ( IKBD_ROM_VERSION , IKBD_Delay_Random ( 0 , 3000 ) );
1.1 root 631: }
632:
1.1.1.2 root 633:
1.1.1.20 root 634:
1.1.1.2 root 635: /*-----------------------------------------------------------------------*/
1.1.1.12 root 636: /**
637: * Save/Restore snapshot of local variables
638: * ('MemorySnapShot_Store' handles type)
639: */
1.1.1.13 root 640: void IKBD_MemorySnapShot_Capture(bool bSave)
1.1 root 641: {
1.1.1.13 root 642: unsigned int i;
643:
1.1.1.12 root 644: /* Save/Restore details */
645: MemorySnapShot_Store(&Keyboard, sizeof(Keyboard));
646: MemorySnapShot_Store(&KeyboardProcessor, sizeof(KeyboardProcessor));
647: MemorySnapShot_Store(&bMouseDisabled, sizeof(bMouseDisabled));
648: MemorySnapShot_Store(&bJoystickDisabled, sizeof(bJoystickDisabled));
649: MemorySnapShot_Store(&bDuringResetCriticalTime, sizeof(bDuringResetCriticalTime));
650: MemorySnapShot_Store(&bBothMouseAndJoy, sizeof(bBothMouseAndJoy));
1.1.1.14 root 651: MemorySnapShot_Store(&bMouseEnabledDuringReset, sizeof(bMouseEnabledDuringReset));
1.1.1.13 root 652:
653: /* restore custom 6301 program if needed */
654: MemorySnapShot_Store(&IKBD_ExeMode, sizeof(IKBD_ExeMode));
655: MemorySnapShot_Store(&MemoryLoadCrc, sizeof(MemoryLoadCrc));
1.1.1.15 root 656: if ((bSave == false) && (IKBD_ExeMode == true)) /* restoring a snapshot with active 6301 emulation */
1.1.1.13 root 657: {
658: for ( i = 0 ; i < sizeof ( CustomCodeDefinitions ) / sizeof ( CustomCodeDefinitions[0] ); i++ )
659: if ( CustomCodeDefinitions[ i ].MainProgCrc == MemoryLoadCrc )
660: {
661: pIKBD_CustomCodeHandler_Read = CustomCodeDefinitions[ i ].ExeMainHandler_Read;
662: pIKBD_CustomCodeHandler_Write = CustomCodeDefinitions[ i ].ExeMainHandler_Write;
663: Keyboard.BufferHead = Keyboard.BufferTail = 0; /* flush all queued bytes that would be read in $fffc02 */
1.1.1.20 root 664: Keyboard.NbBytesInOutputBuffer = 0;
1.1.1.13 root 665: break;
666: }
667:
668: if ( i >= sizeof ( CustomCodeDefinitions ) / sizeof ( CustomCodeDefinitions[0] ) ) /* not found (should not happen) */
1.1.1.15 root 669: IKBD_ExeMode = false; /* turn off exe mode */
1.1.1.13 root 670: }
1.1.1.19 root 671:
1.1.1.20 root 672:
673: /* Save the IKBD's SCI part and restore the callback functions for RX/TX lines with the ACIA */
674: MemorySnapShot_Store(&IKBD, sizeof(IKBD));
675: if (!bSave) /* Restoring a snapshot */
1.1.1.19 root 676: {
1.1.1.20 root 677: IKBD_Init_Pointers ( pACIA_IKBD );
1.1.1.19 root 678: }
1.1 root 679: }
680:
1.1.1.2 root 681:
1.1.1.20 root 682:
683:
684: /************************************************************************/
685: /* This part emulates the IKBD's Serial Communication Interface. */
686: /* This is a simplified implementation that ignores the RMCR content, */
687: /* as we assume the IKBD and the ACIA will be using the same baud rate. */
688: /* The TX/RX baud rate is chosen at the ACIA level, and the IKBD will */
689: /* use the same rate. */
690: /* The SCI only supports 8 bits of data, with 1 start bit, 1 stop bit */
691: /* and no parity bit. */
692: /************************************************************************/
693:
694:
1.1.1.2 root 695: /*-----------------------------------------------------------------------*/
1.1.1.12 root 696: /**
1.1.1.20 root 697: * Prepare a new transfer. Copy TDR to TSR and initialize data size.
698: * Transfer will then start at the next call of IKBD_SCI_Set_Line_TX.
1.1.1.12 root 699: */
1.1.1.20 root 700: static void IKBD_SCI_Prepare_TX ( IKBD_STRUCT *pIKBD )
1.1 root 701: {
1.1.1.20 root 702: pIKBD->TSR = pIKBD->TDR;
703: pIKBD->SCI_TX_Size = 8;
704:
705: pIKBD->TRCSR |= IKBD_TRCSR_BIT_TDRE; /* TDR was copied to TSR. TDR is now empty */
706:
707: LOG_TRACE ( TRACE_IKBD_ACIA, "ikbd acia prepare tx tsr=0x%02x size=%d VBL=%d HBL=%d\n" , pIKBD->TSR , pIKBD->SCI_TX_Size , nVBLs , nHBL );
708: }
1.1 root 709:
1.1.1.12 root 710:
711:
1.1.1.4 root 712:
1.1.1.20 root 713: /*-----------------------------------------------------------------------*/
714: /**
715: * Prepare a new reception. Initialize RSR and data size.
716: */
717: static void IKBD_SCI_Prepare_RX ( IKBD_STRUCT *pIKBD )
718: {
719: pIKBD->RSR = 0;
720: pIKBD->SCI_RX_Size = 8;
721:
722: LOG_TRACE ( TRACE_IKBD_ACIA, "ikbd acia prepare rx size=%d VBL=%d HBL=%d\n" , pIKBD->SCI_RX_Size , nVBLs , nHBL );
1.1 root 723: }
724:
1.1.1.2 root 725:
1.1.1.20 root 726:
727:
1.1.1.2 root 728: /*-----------------------------------------------------------------------*/
1.1.1.12 root 729: /**
1.1.1.20 root 730: * Receive a bit on the IKBD SCI's RX line (this is connected to the ACIA's TX)
731: * This will fill RDR with bits received from the serial line, using RSR.
732: * Incoming bits are stored in bit 7 of RSR, then RSR is shifted to the right.
733: * This is similar to the ACIA's RX, but with fixed parameters : 8 data bits,
734: * no parity bit and 1 stop bit.
1.1.1.12 root 735: */
1.1.1.20 root 736: static void IKBD_SCI_Get_Line_RX ( int rx_bit )
1.1 root 737: {
1.1.1.20 root 738: int StateNext;
1.1.1.12 root 739:
1.1.1.20 root 740:
741: LOG_TRACE ( TRACE_IKBD_ACIA, "ikbd acia rx_state=%d bit=%d VBL=%d HBL=%d\n" , pIKBD->SCI_RX_State , rx_bit , nVBLs , nHBL );
742:
743: StateNext = -1;
744: switch ( pIKBD->SCI_RX_State )
1.1.1.12 root 745: {
1.1.1.20 root 746: case IKBD_SCI_STATE_IDLE :
747: if ( rx_bit == 0 ) /* Receive one "0" start bit */
1.1.1.12 root 748: {
1.1.1.20 root 749: IKBD_SCI_Prepare_RX ( pIKBD );
750: StateNext = IKBD_SCI_STATE_DATA_BIT;
751: }
752: break; /* If no start bit, we stay in idle state */
753:
754: case IKBD_SCI_STATE_DATA_BIT :
755: if ( rx_bit )
756: pIKBD->RSR |= 0x80;
757: pIKBD->SCI_RX_Size--;
758:
759: if ( pIKBD->SCI_RX_Size > 0 ) /* All bits were not received yet */
760: pIKBD->RSR >>= 1;
761: else
762: StateNext = IKBD_SCI_STATE_STOP_BIT;
763: break;
764:
765: case IKBD_SCI_STATE_STOP_BIT :
766: if ( rx_bit == 1 ) /* Wait for one "1" stop bit */
767: {
768: pIKBD->TRCSR &= ~IKBD_TRCSR_BIT_ORFE;
769:
770: if ( ( pIKBD->TRCSR & IKBD_TRCSR_BIT_RDRF ) == 0 )
771: {
772: pIKBD->RDR = pIKBD->RSR;
773: pIKBD->TRCSR |= IKBD_TRCSR_BIT_RDRF;
774: LOG_TRACE ( TRACE_IKBD_ACIA, "ikbd acia get_rx received rsr=0x%02x VBL=%d HBL=%d\n" ,
775: pIKBD->RDR , nVBLs , nHBL );
776:
777: IKBD_Process_RDR ( pIKBD->RDR ); /* Process this new byte */
778: }
1.1.1.12 root 779: else
780: {
1.1.1.20 root 781: pIKBD->TRCSR |= IKBD_TRCSR_BIT_ORFE; /* Overrun Error */
782: LOG_TRACE ( TRACE_IKBD_ACIA, "ikbd acia get_rx received rsr=0x%02x : ignored, rdr=0x%02x and rdrf already set VBL=%d HBL=%d\n" ,
783: pIKBD->RSR , pIKBD->RDR , nVBLs , nHBL );
784:
785: IKBD_Process_RDR ( pIKBD->RDR ); /* RSR is lost, try to process the current RDR which was not read yet */
1.1.1.12 root 786: }
1.1.1.20 root 787: StateNext = IKBD_SCI_STATE_IDLE; /* Go to idle state and wait for start bit */
1.1.1.12 root 788: }
1.1.1.20 root 789: else /* Not a valid stop bit */
1.1.1.12 root 790: {
1.1.1.20 root 791: LOG_TRACE ( TRACE_IKBD_ACIA, "ikbd acia get_rx framing error VBL=%d HBL=%d\n" , nVBLs , nHBL );
792: pIKBD->TRCSR |= IKBD_TRCSR_BIT_ORFE; /* Framing Error */
793: StateNext = IKBD_SCI_STATE_IDLE; /* Go to idle state and wait for start bit */
1.1.1.12 root 794: }
1.1.1.20 root 795: break;
1.1.1.12 root 796: }
1.1.1.20 root 797:
798: if ( StateNext >= 0 )
799: pIKBD->SCI_RX_State = StateNext; /* Go to a new state */
800: }
801:
802:
803:
804:
805: /*-----------------------------------------------------------------------*/
806: /**
807: * Send a bit on the IKBD SCI's TX line (this is connected to the ACIA's RX)
808: * When the SCI is idle, we send '1' stop bits.
809: */
810: static Uint8 IKBD_SCI_Set_Line_TX ( void )
811: {
812: int StateNext;
813: Uint8 tx_bit = 1;
814:
815:
816: LOG_TRACE ( TRACE_IKBD_ACIA, "ikbd acia tx_state=%d tx_delay=%d VBL=%d HBL=%d\n" , pIKBD->SCI_TX_State , pIKBD->SCI_TX_Delay ,
817: nVBLs , nHBL );
818:
819: StateNext = -1;
820: switch ( pIKBD->SCI_TX_State )
1.1.1.12 root 821: {
1.1.1.20 root 822: case IKBD_SCI_STATE_IDLE :
823: tx_bit = 1; /* In idle state, default is to send '1' stop bits */
824:
825: if ( pIKBD->SCI_TX_Delay > 0 ) /* Should we delay the next TDR ? */
1.1.1.12 root 826: {
1.1.1.20 root 827: pIKBD->SCI_TX_Delay--; /* Don't do anything for now, send a stop bit */
828: break;
1.1.1.12 root 829: }
830:
1.1.1.20 root 831: IKBD_Check_New_TDR (); /* Do we have a byte to load in TDR ? */
832:
833: if ( ( pIKBD->TRCSR & IKBD_TRCSR_BIT_TDRE ) == 0 ) /* We have a new byte in TDR */
1.1.1.12 root 834: {
1.1.1.20 root 835: IKBD_SCI_Prepare_TX ( pIKBD );
836: tx_bit = 0; /* Send one '0' start bit */
837: StateNext = IKBD_SCI_STATE_DATA_BIT;
1.1.1.12 root 838: }
1.1.1.20 root 839: break;
840:
841: case IKBD_SCI_STATE_DATA_BIT :
842: tx_bit = pIKBD->TSR & 1; /* New bit to send */
843: pIKBD->TSR >>= 1;
844: pIKBD->SCI_TX_Size--;
845:
846: if ( pIKBD->SCI_TX_Size == 0 )
847: StateNext = IKBD_SCI_STATE_STOP_BIT;
848: break;
849:
850:
851: case IKBD_SCI_STATE_STOP_BIT :
852: tx_bit = 1; /* Send 1 stop bit */
853: StateNext = IKBD_SCI_STATE_IDLE; /* Go to idle state to see if a new TDR need to be sent */
854: break;
1.1.1.12 root 855: }
856:
1.1.1.20 root 857: if ( StateNext >= 0 )
858: pIKBD->SCI_TX_State = StateNext; /* Go to a new state */
859:
860: return tx_bit;
1.1.1.12 root 861: }
862:
863:
1.1.1.20 root 864:
865:
1.1.1.12 root 866: /*-----------------------------------------------------------------------*/
867: /**
1.1.1.20 root 868: * Handle the byte that was received in the RDR from the ACIA.
869: * Depending on the IKBD's emulation mode, we either pass it to the standard
870: * ROM's emulation layer, or we pass it to the custom handlers.
1.1.1.12 root 871: */
1.1.1.20 root 872: static void IKBD_Process_RDR ( Uint8 RDR )
1.1 root 873: {
1.1.1.20 root 874: pIKBD->TRCSR &= ~IKBD_TRCSR_BIT_RDRF; /* RDR was read */
875:
876:
877: /* If IKBD is executing custom code, send the byte to the function handling this code */
878: if ( IKBD_ExeMode && pIKBD_CustomCodeHandler_Write )
879: {
880: (*pIKBD_CustomCodeHandler_Write) ( RDR );
881: return;
882: }
883:
884: if ( MemoryLoadNbBytesLeft == 0 ) /* No pending MemoryLoad command */
885: IKBD_RunKeyboardCommand ( RDR ); /* Check for known commands */
886:
887: else /* MemoryLoad command is not finished yet */
888: IKBD_LoadMemoryByte ( RDR ); /* Process bytes sent to the IKBD's RAM */
1.1 root 889: }
890:
1.1.1.2 root 891:
1.1.1.20 root 892:
893:
1.1.1.2 root 894: /*-----------------------------------------------------------------------*/
1.1.1.12 root 895: /**
1.1.1.20 root 896: * Check if we have a byte to copy to the IKBD's TDR, to send it to the ACIA.
897: * We get new bytes from the buffer filled by IKBD_Send_Byte_Delay
1.1.1.12 root 898: */
1.1.1.20 root 899: static void IKBD_Check_New_TDR ( void )
1.1 root 900: {
1.1.1.20 root 901: // fprintf(stderr , "check new tdr %d %d\n", Keyboard.BufferHead , Keyboard.BufferTail );
902:
1.1.1.21 root 903: if ( ( Keyboard.NbBytesInOutputBuffer > 0 )
904: && ( Keyboard.PauseOutput == false ) )
1.1.1.20 root 905: {
906: pIKBD->TDR = Keyboard.Buffer[ Keyboard.BufferHead++ ];
907: Keyboard.BufferHead &= KEYBOARD_BUFFER_MASK;
908: Keyboard.NbBytesInOutputBuffer--;
909: pIKBD->TRCSR &= ~IKBD_TRCSR_BIT_TDRE;
910: }
1.1 root 911: }
912:
1.1.1.2 root 913:
1.1.1.20 root 914:
915:
1.1.1.2 root 916: /*-----------------------------------------------------------------------*/
1.1.1.12 root 917: /**
1.1.1.20 root 918: * Return true if the output buffer can store 'Nb' new bytes,
919: * else return false.
920: * Some games like 'Downfall' or 'Fokker' are continually issuing the same
921: * IKBD_Cmd_ReturnJoystick command without waiting for the returned bytes,
922: * which will fill the output buffer faster than the CPU can empty it.
923: * In that case, new messages must be discarded until the buffer has some room
924: * again for a whole packet.
1.1.1.12 root 925: */
1.1.1.20 root 926: static bool IKBD_OutputBuffer_CheckFreeCount ( int Nb )
1.1 root 927: {
1.1.1.20 root 928: // fprintf ( stderr , "check %d %d head %d tail %d\n" , Nb , SIZE_KEYBOARD_BUFFER - Keyboard.NbBytesInOutputBuffer ,
929: // Keyboard.BufferHead , Keyboard.BufferTail );
930:
931: if ( SIZE_KEYBOARD_BUFFER - Keyboard.NbBytesInOutputBuffer >= Nb )
932: return true;
933:
934: else
935: {
936: LOG_TRACE ( TRACE_IKBD_ACIA, "ikbd acia output buffer is full, can't send %d bytes VBL=%d HBL=%d\n" ,
937: Nb, nVBLs , nHBL );
938: return false;
939: }
940: }
941:
942:
943:
944:
945: /*-----------------------------------------------------------------------*/
946: /**
947: * Return a random number between 'min' and 'max'.
948: * This is used when the IKBD send bytes to the ACIA, to add some
949: * randomness to the delay (on real hardware, the delay is not constant
950: * when a command return some bytes).
951: */
952: static int IKBD_Delay_Random ( int min , int max )
953: {
954: return min + rand() % ( max - min );
955: }
956:
957:
958: /*-----------------------------------------------------------------------*/
959: /**
960: * This function will buffer all the bytes returned by a specific
961: * IKBD_Cmd_xxx command. If we're using a custom handler, we should filter
962: * these bytes (keyboard, mouse, joystick) as they don't come from the custom handler.
963: */
964: static void IKBD_Cmd_Return_Byte ( Uint8 Data )
965: {
966: if ( IKBD_ExeMode ) /* If IKBD is executing custom code, don't add */
967: return; /* anything to the buffer that comes from an IKBD's command */
968:
969: IKBD_Send_Byte_Delay ( Data , 0 );
970: }
971:
972:
973: /**
974: * Same as IKBD_Cmd_Return_Byte, but with a delay before transmitting
975: * the byte.
976: */
977: static void IKBD_Cmd_Return_Byte_Delay ( Uint8 Data , int Delay_Cycles )
978: {
979: if ( IKBD_ExeMode ) /* If IKBD is executing custom code, don't add */
980: return; /* anything to the buffer that comes from an IKBD's command */
981:
982: IKBD_Send_Byte_Delay ( Data , Delay_Cycles );
983: }
984:
985:
986:
987:
988: /*-----------------------------------------------------------------------*/
989: /**
990: * Send bytes from the IKBD to the ACIA. We store the bytes in a buffer
991: * and we pull a new byte each time TDR needs to be re-filled.
992: *
993: * A possible delay can be specified to simulate the fact that some IKBD's
994: * commands don't return immediately the first byte. This delay is given
995: * in 68000 cycles at 8 MHz and should be converted to a number of bits
996: * at the chosen baud rate.
997: */
998: static void IKBD_Send_Byte_Delay ( Uint8 Data , int Delay_Cycles )
999: {
1000: //fprintf ( stderr , "send byte=0x%02x delay=%d\n" , Data , Delay_Cycles );
1001: /* Is keyboard initialised yet ? Ignore any bytes until it is */
1002: if ( bDuringResetCriticalTime )
1003: {
1004: LOG_TRACE ( TRACE_IKBD_ACIA, "ikbd is resetting, can't send byte=0x%02x VBL=%d HBL=%d\n" , Data, nVBLs , nHBL );
1005: return;
1006: }
1007:
1008: /* Is ACIA's serial line initialised yet ? Ignore any bytes until it is */
1009: if ( pACIA_IKBD->Clock_Divider == 0 )
1010: {
1011: LOG_TRACE ( TRACE_IKBD_ACIA, "ikbd acia not initialized, can't send byte=0x%02x VBL=%d HBL=%d\n" , Data, nVBLs , nHBL );
1012: return;
1013: }
1014:
1015: if ( Delay_Cycles > 0 )
1016: pIKBD->SCI_TX_Delay = Delay_Cycles / 1024; /* 1 bit at 7812.5 baud = 1024 cpu cycles at 8 MHz */
1017:
1018:
1019: /* Check we have space to add one byte */
1020: if ( IKBD_OutputBuffer_CheckFreeCount ( 1 ) )
1021: {
1022: /* Add byte to our buffer */
1023: Keyboard.Buffer[Keyboard.BufferTail++] = Data;
1024: Keyboard.BufferTail &= KEYBOARD_BUFFER_MASK;
1025: Keyboard.NbBytesInOutputBuffer++;
1026: }
1027: else
1028: {
1029: Log_Printf(LOG_ERROR, "IKBD buffer is full, can't send 0x%02x!\n" , Data );
1030: }
1031: }
1032:
1033:
1034:
1035:
1036:
1037:
1038: /************************************************************************/
1039: /* End of the Serial Communication Interface */
1040: /************************************************************************/
1041:
1042:
1043: /**
1044: * Check that the value is a correctly encoded BCD number
1045: */
1046: static bool IKBD_BCD_Check ( Uint8 val )
1047: {
1048: if ( ( ( val & 0x0f ) > 0x09 )
1049: || ( ( val & 0xf0 ) > 0x90 ) )
1050: return false;
1051:
1052: return true;
1053: }
1054:
1055:
1056: /**
1057: * After adding an integer number to a BCD number, the result is no more
1058: * in BCD format. This function adjusts the value to be a valid BCD number again.
1059: * In the HD6301, this is done using the 'DAA' instruction (Decimal Adjust)
1060: * to "propagate" values 10-15 to the next 4 bits and keep each nibble
1061: * in the 0-9 range.
1062: */
1063:
1064: static Uint8 IKBD_BCD_Adjust ( Uint8 val )
1065: {
1066: if ( ( val & 0x0f ) > 0x09 ) /* low nibble no more in BCD */
1067: val += 0x06; /* clear bit 4 and add 1 to high nibble */
1068: if ( ( val & 0xf0 ) > 0x90 ) /* high nibble no more in BCD */
1069: val += 0x60; /* propagate carry (but bits>7 will be lost) */
1070:
1071: return val;
1072: }
1073:
1074:
1075:
1076: /**
1077: * Update the IKBD's internal clock.
1078: *
1079: * This function is called on every VBL and we add the number of microseconds
1080: * per VBL. When we reach 1000000 microseconds (1 sec), we update the Clock[]
1081: * array by incrementing the 'second' byte.
1082: *
1083: * This code uses the same logic as the ROM version in the IKBD,
1084: * don't try to optimise/rewrite it in a different way, as the TOS
1085: * expects data to be handled this way.
1086: * This works directly with BCD numbers and propagates the increment
1087: * to the next byte each time the current byte reaches its maximum
1088: * value.
1089: * - when SetClock is used, the IKBD doesn't check the range of each byte,
1090: * just that it's BCD encoded. So it's possible to set month/day/... to
1091: * invalid values beyond the maximum allowed. These values will not correctly
1092: * propagate to the next byte until they reach 0x99 and start again at 0x00.
1093: * - check leap year for the number of days in february if ( year & 3 == 0 )
1094: * - there's no explicit max for year : if year is 99 and increments,
1095: * next year will be 00 (due to the BCD overflow)
1096: * (used in the game 'Captain Blood' which sets clock to "99 12 31 00 00 00"
1097: * and ends the game when clock reaches "00 01 01 00 00 00")
1098: */
1099: void IKBD_UpdateClockOnVBL ( void )
1100: {
1101: Sint64 FrameDuration_micro;
1102: int i;
1103: Uint8 val;
1104: Uint8 max;
1105: Uint8 year;
1106: Uint8 month;
1107:
1108: /* Max value for year/month/day/hour/minute/second */
1109: Uint8 val_max[ 6 ] = { 0xFF , 0x13 , 0x00 , 0x24 , 0x60 , 0x60 };
1110: /* Max number of days per month ; 18 entries, because the index for this array is a BCD coded month */
1111: Uint8 day_max[ 18 ] = { 0x32, 0x29, 0x32, 0x31, 0x32, 0x31, 0x32, 0x32, 0x31, 0,0,0,0,0,0, 0x32, 0x31, 0x32 };
1112:
1113:
1114: /* Check if more than 1 second passed since last increment of date/time */
1115: FrameDuration_micro = ClocksTimings_GetVBLDuration_micro ( ConfigureParams.System.nMachineType , nScreenRefreshRate );
1116: pIKBD->Clock_micro += FrameDuration_micro;
1117: if ( pIKBD->Clock_micro < 1000000 )
1118: return; /* Less than 1 second, don't increment date/time yet */
1119: pIKBD->Clock_micro -= 1000000;
1120:
1121:
1122: /* 1 second passed, we can increment the clock data */
1123: // LOG_TRACE(TRACE_IKBD_CMDS,
1124: // "IKBD_UpdateClock: %02x %02x %02x %02x %02x %02x -> ", pIKBD->Clock[ 0 ] ,pIKBD->Clock[ 1 ] , pIKBD->Clock[ 2 ] ,
1125: // pIKBD->Clock[ 3 ] , pIKBD->Clock[ 4 ] , pIKBD->Clock[ 5 ] );
1126:
1127: for ( i=5 ; i>=0 ; i-- )
1128: {
1129: val = pIKBD->Clock[ i ] + 1; /* Increment current value */
1130: val = IKBD_BCD_Adjust ( val ); /* Convert to BCD */
1131:
1132: if ( i != 2 )
1133: max = val_max[ i ];
1134:
1135: else /* Special case for days per month */
1136: {
1137: /* WARNING : it's possible to set the IKBD with month > 0x12, but in that case */
1138: /* we would access day_max[] out of range. So, if month > 0x12, we limit to 31 days */
1139: /* (this test is not done in the IKBD, but results would not be correct anyway) */
1140: month = pIKBD->Clock[ 1 ];
1141: if ( month > 0x12 ) /* Hatari specific, check range */
1142: month = 0x12;
1143: max = day_max[ month - 1 ]; /* Number of days for current month */
1144: if ( pIKBD->Clock[ 1 ] == 2 ) /* For february, check leap year */
1145: {
1146: year = pIKBD->Clock[ 0 ];
1147: /* Leap year test comes from the IKBD's ROM */
1148: if ( year & 0x10 )
1149: year += 0x0a;
1150: if ( ( year & 0x03 ) == 0 )
1151: max = 0x30; /* This is a leap year, 29 days */
1152: }
1153: }
1154:
1155: if ( val != max )
1156: {
1157: pIKBD->Clock[ i ] = val; /* Max not reached, stop here */
1158: break;
1159: }
1160: else if ( ( i == 1 ) || ( i == 2 ) )
1161: pIKBD->Clock[ i ] = 1; /* day/month start at 1 */
1162: else
1163: pIKBD->Clock[ i ] = 0; /* hour/minute/second start at 0 */
1164: }
1165:
1166: // LOG_TRACE(TRACE_IKBD_CMDS,
1167: // "%02x %02x %02x %02x %02x %02x\n", pIKBD->Clock[ 0 ] ,pIKBD->Clock[ 1 ] , pIKBD->Clock[ 2 ] ,
1168: // pIKBD->Clock[ 3 ] , pIKBD->Clock[ 4 ] , pIKBD->Clock[ 5 ] );
1169: }
1170:
1171:
1172:
1173:
1174: /*-----------------------------------------------------------------------*/
1175: /**
1176: * Calculate out 'delta' that mouse has moved by each frame, and add this to our internal keyboard position
1177: */
1178: static void IKBD_UpdateInternalMousePosition(void)
1179: {
1180:
1181: KeyboardProcessor.Mouse.DeltaX = KeyboardProcessor.Mouse.dx;
1182: KeyboardProcessor.Mouse.DeltaY = KeyboardProcessor.Mouse.dy;
1183: KeyboardProcessor.Mouse.dx = 0;
1184: KeyboardProcessor.Mouse.dy = 0;
1185:
1186: /* Update internal mouse coords - Y axis moves according to YAxis setting(up/down) */
1187: /* Limit to Max X/Y(inclusive) */
1188: if ( KeyboardProcessor.Mouse.XScale > 1 )
1189: KeyboardProcessor.Abs.X += KeyboardProcessor.Mouse.DeltaX * KeyboardProcessor.Mouse.XScale;
1190: else
1191: KeyboardProcessor.Abs.X += KeyboardProcessor.Mouse.DeltaX;
1192: if (KeyboardProcessor.Abs.X < 0)
1193: KeyboardProcessor.Abs.X = 0;
1194: if (KeyboardProcessor.Abs.X > KeyboardProcessor.Abs.MaxX)
1195: KeyboardProcessor.Abs.X = KeyboardProcessor.Abs.MaxX;
1196:
1197: if ( KeyboardProcessor.Mouse.YScale > 1 )
1198: KeyboardProcessor.Abs.Y += KeyboardProcessor.Mouse.DeltaY*KeyboardProcessor.Mouse.YAxis * KeyboardProcessor.Mouse.YScale;
1199: else
1200: KeyboardProcessor.Abs.Y += KeyboardProcessor.Mouse.DeltaY*KeyboardProcessor.Mouse.YAxis;
1201: if (KeyboardProcessor.Abs.Y < 0)
1202: KeyboardProcessor.Abs.Y = 0;
1203: if (KeyboardProcessor.Abs.Y > KeyboardProcessor.Abs.MaxY)
1204: KeyboardProcessor.Abs.Y = KeyboardProcessor.Abs.MaxY;
1205:
1206: }
1207:
1208:
1209: /*-----------------------------------------------------------------------*/
1210: /**
1211: * When running in maximum speed the emulation will not see 'double-clicks'
1212: * of the mouse as it is running so fast. In this case, we check for a
1213: * double-click and pass the 'up'/'down' messages in emulation time to
1214: * simulate the double-click effect!
1215: */
1216: static void IKBD_CheckForDoubleClicks(void)
1217: {
1218: /*
1219: Things get a little complicated when running max speed as a normal
1220: double-click is a load of 1's, followed by 0's, 1's and 0's - But the
1221: ST does not see this as a double click as the space in 'ST' time
1222: between changes is so great.
1223: Now, when we see a real double-click in max speed we actually send
1224: the down/up/down/up in ST time. To get this correct (and not send
1225: three clicks) we look in a history buffer and start at an index which
1226: gives the correct number of clicks! Phew!
1227: */
1228:
1229: /* Handle double clicks!!! */
1230: if (Keyboard.LButtonDblClk)
1231: {
1232: if (Keyboard.LButtonDblClk == 1) /* First pressed! */
1233: {
1234: if ((Keyboard.LButtonHistory&0x3f) == 0) /* If not pressed button in long time do full dbl-click pattern */
1235: Keyboard.LButtonDblClk = 1;
1236: else
1237: {
1238: Keyboard.LButtonDblClk = 4; /* Otherwise, check where to begin to give 1111000011110000 pattern */
1239: if ((Keyboard.LButtonHistory&0x7) == 0)
1240: Keyboard.LButtonDblClk = 8;
1241: else if ((Keyboard.LButtonHistory&0x3) == 0)
1242: Keyboard.LButtonDblClk = 7;
1243: else if ((Keyboard.LButtonHistory&0x1) == 0)
1244: Keyboard.LButtonDblClk = 6;
1245: }
1246: }
1247:
1248: Keyboard.bLButtonDown = DoubleClickPattern[Keyboard.LButtonDblClk];
1249: Keyboard.LButtonDblClk++;
1.1.1.23! root 1250: if (Keyboard.LButtonDblClk >= ARRAY_SIZE(DoubleClickPattern))
1.1.1.20 root 1251: {
1252: Keyboard.LButtonDblClk = 0;
1253: Keyboard.bLButtonDown = false;
1254: }
1255: }
1256: if (Keyboard.RButtonDblClk)
1257: {
1258: if (Keyboard.RButtonDblClk == 1) /* First pressed! */
1259: {
1260: if ((Keyboard.RButtonHistory&0x3f) == 0) /* If not pressed button in long time do full dbl-click pattern */
1261: Keyboard.RButtonDblClk = 1;
1262: else
1263: {
1264: Keyboard.RButtonDblClk = 4; /* Otherwise, check where to begin to give 1111000011110000 pattern */
1265: if ((Keyboard.RButtonHistory&0x7) == 0)
1266: Keyboard.RButtonDblClk = 8;
1267: else if ((Keyboard.RButtonHistory&0x3) == 0)
1268: Keyboard.RButtonDblClk = 7;
1269: else if ((Keyboard.RButtonHistory&0x1) == 0)
1270: Keyboard.RButtonDblClk = 6;
1271: }
1272: }
1273:
1274: Keyboard.bRButtonDown = DoubleClickPattern[Keyboard.RButtonDblClk];
1275: Keyboard.RButtonDblClk++;
1.1.1.23! root 1276: if (Keyboard.RButtonDblClk >= ARRAY_SIZE(DoubleClickPattern))
1.1.1.20 root 1277: {
1278: Keyboard.RButtonDblClk = 0;
1279: Keyboard.bRButtonDown = false;
1280: }
1281: }
1282:
1283: /* Store presses into history */
1284: Keyboard.LButtonHistory = (Keyboard.LButtonHistory<<1);
1285: if (Keyboard.bLButtonDown)
1286: Keyboard.LButtonHistory |= 0x1;
1287: Keyboard.RButtonHistory = (Keyboard.RButtonHistory<<1);
1288: if (Keyboard.bRButtonDown)
1289: Keyboard.RButtonHistory |= 0x1;
1290: }
1291:
1292:
1293: /*-----------------------------------------------------------------------*/
1294: /**
1295: * Convert button to bool value
1296: */
1297: static bool IKBD_ButtonBool(int Button)
1298: {
1299: /* Button pressed? */
1300: if (Button)
1301: return true;
1302: return false;
1303: }
1304:
1305:
1306: /*-----------------------------------------------------------------------*/
1307: /**
1308: * Return true if buttons match, use this as buttons are a mask and not boolean
1309: */
1310: static bool IKBD_ButtonsEqual(int Button1,int Button2)
1311: {
1312: /* Return bool compare */
1313: return (IKBD_ButtonBool(Button1) == IKBD_ButtonBool(Button2));
1314: }
1315:
1316:
1317: /*-----------------------------------------------------------------------*/
1318: /**
1319: * According to if the mouse is enabled or not the joystick 1 fire
1320: * button/right mouse button will become the same button. That means
1321: * pressing one will also press the other and vice-versa.
1322: * If both mouse and joystick are enabled, report it as a mouse button
1323: * (needed by the game Big Run for example).
1324: */
1325: static void IKBD_DuplicateMouseFireButtons(void)
1326: {
1327: /* If mouse is off then joystick fire button goes to joystick */
1328: if (KeyboardProcessor.MouseMode == AUTOMODE_OFF)
1329: {
1330: /* If pressed right mouse button, should go to joystick 1 */
1331: if (Keyboard.bRButtonDown&BUTTON_MOUSE)
1332: KeyboardProcessor.Joy.JoyData[1] |= 0x80;
1333: /* And left mouse button, should go to joystick 0 */
1334: if (Keyboard.bLButtonDown&BUTTON_MOUSE)
1335: KeyboardProcessor.Joy.JoyData[0] |= 0x80;
1336: }
1337: /* If mouse is on, joystick 1 fire button goes to the mouse instead */
1.1.1.12 root 1338: else
1339: {
1340: /* Is fire button pressed? */
1341: if (KeyboardProcessor.Joy.JoyData[1]&0x80)
1342: {
1343: KeyboardProcessor.Joy.JoyData[1] &= 0x7f; /* Clear fire button bit */
1344: Keyboard.bRButtonDown |= BUTTON_JOYSTICK; /* Mimick on mouse right button */
1345: }
1346: else
1347: Keyboard.bRButtonDown &= ~BUTTON_JOYSTICK;
1348: }
1.1 root 1349: }
1350:
1.1.1.2 root 1351:
1352: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1353: /**
1354: * Send 'relative' mouse position
1355: */
1.1.1.8 root 1356: static void IKBD_SendRelMousePacket(void)
1.1 root 1357: {
1.1.1.12 root 1358: int ByteRelX,ByteRelY;
1359: Uint8 Header;
1.1 root 1360:
1.1.1.12 root 1361: if ( (KeyboardProcessor.Mouse.DeltaX!=0) || (KeyboardProcessor.Mouse.DeltaY!=0)
1362: || (!IKBD_ButtonsEqual(Keyboard.bOldLButtonDown,Keyboard.bLButtonDown)) || (!IKBD_ButtonsEqual(Keyboard.bOldRButtonDown,Keyboard.bRButtonDown)) )
1363: {
1364: /* Send packet to keyboard process */
1.1.1.15 root 1365: while (true)
1.1.1.12 root 1366: {
1367: ByteRelX = KeyboardProcessor.Mouse.DeltaX;
1368: if (ByteRelX>127) ByteRelX = 127;
1369: if (ByteRelX<-128) ByteRelX = -128;
1370: ByteRelY = KeyboardProcessor.Mouse.DeltaY;
1371: if (ByteRelY>127) ByteRelY = 127;
1372: if (ByteRelY<-128) ByteRelY = -128;
1373:
1374: Header = 0xf8;
1375: if (Keyboard.bLButtonDown)
1376: Header |= 0x02;
1377: if (Keyboard.bRButtonDown)
1378: Header |= 0x01;
1.1.1.20 root 1379:
1380: if ( IKBD_OutputBuffer_CheckFreeCount ( 3 ) )
1381: {
1382: IKBD_Cmd_Return_Byte (Header);
1383: IKBD_Cmd_Return_Byte (ByteRelX);
1384: IKBD_Cmd_Return_Byte (ByteRelY*KeyboardProcessor.Mouse.YAxis);
1385: }
1.1.1.12 root 1386:
1387: KeyboardProcessor.Mouse.DeltaX -= ByteRelX;
1388: KeyboardProcessor.Mouse.DeltaY -= ByteRelY;
1389:
1390: if ( (KeyboardProcessor.Mouse.DeltaX==0) && (KeyboardProcessor.Mouse.DeltaY==0) )
1391: break;
1392:
1393: /* Store buttons for next time around */
1394: Keyboard.bOldLButtonDown = Keyboard.bLButtonDown;
1395: Keyboard.bOldRButtonDown = Keyboard.bRButtonDown;
1396: }
1397: }
1.1 root 1398: }
1399:
1.1.1.2 root 1400:
1.1.1.13 root 1401: /**
1402: * Get joystick data
1403: */
1404: static void IKBD_GetJoystickData(void)
1405: {
1406: /* Joystick 1 */
1407: KeyboardProcessor.Joy.JoyData[1] = Joy_GetStickData(1);
1408:
1409: /* If mouse is on, joystick 0 is not connected */
1410: if (KeyboardProcessor.MouseMode==AUTOMODE_OFF
1411: || (bBothMouseAndJoy && KeyboardProcessor.MouseMode==AUTOMODE_MOUSEREL))
1412: KeyboardProcessor.Joy.JoyData[0] = Joy_GetStickData(0);
1413: else
1414: KeyboardProcessor.Joy.JoyData[0] = 0x00;
1415: }
1416:
1417:
1.1.1.2 root 1418: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1419: /**
1420: * Send 'joysticks' bit masks
1421: */
1.1.1.21 root 1422: static void IKBD_SendAutoJoysticks(void)
1.1 root 1423: {
1.1.1.12 root 1424: Uint8 JoyData;
1.1 root 1425:
1.1.1.12 root 1426: /* Did joystick 0/mouse change? */
1427: JoyData = KeyboardProcessor.Joy.JoyData[0];
1428: if (JoyData!=KeyboardProcessor.Joy.PrevJoyData[0])
1429: {
1.1.1.20 root 1430: if ( IKBD_OutputBuffer_CheckFreeCount ( 2 ) )
1431: {
1432: IKBD_Cmd_Return_Byte (0xFE); /* Joystick 0 / Mouse */
1433: IKBD_Cmd_Return_Byte (JoyData);
1434: }
1.1.1.12 root 1435: KeyboardProcessor.Joy.PrevJoyData[0] = JoyData;
1436: }
1437:
1438: /* Did joystick 1(default) change? */
1439: JoyData = KeyboardProcessor.Joy.JoyData[1];
1440: if (JoyData!=KeyboardProcessor.Joy.PrevJoyData[1])
1441: {
1.1.1.20 root 1442: if ( IKBD_OutputBuffer_CheckFreeCount ( 2 ) )
1443: {
1444: IKBD_Cmd_Return_Byte (0xFF); /* Joystick 1 */
1445: IKBD_Cmd_Return_Byte (JoyData);
1446: }
1.1.1.12 root 1447: KeyboardProcessor.Joy.PrevJoyData[1] = JoyData;
1448: }
1.1 root 1449: }
1450:
1451: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1452: /**
1.1.1.21 root 1453: * Send 'joysticks' bit masks when in monitoring mode
1454: * %000000xy ; where y is JOYSTICK1 Fire button
1455: * ; and x is JOYSTICK0 Fire button
1456: * %nnnnmmmm ; where m is JOYSTICK1 state
1457: * ; and n is JOYSTICK0 state
1458: */
1459: static void IKBD_SendAutoJoysticksMonitoring(void)
1460: {
1461: Uint8 Byte1;
1462: Uint8 Byte2;
1463:
1464: Byte1 = ( ( KeyboardProcessor.Joy.JoyData[0] & 0x80 ) >> 6 )
1.1.1.22 root 1465: | ( ( KeyboardProcessor.Joy.JoyData[1] & 0x80 ) >> 7 );
1.1.1.21 root 1466:
1467: Byte2 = ( ( KeyboardProcessor.Joy.JoyData[0] & 0x0f ) << 4 )
1.1.1.22 root 1468: | ( KeyboardProcessor.Joy.JoyData[1] & 0x0f );
1.1.1.21 root 1469:
1470: IKBD_Cmd_Return_Byte (Byte1);
1471: IKBD_Cmd_Return_Byte (Byte2);
1472: //fprintf ( stderr , "joystick monitoring %x %x VBL=%d HBL=%d\n" , Byte1 , Byte2 , nVBLs , nHBL );
1473: }
1474:
1475: /*-----------------------------------------------------------------------*/
1476: /**
1.1.1.12 root 1477: * Send packets which are generated from the mouse action settings
1478: * If relative mode is on, still generate these packets
1479: */
1.1.1.8 root 1480: static void IKBD_SendOnMouseAction(void)
1.1 root 1481: {
1.1.1.15 root 1482: bool bReportPosition = false;
1.1 root 1483:
1.1.1.12 root 1484: /* Report buttons as keys? Do in relative/absolute mode */
1485: if (KeyboardProcessor.Mouse.Action&0x4)
1486: {
1.1.1.20 root 1487: if ( IKBD_OutputBuffer_CheckFreeCount ( 2 ) )
1488: {
1489: /* Left button? */
1490: if ( (IKBD_ButtonBool(Keyboard.bLButtonDown) && (!IKBD_ButtonBool(Keyboard.bOldLButtonDown))) )
1491: IKBD_Cmd_Return_Byte (0x74); /* Left */
1492: else if ( (IKBD_ButtonBool(Keyboard.bOldLButtonDown) && (!IKBD_ButtonBool(Keyboard.bLButtonDown))) )
1493: IKBD_Cmd_Return_Byte (0x74|0x80);
1494: /* Right button? */
1495: if ( (IKBD_ButtonBool(Keyboard.bRButtonDown) && (!IKBD_ButtonBool(Keyboard.bOldRButtonDown))) )
1496: IKBD_Cmd_Return_Byte (0x75); /* Right */
1497: else if ( (IKBD_ButtonBool(Keyboard.bOldRButtonDown) && (!IKBD_ButtonBool(Keyboard.bRButtonDown))) )
1498: IKBD_Cmd_Return_Byte (0x75|0x80);
1499: }
1.1.1.12 root 1500: /* Ignore bottom two bits, so return now */
1501: return;
1502: }
1503:
1504: /* Check MouseAction - report position on press/release */
1505: /* MUST do this before update relative positions as buttons get reset */
1506: if (KeyboardProcessor.Mouse.Action&0x3)
1507: {
1508: /* Check for 'press'? */
1509: if (KeyboardProcessor.Mouse.Action&0x1)
1510: {
1511: /* Did 'press' mouse buttons? */
1512: if ( (IKBD_ButtonBool(Keyboard.bLButtonDown) && (!IKBD_ButtonBool(Keyboard.bOldLButtonDown))) )
1513: {
1.1.1.15 root 1514: bReportPosition = true;
1.1.1.12 root 1515: KeyboardProcessor.Abs.PrevReadAbsMouseButtons &= ~0x04;
1516: KeyboardProcessor.Abs.PrevReadAbsMouseButtons |= 0x02;
1517: }
1518: if ( (IKBD_ButtonBool(Keyboard.bRButtonDown) && (!IKBD_ButtonBool(Keyboard.bOldRButtonDown))) )
1519: {
1.1.1.15 root 1520: bReportPosition = true;
1.1.1.12 root 1521: KeyboardProcessor.Abs.PrevReadAbsMouseButtons &= ~0x01;
1522: KeyboardProcessor.Abs.PrevReadAbsMouseButtons |= 0x08;
1523: }
1524: }
1525: /* Check for 'release'? */
1526: if (KeyboardProcessor.Mouse.Action&0x2)
1527: {
1528: /* Did 'release' mouse buttons? */
1529: if ( (IKBD_ButtonBool(Keyboard.bOldLButtonDown) && (!IKBD_ButtonBool(Keyboard.bLButtonDown))) )
1530: {
1.1.1.15 root 1531: bReportPosition = true;
1.1.1.12 root 1532: KeyboardProcessor.Abs.PrevReadAbsMouseButtons &= ~0x08;
1533: KeyboardProcessor.Abs.PrevReadAbsMouseButtons |= 0x01;
1534: }
1535: if ( (IKBD_ButtonBool(Keyboard.bOldRButtonDown) && (!IKBD_ButtonBool(Keyboard.bRButtonDown))) )
1536: {
1.1.1.15 root 1537: bReportPosition = true;
1.1.1.12 root 1538: KeyboardProcessor.Abs.PrevReadAbsMouseButtons &= ~0x02;
1539: KeyboardProcessor.Abs.PrevReadAbsMouseButtons |= 0x04;
1540: }
1541: }
1542:
1543: /* Do need to report? */
1544: if (bReportPosition)
1545: {
1546: /* Only report if mouse in absolute mode */
1547: if (KeyboardProcessor.MouseMode==AUTOMODE_MOUSEABS)
1548: {
1.1.1.20 root 1549: LOG_TRACE(TRACE_IKBD_CMDS, "Report ABS on MouseAction\n");
1.1.1.12 root 1550: IKBD_Cmd_ReadAbsMousePos();
1551: }
1552: }
1553: }
1554: }
1555:
1556:
1557: /*-----------------------------------------------------------------------*/
1558: /**
1559: * Send mouse movements as cursor keys
1560: */
1.1.1.8 root 1561: static void IKBD_SendCursorMousePacket(void)
1.1 root 1562: {
1.1.1.12 root 1563: int i=0;
1.1 root 1564:
1.1.1.12 root 1565: /* Run each 'Delta' as cursor presses */
1566: /* Limit to '10' loops as host mouse cursor might have a VERY poor quality. */
1567: /* Eg, a single mouse movement on and ST gives delta's of '1', mostly, */
1568: /* but host mouse might go as high as 20+! */
1.1.1.18 root 1569: //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 1570: while ( (i<10) && ((KeyboardProcessor.Mouse.DeltaX!=0) || (KeyboardProcessor.Mouse.DeltaY!=0)
1571: || (!IKBD_ButtonsEqual(Keyboard.bOldLButtonDown,Keyboard.bLButtonDown)) || (!IKBD_ButtonsEqual(Keyboard.bOldRButtonDown,Keyboard.bRButtonDown))) )
1572: {
1573: /* Left? */
1574: if (KeyboardProcessor.Mouse.DeltaX<0)
1575: {
1.1.1.20 root 1576: if ( IKBD_OutputBuffer_CheckFreeCount ( 2 ) )
1577: {
1578: IKBD_Cmd_Return_Byte (75); /* Left cursor */
1579: IKBD_Cmd_Return_Byte (75|0x80);
1580: }
1.1.1.12 root 1581: KeyboardProcessor.Mouse.DeltaX++;
1582: }
1583: /* Right? */
1584: if (KeyboardProcessor.Mouse.DeltaX>0)
1585: {
1.1.1.20 root 1586: if ( IKBD_OutputBuffer_CheckFreeCount ( 2 ) )
1587: {
1588: IKBD_Cmd_Return_Byte (77); /* Right cursor */
1589: IKBD_Cmd_Return_Byte (77|0x80);
1590: }
1.1.1.12 root 1591: KeyboardProcessor.Mouse.DeltaX--;
1592: }
1593: /* Up? */
1594: if (KeyboardProcessor.Mouse.DeltaY<0)
1595: {
1.1.1.20 root 1596: if ( IKBD_OutputBuffer_CheckFreeCount ( 2 ) )
1597: {
1598: IKBD_Cmd_Return_Byte (72); /* Up cursor */
1599: IKBD_Cmd_Return_Byte (72|0x80);
1600: }
1.1.1.12 root 1601: KeyboardProcessor.Mouse.DeltaY++;
1602: }
1603: /* Down? */
1604: if (KeyboardProcessor.Mouse.DeltaY>0)
1605: {
1.1.1.20 root 1606: if ( IKBD_OutputBuffer_CheckFreeCount ( 2 ) )
1607: {
1608: IKBD_Cmd_Return_Byte (80); /* Down cursor */
1609: IKBD_Cmd_Return_Byte (80|0x80);
1610: }
1.1.1.12 root 1611: KeyboardProcessor.Mouse.DeltaY--;
1612: }
1613:
1.1.1.20 root 1614: if ( IKBD_OutputBuffer_CheckFreeCount ( 2 ) )
1615: {
1616: /* Left button? */
1617: if ( (IKBD_ButtonBool(Keyboard.bLButtonDown) && (!IKBD_ButtonBool(Keyboard.bOldLButtonDown))) )
1618: IKBD_Cmd_Return_Byte (0x74); /* Left */
1619: else if ( (IKBD_ButtonBool(Keyboard.bOldLButtonDown) && (!IKBD_ButtonBool(Keyboard.bLButtonDown))) )
1620: IKBD_Cmd_Return_Byte (0x74|0x80);
1621: /* Right button? */
1622: if ( (IKBD_ButtonBool(Keyboard.bRButtonDown) && (!IKBD_ButtonBool(Keyboard.bOldRButtonDown))) )
1623: IKBD_Cmd_Return_Byte (0x75); /* Right */
1624: else if ( (IKBD_ButtonBool(Keyboard.bOldRButtonDown) && (!IKBD_ButtonBool(Keyboard.bRButtonDown))) )
1625: IKBD_Cmd_Return_Byte (0x75|0x80);
1626: }
1.1.1.12 root 1627: Keyboard.bOldLButtonDown = Keyboard.bLButtonDown;
1628: Keyboard.bOldRButtonDown = Keyboard.bRButtonDown;
1629:
1630: /* Count, so exit if try too many times! */
1631: i++;
1632: }
1.1 root 1633: }
1634:
1.1.1.2 root 1635:
1636: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1637: /**
1638: * Return packets from keyboard for auto, rel mouse, joystick etc...
1639: */
1.1.1.14 root 1640: static void IKBD_SendAutoKeyboardCommands(void)
1.1 root 1641: {
1.1.1.12 root 1642: /* Don't do anything until processor is first reset */
1.1.1.20 root 1643: if ( bDuringResetCriticalTime )
1.1.1.12 root 1644: return;
1645:
1646: /* Read joysticks for this frame */
1.1.1.13 root 1647: IKBD_GetJoystickData();
1.1.1.12 root 1648:
1649: /* Check for double-clicks in maximum speed mode */
1650: IKBD_CheckForDoubleClicks();
1651:
1652: /* Handle Joystick/Mouse fire buttons */
1653: IKBD_DuplicateMouseFireButtons();
1654:
1655: /* Send any packets which are to be reported by mouse action */
1656: IKBD_SendOnMouseAction();
1657:
1658: /* Update internal mouse absolute position by find 'delta' of mouse movement */
1659: IKBD_UpdateInternalMousePosition();
1660:
1.1.1.21 root 1661: /* If IKBD is monitoring only joysticks, don't report other events */
1662: if ( KeyboardProcessor.JoystickMode == AUTOMODE_JOYSTICK_MONITORING )
1663: {
1664: IKBD_SendAutoJoysticksMonitoring();
1665: return;
1666: }
1667:
1.1.1.12 root 1668: /* Send automatic joystick packets */
1669: if (KeyboardProcessor.JoystickMode==AUTOMODE_JOYSTICK)
1.1.1.21 root 1670: IKBD_SendAutoJoysticks();
1.1.1.12 root 1671: /* Send automatic relative mouse positions(absolute are not send automatically) */
1672: if (KeyboardProcessor.MouseMode==AUTOMODE_MOUSEREL)
1673: IKBD_SendRelMousePacket();
1674: /* Send cursor key directions for movements */
1675: else if (KeyboardProcessor.MouseMode==AUTOMODE_MOUSECURSOR)
1676: IKBD_SendCursorMousePacket();
1677:
1678: /* Store buttons for next time around */
1679: Keyboard.bOldLButtonDown = Keyboard.bLButtonDown;
1680: Keyboard.bOldRButtonDown = Keyboard.bRButtonDown;
1681:
1682: /* Send joystick button '2' as 'Space bar' key - MUST do here so does not get mixed up in middle of joystick packets! */
1683: if (JoystickSpaceBar)
1684: {
1685: /* As we simulating space bar? */
1686: if (JoystickSpaceBar==JOYSTICK_SPACE_DOWN)
1687: {
1.1.1.15 root 1688: IKBD_PressSTKey(57, true); /* Press */
1.1.1.12 root 1689: JoystickSpaceBar = JOYSTICK_SPACE_UP;
1690: }
1691: else //if (JoystickSpaceBar==JOYSTICK_SPACE_UP) {
1692: {
1.1.1.15 root 1693: IKBD_PressSTKey(57, false); /* Release */
1694: JoystickSpaceBar = false; /* Complete */
1.1.1.12 root 1695: }
1696: }
1.1.1.20 root 1697:
1698:
1699: /* If we're executing a custom IKBD program, call it to process the key/mouse/joystick event */
1700: if ( IKBD_ExeMode && pIKBD_CustomCodeHandler_Read )
1701: (*pIKBD_CustomCodeHandler_Read) ();
1702: }
1703:
1704:
1705: /*-----------------------------------------------------------------------*/
1706: /**
1707: * When press/release key under host OS, execute this function.
1708: */
1709: void IKBD_PressSTKey(Uint8 ScanCode, bool bPress)
1710: {
1.1.1.21 root 1711: /* If IKBD is monitoring only joysticks, don't report key */
1712: if ( KeyboardProcessor.JoystickMode == AUTOMODE_JOYSTICK_MONITORING )
1713: return;
1714:
1.1.1.20 root 1715: /* Store the state of each ST scancode : 1=pressed 0=released */
1716: if ( bPress ) ScanCodeState[ ScanCode & 0x7f ] = 1;
1717: else ScanCodeState[ ScanCode & 0x7f ] = 0;
1718:
1719: if (!bPress)
1720: ScanCode |= 0x80; /* Set top bit if released key */
1721:
1722: if ( IKBD_OutputBuffer_CheckFreeCount ( 1 ) )
1723: {
1.1.1.21 root 1724: IKBD_Cmd_Return_Byte (ScanCode); /* Add to the IKBD's output buffer */
1.1.1.20 root 1725: }
1726:
1727: /* If we're executing a custom IKBD program, call it to process the key event */
1728: if ( IKBD_ExeMode && pIKBD_CustomCodeHandler_Read )
1729: (*pIKBD_CustomCodeHandler_Read) ();
1.1 root 1730: }
1731:
1.1.1.2 root 1732:
1733: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1734: /**
1.1.1.14 root 1735: * This function is called regularly to automatically send keyboard, mouse
1736: * and joystick updates.
1737: */
1738: void IKBD_InterruptHandler_AutoSend(void)
1739: {
1740: /* Handle user events and other messages, (like quit message) */
1741: Main_EventHandler();
1742:
1.1.1.17 root 1743: /* Remove this interrupt from list and re-order.
1744: * (needs to be done after UI event handling so
1745: * that snapshots saved from UI and restored from
1746: * command line don't miss the AUTOSEND interrupt)
1747: */
1748: CycInt_AcknowledgeInterrupt();
1749:
1.1.1.14 root 1750: /* Did user try to quit? */
1751: if (bQuitProgram)
1752: {
1753: /* Pass NULL interrupt function to quit cleanly */
1.1.1.16 root 1754: CycInt_AddAbsoluteInterrupt(4, INT_CPU_CYCLE, INTERRUPT_NULL);
1.1.1.14 root 1755: /* Assure that CPU core shuts down */
1756: M68000_SetSpecial(SPCFLAG_BRK);
1757: return;
1758: }
1759:
1760: /* Trigger this auto-update function again after a while */
1.1.1.23! root 1761: #ifdef OLD_CPU_SHIFT
1.1.1.21 root 1762: CycInt_AddRelativeInterrupt(Keyboard.AutoSendCycles, INT_CPU_CYCLE, INTERRUPT_IKBD_AUTOSEND);
1.1.1.23! root 1763: #else
! 1764: CycInt_AddRelativeInterrupt(Keyboard.AutoSendCycles, INT_CPU8_CYCLE, INTERRUPT_IKBD_AUTOSEND);
! 1765: #endif
1.1.1.14 root 1766:
1767: /* We don't send keyboard data automatically within the first few
1768: * VBLs to avoid that TOS gets confused during its boot time */
1769: if (nVBLs > 20)
1770: {
1771: /* Send automatic keyboard packets for mouse, joysticks etc... */
1772: IKBD_SendAutoKeyboardCommands();
1773: }
1774: }
1775:
1776:
1777: /*-----------------------------------------------------------------------*/
1778: /**
1.1.1.12 root 1779: * On ST if disable Mouse AND Joystick with a set time of a RESET command they are
1780: * actually turned back on! (A number of games do this so can get mouse and joystick
1781: * packets at the same time)
1782: */
1.1.1.8 root 1783: static void IKBD_CheckResetDisableBug(void)
1.1 root 1784: {
1.1.1.12 root 1785: /* Have disabled BOTH mouse and joystick? */
1786: if (bMouseDisabled && bJoystickDisabled)
1787: {
1788: /* And in critical time? */
1789: if (bDuringResetCriticalTime)
1790: {
1791: /* Emulate relative mouse and joystick reports being turned back on */
1792: KeyboardProcessor.MouseMode = AUTOMODE_MOUSEREL;
1793: KeyboardProcessor.JoystickMode = AUTOMODE_JOYSTICK;
1.1.1.15 root 1794: bBothMouseAndJoy = true;
1.1.1.6 root 1795:
1.1.1.19 root 1796: LOG_TRACE(TRACE_IKBD_ALL, "ikbd cancel commands 0x12 and 0x1a received during reset,"
1797: " enabling joystick and mouse reporting at the same time\n" );
1.1.1.12 root 1798: }
1799: }
1.1 root 1800: }
1801:
1.1.1.2 root 1802:
1.1.1.20 root 1803:
1.1.1.2 root 1804: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1805: /**
1.1.1.20 root 1806: * When a byte is received by the IKBD, it is added to a small 8 byte buffer.
1807: * If the first byte is a valid command, we wait for additionnal bytes if needed
1808: * and then we execute the command's handler.
1809: * If the first byte is not a valid command or after a successful command, we
1810: * empty the input buffer (extra bytes, if any, are lost)
1811: * If the input buffer is full when a new byte is received, the new byte is lost.
1.1.1.12 root 1812: */
1.1.1.20 root 1813: static void IKBD_RunKeyboardCommand(Uint8 aciabyte)
1.1 root 1814: {
1.1.1.20 root 1815: int i=0;
1.1.1.19 root 1816:
1.1.1.20 root 1817: /* Write into our keyboard input buffer if it's not full yet */
1818: if ( Keyboard.nBytesInInputBuffer < SIZE_KEYBOARDINPUT_BUFFER )
1819: Keyboard.InputBuffer[Keyboard.nBytesInInputBuffer++] = aciabyte;
1.1 root 1820:
1.1.1.20 root 1821: /* Now check bytes to see if we have a valid/in-valid command string set */
1822: while (KeyboardCommands[i].Command!=0xff)
1823: {
1824: /* Found command? */
1825: if (KeyboardCommands[i].Command==Keyboard.InputBuffer[0])
1826: {
1.1.1.21 root 1827: /* If the command is complete (with its possible parameters) we can execute it */
1.1.1.20 root 1828: /* Else, we wait for the next bytes until the command is complete */
1829: if (KeyboardCommands[i].NumParameters==Keyboard.nBytesInInputBuffer)
1830: {
1.1.1.21 root 1831: /* Any new valid command will unpause the output (if command 0x13 was used) */
1832: Keyboard.PauseOutput = false;
1833:
1.1.1.20 root 1834: CALL_VAR(KeyboardCommands[i].pCallFunction);
1835: Keyboard.nBytesInInputBuffer = 0; /* Clear input buffer after processing a command */
1836: }
1.1.1.9 root 1837:
1.1.1.20 root 1838: return;
1839: }
1840:
1841: i++;
1842: }
1843:
1844: /* Command not known, reset buffer(IKBD assumes a NOP) */
1845: Keyboard.nBytesInInputBuffer = 0;
1.1 root 1846: }
1847:
1848:
1849:
1.1.1.20 root 1850:
1851: /************************************************************************/
1852: /* List of keyboard commands handled by the standard IKBD's ROM. */
1853: /* Each IKBD's command is emulated to get the same result as if we were */
1854: /* running a full HD6301 emulation. */
1855: /************************************************************************/
1.1 root 1856:
1857:
1.1.1.2 root 1858: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1859: /**
1860: * RESET
1861: *
1862: * 0x80
1863: * 0x01
1864: *
1.1.1.20 root 1865: * Performs self test and checks for stuck (closed) keys, if OK returns
1866: * IKBD_ROM_VERSION (0xF1). Otherwise returns break codes for keys (not emulated).
1.1.1.12 root 1867: */
1.1.1.13 root 1868: static void IKBD_Cmd_Reset(void)
1.1 root 1869: {
1.1.1.19 root 1870: LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_Reset VBLs=%i framecyc=%i\n",
1.1.1.15 root 1871: nVBLs, Cycles_GetCounter(CYCLES_COUNTER_VIDEO));
1.1.1.14 root 1872:
1.1.1.20 root 1873: /* Check that 0x01 was received after 0x80 */
1.1.1.12 root 1874: if (Keyboard.InputBuffer[1] == 0x01)
1875: {
1.1.1.20 root 1876: IKBD_Boot_ROM ( false );
1.1.1.12 root 1877: }
1878: /* else if not 0x80,0x01 just ignore */
1.1 root 1879: }
1880:
1.1.1.2 root 1881:
1882: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1883: /**
1884: * SET MOUSE BUTTON ACTION
1885: *
1886: * 0x07
1887: * %00000mss ; mouse button action
1888: * ; (m is presumed =1 when in MOUSE KEYCODE mode)
1889: * ; mss=0xy, mouse button press or release causes mouse
1890: * ; position report
1891: * ; where y=1, mouse key press causes absolute report
1892: * ; and x=1, mouse key release causes absolute report
1893: * ; mss=100, mouse buttons act like keys
1894: */
1.1.1.13 root 1895: static void IKBD_Cmd_MouseAction(void)
1.1 root 1896: {
1.1.1.12 root 1897: KeyboardProcessor.Mouse.Action = Keyboard.InputBuffer[1];
1898: KeyboardProcessor.Abs.PrevReadAbsMouseButtons = ABS_PREVBUTTONS;
1.1.1.13 root 1899:
1.1.1.15 root 1900: LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_MouseAction %d\n",
1901: (unsigned int)KeyboardProcessor.Mouse.Action);
1.1 root 1902: }
1903:
1.1.1.2 root 1904:
1905: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1906: /**
1907: * SET RELATIVE MOUSE POSITION REPORTING
1908: *
1909: * 0x08
1910: */
1.1.1.13 root 1911: static void IKBD_Cmd_RelMouseMode(void)
1.1 root 1912: {
1.1.1.12 root 1913: KeyboardProcessor.MouseMode = AUTOMODE_MOUSEREL;
1.1.1.13 root 1914:
1.1.1.14 root 1915: /* Some games (like Barbarian by Psygnosis) enable both, mouse and
1916: * joystick directly after a reset. This causes the IKBD to send both
1917: * type of packets. To emulate this feature, we've got to remember
1918: * that the mouse has been enabled during reset. */
1919: if (bDuringResetCriticalTime)
1.1.1.15 root 1920: bMouseEnabledDuringReset = true;
1.1.1.14 root 1921:
1.1.1.15 root 1922: LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_RelMouseMode\n");
1.1 root 1923: }
1924:
1.1.1.2 root 1925:
1926: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1927: /**
1928: * SET ABSOLUTE MOUSE POSITIONING
1929: *
1930: * 0x09
1931: * XMSB ;X maximum (in scaled mouse clicks)
1932: * XLSB
1933: * YMSB ;Y maximum (in scaled mouse clicks)
1934: * YLSB
1935: */
1.1.1.13 root 1936: static void IKBD_Cmd_AbsMouseMode(void)
1.1 root 1937: {
1.1.1.12 root 1938: /* These maximums are 'inclusive' */
1939: KeyboardProcessor.MouseMode = AUTOMODE_MOUSEABS;
1940: KeyboardProcessor.Abs.MaxX = (((unsigned int)Keyboard.InputBuffer[1])<<8) | (unsigned int)Keyboard.InputBuffer[2];
1941: KeyboardProcessor.Abs.MaxY = (((unsigned int)Keyboard.InputBuffer[3])<<8) | (unsigned int)Keyboard.InputBuffer[4];
1.1.1.13 root 1942:
1.1.1.15 root 1943: LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_AbsMouseMode %d,%d\n",
1944: KeyboardProcessor.Abs.MaxX, KeyboardProcessor.Abs.MaxY);
1.1 root 1945: }
1946:
1.1.1.2 root 1947:
1948: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1949: /**
1950: * SET MOUSE KEYCODE MODE
1951: *
1952: * 0x0A
1953: * deltax ; distance in X clicks to return (LEFT) or (RIGHT)
1954: * deltay ; distance in Y clicks to return (UP) or (DOWN)
1955: */
1.1.1.13 root 1956: static void IKBD_Cmd_MouseCursorKeycodes(void)
1.1 root 1957: {
1.1.1.12 root 1958: KeyboardProcessor.MouseMode = AUTOMODE_MOUSECURSOR;
1959: KeyboardProcessor.Mouse.KeyCodeDeltaX = Keyboard.InputBuffer[1];
1960: KeyboardProcessor.Mouse.KeyCodeDeltaY = Keyboard.InputBuffer[2];
1.1.1.13 root 1961:
1.1.1.15 root 1962: LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_MouseCursorKeycodes %d,%d\n",
1963: (int)KeyboardProcessor.Mouse.KeyCodeDeltaX,
1964: (int)KeyboardProcessor.Mouse.KeyCodeDeltaY);
1.1 root 1965: }
1966:
1.1.1.2 root 1967:
1968: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1969: /**
1970: * SET MOUSE THRESHOLD
1971: *
1972: * 0x0B
1973: * X ; x threshold in mouse ticks (positive integers)
1974: * Y ; y threshold in mouse ticks (positive integers)
1975: */
1.1.1.13 root 1976: static void IKBD_Cmd_SetMouseThreshold(void)
1.1 root 1977: {
1.1.1.12 root 1978: KeyboardProcessor.Mouse.XThreshold = (unsigned int)Keyboard.InputBuffer[1];
1979: KeyboardProcessor.Mouse.YThreshold = (unsigned int)Keyboard.InputBuffer[2];
1.1.1.13 root 1980:
1.1.1.15 root 1981: LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_SetMouseThreshold %d,%d\n",
1982: KeyboardProcessor.Mouse.XThreshold, KeyboardProcessor.Mouse.YThreshold);
1.1 root 1983: }
1984:
1.1.1.2 root 1985:
1986: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1987: /**
1988: * SET MOUSE SCALE
1989: *
1990: * 0x0C
1991: * X ; horizontal mouse ticks per internel X
1992: * Y ; vertical mouse ticks per internel Y
1993: */
1.1.1.13 root 1994: static void IKBD_Cmd_SetMouseScale(void)
1.1 root 1995: {
1.1.1.12 root 1996: KeyboardProcessor.Mouse.XScale = (unsigned int)Keyboard.InputBuffer[1];
1997: KeyboardProcessor.Mouse.YScale = (unsigned int)Keyboard.InputBuffer[2];
1.1.1.13 root 1998:
1.1.1.15 root 1999: LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_SetMouseScale %d,%d\n",
2000: KeyboardProcessor.Mouse.XScale, KeyboardProcessor.Mouse.YScale);
1.1 root 2001: }
2002:
2003:
1.1.1.12 root 2004: /*-----------------------------------------------------------------------*/
2005: /**
2006: * INTERROGATE MOUSE POSITION
2007: *
2008: * 0x0D
2009: * Returns: 0xF7 ; absolute mouse position header
2010: * BUTTONS
2011: * 0000dcba
2012: * where a is right button down since last interrogation
2013: * b is right button up since last
2014: * c is left button down since last
2015: * d is left button up since last
2016: * XMSB ; X coordinate
2017: * XLSB
2018: * YMSB ; Y coordinate
2019: * YLSB
2020: */
1.1.1.13 root 2021: static void IKBD_Cmd_ReadAbsMousePos(void)
1.1 root 2022: {
1.1.1.12 root 2023: Uint8 Buttons,PrevButtons;
1.1 root 2024:
1.1.1.12 root 2025: /* Test buttons */
2026: Buttons = 0;
2027: /* Set buttons to show if up/down */
2028: if (Keyboard.bRButtonDown)
2029: Buttons |= 0x01;
2030: else
2031: Buttons |= 0x02;
2032: if (Keyboard.bLButtonDown)
2033: Buttons |= 0x04;
2034: else
2035: Buttons |= 0x08;
2036: /* Mask off it didn't send last time */
2037: PrevButtons = KeyboardProcessor.Abs.PrevReadAbsMouseButtons;
2038: KeyboardProcessor.Abs.PrevReadAbsMouseButtons = Buttons;
2039: Buttons &= ~PrevButtons;
2040:
2041: /* And send packet */
1.1.1.20 root 2042: if ( IKBD_OutputBuffer_CheckFreeCount ( 6 ) )
2043: {
2044: IKBD_Cmd_Return_Byte_Delay (0xf7, 18000-ACIA_CYCLES);
2045: IKBD_Cmd_Return_Byte (Buttons);
2046: IKBD_Cmd_Return_Byte ((unsigned int)KeyboardProcessor.Abs.X>>8);
2047: IKBD_Cmd_Return_Byte ((unsigned int)KeyboardProcessor.Abs.X&0xff);
2048: IKBD_Cmd_Return_Byte ((unsigned int)KeyboardProcessor.Abs.Y>>8);
2049: IKBD_Cmd_Return_Byte ((unsigned int)KeyboardProcessor.Abs.Y&0xff);
2050: }
1.1.1.12 root 2051:
1.1.1.15 root 2052: LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_ReadAbsMousePos %d,%d 0x%X\n",
2053: KeyboardProcessor.Abs.X, KeyboardProcessor.Abs.Y, Buttons);
1.1 root 2054: }
2055:
2056:
1.1.1.12 root 2057: /*-----------------------------------------------------------------------*/
2058: /**
2059: * LOAD MOUSE POSITION
2060: *
2061: * 0x0E
2062: * 0x00 ; filler
2063: * XMSB ; X coordinate
2064: * XLSB ; (in scaled coordinate system)
2065: * YMSB ; Y coordinate
2066: * YLSB
2067: */
1.1.1.13 root 2068: static void IKBD_Cmd_SetInternalMousePos(void)
1.1.1.7 root 2069: {
1.1.1.12 root 2070: /* Setting these do not clip internal position(this happens on next update) */
2071: KeyboardProcessor.Abs.X = (((unsigned int)Keyboard.InputBuffer[2])<<8) | (unsigned int)Keyboard.InputBuffer[3];
2072: KeyboardProcessor.Abs.Y = (((unsigned int)Keyboard.InputBuffer[4])<<8) | (unsigned int)Keyboard.InputBuffer[5];
1.1.1.13 root 2073:
1.1.1.15 root 2074: LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_SetInternalMousePos %d,%d\n",
2075: KeyboardProcessor.Abs.X, KeyboardProcessor.Abs.Y);
1.1 root 2076: }
2077:
1.1.1.2 root 2078:
2079: /*-----------------------------------------------------------------------*/
1.1.1.12 root 2080: /**
2081: * SET Y=0 AT BOTTOM
2082: *
2083: * 0x0F
2084: */
1.1.1.13 root 2085: static void IKBD_Cmd_SetYAxisDown(void)
1.1 root 2086: {
1.1.1.12 root 2087: KeyboardProcessor.Mouse.YAxis = -1;
1.1.1.13 root 2088:
1.1.1.15 root 2089: LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_SetYAxisDown\n");
1.1 root 2090: }
2091:
1.1.1.2 root 2092:
2093: /*-----------------------------------------------------------------------*/
1.1.1.12 root 2094: /**
2095: * SET Y=0 AT TOP
2096: *
2097: * 0x10
2098: */
1.1.1.13 root 2099: static void IKBD_Cmd_SetYAxisUp(void)
1.1 root 2100: {
1.1.1.12 root 2101: KeyboardProcessor.Mouse.YAxis = 1;
1.1.1.13 root 2102:
1.1.1.15 root 2103: LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_SetYAxisUp\n");
1.1 root 2104: }
2105:
1.1.1.2 root 2106:
2107: /*-----------------------------------------------------------------------*/
1.1.1.12 root 2108: /**
1.1.1.21 root 2109: * RESUME
2110: *
2111: * Any command received by the IKBD will also resume the output if it was
2112: * paused by command 0x13, so this command is redundant.
1.1.1.12 root 2113: *
2114: * 0x11
2115: */
1.1.1.13 root 2116: static void IKBD_Cmd_StartKeyboardTransfer(void)
1.1 root 2117: {
1.1.1.21 root 2118: LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_StartKeyboardTransfer\n");
2119: Keyboard.PauseOutput = false;
1.1 root 2120: }
2121:
1.1.1.2 root 2122:
2123: /*-----------------------------------------------------------------------*/
1.1.1.12 root 2124: /**
2125: * DISABLE MOUSE
2126: *
2127: * 0x12
2128: */
1.1.1.13 root 2129: static void IKBD_Cmd_TurnMouseOff(void)
1.1 root 2130: {
1.1.1.12 root 2131: KeyboardProcessor.MouseMode = AUTOMODE_OFF;
1.1.1.15 root 2132: bMouseDisabled = true;
1.1.1.13 root 2133:
1.1.1.15 root 2134: LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_TurnMouseOff\n");
1.1 root 2135:
1.1.1.12 root 2136: IKBD_CheckResetDisableBug();
1.1 root 2137: }
2138:
1.1.1.2 root 2139:
2140: /*-----------------------------------------------------------------------*/
1.1.1.12 root 2141: /**
2142: * PAUSE OUTPUT
2143: *
2144: * 0x13
2145: */
1.1.1.13 root 2146: static void IKBD_Cmd_StopKeyboardTransfer(void)
1.1 root 2147: {
1.1.1.21 root 2148: if (bDuringResetCriticalTime)
2149: {
2150: /* Required for the loader of 'Just Bugging' by ACF */
2151: LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_StopKeyboardTransfer ignored during ikbd reset\n");
2152: return;
2153: }
2154:
2155: LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_StopKeyboardTransfer\n");
2156: Keyboard.PauseOutput = true;
1.1 root 2157: }
2158:
1.1.1.2 root 2159:
2160: /*-----------------------------------------------------------------------*/
1.1.1.12 root 2161: /**
2162: * SET JOYSTICK EVENT REPORTING
2163: *
2164: * 0x14
2165: */
1.1.1.13 root 2166: static void IKBD_Cmd_ReturnJoystickAuto(void)
1.1 root 2167: {
1.1.1.15 root 2168: LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_ReturnJoystickAuto\n");
1.1.1.14 root 2169:
1.1.1.12 root 2170: KeyboardProcessor.JoystickMode = AUTOMODE_JOYSTICK;
2171: KeyboardProcessor.MouseMode = AUTOMODE_OFF;
1.1.1.6 root 2172:
1.1.1.19 root 2173: /* If mouse was also enabled within time of a reset (0x08 command) it isn't disabled now!
2174: * (used by the game Barbarian 1 by Psygnosis for example) */
2175: if ( bDuringResetCriticalTime && bMouseEnabledDuringReset )
2176: {
2177: KeyboardProcessor.MouseMode = AUTOMODE_MOUSEREL;
2178: bBothMouseAndJoy = true;
2179: LOG_TRACE(TRACE_IKBD_ALL, "ikbd commands 0x08 and 0x14 received during reset,"
2180: " enabling joystick and mouse reporting at the same time\n" );
2181: }
2182: /* If mouse was disabled during the reset (0x12 command) it is enabled again
2183: * (used by the game Hammerfist for example) */
2184: else if ( bDuringResetCriticalTime && bMouseDisabled )
1.1.1.12 root 2185: {
2186: KeyboardProcessor.MouseMode = AUTOMODE_MOUSEREL;
1.1.1.15 root 2187: bBothMouseAndJoy = true;
1.1.1.19 root 2188: LOG_TRACE(TRACE_IKBD_ALL, "ikbd commands 0x12 and 0x14 received during reset,"
2189: " enabling joystick and mouse reporting at the same time\n" );
1.1.1.12 root 2190: }
1.1.1.6 root 2191:
1.1.1.13 root 2192: /* This command resets the internally previously stored joystick states */
2193: KeyboardProcessor.Joy.PrevJoyData[0] = KeyboardProcessor.Joy.PrevJoyData[1] = 0;
2194:
2195: /* This is a hack for the STE Utopos (=> v1.50) and Falcon Double Bubble
2196: * 2000 games. They expect the joystick data to be sent within a certain
2197: * amount of time after this command, without checking the ACIA control
2198: * register first.
2199: */
2200: IKBD_GetJoystickData();
1.1.1.21 root 2201: IKBD_SendAutoJoysticks();
1.1 root 2202: }
2203:
1.1.1.2 root 2204:
2205: /*-----------------------------------------------------------------------*/
1.1.1.12 root 2206: /**
2207: * SET JOYSTICK INTERROGATION MODE
2208: *
2209: * 0x15
2210: */
1.1.1.13 root 2211: static void IKBD_Cmd_StopJoystick(void)
1.1 root 2212: {
1.1.1.12 root 2213: KeyboardProcessor.JoystickMode = AUTOMODE_OFF;
1.1.1.15 root 2214: LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_StopJoystick\n");
1.1 root 2215: }
2216:
1.1.1.2 root 2217:
2218: /*-----------------------------------------------------------------------*/
1.1.1.12 root 2219: /**
2220: * JOYSTICK INTERROGATE
2221: *
2222: * 0x16
2223: */
1.1.1.13 root 2224: static void IKBD_Cmd_ReturnJoystick(void)
1.1 root 2225: {
1.1.1.17 root 2226: LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_ReturnJoystick\n");
2227:
1.1.1.20 root 2228: if ( IKBD_OutputBuffer_CheckFreeCount ( 3 ) )
2229: {
2230: IKBD_Cmd_Return_Byte_Delay ( 0xFD , IKBD_Delay_Random ( 7500 , 10000 ) );
2231: IKBD_Cmd_Return_Byte (Joy_GetStickData(0));
2232: IKBD_Cmd_Return_Byte (Joy_GetStickData(1));
2233: }
1.1 root 2234: }
2235:
1.1.1.2 root 2236:
2237: /*-----------------------------------------------------------------------*/
1.1.1.12 root 2238: /**
2239: * SET JOYSTICK MONITORING
2240: *
2241: * 0x17
2242: * rate ; time between samples in hundreths of a second
2243: * Returns: (in packets of two as long as in mode)
2244: * %000000xy where y is JOYSTICK1 Fire button
2245: * and x is JOYSTICK0 Fire button
2246: * %nnnnmmmm where m is JOYSTICK1 state
2247: * and n is JOYSTICK0 state
1.1.1.21 root 2248: *
2249: * TODO : we use a fixed 8 MHz clock to convert rate in 1/100th of sec into cycles.
2250: * This should be replaced by using MachineClocks.CPU_Freq.
1.1.1.12 root 2251: */
1.1.1.21 root 2252: static void IKBD_Cmd_SetJoystickMonitoring(void)
1.1 root 2253: {
1.1.1.21 root 2254: int Rate;
2255: int Cycles;
2256:
2257: Rate = (unsigned int)Keyboard.InputBuffer[1];
2258:
2259: KeyboardProcessor.JoystickMode = AUTOMODE_JOYSTICK_MONITORING;
2260: KeyboardProcessor.MouseMode = AUTOMODE_OFF;
2261:
2262: LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_SetJoystickMonitoring %d\n" , Rate );
2263:
2264: if ( Rate == 0 )
2265: Rate = 1;
2266:
2267: Cycles = 8021247 * Rate / 100;
1.1.1.23! root 2268: #ifdef OLD_CPU_SHIFT
1.1.1.21 root 2269: Cycles <<= nCpuFreqShift; /* Compensate for x2 or x4 cpu speed */
2270: CycInt_AddRelativeInterrupt ( Cycles, INT_CPU_CYCLE, INTERRUPT_IKBD_AUTOSEND );
1.1.1.23! root 2271: #else
! 2272: CycInt_AddRelativeInterrupt ( Cycles, INT_CPU8_CYCLE, INTERRUPT_IKBD_AUTOSEND );
! 2273: #endif
1.1.1.21 root 2274: Keyboard.AutoSendCycles = Cycles;
1.1 root 2275: }
2276:
1.1.1.2 root 2277:
2278: /*-----------------------------------------------------------------------*/
1.1.1.12 root 2279: /**
2280: * SET FIRE BUTTON MONITORING
2281: *
2282: * 0x18
2283: * Returns: (as long as in mode)
2284: * %bbbbbbbb ; state of the JOYSTICK1 fire button packed
2285: * ; 8 bits per byte, the first sample if the MSB
2286: */
1.1.1.13 root 2287: static void IKBD_Cmd_SetJoystickFireDuration(void)
1.1 root 2288: {
1.1.1.20 root 2289: LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_SetJoystickFireDuration (not implemented)\n");
1.1 root 2290: }
2291:
1.1.1.2 root 2292:
2293: /*-----------------------------------------------------------------------*/
1.1.1.12 root 2294: /**
2295: * SET JOYSTICK KEYCODE MODE
2296: *
2297: * 0x19
2298: * RX ; length of time (in tenths of seconds) until
2299: * ; horizontal velocity breakpoint is reached
2300: * RY ; length of time (in tenths of seconds) until
2301: * ; vertical velocity breakpoint is reached
2302: * TX ; length (in tenths of seconds) of joystick closure
2303: * ; until horizontal cursor key is generated before RX
2304: * ; has elapsed
2305: * TY ; length (in tenths of seconds) of joystick closure
2306: * ; until vertical cursor key is generated before RY
2307: * ; has elapsed
2308: * VX ; length (in tenths of seconds) of joystick closure
2309: * ; until horizontal cursor keystokes are generated after RX
2310: * ; has elapsed
2311: * VY ; length (in tenths of seconds) of joystick closure
2312: * ; until vertical cursor keystokes are generated after RY
2313: * ; has elapsed
2314: */
1.1.1.13 root 2315: static void IKBD_Cmd_SetCursorForJoystick(void)
1.1 root 2316: {
1.1.1.20 root 2317: LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_SetCursorForJoystick (not implemented)\n");
1.1 root 2318: }
2319:
1.1.1.2 root 2320:
2321: /*-----------------------------------------------------------------------*/
1.1.1.12 root 2322: /**
2323: * DISABLE JOYSTICKS
2324: *
2325: * 0x1A
2326: */
1.1.1.13 root 2327: static void IKBD_Cmd_DisableJoysticks(void)
1.1 root 2328: {
1.1.1.12 root 2329: KeyboardProcessor.JoystickMode = AUTOMODE_OFF;
1.1.1.15 root 2330: bJoystickDisabled = true;
1.1.1.13 root 2331:
1.1.1.15 root 2332: LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_DisableJoysticks\n");
1.1 root 2333:
1.1.1.12 root 2334: IKBD_CheckResetDisableBug();
1.1 root 2335: }
2336:
1.1.1.2 root 2337:
1.1.1.20 root 2338: /*-----------------------------------------------------------------------*/
1.1.1.12 root 2339: /**
2340: * TIME-OF-DAY CLOCK SET
2341: *
2342: * 0x1B
2343: * YY ; year (2 least significant digits)
2344: * MM ; month
2345: * DD ; day
2346: * hh ; hour
2347: * mm ; minute
2348: * ss ; second
1.1.1.20 root 2349: *
2350: * All bytes are stored in BCD format. If a byte is not in BCD, we ignore it
2351: * but we process the rest of the bytes.
2352: * Note that the IKBD doesn't check that month/day/hour/second/minute are in
2353: * their correct range, just that they're BCD encoded (so you can store 0x30 in hour
2354: * for example, see IKBD_UpdateClockOnVBL())
1.1.1.12 root 2355: */
1.1.1.13 root 2356: static void IKBD_Cmd_SetClock(void)
1.1 root 2357: {
1.1.1.20 root 2358: int i;
2359: Uint8 val;
1.1.1.13 root 2360:
1.1.1.19 root 2361: LOG_TRACE(TRACE_IKBD_CMDS,
2362: "IKBD_Cmd_SetClock: %02x %02x %02x %02x %02x %02x\n",
2363: Keyboard.InputBuffer[1], Keyboard.InputBuffer[2],
2364: Keyboard.InputBuffer[3], Keyboard.InputBuffer[4],
2365: Keyboard.InputBuffer[5], Keyboard.InputBuffer[6]);
2366:
1.1.1.20 root 2367: for ( i=1 ; i<=6 ; i++ )
2368: {
2369: val = Keyboard.InputBuffer[ i ];
2370: if ( IKBD_BCD_Check ( val ) ) /* Check if valid BCD, else ignore */
2371: pIKBD->Clock[ i-1 ] = val; /* Store new value */
2372: }
1.1 root 2373: }
2374:
1.1.1.2 root 2375:
1.1.1.20 root 2376: /*-----------------------------------------------------------------------*/
1.1.1.12 root 2377: /**
1.1.1.20 root 2378: * INTERROGATE TIME-OF-DAY CLOCK
1.1.1.12 root 2379: *
2380: * 0x1C
2381: * Returns:
2382: * 0xFC ; time-of-day event header
2383: * YY ; year (2 least significant digits)
2384: * MM ; month
2385: * DD ; day
2386: * hh ; hour
2387: * mm ; minute
2388: * ss ; second
1.1.1.20 root 2389: *
2390: * All bytes are stored/returned in BCD format.
2391: * Date/Time is updated in IKBD_UpdateClockOnVBL()
1.1.1.12 root 2392: */
1.1.1.13 root 2393: static void IKBD_Cmd_ReadClock(void)
1.1 root 2394: {
1.1.1.20 root 2395: int i;
1.1.1.13 root 2396:
1.1.1.20 root 2397: LOG_TRACE(TRACE_IKBD_CMDS,
2398: "IKBD_Cmd_ReadClock: %02x %02x %02x %02x %02x %02x\n",
2399: pIKBD->Clock[ 0 ] ,pIKBD->Clock[ 1 ] , pIKBD->Clock[ 2 ] ,
2400: pIKBD->Clock[ 3 ] , pIKBD->Clock[ 4 ] , pIKBD->Clock[ 5 ] );
2401:
2402: /* Return packet header */
2403: if ( IKBD_OutputBuffer_CheckFreeCount ( 7 ) )
2404: {
2405: IKBD_Cmd_Return_Byte_Delay ( 0xFC , IKBD_Delay_Random ( 7000 , 7500 ) );
2406:
2407: /* Return the 6 clock bytes */
2408: for ( i=0 ; i<6 ; i++ )
2409: IKBD_Cmd_Return_Byte ( pIKBD->Clock[ i ] );
2410: }
1.1 root 2411: }
2412:
1.1.1.2 root 2413:
2414: /*-----------------------------------------------------------------------*/
1.1.1.12 root 2415: /**
2416: * MEMORY LOAD
2417: *
2418: * 0x20
2419: * ADRMSB ; address in controller
2420: * ADRLSB ; memory to be loaded
2421: * NUM ; number of bytes (0-128)
2422: * { data }
2423: */
1.1.1.13 root 2424: static void IKBD_Cmd_LoadMemory(void)
1.1 root 2425: {
1.1.1.15 root 2426: LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_LoadMemory addr 0x%x count %d\n",
2427: (Keyboard.InputBuffer[1] << 8) + Keyboard.InputBuffer[2], Keyboard.InputBuffer[3]);
1.1.1.13 root 2428:
2429: MemoryLoadNbBytesTotal = Keyboard.InputBuffer[3];
2430: MemoryLoadNbBytesLeft = MemoryLoadNbBytesTotal;
2431: crc32_reset ( &MemoryLoadCrc );
1.1 root 2432: }
2433:
1.1.1.2 root 2434:
2435: /*-----------------------------------------------------------------------*/
1.1.1.12 root 2436: /**
2437: * MEMORY READ
2438: *
2439: * 0x21
2440: * ADRMSB ; address in controller
2441: * ADRLSB ; memory to be read
2442: * Returns:
2443: * 0xF6 ; status header
2444: * 0x20 ; memory access
2445: * { data } ; 6 data bytes starting at ADR
1.1.1.20 root 2446: *
2447: * NOTE : This function requires to handle the IKBD's RAM, which is only
2448: * possible when emulating a real HD6301 CPU. For now, we only return
2449: * the correct header and 6 empty bytes.
1.1.1.12 root 2450: */
1.1.1.13 root 2451: static void IKBD_Cmd_ReadMemory(void)
1.1 root 2452: {
1.1.1.20 root 2453: int i;
2454:
2455: LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_ReadMemory (not implemented)\n");
2456:
2457: /* Return packet header */
2458: if ( IKBD_OutputBuffer_CheckFreeCount ( 8 ) )
2459: {
2460: IKBD_Cmd_Return_Byte_Delay ( 0xF6 , IKBD_Delay_Random ( 7000 , 7500 ) );
2461: IKBD_Cmd_Return_Byte ( 0x20 );
2462:
2463: /* Return 6 empty bytes */
2464: for ( i=0 ; i<6 ; i++ )
2465: IKBD_Cmd_Return_Byte ( 0x00 );
2466: }
1.1 root 2467: }
2468:
1.1.1.2 root 2469:
2470: /*-----------------------------------------------------------------------*/
1.1.1.12 root 2471: /**
2472: * CONTROLLER EXECUTE
2473: *
2474: * 0x22
2475: * ADRMSB ; address of subroutine in
2476: * ADRLSB ; controller memory to be called
2477: */
1.1.1.13 root 2478: static void IKBD_Cmd_Execute(void)
2479: {
1.1.1.17 root 2480: LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_Execute addr 0x%x\n",
2481: (Keyboard.InputBuffer[1] << 8) + Keyboard.InputBuffer[2]);
1.1.1.13 root 2482:
2483: if ( pIKBD_CustomCodeHandler_Write )
2484: {
1.1.1.15 root 2485: LOG_TRACE(TRACE_IKBD_EXEC, "ikbd execute addr 0x%x using custom handler\n",
2486: (Keyboard.InputBuffer[1] << 8) + Keyboard.InputBuffer[2]);
1.1.1.13 root 2487:
1.1.1.15 root 2488: IKBD_ExeMode = true; /* turn 6301's custom mode ON */
1.1.1.13 root 2489: }
2490: else /* unknown code uploaded to ikbd RAM */
2491: {
1.1.1.15 root 2492: LOG_TRACE(TRACE_IKBD_EXEC, "ikbd execute addr 0x%x ignored, no custom handler found\n",
2493: (Keyboard.InputBuffer[1] << 8) + Keyboard.InputBuffer[2]);
1.1.1.13 root 2494: }
2495: }
2496:
2497:
2498: /*-----------------------------------------------------------------------*/
2499: /**
2500: * REPORT MOUSE BUTTON ACTION
2501: *
2502: * 0x87
2503: */
2504: static void IKBD_Cmd_ReportMouseAction(void)
2505: {
1.1.1.15 root 2506: LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_ReportMouseAction\n");
1.1.1.13 root 2507:
1.1.1.20 root 2508: if ( IKBD_OutputBuffer_CheckFreeCount ( 8 ) )
2509: {
2510: IKBD_Cmd_Return_Byte_Delay ( 0xF6 , IKBD_Delay_Random ( 7000 , 7500 ) );
2511: IKBD_Cmd_Return_Byte (7);
2512: IKBD_Cmd_Return_Byte (KeyboardProcessor.Mouse.Action);
2513: IKBD_Cmd_Return_Byte (0);
2514: IKBD_Cmd_Return_Byte (0);
2515: IKBD_Cmd_Return_Byte (0);
2516: IKBD_Cmd_Return_Byte (0);
2517: IKBD_Cmd_Return_Byte (0);
2518: }
1.1.1.13 root 2519: }
2520:
2521:
2522: /*-----------------------------------------------------------------------*/
2523: /**
2524: * REPORT MOUSE MODE
2525: *
2526: * 0x88 or 0x89 or 0x8A
2527: */
2528: static void IKBD_Cmd_ReportMouseMode(void)
2529: {
1.1.1.15 root 2530: LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_ReportMouseMode\n");
1.1.1.13 root 2531:
1.1.1.20 root 2532: if ( IKBD_OutputBuffer_CheckFreeCount ( 8 ) )
1.1.1.13 root 2533: {
1.1.1.20 root 2534: IKBD_Cmd_Return_Byte_Delay ( 0xF6 , IKBD_Delay_Random ( 7000 , 7500 ) );
2535: switch (KeyboardProcessor.MouseMode)
2536: {
2537: case AUTOMODE_MOUSEREL:
2538: IKBD_Cmd_Return_Byte (8);
2539: IKBD_Cmd_Return_Byte (0);
2540: IKBD_Cmd_Return_Byte (0);
2541: IKBD_Cmd_Return_Byte (0);
2542: IKBD_Cmd_Return_Byte (0);
2543: IKBD_Cmd_Return_Byte (0);
2544: IKBD_Cmd_Return_Byte (0);
2545: break;
2546: case AUTOMODE_MOUSEABS:
2547: IKBD_Cmd_Return_Byte (9);
2548: IKBD_Cmd_Return_Byte (KeyboardProcessor.Abs.MaxX >> 8);
2549: IKBD_Cmd_Return_Byte (KeyboardProcessor.Abs.MaxX);
2550: IKBD_Cmd_Return_Byte (KeyboardProcessor.Abs.MaxY >> 8);
2551: IKBD_Cmd_Return_Byte (KeyboardProcessor.Abs.MaxY);
2552: IKBD_Cmd_Return_Byte (0);
2553: IKBD_Cmd_Return_Byte (0);
2554: break;
2555: case AUTOMODE_MOUSECURSOR:
2556: IKBD_Cmd_Return_Byte (10);
2557: IKBD_Cmd_Return_Byte (KeyboardProcessor.Mouse.KeyCodeDeltaX);
2558: IKBD_Cmd_Return_Byte (KeyboardProcessor.Mouse.KeyCodeDeltaY);
2559: IKBD_Cmd_Return_Byte (0);
2560: IKBD_Cmd_Return_Byte (0);
2561: IKBD_Cmd_Return_Byte (0);
2562: IKBD_Cmd_Return_Byte (0);
2563: break;
2564: }
1.1.1.13 root 2565: }
2566: }
2567:
2568:
2569: /*-----------------------------------------------------------------------*/
2570: /**
2571: * REPORT MOUSE THRESHOLD
2572: *
2573: * 0x8B
2574: */
2575: static void IKBD_Cmd_ReportMouseThreshold(void)
2576: {
1.1.1.15 root 2577: LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_ReportMouseThreshold\n");
1.1.1.13 root 2578:
1.1.1.20 root 2579: if ( IKBD_OutputBuffer_CheckFreeCount ( 8 ) )
2580: {
2581: IKBD_Cmd_Return_Byte_Delay ( 0xF6 , IKBD_Delay_Random ( 7000 , 7500 ) );
2582: IKBD_Cmd_Return_Byte (0x0B);
2583: IKBD_Cmd_Return_Byte (KeyboardProcessor.Mouse.XThreshold);
2584: IKBD_Cmd_Return_Byte (KeyboardProcessor.Mouse.YThreshold);
2585: IKBD_Cmd_Return_Byte (0);
2586: IKBD_Cmd_Return_Byte (0);
2587: IKBD_Cmd_Return_Byte (0);
2588: IKBD_Cmd_Return_Byte (0);
2589: }
1.1.1.13 root 2590: }
2591:
2592:
2593: /*-----------------------------------------------------------------------*/
2594: /**
2595: * REPORT MOUSE SCALE
2596: *
2597: * 0x8C
2598: */
2599: static void IKBD_Cmd_ReportMouseScale(void)
2600: {
1.1.1.15 root 2601: LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_ReportMouseScale\n");
1.1.1.13 root 2602:
1.1.1.20 root 2603: if ( IKBD_OutputBuffer_CheckFreeCount ( 8 ) )
2604: {
2605: IKBD_Cmd_Return_Byte_Delay ( 0xF6 , IKBD_Delay_Random ( 7000 , 7500 ) );
2606: IKBD_Cmd_Return_Byte (0x0C);
2607: IKBD_Cmd_Return_Byte (KeyboardProcessor.Mouse.XScale);
2608: IKBD_Cmd_Return_Byte (KeyboardProcessor.Mouse.YScale);
2609: IKBD_Cmd_Return_Byte (0);
2610: IKBD_Cmd_Return_Byte (0);
2611: IKBD_Cmd_Return_Byte (0);
2612: IKBD_Cmd_Return_Byte (0);
2613: }
1.1.1.13 root 2614: }
2615:
2616:
2617: /*-----------------------------------------------------------------------*/
2618: /**
2619: * REPORT MOUSE VERTICAL COORDINATES
2620: *
2621: * 0x8F and 0x90
2622: */
2623: static void IKBD_Cmd_ReportMouseVertical(void)
2624: {
1.1.1.15 root 2625: LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_ReportMouseVertical\n");
1.1.1.13 root 2626:
1.1.1.20 root 2627: if ( IKBD_OutputBuffer_CheckFreeCount ( 8 ) )
2628: {
2629: IKBD_Cmd_Return_Byte_Delay ( 0xF6 , IKBD_Delay_Random ( 7000 , 7500 ) );
2630: if (KeyboardProcessor.Mouse.YAxis == -1)
2631: IKBD_Cmd_Return_Byte (0x0F);
2632: else
2633: IKBD_Cmd_Return_Byte (0x10);
2634: IKBD_Cmd_Return_Byte (0);
2635: IKBD_Cmd_Return_Byte (0);
2636: IKBD_Cmd_Return_Byte (0);
2637: IKBD_Cmd_Return_Byte (0);
2638: IKBD_Cmd_Return_Byte (0);
2639: IKBD_Cmd_Return_Byte (0);
2640: }
1.1.1.13 root 2641: }
2642:
2643:
2644: /*-----------------------------------------------------------------------*/
2645: /**
2646: * REPORT MOUSE AVAILABILITY
2647: *
2648: * 0x92
2649: */
2650: static void IKBD_Cmd_ReportMouseAvailability(void)
2651: {
1.1.1.15 root 2652: LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_ReportMouseAvailability\n");
1.1.1.13 root 2653:
1.1.1.20 root 2654: if ( IKBD_OutputBuffer_CheckFreeCount ( 8 ) )
2655: {
2656: IKBD_Cmd_Return_Byte_Delay ( 0xF6 , IKBD_Delay_Random ( 7000 , 7500 ) );
2657: if (KeyboardProcessor.MouseMode == AUTOMODE_OFF)
2658: IKBD_Cmd_Return_Byte (0x12);
2659: else
2660: IKBD_Cmd_Return_Byte (0x00);
2661: IKBD_Cmd_Return_Byte (0);
2662: IKBD_Cmd_Return_Byte (0);
2663: IKBD_Cmd_Return_Byte (0);
2664: IKBD_Cmd_Return_Byte (0);
2665: IKBD_Cmd_Return_Byte (0);
2666: IKBD_Cmd_Return_Byte (0);
2667: }
1.1.1.13 root 2668: }
2669:
2670:
2671: /*-----------------------------------------------------------------------*/
2672: /**
2673: * REPORT JOYSTICK MODE
2674: *
2675: * 0x94 or 0x95 or 0x99
2676: */
2677: static void IKBD_Cmd_ReportJoystickMode(void)
1.1 root 2678: {
1.1.1.15 root 2679: LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_ReportJoystickMode\n");
1.1.1.13 root 2680:
1.1.1.20 root 2681: if ( IKBD_OutputBuffer_CheckFreeCount ( 8 ) )
1.1.1.13 root 2682: {
1.1.1.20 root 2683: IKBD_Cmd_Return_Byte_Delay ( 0xF6 , IKBD_Delay_Random ( 7000 , 7500 ) );
2684: switch (KeyboardProcessor.JoystickMode)
2685: {
2686: case AUTOMODE_JOYSTICK:
2687: IKBD_Cmd_Return_Byte (0x14);
2688: IKBD_Cmd_Return_Byte (0);
2689: IKBD_Cmd_Return_Byte (0);
2690: IKBD_Cmd_Return_Byte (0);
2691: IKBD_Cmd_Return_Byte (0);
2692: IKBD_Cmd_Return_Byte (0);
2693: IKBD_Cmd_Return_Byte (0);
2694: break;
2695: default: /* TODO: Joystick keycodes mode not supported yet! */
2696: IKBD_Cmd_Return_Byte (0x15);
2697: IKBD_Cmd_Return_Byte (0);
2698: IKBD_Cmd_Return_Byte (0);
2699: IKBD_Cmd_Return_Byte (0);
2700: IKBD_Cmd_Return_Byte (0);
2701: IKBD_Cmd_Return_Byte (0);
2702: IKBD_Cmd_Return_Byte (0);
2703: break;
2704: }
1.1.1.13 root 2705: }
2706: }
2707:
2708:
2709: /*-----------------------------------------------------------------------*/
2710: /**
2711: * REPORT JOYSTICK AVAILABILITY
2712: *
2713: * 0x9A
2714: */
2715: static void IKBD_Cmd_ReportJoystickAvailability(void)
2716: {
1.1.1.15 root 2717: LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_ReportJoystickAvailability\n");
1.1.1.13 root 2718:
1.1.1.20 root 2719: if ( IKBD_OutputBuffer_CheckFreeCount ( 8 ) )
1.1.1.19 root 2720: {
1.1.1.20 root 2721: IKBD_Cmd_Return_Byte_Delay ( 0xF6 , IKBD_Delay_Random ( 7000 , 7500 ) );
2722: if (KeyboardProcessor.JoystickMode == AUTOMODE_OFF)
2723: IKBD_Cmd_Return_Byte (0x1A);
2724: else
2725: IKBD_Cmd_Return_Byte (0x00);
2726: IKBD_Cmd_Return_Byte (0);
2727: IKBD_Cmd_Return_Byte (0);
2728: IKBD_Cmd_Return_Byte (0);
2729: IKBD_Cmd_Return_Byte (0);
2730: IKBD_Cmd_Return_Byte (0);
2731: IKBD_Cmd_Return_Byte (0);
1.1.1.19 root 2732: }
1.1.1.10 root 2733: }
2734:
1.1.1.12 root 2735:
1.1.1.18 root 2736:
1.1.1.19 root 2737:
1.1.1.20 root 2738: /************************************************************************/
2739: /* End of the IKBD's commands emulation. */
2740: /************************************************************************/
1.1.1.19 root 2741:
1.1.1.18 root 2742:
1.1.1.13 root 2743:
2744:
2745: /*************************************************************************/
2746: /**
1.1.1.20 root 2747: * Below part is for emulating custom 6301 program sent to the IKBD's RAM
1.1.1.13 root 2748: * Specific read/write functions for each demo/game should be added here,
2749: * after being defined in the CustomCodeDefinitions[] array.
2750: *
2751: * The 6301 has 256 bytes of RAM, but only 128 bytes are available to
2752: * put a program (from $80 to $ff).
2753: *
2754: * Executing a program in the 6301 is a 2 steps process :
2755: * 1) a very small program is sent to the RAM using the 0x20 command.
2756: * This is often loaded at address $b0.
2757: * This program will stop interruptions in the 6301 and will accept
2758: * a second small program that will relocate itself to $80.
2759: * 2) the relocated program at address $80 will accept a third (main)
2760: * program and will execute it once reception is complete.
2761: *
2762: * Writes during step 1 are handled with the ExeBootHandler matching the
2763: * LoadMemory CRC.
2764: * ExeBootHandler will compute a 2nd CRC for the writes corresponding to
2765: * the 2nd and 3rd programs sent to the 6301's RAM.
2766: *
1.1.1.20 root 2767: * If a match is found for this 2nd CRC, we will override default IKBD's behaviour
1.1.1.13 root 2768: * for reading/writing to $fffc02 with ExeMainHandler_Read / ExeMainHandler_Write
2769: * (once the Execute command 0x22 is received).
2770: *
1.1.1.15 root 2771: * When using custom program (ExeMode==true), we must ignore all keyboard/mouse/joystick
1.1.1.20 root 2772: * events sent to IKBD_Cmd_Return_Byte . Only our functions can add bytes
1.1.1.13 root 2773: * to the keyboard buffer.
2774: *
2775: * To exit 6301's execution mode, we can use the 68000 'reset' instruction.
2776: * Some 6301's programs also handle a write to $fffc02 as an exit signal.
2777: */
2778:
2779:
2780: /*-----------------------------------------------------------------------*/
2781: /**
1.1.1.20 root 2782: * Handle writes to $fffc02 when loading bytes in the IKBD's RAM.
1.1.1.13 root 2783: * We compute a CRC of the bytes that are sent until MemoryLoadNbBytesLeft
2784: * reaches 0.
2785: * When all bytes are loaded, we look for a matching CRC ; if found, we
2786: * use the ExeBootHandler defined for this CRC to process the next writes
2787: * that will occur in $fffc02.
2788: * LoadMemory is often used to load a small boot code into the 6301's RAM.
2789: * This small program will be executed later using the command 0x22.
2790: */
2791:
2792: static void IKBD_LoadMemoryByte ( Uint8 aciabyte )
2793: {
2794: unsigned int i;
2795:
1.1.1.20 root 2796: /* Write received bytes to a file for debug */
2797: // FILE *f = fopen ( "/tmp/ikbd_loadmemory.dump" , "ab" ) ; fprintf ( f , "%c" , aciabyte ) ; fclose ( f );
2798:
1.1.1.13 root 2799: crc32_add_byte ( &MemoryLoadCrc , aciabyte );
2800:
2801: MemoryLoadNbBytesLeft--;
2802: if ( MemoryLoadNbBytesLeft == 0 ) /* all bytes were received */
2803: {
2804: /* Search for a match amongst the known custom routines */
2805: for ( i = 0 ; i < sizeof ( CustomCodeDefinitions ) / sizeof ( CustomCodeDefinitions[0] ) ; i++ )
2806: if ( CustomCodeDefinitions[ i ].LoadMemCrc == MemoryLoadCrc )
2807: break;
2808:
2809: if ( i < sizeof ( CustomCodeDefinitions ) / sizeof ( CustomCodeDefinitions[0] ) ) /* found */
2810: {
1.1.1.15 root 2811: LOG_TRACE(TRACE_IKBD_EXEC, "ikbd loadmemory %d bytes crc=0x%x matches <%s>\n",
2812: MemoryLoadNbBytesTotal, MemoryLoadCrc, CustomCodeDefinitions[ i ].Name);
1.1.1.13 root 2813:
2814: crc32_reset ( &MemoryLoadCrc );
2815: MemoryExeNbBytes = 0;
2816: pIKBD_CustomCodeHandler_Read = NULL;
2817: pIKBD_CustomCodeHandler_Write = CustomCodeDefinitions[ i ].ExeBootHandler;
2818: }
2819:
1.1.1.20 root 2820: else /* unknown code uploaded to IKBD's RAM */
1.1.1.13 root 2821: {
1.1.1.15 root 2822: LOG_TRACE(TRACE_IKBD_EXEC, "ikbd loadmemory %d bytes crc=0x%x : unknown code\n",
2823: MemoryLoadNbBytesTotal, MemoryLoadCrc);
1.1.1.13 root 2824:
2825: pIKBD_CustomCodeHandler_Read = NULL;
2826: pIKBD_CustomCodeHandler_Write = NULL;
2827: }
2828: }
2829: }
2830:
2831:
2832:
2833: /*-----------------------------------------------------------------------*/
2834: /**
1.1.1.20 root 2835: * Handle writes to $fffc02 when executing custom code in the IKBD's RAM.
2836: * This is used to send the small IKBD program that will handle
2837: * keyboard/mouse/joystick input.
1.1.1.13 root 2838: * We compute a CRC of the bytes that are sent until we found a match
1.1.1.20 root 2839: * with a known custom IKBD program.
1.1.1.13 root 2840: */
2841:
2842: static void IKBD_CustomCodeHandler_CommonBoot ( Uint8 aciabyte )
2843: {
2844: unsigned int i;
2845:
1.1.1.20 root 2846: /* Write received bytes to a file for debug */
2847: // FILE *f = fopen ( "/tmp/ikbd_custom_program.dump" , "ab" ) ; fprintf ( f , "%c" , aciabyte ) ; fclose ( f );
2848:
1.1.1.13 root 2849: crc32_add_byte ( &MemoryLoadCrc , aciabyte );
2850: MemoryExeNbBytes++;
2851:
1.1.1.15 root 2852: LOG_TRACE(TRACE_IKBD_EXEC, "ikbd custom exe common boot write 0x%02x count %d crc=0x%x\n",
2853: aciabyte, MemoryExeNbBytes, MemoryLoadCrc);
1.1.1.13 root 2854:
2855: /* Search for a match amongst the known custom routines */
2856: for ( i = 0 ; i < sizeof ( CustomCodeDefinitions ) / sizeof ( CustomCodeDefinitions[0] ) ; i++ )
2857: if ( ( CustomCodeDefinitions[ i ].MainProgNbBytes == MemoryExeNbBytes )
2858: && ( CustomCodeDefinitions[ i ].MainProgCrc == MemoryLoadCrc ) )
2859: break;
2860:
2861: if ( i < sizeof ( CustomCodeDefinitions ) / sizeof ( CustomCodeDefinitions[0] ) ) /* found */
2862: {
1.1.1.15 root 2863: LOG_TRACE(TRACE_IKBD_EXEC, "ikbd custom exe common boot, uploaded code matches <%s>\n",
2864: CustomCodeDefinitions[i].Name);
1.1.1.13 root 2865:
2866: pIKBD_CustomCodeHandler_Read = CustomCodeDefinitions[ i ].ExeMainHandler_Read;
2867: pIKBD_CustomCodeHandler_Write = CustomCodeDefinitions[ i ].ExeMainHandler_Write;
2868:
2869: Keyboard.BufferHead = Keyboard.BufferTail = 0; /* flush all queued bytes that would be read in $fffc02 */
1.1.1.20 root 2870: Keyboard.NbBytesInOutputBuffer = 0;
1.1.1.13 root 2871: }
2872:
2873: /* If not found, we keep on accumulating bytes until we find a matching crc */
2874: }
2875:
2876:
2877:
2878: /*----------------------------------------------------------------------*/
2879: /* Froggies Over The Fence menu. */
1.1.1.20 root 2880: /* Returns 'n' bytes with the mouse position, keyboard can be used too. */
2881: /* Writing a <0 byte to $fffc02 will cause the 6301 to exit custom exe */
2882: /* mode (jmp $f000). */
2883: /* When writing byte 'n' >0 to $fffc02, the 6301 will return the content*/
2884: /* of RAM $7f+n to $7f+1. */
2885: /* $80/$81 contains deltaY/deltaX + left mouse button in bit 7, $82 */
2886: /* contains LMB in bit 7 and $83 contains a fixed value 0xfc. */
2887: /* On each VBL, the demo will ask for 1 byte, then for 4 bytes ; only */
2888: /* the last 2 bytes ($81/$80) will be used, $83/$82 are ignored. */
2889: /* IKBD's $81 will be stored in $600 (CPU RAM), and $80 in $601. */
2890: /* */
2891: /* TODO : an extra delay of 7000 cycles is necessary to have $81 and $80*/
2892: /* received after the overrun condition was cleared at the 68000 level. */
2893: /* Does it mean some timings are wrong with acia/ikbd ? */
1.1.1.13 root 2894: /*----------------------------------------------------------------------*/
2895:
2896: static void IKBD_CustomCodeHandler_FroggiesMenu_Read ( void )
2897: {
1.1.1.20 root 2898: /* Ignore read */
1.1.1.13 root 2899: }
2900:
2901: static void IKBD_CustomCodeHandler_FroggiesMenu_Write ( Uint8 aciabyte )
2902: {
1.1.1.20 root 2903: Uint8 res80 = 0;
2904: Uint8 res81 = 0;
2905: Uint8 res82 = 0;
2906: Uint8 res83 = 0xfc; /* fixed value, not used */
2907:
2908: /* When writing a <0 byte to $fffc02, Froggies ikbd's program will terminate itself */
2909: /* and leave Execution mode (jmp $f000) */
2910: if ( aciabyte & 0x80 )
2911: {
2912: IKBD_Boot_ROM ( false );
2913: return;
2914: }
2915:
2916: if ( KeyboardProcessor.Mouse.DeltaY < 0 ) res80 = 0x7a; /* mouse up */
2917: if ( KeyboardProcessor.Mouse.DeltaY > 0 ) res80 = 0x06; /* mouse down */
2918: if ( KeyboardProcessor.Mouse.DeltaX < 0 ) res81 = 0x7a; /* mouse left */
2919: if ( KeyboardProcessor.Mouse.DeltaX > 0 ) res81 = 0x06; /* mouse right */
2920: if ( Keyboard.bLButtonDown & BUTTON_MOUSE ) res82 |= 0x80; /* left mouse button */
2921:
2922: if ( ScanCodeState[ 0x48 ] ) res80 |= 0x7a; /* up */
2923: if ( ScanCodeState[ 0x50 ] ) res80 |= 0x06; /* down */
2924: if ( ScanCodeState[ 0x4b ] ) res81 |= 0x7a; /* left */
2925: if ( ScanCodeState[ 0x4d ] ) res81 |= 0x06; /* right */
2926: if ( ScanCodeState[ 0x70 ] ) res82 |= 0x80; /* keypad 0 */
2927:
2928: res80 |= res82; /* bit 7 is left mouse button */
2929: res81 |= res82;
2930:
2931: // res80 = 0x10 ; res81 = 0x11 ; res82 = 0x12 ; res83 = 0x13 ; /* force some discernible values to debug */
2932:
2933: if ( aciabyte == 1 ) /* Send 1 byte */
2934: IKBD_Send_Byte_Delay ( res80 , 0 ); /* $80 in IKBD's RAM */
2935:
2936: else if ( aciabyte == 4 ) /* Send 4 bytes */
2937: {
2938: IKBD_Send_Byte_Delay ( res83 , 7000 ); /* $83 in IKBD's RAM */
2939: IKBD_Send_Byte_Delay ( res82 , 0 ); /* $82 in IKBD's RAM */
2940: IKBD_Send_Byte_Delay ( res81 , 0 ); /* $81 in IKBD's RAM */
2941: IKBD_Send_Byte_Delay ( res80 , 0 ); /* $80 in IKBD's RAM */
2942: }
1.1.1.13 root 2943: }
2944:
2945:
2946:
2947: /*----------------------------------------------------------------------*/
2948: /* Transbeauce II menu. */
2949: /* Returns 1 byte with the joystick position, keyboard can be used too. */
2950: /*----------------------------------------------------------------------*/
2951:
2952: static void IKBD_CustomCodeHandler_Transbeauce2Menu_Read ( void )
2953: {
2954: Uint8 res = 0;
2955:
2956: /* keyboard emulation */
2957: if ( ScanCodeState[ 0x48 ] ) res |= 0x01; /* up */
2958: if ( ScanCodeState[ 0x50 ] ) res |= 0x02; /* down */
2959: if ( ScanCodeState[ 0x4b ] ) res |= 0x04; /* left */
2960: if ( ScanCodeState[ 0x4d ] ) res |= 0x08; /* right */
2961: if ( ScanCodeState[ 0x62 ] ) res |= 0x40; /* help */
2962: if ( ScanCodeState[ 0x39 ] ) res |= 0x80; /* space */
2963:
2964: /* joystick emulation (bit mapping is same as cursor above, with bit 7 = fire button */
2965: res |= ( Joy_GetStickData(1) & 0x8f ) ; /* keep bits 0-3 and 7 */
2966:
1.1.1.20 root 2967: IKBD_Send_Byte_Delay ( res , 0 );
1.1.1.13 root 2968: }
2969:
2970: static void IKBD_CustomCodeHandler_Transbeauce2Menu_Write ( Uint8 aciabyte )
2971: {
2972: /* Ignore write */
2973: }
2974:
2975:
2976:
2977: /*----------------------------------------------------------------------*/
2978: /* Dragonnels demo menu. */
1.1.1.20 root 2979: /* When any byte is written in $fffc02, returns one byte with the */
2980: /* Y position of the mouse and the state of the left button. */
1.1.1.13 root 2981: /*----------------------------------------------------------------------*/
2982:
2983: static void IKBD_CustomCodeHandler_DragonnelsMenu_Read ( void )
2984: {
1.1.1.20 root 2985: /* Ignore read */
2986: }
2987:
2988: static void IKBD_CustomCodeHandler_DragonnelsMenu_Write ( Uint8 aciabyte )
2989: {
1.1.1.13 root 2990: Uint8 res = 0;
2991:
2992: if ( KeyboardProcessor.Mouse.DeltaY < 0 ) res = 0xfc; /* mouse up */
2993: if ( KeyboardProcessor.Mouse.DeltaY > 0 ) res = 0x04; /* mouse down */
2994:
2995: if ( Keyboard.bLButtonDown & BUTTON_MOUSE ) res = 0x80; /* left mouse button */
2996:
1.1.1.20 root 2997: IKBD_Send_Byte_Delay ( res , 0 );
1.1.1.13 root 2998: }
2999:
1.1.1.17 root 3000:
3001:
3002: /*----------------------------------------------------------------------*/
3003: /* Chaos A.D. protection's decoder */
3004: /* This custom program reads bytes, decode them and send back the result*/
3005: /* to the 68000. */
3006: /* The program first returns $fe to indicate it's ready to receive the */
3007: /* encoded bytes. */
3008: /* The program then receives the 8 bytes used to decode the data and */
3009: /* store them in $f0 - $f7 (KeyBuffer is already initialized, so we */
3010: /* ignore those 8 bytes). */
3011: /* Then for any received byte a XOR is made with one of the byte in the */
3012: /* 8 bytes buffer, by incrementing an index in this buffer. */
3013: /* The decoded byte is written to addr $13 (TDR) to be received by ACIA */
3014: /*----------------------------------------------------------------------*/
3015:
3016: static void IKBD_CustomCodeHandler_ChaosAD_Read ( void )
3017: {
3018: static bool FirstCall = true;
3019:
3020: if ( FirstCall == true )
1.1.1.20 root 3021: IKBD_Send_Byte_Delay ( 0xfe , 0 );
1.1.1.17 root 3022:
3023: FirstCall = false;
3024: }
3025:
3026: static void IKBD_CustomCodeHandler_ChaosAD_Write ( Uint8 aciabyte )
3027: {
3028: static int IgnoreNb = 8;
3029: Uint8 KeyBuffer[] = { 0xca , 0x0a , 0xbc , 0x00 , 0xde , 0xde , 0xfe , 0xca };
3030: static int Index = 0;
3031: static int Count = 0;
3032:
3033: /* We ignore the first 8 bytes we received (they're already in KeyBuffer) */
3034: if ( IgnoreNb > 0 )
3035: {
3036: IgnoreNb--;
3037: return;
3038: }
3039:
3040: if ( Count <= 6080 ) /* there're 6081 bytes to decode */
3041: {
3042: Count++;
3043:
3044: aciabyte ^= KeyBuffer[ Index ];
3045: Index++;
3046: Index &= 0x07;
3047:
1.1.1.20 root 3048: IKBD_Send_Byte_Delay ( aciabyte , 0 );
1.1.1.17 root 3049: }
3050:
3051: else
3052: {
3053: /* When all bytes were decoded if 0x08 is written to $fffc02 */
3054: /* the program will terminate itself and leave Execution mode */
3055: if ( aciabyte == 0x08 )
1.1.1.20 root 3056: IKBD_Boot_ROM ( false );
1.1.1.17 root 3057: }
3058: }
3059:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.