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

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

unix.superglobalmegacorp.com

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