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