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

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

unix.superglobalmegacorp.com

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