Annotation of hatari/src/ikbd.c, revision 1.1.1.20

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.