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

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

unix.superglobalmegacorp.com

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