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