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