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

1.1       root        1: /*
1.1.1.6   root        2:   Hatari - ikbd.c
                      3: 
                      4:   This file is distributed under the GNU Public License, version 2 or at
                      5:   your option any later version. Read the file gpl.txt for details.
1.1       root        6: 
1.1.1.12  root        7:   The keyboard processor(6301) handles any joystick/mouse task and sends bytes
                      8:   to the ACIA(6850). When a byte arrives in the ACIA (which takes just over
                      9:   7000 CPU cycles) an MFP interrupt is flagged. The CPU can now read the byte
                     10:   from the ACIA by reading address $fffc02.
                     11:   An annoying bug can be found in Dungeon Master. This, when run, turns off the
                     12:   mouse input - but of course then you are unable to play the game! A bodge
                     13:   flag has been added so we need to be told twice to turn off the mouse input
                     14:   (although I think this causes errors in other games...).
                     15:   Also, the ACIA_CYCLES time is very important for games such as Carrier
                     16:   Command. The keyboard handler in this game has a bug in it, which corrupts
                     17:   its own registers if more than one byte is queued up. This value was found by
                     18:   a test program on a real ST and has correctly emulated the behaviour.
                     19: */
1.1.1.14  root       20: const char IKBD_fileid[] = "Hatari ikbd.c : " __DATE__ " " __TIME__;
1.1.1.12  root       21: 
                     22: /* 2007/09/29  [NP]    Use the new int.c to add interrupts with INT_CPU_CYCLE / INT_MFP_CYCLE.         */
                     23: /* 2007/12/09  [NP]    If reset is written to ACIA control register, we must call ACIA_Reset to reset  */
                     24: /*                     RX/TX status. Reading the control register fffc00 just after a reset should     */
                     25: /*                     return the value 0x02 (used in Transbeauce 2 demo loader).                      */
1.1.1.13  root       26: /* 2008/07/06  [NP]    Add support for executing 8 bit code sent to the 6301 processor.                */
                     27: /*                     Instead of implementing a full 6301 emulator, we compute a checksum for each    */
                     28: /*                     program sent to the 6301 RAM. If the checksum is recognized, we call some       */
                     29: /*                     functions to emulate the behaviour of the 6301 in that case.                    */
                     30: /*                     When the 6301 is in 'Execute' mode (command 0x22), we must stop the normal      */
                     31: /*                     reporting of key/mouse/joystick and use our custom handlers for each read or    */
                     32: /*                     write to $fffc02.                                                               */
                     33: /*                     After a reset command, returns $F1 after $F0 (needed by Dragonnels Demo).       */
                     34: /*                     This fixes the Transbeauce 2 demo menu, the Dragonnels demo menu and the        */
                     35: /*                     Froggies Over The Fence demo menu (yeah ! enjoy this master piece of demo !).   */
1.1.1.17! root       36: /* 2011/05/11  [NP]    Add proper support for emulating TX buffer empty/full in status register bit 1  */
        !            37: /*                     when writing to $fffc02 (using an internal timer).                              */
        !            38: /* 2011/07/14  [NP]    Don't clear bytes in transit when ACIA_Reset is called ; if a byte is sent to   */
        !            39: /*                     the ikbd it should not be cancelled ? FIXME : this would need more tests on a   */
        !            40: /*                     real ST (fix Froggies Over The Fence's menu when selecting a demo).             */
1.1.1.13  root       41: 
1.1.1.6   root       42: 
                     43: #include <time.h>
1.1       root       44: 
                     45: #include "main.h"
                     46: #include "ikbd.h"
1.1.1.16  root       47: #include "cycInt.h"
1.1.1.10  root       48: #include "ioMem.h"
1.1       root       49: #include "joy.h"
                     50: #include "m68000.h"
                     51: #include "memorySnapShot.h"
                     52: #include "mfp.h"
1.1.1.17! root       53: #include "screen.h"
1.1       root       54: #include "video.h"
1.1.1.13  root       55: #include "utils.h"
1.1.1.10  root       56: 
1.1       root       57: 
                     58: #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       59: #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       60: 
1.1.1.13  root       61: #define IKBD_RESET_CYCLES  223500   /* Cycles after RESET before complete */
1.1       root       62: 
                     63: #define ABS_X_ONRESET    0          /* Initial XY for absolute mouse position after RESET command */
                     64: #define ABS_Y_ONRESET    0
                     65: #define ABS_MAX_X_ONRESET  320      /* Initial absolute mouse limits after RESET command */
                     66: #define ABS_MAY_Y_ONRESET  200      /* These values are never actually used as user MUST call 'IKBD_Cmd_AbsMouseMode' before ever using them */
                     67: 
1.1.1.10  root       68: #define ABS_PREVBUTTONS  (0x02|0x8) /* Don't report any buttons up on first call to 'IKBD_Cmd_ReadAbsMousePos' */
1.1       root       69: 
                     70: 
                     71: /* Keyboard state */
                     72: KEYBOARD Keyboard;
                     73: 
                     74: /* Keyboard processor */
                     75: KEYBOARD_PROCESSOR KeyboardProcessor;   /* Keyboard processor details */
1.1.1.11  root       76: 
                     77: /* Pattern of mouse button up/down in ST frames (run off a double-click message) */
1.1.1.17! root       78: static const Uint8 DoubleClickPattern[] =
1.1.1.12  root       79: {
                     80:        BUTTON_MOUSE,BUTTON_MOUSE,BUTTON_MOUSE,BUTTON_MOUSE,
                     81:        0,0,0,0,BUTTON_MOUSE,BUTTON_MOUSE,BUTTON_MOUSE,BUTTON_MOUSE
                     82: };
1.1.1.6   root       83: 
1.1.1.13  root       84: static bool bMouseDisabled, bJoystickDisabled;
                     85: static bool bDuringResetCriticalTime, bBothMouseAndJoy;
1.1.1.14  root       86: static bool bMouseEnabledDuringReset;
1.1       root       87: 
                     88: /* ACIA */
1.1.1.10  root       89: static Uint8 ACIAControlRegister = 0;
                     90: static Uint8 ACIAStatusRegister = ACIA_STATUS_REGISTER__TX_BUFFER_EMPTY;  /* Pass when read 0xfffc00 */
1.1.1.13  root       91: static Uint8 ACIAByte;                         /* When a byte has arrived at the ACIA (from the keyboard) it is stored here */
1.1.1.17! root       92: static Uint8 ACIATxDataRegister;               /* When a byte must be sent by the ACIA (to the keyboard) it is stored here */
1.1.1.15  root       93: static bool bByteInTransitToACIA = false;      /* Is a byte being sent to the ACIA from the keyboard? */
1.1.1.17! root       94: static bool bByteInTransitFromACIA = false;    /* Is a byte being sent from the ACIA to the keyboard? */
1.1       root       95: 
                     96: /*
                     97:   6850 ACIA (Asynchronous Communications Inferface Apdater)
                     98:   Page 41, ST Internals. Also ST Update Magazine, February 1989 (I glad I kept that!)
                     99: 
                    100:   Pins:-
                    101:     Vss
                    102:     RX DATA Receive Data
                    103:     RX CLK Receive Clock
                    104:     TX CLK Transmitter Clock
                    105:     RTS Request To Send
                    106:     TX DATA Transmitter Data
                    107:     IRQ Interrupt Request
                    108:     CS 0,1,2 Chip Select
                    109:     RS Register Select
                    110:     Vcc Voltage
                    111:     R/W Read/Write
                    112:     E Enable
                    113:     D0-D7 Data
                    114:     DCD Data Carrier Detect
                    115:     CTS Clear To Send
                    116: 
                    117:   Registers:-
                    118:     0xfffc00 Keyboard ACIA Control (write)/Status(read)
                    119:     0xfffc02 Keyboard ACIA Data
                    120:     0xfffc04 MIDI ACIA Control (write)/Status(read)
                    121:     0xfffc06 MIDI ACIA Data
                    122: 
                    123:   Control Register (0xfffc00 write):-
                    124:     Bits 0,1 - These bits determine by which factor the transmitter and receiver
                    125:       clock will be divided. These bits also are joined with a master reset
                    126:       function. The 6850 has no separate reset line, so it must be
                    127:       accomplished though software.
                    128:         0 0    RXCLK/TXCLK without division
                    129:         0 1    RXCLK/TXCLK by 16 (MIDI)
                    130:         1 0    RXCLK/TXCLK by 64 (Keyboard)
                    131:         1 1    Master RESET
                    132:     Bits 2,3,4 - These so-called Word Select bits tell whether 7 or 8 data-bits are
                    133:       involved; whether 1 or 2 stop-bits are transferred; and the type of parity
                    134:     Bits 5,6 - These Transmitter Control bits set the RTS output pin, and allow or prevent
                    135:       an interrupt through the ACIA when the send register is emptied. Also, BREAK signals
                    136:       can be sent over the serial output by this line. A BREAK signal is nothing more than
                    137:       a long seqence of null bits
                    138:         0 0    RTS low, transmitter IRQ disabled
                    139:         0 1    RTS low, transmitter IRQ enabled
                    140:         1 0    RTS high, transmitter IRQ disabled
                    141:         1 1    RTS low, transmitter IRQ disabled, BREAK sent
                    142:     Bit 7 - The Receiver Interrupt Enable bit determines whether the receiver interrupt
                    143:       will be on. An interrupt can be caused by the DCD line chaning from low to high, or
                    144:       by the receiver data buffer filling. Besides that, an interrupt can occur from an
                    145:       OVERRUN ( a received character isn't properly read from the processior).
                    146:         0 Interrupt disabled
                    147:         1 Interrupt enabled
                    148: 
                    149:   Status Register (0xfffc00 read):-
                    150:     Bit 0 - When this bit is high, the RX data register is full. The byte must be read
                    151:       before a new character is received (otherwise an OVERRUN happens)
                    152:     Bit 1 - This bit reflects the status of the TX data buffer. An empty register
                    153:       set the bit.
                    154:     Bit 2 - A low-high change in pin DCD sets bit 2. If the receiver interrupt is allowable, the IRQ
                    155:       is cancelled. The bit is cleared when the status register and the receiver register are
                    156:       read. This also cancels the IRQ. Bit 2 register remains highis the signal on the DCD pin
                    157:       is still high; Bit 2 register low if DCD becomes low.
                    158:     Bit 3 - This line shows the status of CTS. This signal cannot be altered by a mater reset,
                    159:       or by ACIA programming.
                    160:     Bit 4 - Shows 'Frame Errors'. Frame errors are when no stop-bit is recognized in receiver
                    161:       switching. It can be set with every new character.
                    162:     Bit 5 - This bit display the previously mentioned OVERRUN condition. Bit 5 is reset when the
                    163:       RX buffer is read.
                    164:     Bit 6 - This bit recognizes whether the parity of a received character is correct. The bit is
                    165:       set on an error.
                    166:     Bit 7 - This signals the state of the IRQ pins; this bit make it possible to switch several
                    167:       IRQ lines on one interrupt input. In cases where an interrupt is program-generated, bit 7
                    168:       can tell which IC cut off the interrupt.
1.1.1.7   root      169: 
1.1       root      170:   ST ACIA:-
                    171:     Note CTS,DCD and RTS are not connected! Phew!
                    172:     The keyboard ACIA are address 0xfffc000 and 0xfffc02.
1.1.1.17! root      173:     Default parameters are :- 8-bit word, 1 stopbit, no parity, 7812.5 baud; 500KHz/64 (keyboard clock div)
1.1       root      174:     Default MIDI parameters are are above but :- 31250 baud; 500KHz/16 (MIDI clock div)
                    175: */
                    176: 
1.1.1.2   root      177: /* List of possible keyboard commands, others are seen as NOPs by keyboard processor */
1.1.1.13  root      178: static void IKBD_Cmd_Reset(void);
                    179: static void IKBD_Cmd_MouseAction(void);
                    180: static void IKBD_Cmd_RelMouseMode(void);
                    181: static void IKBD_Cmd_AbsMouseMode(void);
                    182: static void IKBD_Cmd_MouseCursorKeycodes(void);
                    183: static void IKBD_Cmd_SetMouseThreshold(void);
                    184: static void IKBD_Cmd_SetMouseScale(void);
                    185: static void IKBD_Cmd_ReadAbsMousePos(void);
                    186: static void IKBD_Cmd_SetInternalMousePos(void);
                    187: static void IKBD_Cmd_SetYAxisDown(void);
                    188: static void IKBD_Cmd_SetYAxisUp(void);
                    189: static void IKBD_Cmd_StartKeyboardTransfer(void);
                    190: static void IKBD_Cmd_TurnMouseOff(void);
                    191: static void IKBD_Cmd_StopKeyboardTransfer(void);
                    192: static void IKBD_Cmd_ReturnJoystickAuto(void);
                    193: static void IKBD_Cmd_StopJoystick(void);
                    194: static void IKBD_Cmd_ReturnJoystick(void);
                    195: static void IKBD_Cmd_SetJoystickDuration(void);
                    196: static void IKBD_Cmd_SetJoystickFireDuration(void);
                    197: static void IKBD_Cmd_SetCursorForJoystick(void);
                    198: static void IKBD_Cmd_DisableJoysticks(void);
                    199: static void IKBD_Cmd_SetClock(void);
                    200: static void IKBD_Cmd_ReadClock(void);
                    201: static void IKBD_Cmd_LoadMemory(void);
                    202: static void IKBD_Cmd_ReadMemory(void);
                    203: static void IKBD_Cmd_Execute(void);
                    204: static void IKBD_Cmd_ReportMouseAction(void);
                    205: static void IKBD_Cmd_ReportMouseMode(void);
                    206: static void IKBD_Cmd_ReportMouseThreshold(void);
                    207: static void IKBD_Cmd_ReportMouseScale(void);
                    208: static void IKBD_Cmd_ReportMouseVertical(void);
                    209: static void IKBD_Cmd_ReportMouseAvailability(void);
                    210: static void IKBD_Cmd_ReportJoystickMode(void);
                    211: static void IKBD_Cmd_ReportJoystickAvailability(void);
                    212: 
1.1.1.17! root      213: /* Keyboard Command */
        !           214: static const struct {
        !           215:   Uint8 Command;
        !           216:   Uint8 NumParameters;
        !           217:   void (*pCallFunction)(void);
        !           218: } KeyboardCommands[] =
1.1.1.12  root      219: {
                    220:        /* Known messages, counts include command byte */
                    221:        { 0x80,2,  IKBD_Cmd_Reset },
                    222:        { 0x07,2,  IKBD_Cmd_MouseAction },
                    223:        { 0x08,1,  IKBD_Cmd_RelMouseMode },
                    224:        { 0x09,5,  IKBD_Cmd_AbsMouseMode },
                    225:        { 0x0A,3,  IKBD_Cmd_MouseCursorKeycodes },
                    226:        { 0x0B,3,  IKBD_Cmd_SetMouseThreshold },
                    227:        { 0x0C,3,  IKBD_Cmd_SetMouseScale },
                    228:        { 0x0D,1,  IKBD_Cmd_ReadAbsMousePos },
                    229:        { 0x0E,6,  IKBD_Cmd_SetInternalMousePos },
                    230:        { 0x0F,1,  IKBD_Cmd_SetYAxisDown },
                    231:        { 0x10,1,  IKBD_Cmd_SetYAxisUp },
                    232:        { 0x11,1,  IKBD_Cmd_StartKeyboardTransfer },
                    233:        { 0x12,1,  IKBD_Cmd_TurnMouseOff },
                    234:        { 0x13,1,  IKBD_Cmd_StopKeyboardTransfer },
                    235:        { 0x14,1,  IKBD_Cmd_ReturnJoystickAuto },
                    236:        { 0x15,1,  IKBD_Cmd_StopJoystick },
                    237:        { 0x16,1,  IKBD_Cmd_ReturnJoystick },
                    238:        { 0x17,2,  IKBD_Cmd_SetJoystickDuration },
                    239:        { 0x18,1,  IKBD_Cmd_SetJoystickFireDuration },
                    240:        { 0x19,7,  IKBD_Cmd_SetCursorForJoystick },
                    241:        { 0x1A,1,  IKBD_Cmd_DisableJoysticks },
                    242:        { 0x1B,7,  IKBD_Cmd_SetClock },
                    243:        { 0x1C,1,  IKBD_Cmd_ReadClock },
                    244:        { 0x20,4,  IKBD_Cmd_LoadMemory },
                    245:        { 0x21,3,  IKBD_Cmd_ReadMemory },
                    246:        { 0x22,3,  IKBD_Cmd_Execute },
                    247: 
1.1.1.13  root      248:        /* Report message (top bit set) */
                    249:        { 0x87,1,  IKBD_Cmd_ReportMouseAction },
                    250:        { 0x88,1,  IKBD_Cmd_ReportMouseMode },
                    251:        { 0x89,1,  IKBD_Cmd_ReportMouseMode },
                    252:        { 0x8A,1,  IKBD_Cmd_ReportMouseMode },
                    253:        { 0x8B,1,  IKBD_Cmd_ReportMouseThreshold },
                    254:        { 0x8C,1,  IKBD_Cmd_ReportMouseScale },
                    255:        { 0x8F,1,  IKBD_Cmd_ReportMouseVertical },
                    256:        { 0x90,1,  IKBD_Cmd_ReportMouseVertical },
                    257:        { 0x92,1,  IKBD_Cmd_ReportMouseAvailability },
                    258:        { 0x94,1,  IKBD_Cmd_ReportJoystickMode },
                    259:        { 0x95,1,  IKBD_Cmd_ReportJoystickMode },
                    260:        { 0x99,1,  IKBD_Cmd_ReportJoystickMode },
                    261:        { 0x9A,1,  IKBD_Cmd_ReportJoystickAvailability },
1.1       root      262: 
1.1.1.12  root      263:        { 0xFF,0,  NULL }  /* Term */
1.1       root      264: };
                    265: 
1.1.1.2   root      266: 
1.1.1.13  root      267: static void IKBD_SendByteToKeyboardProcessor(Uint16 bl);
                    268: static Uint16 IKBD_GetByteFromACIA(void);
                    269: static void IKBD_SendByteToACIA(int nAciaCycles);
                    270: static void IKBD_AddKeyToKeyboardBuffer(Uint8 Data);
                    271: static void IKBD_AddKeyToKeyboardBufferWithDelay(Uint8 Data, int nAciaCycles);
                    272: static void IKBD_AddKeyToKeyboardBuffer_Real(Uint8 Data, int nAciaCycles);
                    273: 
                    274: 
                    275: /* Belows part is used to emulate the behaviour of custom 6301 programs */
                    276: /* sent to the ikbd RAM. */
                    277: 
                    278: static void IKBD_LoadMemoryByte ( Uint8 aciabyte );
                    279: 
                    280: static void IKBD_CustomCodeHandler_CommonBoot ( Uint8 aciabyte );
                    281: 
                    282: static void IKBD_CustomCodeHandler_FroggiesMenu_Read ( void );
                    283: static void IKBD_CustomCodeHandler_FroggiesMenu_Write ( Uint8 aciabyte );
                    284: static void IKBD_CustomCodeHandler_Transbeauce2Menu_Read ( void );
                    285: static void IKBD_CustomCodeHandler_Transbeauce2Menu_Write ( Uint8 aciabyte );
                    286: static void IKBD_CustomCodeHandler_DragonnelsMenu_Read ( void );
                    287: static void IKBD_CustomCodeHandler_DragonnelsMenu_Write ( Uint8 aciabyte );
1.1.1.17! root      288: static void IKBD_CustomCodeHandler_ChaosAD_Read ( void );
        !           289: static void IKBD_CustomCodeHandler_ChaosAD_Write ( Uint8 aciabyte );
1.1.1.13  root      290: 
                    291: 
1.1.1.17! root      292: static int     MemoryLoadNbBytesTotal = 0;             /* total number of bytes to send with the command 0x20 */
        !           293: static int     MemoryLoadNbBytesLeft = 0;              /* number of bytes that remain to be sent  */
        !           294: static Uint32  MemoryLoadCrc = 0xffffffff;             /* CRC of the bytes sent to the ikbd */
        !           295: static int     MemoryExeNbBytes = 0;                   /* current number of bytes sent to the ikbd when IKBD_ExeMode is true */
1.1.1.13  root      296: 
1.1.1.17! root      297: static void    (*pIKBD_CustomCodeHandler_Read) ( void );
        !           298: static void    (*pIKBD_CustomCodeHandler_Write) ( Uint8 );
        !           299: static bool    IKBD_ExeMode = false;
        !           300: 
        !           301: static Uint8   ScanCodeState[ 128 ];                   /* state of each key : 0=released 1=pressed */
1.1.1.13  root      302: 
                    303: /* This array contains all known custom 6301 programs, with their CRC */
1.1.1.17! root      304: static const struct
1.1.1.13  root      305: {
                    306:        Uint32          LoadMemCrc;                     /* CRC of the bytes sent using the command 0x20 */
                    307:        void            (*ExeBootHandler) ( Uint8 );    /* function handling write to $fffc02 during the 'boot' mode */
                    308:        int             MainProgNbBytes;                /* number of bytes of the main 6301 program */
                    309:        Uint32          MainProgCrc;                    /* CRC of the main 6301 program */
                    310:        void            (*ExeMainHandler_Read) ( void );/* function handling read to $fffc02 in the main 6301 program */
                    311:        void            (*ExeMainHandler_Write) ( Uint8 ); /* funciton handling write to $fffc02 in the main 6301 program */
                    312:        const char      *Name;
                    313: }
                    314: CustomCodeDefinitions[] =
                    315: {
                    316:        {
                    317:                0x2efb11b1 ,
                    318:                IKBD_CustomCodeHandler_CommonBoot ,
                    319:                167,
                    320:                0xe7110b6d ,
                    321:                IKBD_CustomCodeHandler_FroggiesMenu_Read ,
                    322:                IKBD_CustomCodeHandler_FroggiesMenu_Write ,
                    323:                "Froggies Over The Fence Main Menu"
                    324:        } ,
                    325:        {
                    326:                0xadb6b503 ,
                    327:                IKBD_CustomCodeHandler_CommonBoot ,
                    328:                165,
                    329:                0x5617c33c ,
                    330:                IKBD_CustomCodeHandler_Transbeauce2Menu_Read ,
                    331:                IKBD_CustomCodeHandler_Transbeauce2Menu_Write ,
                    332:                "Transbeauce 2 Main Menu"
                    333:        } ,
                    334:        {
                    335:                0x33c23cdf ,
                    336:                IKBD_CustomCodeHandler_CommonBoot ,
                    337:                83 ,
                    338:                0xdf3e5a88 ,
                    339:                IKBD_CustomCodeHandler_DragonnelsMenu_Read ,
                    340:                IKBD_CustomCodeHandler_DragonnelsMenu_Write ,
                    341:                "Dragonnels Main Menu"
1.1.1.17! root      342:        },
        !           343:        {
        !           344:                0x9ad7fcdf ,
        !           345:                IKBD_CustomCodeHandler_CommonBoot ,
        !           346:                109 ,
        !           347:                0xa11d8be5 ,
        !           348:                IKBD_CustomCodeHandler_ChaosAD_Read ,
        !           349:                IKBD_CustomCodeHandler_ChaosAD_Write ,
        !           350:                "Chaos A.D."
1.1.1.13  root      351:        }
                    352: };
                    353: 
                    354: 
                    355: 
1.1.1.2   root      356: /*-----------------------------------------------------------------------*/
1.1.1.12  root      357: /**
                    358:  * Reset the ACIA
                    359:  */
                    360: void ACIA_Reset(void)
                    361: {
1.1.1.17! root      362:        LOG_TRACE(TRACE_IKBD_EXEC, "ikbd acia reset\n");
        !           363: 
        !           364: /* [NP] 2011/07/14 FIXME : Acia reset should not clear bytes in transit ? */
        !           365: /* Else, "Froggies Over The Fence" doesn't exit the custom ikbd mode */
        !           366: #if 0
1.1.1.15  root      367:        bByteInTransitToACIA = false;
1.1.1.17! root      368:        bByteInTransitFromACIA = false;
        !           369: #endif
1.1.1.12  root      370:        ACIAControlRegister = 0;
                    371:        ACIAStatusRegister = ACIA_STATUS_REGISTER__TX_BUFFER_EMPTY;
                    372: }
                    373: 
                    374: 
                    375: /*-----------------------------------------------------------------------*/
                    376: /**
                    377:  * Reset the IKBD processor
                    378:  */
1.1.1.13  root      379: 
                    380: /* Cancel execution of any program that was uploaded to the 6301's RAM */
                    381: /* This function is also called when performing a 68000 'reset' ; in that */
                    382: /* case we need to return $F0 and $F1. */
                    383: 
                    384: void IKBD_Reset_ExeMode ( void )
1.1       root      385: {
1.1.1.15  root      386:        LOG_TRACE(TRACE_IKBD_EXEC, "ikbd custom exe off\n");
1.1.1.13  root      387: 
                    388:        /* Reset any custom code run with the Execute command 0x22 */
                    389:        MemoryLoadNbBytesLeft = 0;
                    390:        pIKBD_CustomCodeHandler_Read = NULL;
                    391:        pIKBD_CustomCodeHandler_Write = NULL;
1.1.1.15  root      392:        IKBD_ExeMode = false;
1.1.1.13  root      393: 
                    394:        Keyboard.BufferHead = Keyboard.BufferTail = 0;  /* flush all queued bytes that would be read in $fffc02 */
1.1.1.15  root      395:        bByteInTransitToACIA = false;
1.1.1.17! root      396:        bByteInTransitFromACIA = false;
1.1.1.15  root      397:        // IKBD_AddKeyToKeyboardBuffer(0xF0);           /* Assume OK, return correct code */
1.1.1.13  root      398:        IKBD_AddKeyToKeyboardBuffer(0xF1);              /* [NP] Dragonnels demo needs this */
                    399: }
                    400: 
                    401: 
                    402: void IKBD_Reset(bool bCold)
                    403: {
                    404:        int     i;
                    405: 
                    406: 
1.1.1.12  root      407:        /* Reset internal keyboard processor details */
                    408:        if (bCold)
                    409:        {
1.1.1.15  root      410:                KeyboardProcessor.bReset = false;
1.1.1.16  root      411:                if (CycInt_InterruptActive(INTERRUPT_IKBD_RESETTIMER))
                    412:                        CycInt_RemovePendingInterrupt(INTERRUPT_IKBD_RESETTIMER);
1.1.1.12  root      413:        }
                    414: 
                    415:        KeyboardProcessor.MouseMode = AUTOMODE_MOUSEREL;
                    416:        KeyboardProcessor.JoystickMode = AUTOMODE_JOYSTICK;
                    417: 
                    418:        KeyboardProcessor.Abs.X = ABS_X_ONRESET;
                    419:        KeyboardProcessor.Abs.Y = ABS_Y_ONRESET;
                    420:        KeyboardProcessor.Abs.MaxX = ABS_MAX_X_ONRESET;
                    421:        KeyboardProcessor.Abs.MaxY = ABS_MAY_Y_ONRESET;
                    422:        KeyboardProcessor.Abs.PrevReadAbsMouseButtons = ABS_PREVBUTTONS;
                    423: 
                    424:        KeyboardProcessor.Mouse.DeltaX = KeyboardProcessor.Mouse.DeltaY = 0;
                    425:        KeyboardProcessor.Mouse.XScale = KeyboardProcessor.Mouse.YScale = 0;
                    426:        KeyboardProcessor.Mouse.XThreshold = KeyboardProcessor.Mouse.YThreshold = 1;
                    427:        KeyboardProcessor.Mouse.YAxis = 1;          /* Y origin at top */
                    428:        KeyboardProcessor.Mouse.Action = 0;
                    429: 
                    430:        KeyboardProcessor.Joy.PrevJoyData[0] = KeyboardProcessor.Joy.PrevJoyData[1] = 0;
                    431: 
1.1.1.13  root      432:        for ( i=0 ; i<128 ; i++ )
                    433:                ScanCodeState[ i ] = 0;                         /* key is released */
                    434: 
1.1.1.12  root      435:        /* Reset our ACIA status */
                    436:        ACIA_Reset();
                    437:        /* And our keyboard states and clear key state table */
                    438:        Keyboard.BufferHead = Keyboard.BufferTail = 0;
                    439:        Keyboard.nBytesInInputBuffer = 0;
                    440:        memset(Keyboard.KeyStates, 0, sizeof(Keyboard.KeyStates));
                    441:        Keyboard.bLButtonDown = BUTTON_NULL;
                    442:        Keyboard.bRButtonDown = BUTTON_NULL;
                    443:        Keyboard.bOldLButtonDown = Keyboard.bOldRButtonDown = BUTTON_NULL;
                    444:        Keyboard.LButtonDblClk = Keyboard.RButtonDblClk = 0;
                    445:        Keyboard.LButtonHistory = Keyboard.RButtonHistory = 0;
                    446: 
1.1.1.13  root      447:        /* Store bool for when disable mouse or joystick */
1.1.1.15  root      448:        bMouseDisabled = bJoystickDisabled = false;
1.1.1.12  root      449:        /* do emulate hardware 'quirk' where if disable both with 'x' time
                    450:         * of a RESET command they are ignored! */
1.1.1.15  root      451:        bDuringResetCriticalTime = bBothMouseAndJoy = false;
                    452:        bMouseEnabledDuringReset = false;
1.1.1.13  root      453: 
                    454:        /* Remove any custom handlers used to emulate code loaded to the 6301's RAM */
                    455:        IKBD_Reset_ExeMode ();
1.1.1.14  root      456: 
                    457:        /* Add auto-update function to the queue */
1.1.1.16  root      458:        CycInt_AddRelativeInterrupt(150000, INT_CPU_CYCLE, INTERRUPT_IKBD_AUTOSEND);
1.1       root      459: }
                    460: 
1.1.1.2   root      461: 
                    462: /*-----------------------------------------------------------------------*/
1.1.1.12  root      463: /**
                    464:  * Save/Restore snapshot of local variables
                    465:  * ('MemorySnapShot_Store' handles type)
                    466:  */
1.1.1.13  root      467: void IKBD_MemorySnapShot_Capture(bool bSave)
1.1       root      468: {
1.1.1.13  root      469:        unsigned int i;
                    470: 
1.1.1.12  root      471:        /* Save/Restore details */
                    472:        MemorySnapShot_Store(&Keyboard, sizeof(Keyboard));
                    473:        MemorySnapShot_Store(&KeyboardProcessor, sizeof(KeyboardProcessor));
                    474:        MemorySnapShot_Store(&ACIAControlRegister, sizeof(ACIAControlRegister));
                    475:        MemorySnapShot_Store(&ACIAStatusRegister, sizeof(ACIAStatusRegister));
                    476:        MemorySnapShot_Store(&ACIAByte, sizeof(ACIAByte));
1.1.1.17! root      477:        MemorySnapShot_Store(&ACIATxDataRegister, sizeof(ACIATxDataRegister));
1.1.1.12  root      478:        MemorySnapShot_Store(&bByteInTransitToACIA, sizeof(bByteInTransitToACIA));
1.1.1.17! root      479:        MemorySnapShot_Store(&bByteInTransitFromACIA, sizeof(bByteInTransitFromACIA));
1.1.1.12  root      480:        MemorySnapShot_Store(&bMouseDisabled, sizeof(bMouseDisabled));
                    481:        MemorySnapShot_Store(&bJoystickDisabled, sizeof(bJoystickDisabled));
                    482:        MemorySnapShot_Store(&bDuringResetCriticalTime, sizeof(bDuringResetCriticalTime));
                    483:        MemorySnapShot_Store(&bBothMouseAndJoy, sizeof(bBothMouseAndJoy));
1.1.1.14  root      484:        MemorySnapShot_Store(&bMouseEnabledDuringReset, sizeof(bMouseEnabledDuringReset));
1.1.1.13  root      485: 
                    486:        /* restore custom 6301 program if needed */
                    487:        MemorySnapShot_Store(&IKBD_ExeMode, sizeof(IKBD_ExeMode));
                    488:        MemorySnapShot_Store(&MemoryLoadCrc, sizeof(MemoryLoadCrc));
1.1.1.15  root      489:        if ((bSave == false) && (IKBD_ExeMode == true))         /* restoring a snapshot with active 6301 emulation */
1.1.1.13  root      490:        {
                    491:                for ( i = 0 ; i < sizeof ( CustomCodeDefinitions ) / sizeof ( CustomCodeDefinitions[0] ); i++ )
                    492:                        if ( CustomCodeDefinitions[ i ].MainProgCrc == MemoryLoadCrc )
                    493:                        {
                    494:                                pIKBD_CustomCodeHandler_Read = CustomCodeDefinitions[ i ].ExeMainHandler_Read;
                    495:                                pIKBD_CustomCodeHandler_Write = CustomCodeDefinitions[ i ].ExeMainHandler_Write;
                    496:                                Keyboard.BufferHead = Keyboard.BufferTail = 0;  /* flush all queued bytes that would be read in $fffc02 */
                    497: //                             (*pIKBD_CustomCodeHandler_Read) ();             /* initialize ACIAByte */
                    498:                                ACIAByte = 0;                   /* initialize ACIAByte, don't call IKBD_AddKeyToKeyboardBuffer_Real now */
                    499:                                break;
                    500:                        }
                    501: 
                    502:                if ( i >= sizeof ( CustomCodeDefinitions ) / sizeof ( CustomCodeDefinitions[0] ) )      /* not found (should not happen) */
1.1.1.15  root      503:                        IKBD_ExeMode = false;                   /* turn off exe mode */
1.1.1.13  root      504:        }
1.1       root      505: }
                    506: 
1.1.1.2   root      507: 
                    508: /*-----------------------------------------------------------------------*/
1.1.1.12  root      509: /**
                    510:  * Calculate out 'delta' that mouse has moved by each frame, and add this to our internal keyboard position
                    511:  */
1.1.1.8   root      512: static void IKBD_UpdateInternalMousePosition(void)
1.1       root      513: {
                    514: 
1.1.1.12  root      515:        KeyboardProcessor.Mouse.DeltaX = KeyboardProcessor.Mouse.dx;
                    516:        KeyboardProcessor.Mouse.DeltaY = KeyboardProcessor.Mouse.dy;
                    517:        KeyboardProcessor.Mouse.dx = 0;
                    518:        KeyboardProcessor.Mouse.dy = 0;
                    519: 
                    520:        /* Update internal mouse coords - Y axis moves according to YAxis setting(up/down) */
                    521:        /* Limit to Max X/Y(inclusive) */
                    522:        KeyboardProcessor.Abs.X += KeyboardProcessor.Mouse.DeltaX;
                    523:        if (KeyboardProcessor.Abs.X < 0)
                    524:                KeyboardProcessor.Abs.X = 0;
                    525:        if (KeyboardProcessor.Abs.X > KeyboardProcessor.Abs.MaxX)
                    526:                KeyboardProcessor.Abs.X = KeyboardProcessor.Abs.MaxX;
                    527: 
                    528:        KeyboardProcessor.Abs.Y += KeyboardProcessor.Mouse.DeltaY*KeyboardProcessor.Mouse.YAxis;  /* Needed '+' for Falcon... */
                    529:        if (KeyboardProcessor.Abs.Y < 0)
                    530:                KeyboardProcessor.Abs.Y = 0;
                    531:        if (KeyboardProcessor.Abs.Y > KeyboardProcessor.Abs.MaxY)
                    532:                KeyboardProcessor.Abs.Y = KeyboardProcessor.Abs.MaxY;
1.1.1.4   root      533: 
1.1       root      534: }
                    535: 
1.1.1.2   root      536: 
                    537: /*-----------------------------------------------------------------------*/
1.1.1.12  root      538: /**
                    539:  * When running in maximum speed the emulation will not see 'double-clicks'
                    540:  * of the mouse as it is running so fast. In this case, we check for a
                    541:  * double-click and pass the 'up'/'down' messages in emulation time to
                    542:  * simulate the double-click effect!
                    543:  */
1.1.1.8   root      544: static void IKBD_CheckForDoubleClicks(void)
1.1       root      545: {
1.1.1.12  root      546:        /*
                    547:          Things get a little complicated when running max speed as a normal
                    548:          double-click is a load of 1's, followed by 0's, 1's and 0's - But the
                    549:          ST does not see this as a double click as the space in 'ST' time
                    550:          between changes is so great.
                    551:          Now, when we see a real double-click in max speed we actually send
                    552:          the down/up/down/up in ST time. To get this correct (and not send
                    553:          three clicks) we look in a history buffer and start at an index which
                    554:          gives the correct number of clicks! Phew!
                    555:        */
                    556: 
                    557:        /* Handle double clicks!!! */
                    558:        if (Keyboard.LButtonDblClk)
                    559:        {
                    560:                if (Keyboard.LButtonDblClk == 1)              /* First pressed! */
                    561:                {
                    562:                        if ((Keyboard.LButtonHistory&0x3f) == 0)  /* If not pressed button in long time do full dbl-click pattern */
                    563:                                Keyboard.LButtonDblClk = 1;
                    564:                        else
                    565:                        {
                    566:                                Keyboard.LButtonDblClk = 4;           /* Otherwise, check where to begin to give 1111000011110000 pattern */
                    567:                                if ((Keyboard.LButtonHistory&0x7) == 0)
                    568:                                        Keyboard.LButtonDblClk = 8;
                    569:                                else if ((Keyboard.LButtonHistory&0x3) == 0)
                    570:                                        Keyboard.LButtonDblClk = 7;
                    571:                                else if ((Keyboard.LButtonHistory&0x1) == 0)
                    572:                                        Keyboard.LButtonDblClk = 6;
                    573:                        }
                    574:                }
                    575: 
                    576:                Keyboard.bLButtonDown = DoubleClickPattern[Keyboard.LButtonDblClk];
                    577:                Keyboard.LButtonDblClk++;
                    578:                if (Keyboard.LButtonDblClk >= 13)             /* Check for end of sequence */
                    579:                {
                    580:                        Keyboard.LButtonDblClk = 0;
1.1.1.15  root      581:                        Keyboard.bLButtonDown = false;
1.1.1.12  root      582:                }
                    583:        }
                    584:        if (Keyboard.RButtonDblClk)
                    585:        {
                    586:                if (Keyboard.RButtonDblClk == 1)              /* First pressed! */
                    587:                {
                    588:                        if ((Keyboard.RButtonHistory&0x3f) == 0)  /* If not pressed button in long time do full dbl-click pattern */
                    589:                                Keyboard.RButtonDblClk = 1;
                    590:                        else
                    591:                        {
                    592:                                Keyboard.RButtonDblClk = 4;           /* Otherwise, check where to begin to give 1111000011110000 pattern */
                    593:                                if ((Keyboard.RButtonHistory&0x7) == 0)
                    594:                                        Keyboard.RButtonDblClk = 8;
                    595:                                else if ((Keyboard.RButtonHistory&0x3) == 0)
                    596:                                        Keyboard.RButtonDblClk = 7;
                    597:                                else if ((Keyboard.RButtonHistory&0x1) == 0)
                    598:                                        Keyboard.RButtonDblClk = 6;
                    599:                        }
                    600:                }
                    601: 
                    602:                Keyboard.bRButtonDown = DoubleClickPattern[Keyboard.RButtonDblClk];
                    603:                Keyboard.RButtonDblClk++;
                    604:                if (Keyboard.RButtonDblClk >= 13)             /* Check for end of sequence */
                    605:                {
                    606:                        Keyboard.RButtonDblClk = 0;
1.1.1.15  root      607:                        Keyboard.bRButtonDown = false;
1.1.1.12  root      608:                }
                    609:        }
                    610: 
                    611:        /* Store presses into history */
                    612:        Keyboard.LButtonHistory = (Keyboard.LButtonHistory<<1);
                    613:        if (Keyboard.bLButtonDown)
                    614:                Keyboard.LButtonHistory |= 0x1;
                    615:        Keyboard.RButtonHistory = (Keyboard.RButtonHistory<<1);
                    616:        if (Keyboard.bRButtonDown)
                    617:                Keyboard.RButtonHistory |= 0x1;
                    618: }
                    619: 
                    620: 
                    621: /*-----------------------------------------------------------------------*/
                    622: /**
1.1.1.13  root      623:  * Convert button to bool value
1.1.1.12  root      624:  */
1.1.1.13  root      625: static bool IKBD_ButtonBool(int Button)
1.1       root      626: {
1.1.1.12  root      627:        /* Button pressed? */
                    628:        if (Button)
1.1.1.15  root      629:                return true;
                    630:        return false;
1.1       root      631: }
                    632: 
1.1.1.2   root      633: 
                    634: /*-----------------------------------------------------------------------*/
1.1.1.12  root      635: /**
1.1.1.15  root      636:  * Return true if buttons match, use this as buttons are a mask and not boolean
1.1.1.12  root      637:  */
1.1.1.13  root      638: static bool IKBD_ButtonsEqual(int Button1,int Button2)
1.1       root      639: {
1.1.1.13  root      640:        /* Return bool compare */
1.1.1.12  root      641:        return (IKBD_ButtonBool(Button1) == IKBD_ButtonBool(Button2));
1.1       root      642: }
                    643: 
1.1.1.2   root      644: 
                    645: /*-----------------------------------------------------------------------*/
1.1.1.12  root      646: /**
1.1.1.13  root      647:  * According to if the mouse is enabled or not the joystick 1 fire
                    648:  * button/right mouse button will become the same button. That means
                    649:  * pressing one will also press the other and vice-versa.
                    650:  * If both mouse and joystick are enabled, report it as a mouse button
                    651:  * (needed by the game Big Run for example).
1.1.1.12  root      652:  */
1.1.1.8   root      653: static void IKBD_DuplicateMouseFireButtons(void)
1.1       root      654: {
1.1.1.12  root      655:        /* If mouse is off then joystick fire button goes to joystick */
1.1.1.14  root      656:        if (KeyboardProcessor.MouseMode == AUTOMODE_OFF)
1.1.1.12  root      657:        {
                    658:                /* If pressed right mouse button, should go to joystick 1 */
                    659:                if (Keyboard.bRButtonDown&BUTTON_MOUSE)
                    660:                        KeyboardProcessor.Joy.JoyData[1] |= 0x80;
                    661:                /* And left mouse button, should go to joystick 0 */
                    662:                if (Keyboard.bLButtonDown&BUTTON_MOUSE)
                    663:                        KeyboardProcessor.Joy.JoyData[0] |= 0x80;
                    664:        }
1.1.1.13  root      665:        /* If mouse is on, joystick 1 fire button goes to the mouse instead */
1.1.1.12  root      666:        else
                    667:        {
                    668:                /* Is fire button pressed? */
                    669:                if (KeyboardProcessor.Joy.JoyData[1]&0x80)
                    670:                {
                    671:                        KeyboardProcessor.Joy.JoyData[1] &= 0x7f;  /* Clear fire button bit */
                    672:                        Keyboard.bRButtonDown |= BUTTON_JOYSTICK;  /* Mimick on mouse right button */
                    673:                }
                    674:                else
                    675:                        Keyboard.bRButtonDown &= ~BUTTON_JOYSTICK;
                    676:        }
1.1       root      677: }
                    678: 
1.1.1.2   root      679: 
                    680: /*-----------------------------------------------------------------------*/
1.1.1.12  root      681: /**
                    682:  * Send 'relative' mouse position
                    683:  */
1.1.1.8   root      684: static void IKBD_SendRelMousePacket(void)
1.1       root      685: {
1.1.1.12  root      686:        int ByteRelX,ByteRelY;
                    687:        Uint8 Header;
1.1       root      688: 
1.1.1.12  root      689:        if ( (KeyboardProcessor.Mouse.DeltaX!=0) || (KeyboardProcessor.Mouse.DeltaY!=0)
                    690:                || (!IKBD_ButtonsEqual(Keyboard.bOldLButtonDown,Keyboard.bLButtonDown)) || (!IKBD_ButtonsEqual(Keyboard.bOldRButtonDown,Keyboard.bRButtonDown)) )
                    691:        {
                    692:                /* Send packet to keyboard process */
1.1.1.15  root      693:                while (true)
1.1.1.12  root      694:                {
                    695:                        ByteRelX = KeyboardProcessor.Mouse.DeltaX;
                    696:                        if (ByteRelX>127)  ByteRelX = 127;
                    697:                        if (ByteRelX<-128)  ByteRelX = -128;
                    698:                        ByteRelY = KeyboardProcessor.Mouse.DeltaY;
                    699:                        if (ByteRelY>127)  ByteRelY = 127;
                    700:                        if (ByteRelY<-128)  ByteRelY = -128;
                    701: 
                    702:                        Header = 0xf8;
                    703:                        if (Keyboard.bLButtonDown)
                    704:                                Header |= 0x02;
                    705:                        if (Keyboard.bRButtonDown)
                    706:                                Header |= 0x01;
                    707:                        IKBD_AddKeyToKeyboardBuffer(Header);
                    708:                        IKBD_AddKeyToKeyboardBuffer(ByteRelX);
                    709:                        IKBD_AddKeyToKeyboardBuffer(ByteRelY*KeyboardProcessor.Mouse.YAxis);
                    710: 
                    711:                        KeyboardProcessor.Mouse.DeltaX -= ByteRelX;
                    712:                        KeyboardProcessor.Mouse.DeltaY -= ByteRelY;
                    713: 
                    714:                        if ( (KeyboardProcessor.Mouse.DeltaX==0) && (KeyboardProcessor.Mouse.DeltaY==0) )
                    715:                                break;
                    716: 
                    717:                        /* Store buttons for next time around */
                    718:                        Keyboard.bOldLButtonDown = Keyboard.bLButtonDown;
                    719:                        Keyboard.bOldRButtonDown = Keyboard.bRButtonDown;
                    720:                }
                    721:        }
1.1       root      722: }
                    723: 
1.1.1.2   root      724: 
1.1.1.13  root      725: /**
                    726:  * Get joystick data
                    727:  */
                    728: static void IKBD_GetJoystickData(void)
                    729: {
                    730:        /* Joystick 1 */
                    731:        KeyboardProcessor.Joy.JoyData[1] = Joy_GetStickData(1);
                    732: 
                    733:        /* If mouse is on, joystick 0 is not connected */
                    734:        if (KeyboardProcessor.MouseMode==AUTOMODE_OFF
                    735:                || (bBothMouseAndJoy && KeyboardProcessor.MouseMode==AUTOMODE_MOUSEREL))
                    736:                KeyboardProcessor.Joy.JoyData[0] = Joy_GetStickData(0);
                    737:        else
                    738:                KeyboardProcessor.Joy.JoyData[0] = 0x00;
                    739: }
                    740: 
                    741: 
1.1.1.2   root      742: /*-----------------------------------------------------------------------*/
1.1.1.12  root      743: /**
                    744:  * Send 'joysticks' bit masks
                    745:  */
1.1.1.8   root      746: static void IKBD_SelAutoJoysticks(void)
1.1       root      747: {
1.1.1.12  root      748:        Uint8 JoyData;
1.1       root      749: 
1.1.1.12  root      750:        /* Did joystick 0/mouse change? */
                    751:        JoyData = KeyboardProcessor.Joy.JoyData[0];
                    752:        if (JoyData!=KeyboardProcessor.Joy.PrevJoyData[0])
                    753:        {
                    754:                IKBD_AddKeyToKeyboardBuffer(0xFE);    /* Joystick 0/Mouse */
                    755:                IKBD_AddKeyToKeyboardBuffer(JoyData);
                    756: 
                    757:                KeyboardProcessor.Joy.PrevJoyData[0] = JoyData;
                    758:        }
                    759: 
                    760:        /* Did joystick 1(default) change? */
                    761:        JoyData = KeyboardProcessor.Joy.JoyData[1];
                    762:        if (JoyData!=KeyboardProcessor.Joy.PrevJoyData[1])
                    763:        {
                    764:                IKBD_AddKeyToKeyboardBuffer(0xFF);    /* Joystick 1 */
                    765:                IKBD_AddKeyToKeyboardBuffer(JoyData);
                    766: 
                    767:                KeyboardProcessor.Joy.PrevJoyData[1] = JoyData;
                    768:        }
1.1       root      769: }
                    770: 
                    771: /*-----------------------------------------------------------------------*/
1.1.1.12  root      772: /**
                    773:  * Send packets which are generated from the mouse action settings
                    774:  * If relative mode is on, still generate these packets
                    775:  */
1.1.1.8   root      776: static void IKBD_SendOnMouseAction(void)
1.1       root      777: {
1.1.1.15  root      778:        bool bReportPosition = false;
1.1       root      779: 
1.1.1.12  root      780:        /* Report buttons as keys? Do in relative/absolute mode */
                    781:        if (KeyboardProcessor.Mouse.Action&0x4)
                    782:        {
                    783:                /* Left button? */
                    784:                if ( (IKBD_ButtonBool(Keyboard.bLButtonDown) && (!IKBD_ButtonBool(Keyboard.bOldLButtonDown))) )
                    785:                        IKBD_AddKeyToKeyboardBuffer(0x74);    /* Left */
                    786:                else if ( (IKBD_ButtonBool(Keyboard.bOldLButtonDown) && (!IKBD_ButtonBool(Keyboard.bLButtonDown))) )
                    787:                        IKBD_AddKeyToKeyboardBuffer(0x74|0x80);
                    788:                /* Right button? */
                    789:                if ( (IKBD_ButtonBool(Keyboard.bRButtonDown) && (!IKBD_ButtonBool(Keyboard.bOldRButtonDown))) )
                    790:                        IKBD_AddKeyToKeyboardBuffer(0x75);    /* Right */
                    791:                else if ( (IKBD_ButtonBool(Keyboard.bOldRButtonDown) && (!IKBD_ButtonBool(Keyboard.bRButtonDown))) )
                    792:                        IKBD_AddKeyToKeyboardBuffer(0x75|0x80);
                    793: 
                    794:                /* Ignore bottom two bits, so return now */
                    795:                return;
                    796:        }
                    797: 
                    798:        /* Check MouseAction - report position on press/release */
                    799:        /* MUST do this before update relative positions as buttons get reset */
                    800:        if (KeyboardProcessor.Mouse.Action&0x3)
                    801:        {
                    802:                /* Check for 'press'? */
                    803:                if (KeyboardProcessor.Mouse.Action&0x1)
                    804:                {
                    805:                        /* Did 'press' mouse buttons? */
                    806:                        if ( (IKBD_ButtonBool(Keyboard.bLButtonDown) && (!IKBD_ButtonBool(Keyboard.bOldLButtonDown))) )
                    807:                        {
1.1.1.15  root      808:                                bReportPosition = true;
1.1.1.12  root      809:                                KeyboardProcessor.Abs.PrevReadAbsMouseButtons &= ~0x04;
                    810:                                KeyboardProcessor.Abs.PrevReadAbsMouseButtons |= 0x02;
                    811:                        }
                    812:                        if ( (IKBD_ButtonBool(Keyboard.bRButtonDown) && (!IKBD_ButtonBool(Keyboard.bOldRButtonDown))) )
                    813:                        {
1.1.1.15  root      814:                                bReportPosition = true;
1.1.1.12  root      815:                                KeyboardProcessor.Abs.PrevReadAbsMouseButtons &= ~0x01;
                    816:                                KeyboardProcessor.Abs.PrevReadAbsMouseButtons |= 0x08;
                    817:                        }
                    818:                }
                    819:                /* Check for 'release'? */
                    820:                if (KeyboardProcessor.Mouse.Action&0x2)
                    821:                {
                    822:                        /* Did 'release' mouse buttons? */
                    823:                        if ( (IKBD_ButtonBool(Keyboard.bOldLButtonDown) && (!IKBD_ButtonBool(Keyboard.bLButtonDown))) )
                    824:                        {
1.1.1.15  root      825:                                bReportPosition = true;
1.1.1.12  root      826:                                KeyboardProcessor.Abs.PrevReadAbsMouseButtons &= ~0x08;
                    827:                                KeyboardProcessor.Abs.PrevReadAbsMouseButtons |= 0x01;
                    828:                        }
                    829:                        if ( (IKBD_ButtonBool(Keyboard.bOldRButtonDown) && (!IKBD_ButtonBool(Keyboard.bRButtonDown))) )
                    830:                        {
1.1.1.15  root      831:                                bReportPosition = true;
1.1.1.12  root      832:                                KeyboardProcessor.Abs.PrevReadAbsMouseButtons &= ~0x02;
                    833:                                KeyboardProcessor.Abs.PrevReadAbsMouseButtons |= 0x04;
                    834:                        }
                    835:                }
                    836: 
                    837:                /* Do need to report? */
                    838:                if (bReportPosition)
                    839:                {
                    840:                        /* Only report if mouse in absolute mode */
                    841:                        if (KeyboardProcessor.MouseMode==AUTOMODE_MOUSEABS)
                    842:                        {
1.1.1.15  root      843:                                LOG_TRACE(TRACE_IKBD_ALL, "Report ABS on MouseAction\n");
1.1.1.12  root      844:                                IKBD_Cmd_ReadAbsMousePos();
                    845:                        }
                    846:                }
                    847:        }
                    848: }
                    849: 
                    850: 
                    851: /*-----------------------------------------------------------------------*/
                    852: /**
                    853:  * Send mouse movements as cursor keys
                    854:  */
1.1.1.8   root      855: static void IKBD_SendCursorMousePacket(void)
1.1       root      856: {
1.1.1.12  root      857:        int i=0;
1.1       root      858: 
1.1.1.12  root      859:        /* Run each 'Delta' as cursor presses */
                    860:        /* Limit to '10' loops as host mouse cursor might have a VERY poor quality. */
                    861:        /* Eg, a single mouse movement on and ST gives delta's of '1', mostly, */
                    862:        /* but host mouse might go as high as 20+! */
                    863:        while ( (i<10) && ((KeyboardProcessor.Mouse.DeltaX!=0) || (KeyboardProcessor.Mouse.DeltaY!=0)
                    864:                           || (!IKBD_ButtonsEqual(Keyboard.bOldLButtonDown,Keyboard.bLButtonDown)) || (!IKBD_ButtonsEqual(Keyboard.bOldRButtonDown,Keyboard.bRButtonDown))) )
                    865:        {
                    866:                /* Left? */
                    867:                if (KeyboardProcessor.Mouse.DeltaX<0)
                    868:                {
                    869:                        IKBD_AddKeyToKeyboardBuffer(75);    /* Left cursor */
                    870:                        IKBD_AddKeyToKeyboardBuffer(75|0x80);
                    871:                        KeyboardProcessor.Mouse.DeltaX++;
                    872:                }
                    873:                /* Right? */
                    874:                if (KeyboardProcessor.Mouse.DeltaX>0)
                    875:                {
                    876:                        IKBD_AddKeyToKeyboardBuffer(77);    /* Right cursor */
                    877:                        IKBD_AddKeyToKeyboardBuffer(77|0x80);
                    878:                        KeyboardProcessor.Mouse.DeltaX--;
                    879:                }
                    880:                /* Up? */
                    881:                if (KeyboardProcessor.Mouse.DeltaY<0)
                    882:                {
                    883:                        IKBD_AddKeyToKeyboardBuffer(72);    /* Up cursor */
                    884:                        IKBD_AddKeyToKeyboardBuffer(72|0x80);
                    885:                        KeyboardProcessor.Mouse.DeltaY++;
                    886:                }
                    887:                /* Down? */
                    888:                if (KeyboardProcessor.Mouse.DeltaY>0)
                    889:                {
                    890:                        IKBD_AddKeyToKeyboardBuffer(80);    /* Down cursor */
                    891:                        IKBD_AddKeyToKeyboardBuffer(80|0x80);
                    892:                        KeyboardProcessor.Mouse.DeltaY--;
                    893:                }
                    894: 
                    895:                /* Left button? */
                    896:                if ( (IKBD_ButtonBool(Keyboard.bLButtonDown) && (!IKBD_ButtonBool(Keyboard.bOldLButtonDown))) )
                    897:                        IKBD_AddKeyToKeyboardBuffer(0x74);    /* Left */
                    898:                else if ( (IKBD_ButtonBool(Keyboard.bOldLButtonDown) && (!IKBD_ButtonBool(Keyboard.bLButtonDown))) )
                    899:                        IKBD_AddKeyToKeyboardBuffer(0x74|0x80);
                    900:                /* Right button? */
                    901:                if ( (IKBD_ButtonBool(Keyboard.bRButtonDown) && (!IKBD_ButtonBool(Keyboard.bOldRButtonDown))) )
                    902:                        IKBD_AddKeyToKeyboardBuffer(0x75);    /* Right */
                    903:                else if ( (IKBD_ButtonBool(Keyboard.bOldRButtonDown) && (!IKBD_ButtonBool(Keyboard.bRButtonDown))) )
                    904:                        IKBD_AddKeyToKeyboardBuffer(0x75|0x80);
                    905: 
                    906:                Keyboard.bOldLButtonDown = Keyboard.bLButtonDown;
                    907:                Keyboard.bOldRButtonDown = Keyboard.bRButtonDown;
                    908: 
                    909:                /* Count, so exit if try too many times! */
                    910:                i++;
                    911:        }
1.1       root      912: }
                    913: 
1.1.1.2   root      914: 
                    915: /*-----------------------------------------------------------------------*/
1.1.1.12  root      916: /**
                    917:  * Return packets from keyboard for auto, rel mouse, joystick etc...
                    918:  */
1.1.1.14  root      919: static void IKBD_SendAutoKeyboardCommands(void)
1.1       root      920: {
1.1.1.12  root      921:        /* Don't do anything until processor is first reset */
                    922:        if (!KeyboardProcessor.bReset)
                    923:                return;
                    924: 
                    925:        /* Read joysticks for this frame */
1.1.1.13  root      926:        IKBD_GetJoystickData();
1.1.1.12  root      927: 
                    928:        /* Check for double-clicks in maximum speed mode */
                    929:        IKBD_CheckForDoubleClicks();
                    930: 
                    931:        /* Handle Joystick/Mouse fire buttons */
                    932:        IKBD_DuplicateMouseFireButtons();
                    933: 
                    934:        /* Send any packets which are to be reported by mouse action */
                    935:        IKBD_SendOnMouseAction();
                    936: 
                    937:        /* Update internal mouse absolute position by find 'delta' of mouse movement */
                    938:        IKBD_UpdateInternalMousePosition();
                    939: 
                    940:        /* Send automatic joystick packets */
                    941:        if (KeyboardProcessor.JoystickMode==AUTOMODE_JOYSTICK)
                    942:                IKBD_SelAutoJoysticks();
                    943:        /* Send automatic relative mouse positions(absolute are not send automatically) */
                    944:        if (KeyboardProcessor.MouseMode==AUTOMODE_MOUSEREL)
                    945:                IKBD_SendRelMousePacket();
                    946:        /* Send cursor key directions for movements */
                    947:        else if (KeyboardProcessor.MouseMode==AUTOMODE_MOUSECURSOR)
                    948:                IKBD_SendCursorMousePacket();
                    949: 
                    950:        /* Store buttons for next time around */
                    951:        Keyboard.bOldLButtonDown = Keyboard.bLButtonDown;
                    952:        Keyboard.bOldRButtonDown = Keyboard.bRButtonDown;
                    953: 
                    954:        /* Send joystick button '2' as 'Space bar' key - MUST do here so does not get mixed up in middle of joystick packets! */
                    955:        if (JoystickSpaceBar)
                    956:        {
                    957:                /* As we simulating space bar? */
                    958:                if (JoystickSpaceBar==JOYSTICK_SPACE_DOWN)
                    959:                {
1.1.1.15  root      960:                        IKBD_PressSTKey(57, true);         /* Press */
1.1.1.12  root      961:                        JoystickSpaceBar = JOYSTICK_SPACE_UP;
                    962:                }
                    963:                else   //if (JoystickSpaceBar==JOYSTICK_SPACE_UP) {
                    964:                {
1.1.1.15  root      965:                        IKBD_PressSTKey(57, false);       /* Release */
                    966:                        JoystickSpaceBar = false;         /* Complete */
1.1.1.12  root      967:                }
                    968:        }
1.1       root      969: }
                    970: 
1.1.1.2   root      971: 
                    972: /*-----------------------------------------------------------------------*/
1.1.1.12  root      973: /**
1.1.1.14  root      974:  * This function is called regularly to automatically send keyboard, mouse
                    975:  * and joystick updates.
                    976:  */
                    977: void IKBD_InterruptHandler_AutoSend(void)
                    978: {
                    979:        /* Handle user events and other messages, (like quit message) */
                    980:        Main_EventHandler();
                    981: 
1.1.1.17! root      982:        /* Remove this interrupt from list and re-order.
        !           983:         * (needs to be done after UI event handling so
        !           984:         * that snapshots saved from UI and restored from
        !           985:         * command line don't miss the AUTOSEND interrupt)
        !           986:         */
        !           987:        CycInt_AcknowledgeInterrupt();
        !           988: 
1.1.1.14  root      989:        /* Did user try to quit? */
                    990:        if (bQuitProgram)
                    991:        {
                    992:                /* Pass NULL interrupt function to quit cleanly */
1.1.1.16  root      993:                CycInt_AddAbsoluteInterrupt(4, INT_CPU_CYCLE, INTERRUPT_NULL);
1.1.1.14  root      994:                /* Assure that CPU core shuts down */
                    995:                M68000_SetSpecial(SPCFLAG_BRK);
                    996:                return;
                    997:        }
                    998: 
                    999:        /* Trigger this auto-update function again after a while */
1.1.1.16  root     1000:        CycInt_AddRelativeInterrupt(150000, INT_CPU_CYCLE, INTERRUPT_IKBD_AUTOSEND);
1.1.1.14  root     1001: 
                   1002:        /* We don't send keyboard data automatically within the first few
                   1003:         * VBLs to avoid that TOS gets confused during its boot time */
                   1004:        if (nVBLs > 20)
                   1005:        {
                   1006:                /* Send automatic keyboard packets for mouse, joysticks etc... */
                   1007:                IKBD_SendAutoKeyboardCommands();
                   1008:        }
                   1009: }
                   1010: 
                   1011: 
                   1012: /*-----------------------------------------------------------------------*/
                   1013: /**
1.1.1.12  root     1014:  * On ST if disable Mouse AND Joystick with a set time of a RESET command they are
                   1015:  * actually turned back on! (A number of games do this so can get mouse and joystick
                   1016:  * packets at the same time)
                   1017:  */
1.1.1.8   root     1018: static void IKBD_CheckResetDisableBug(void)
1.1       root     1019: {
1.1.1.12  root     1020:        /* Have disabled BOTH mouse and joystick? */
                   1021:        if (bMouseDisabled && bJoystickDisabled)
                   1022:        {
                   1023:                /* And in critical time? */
                   1024:                if (bDuringResetCriticalTime)
                   1025:                {
                   1026:                        /* Emulate relative mouse and joystick reports being turned back on */
                   1027:                        KeyboardProcessor.MouseMode = AUTOMODE_MOUSEREL;
                   1028:                        KeyboardProcessor.JoystickMode = AUTOMODE_JOYSTICK;
1.1.1.15  root     1029:                        bBothMouseAndJoy = true;
1.1.1.6   root     1030: 
1.1.1.15  root     1031:                        LOG_TRACE(TRACE_IKBD_ALL, "IKBD Mouse+Joystick disabled "
                   1032:                                  "during RESET. Revert.\n");
1.1.1.12  root     1033:                }
                   1034:        }
1.1       root     1035: }
                   1036: 
1.1.1.2   root     1037: 
                   1038: /*-----------------------------------------------------------------------*/
1.1.1.12  root     1039: /**
                   1040:  * Start timer after keyboard RESET command to emulate 'quirk'
                   1041:  * If some IKBD commands are sent during time after a RESET they may be ignored
                   1042:  */
1.1       root     1043: void IKBD_InterruptHandler_ResetTimer(void)
                   1044: {
1.1.1.12  root     1045:        /* Remove this interrupt from list and re-order */
1.1.1.16  root     1046:        CycInt_AcknowledgeInterrupt();
1.1       root     1047: 
1.1.1.12  root     1048:        /* Turn processor on; can now process commands */
1.1.1.15  root     1049:        KeyboardProcessor.bReset = true;
1.1.1.9   root     1050: 
1.1.1.12  root     1051:        /* Critical timer is over */
1.1.1.15  root     1052:        bDuringResetCriticalTime = false;
                   1053:        bMouseEnabledDuringReset = false;
1.1       root     1054: }
                   1055: 
                   1056: 
                   1057: 
1.1.1.2   root     1058: /*-----------------------------------------------------------------------*/
1.1       root     1059: /*
                   1060:   List of keyboard commands
                   1061: */
                   1062: 
                   1063: 
1.1.1.2   root     1064: /*-----------------------------------------------------------------------*/
1.1.1.12  root     1065: /**
                   1066:  * RESET
                   1067:  *
                   1068:  * 0x80
                   1069:  * 0x01
                   1070:  *
1.1.1.15  root     1071:  * Performs self test and checks for stuck (closed) keys, if OK returns 0xF0 or
                   1072:  * 0xF1. Otherwise returns break codes for keys (not emulated).
1.1.1.12  root     1073:  */
1.1.1.13  root     1074: static void IKBD_Cmd_Reset(void)
1.1       root     1075: {
1.1.1.15  root     1076:        LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_Reset. VBLs=%i framecyc=%i\n",
                   1077:                  nVBLs, Cycles_GetCounter(CYCLES_COUNTER_VIDEO));
1.1.1.14  root     1078: 
1.1.1.12  root     1079:        /* Check for error series of bytes, eg 0x80,0x01 */
                   1080:        if (Keyboard.InputBuffer[1] == 0x01)
                   1081:        {
                   1082:                /* Set defaults */
                   1083:                KeyboardProcessor.MouseMode = AUTOMODE_MOUSEREL;
                   1084:                KeyboardProcessor.JoystickMode = AUTOMODE_JOYSTICK;
                   1085:                KeyboardProcessor.Abs.X = ABS_X_ONRESET;
                   1086:                KeyboardProcessor.Abs.Y = ABS_Y_ONRESET;
                   1087:                KeyboardProcessor.Abs.MaxX = ABS_MAX_X_ONRESET;
                   1088:                KeyboardProcessor.Abs.MaxY = ABS_MAY_Y_ONRESET;
                   1089:                KeyboardProcessor.Abs.PrevReadAbsMouseButtons = ABS_PREVBUTTONS;
                   1090: 
1.1.1.15  root     1091:                /* flush all queued bytes that would be read in $fffc02 */
                   1092:                Keyboard.BufferHead = Keyboard.BufferTail = 0;
                   1093: 
                   1094:                /* This command returns either the byte 0xf0 or 0xf1 (depending
                   1095:                 * on the version of the IKBD ROM) when the reset has been
                   1096:                 * successful. Some notes:
                   1097:                 * - Dragonnels demo requires 0xf1 so we use only this value
                   1098:                 *   right now.
                   1099:                 * - Lotus Turbo Esprit 2 requires at least a delay of 50000
                   1100:                 *   cycles or it will crash during start up.
                   1101:                 */
                   1102:                IKBD_AddKeyToKeyboardBufferWithDelay(0xf1, 50000);
1.1.1.12  root     1103: 
                   1104:                /* Start timer - some commands are send during this time they may be ignored (see real ST!) */
1.1.1.16  root     1105:                CycInt_AddRelativeInterrupt(IKBD_RESET_CYCLES, INT_CPU_CYCLE, INTERRUPT_IKBD_RESETTIMER);
1.1.1.12  root     1106: 
                   1107:                /* Set this 'critical' flag, gets reset when timer expires */
1.1.1.15  root     1108:                bDuringResetCriticalTime = true;
                   1109:                bMouseDisabled = bJoystickDisabled = false;
                   1110:                bBothMouseAndJoy = false;
                   1111:                bMouseEnabledDuringReset = false;
1.1.1.14  root     1112: 
1.1.1.15  root     1113:                LOG_TRACE(TRACE_IKBD_ALL, "IKBD reset done.\n");
1.1.1.12  root     1114:        }
                   1115:        /* else if not 0x80,0x01 just ignore */
1.1       root     1116: }
                   1117: 
1.1.1.2   root     1118: 
                   1119: /*-----------------------------------------------------------------------*/
1.1.1.12  root     1120: /**
                   1121:  * SET MOUSE BUTTON ACTION
                   1122:  *
                   1123:  * 0x07
                   1124:  * %00000mss  ; mouse button action
                   1125:  *       ;  (m is presumed =1 when in MOUSE KEYCODE mode)
                   1126:  *       ; mss=0xy, mouse button press or release causes mouse
                   1127:  *       ;  position report
                   1128:  *       ;  where y=1, mouse key press causes absolute report
                   1129:  *       ;  and x=1, mouse key release causes absolute report
                   1130:  *       ; mss=100, mouse buttons act like keys
                   1131:  */
1.1.1.13  root     1132: static void IKBD_Cmd_MouseAction(void)
1.1       root     1133: {
1.1.1.12  root     1134:        KeyboardProcessor.Mouse.Action = Keyboard.InputBuffer[1];
                   1135:        KeyboardProcessor.Abs.PrevReadAbsMouseButtons = ABS_PREVBUTTONS;
1.1.1.13  root     1136: 
1.1.1.15  root     1137:        LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_MouseAction %d\n",
                   1138:                  (unsigned int)KeyboardProcessor.Mouse.Action);
1.1       root     1139: }
                   1140: 
1.1.1.2   root     1141: 
                   1142: /*-----------------------------------------------------------------------*/
1.1.1.12  root     1143: /**
                   1144:  * SET RELATIVE MOUSE POSITION REPORTING
                   1145:  *
                   1146:  * 0x08
                   1147:  */
1.1.1.13  root     1148: static void IKBD_Cmd_RelMouseMode(void)
1.1       root     1149: {
1.1.1.12  root     1150:        KeyboardProcessor.MouseMode = AUTOMODE_MOUSEREL;
1.1.1.13  root     1151: 
1.1.1.14  root     1152:        /* Some games (like Barbarian by Psygnosis) enable both, mouse and
                   1153:         * joystick directly after a reset. This causes the IKBD to send both
                   1154:         * type of packets. To emulate this feature, we've got to remember
                   1155:         * that the mouse has been enabled during reset. */
                   1156:        if (bDuringResetCriticalTime)
1.1.1.15  root     1157:                bMouseEnabledDuringReset = true;
1.1.1.14  root     1158: 
1.1.1.15  root     1159:        LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_RelMouseMode\n");
1.1       root     1160: }
                   1161: 
1.1.1.2   root     1162: 
                   1163: /*-----------------------------------------------------------------------*/
1.1.1.12  root     1164: /**
                   1165:  * SET ABSOLUTE MOUSE POSITIONING
                   1166:  *
                   1167:  * 0x09
                   1168:  * XMSB      ;X maximum (in scaled mouse clicks)
                   1169:  * XLSB
                   1170:  * YMSB      ;Y maximum (in scaled mouse clicks)
                   1171:  * YLSB
                   1172:  */
1.1.1.13  root     1173: static void IKBD_Cmd_AbsMouseMode(void)
1.1       root     1174: {
1.1.1.12  root     1175:        /* These maximums are 'inclusive' */
                   1176:        KeyboardProcessor.MouseMode = AUTOMODE_MOUSEABS;
                   1177:        KeyboardProcessor.Abs.MaxX = (((unsigned int)Keyboard.InputBuffer[1])<<8) | (unsigned int)Keyboard.InputBuffer[2];
                   1178:        KeyboardProcessor.Abs.MaxY = (((unsigned int)Keyboard.InputBuffer[3])<<8) | (unsigned int)Keyboard.InputBuffer[4];
1.1.1.13  root     1179: 
1.1.1.15  root     1180:        LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_AbsMouseMode %d,%d\n",
                   1181:                  KeyboardProcessor.Abs.MaxX, KeyboardProcessor.Abs.MaxY);
1.1       root     1182: }
                   1183: 
1.1.1.2   root     1184: 
                   1185: /*-----------------------------------------------------------------------*/
1.1.1.12  root     1186: /**
                   1187:  * SET MOUSE KEYCODE MODE
                   1188:  *
                   1189:  * 0x0A
                   1190:  * deltax      ; distance in X clicks to return (LEFT) or (RIGHT)
                   1191:  * deltay      ; distance in Y clicks to return (UP) or (DOWN)
                   1192:  */
1.1.1.13  root     1193: static void IKBD_Cmd_MouseCursorKeycodes(void)
1.1       root     1194: {
1.1.1.12  root     1195:        KeyboardProcessor.MouseMode = AUTOMODE_MOUSECURSOR;
                   1196:        KeyboardProcessor.Mouse.KeyCodeDeltaX = Keyboard.InputBuffer[1];
                   1197:        KeyboardProcessor.Mouse.KeyCodeDeltaY = Keyboard.InputBuffer[2];
1.1.1.13  root     1198: 
1.1.1.15  root     1199:        LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_MouseCursorKeycodes %d,%d\n",
                   1200:                  (int)KeyboardProcessor.Mouse.KeyCodeDeltaX,
                   1201:                  (int)KeyboardProcessor.Mouse.KeyCodeDeltaY);
1.1       root     1202: }
                   1203: 
1.1.1.2   root     1204: 
                   1205: /*-----------------------------------------------------------------------*/
1.1.1.12  root     1206: /**
                   1207:  * SET MOUSE THRESHOLD
                   1208:  *
                   1209:  * 0x0B
                   1210:  * X      ; x threshold in mouse ticks (positive integers)
                   1211:  * Y      ; y threshold in mouse ticks (positive integers)
                   1212:  */
1.1.1.13  root     1213: static void IKBD_Cmd_SetMouseThreshold(void)
1.1       root     1214: {
1.1.1.12  root     1215:        KeyboardProcessor.Mouse.XThreshold = (unsigned int)Keyboard.InputBuffer[1];
                   1216:        KeyboardProcessor.Mouse.YThreshold = (unsigned int)Keyboard.InputBuffer[2];
1.1.1.13  root     1217: 
1.1.1.15  root     1218:        LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_SetMouseThreshold %d,%d\n",
                   1219:                  KeyboardProcessor.Mouse.XThreshold, KeyboardProcessor.Mouse.YThreshold);
1.1       root     1220: }
                   1221: 
1.1.1.2   root     1222: 
                   1223: /*-----------------------------------------------------------------------*/
1.1.1.12  root     1224: /**
                   1225:  * SET MOUSE SCALE
                   1226:  *
                   1227:  * 0x0C
                   1228:  * X      ; horizontal mouse ticks per internel X
                   1229:  * Y      ; vertical mouse ticks per internel Y
                   1230:  */
1.1.1.13  root     1231: static void IKBD_Cmd_SetMouseScale(void)
1.1       root     1232: {
1.1.1.12  root     1233:        KeyboardProcessor.Mouse.XScale = (unsigned int)Keyboard.InputBuffer[1];
                   1234:        KeyboardProcessor.Mouse.YScale = (unsigned int)Keyboard.InputBuffer[2];
1.1.1.13  root     1235: 
1.1.1.15  root     1236:        LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_SetMouseScale %d,%d\n",
                   1237:                  KeyboardProcessor.Mouse.XScale, KeyboardProcessor.Mouse.YScale);
1.1       root     1238: }
                   1239: 
                   1240: 
1.1.1.12  root     1241: /*-----------------------------------------------------------------------*/
                   1242: /**
                   1243:  * INTERROGATE MOUSE POSITION
                   1244:  *
                   1245:  * 0x0D
                   1246:  *   Returns:  0xF7  ; absolute mouse position header
                   1247:  *     BUTTONS
                   1248:  *       0000dcba
                   1249:  *       where a is right button down since last interrogation
                   1250:  *       b is right button up since last
                   1251:  *       c is left button down since last
                   1252:  *       d is left button up since last
                   1253:  *     XMSB      ; X coordinate
                   1254:  *     XLSB
                   1255:  *     YMSB      ; Y coordinate
                   1256:  *     YLSB
                   1257:  */
1.1.1.13  root     1258: static void IKBD_Cmd_ReadAbsMousePos(void)
1.1       root     1259: {
1.1.1.12  root     1260:        Uint8 Buttons,PrevButtons;
1.1       root     1261: 
1.1.1.12  root     1262:        /* Test buttons */
                   1263:        Buttons = 0;
                   1264:        /* Set buttons to show if up/down */
                   1265:        if (Keyboard.bRButtonDown)
                   1266:                Buttons |= 0x01;
                   1267:        else
                   1268:                Buttons |= 0x02;
                   1269:        if (Keyboard.bLButtonDown)
                   1270:                Buttons |= 0x04;
                   1271:        else
                   1272:                Buttons |= 0x08;
                   1273:        /* Mask off it didn't send last time */
                   1274:        PrevButtons = KeyboardProcessor.Abs.PrevReadAbsMouseButtons;
                   1275:        KeyboardProcessor.Abs.PrevReadAbsMouseButtons = Buttons;
                   1276:        Buttons &= ~PrevButtons;
                   1277: 
                   1278:        /* And send packet */
1.1.1.13  root     1279:        IKBD_AddKeyToKeyboardBufferWithDelay(0xf7, 18000);
1.1.1.12  root     1280:        IKBD_AddKeyToKeyboardBuffer(Buttons);
                   1281:        IKBD_AddKeyToKeyboardBuffer((unsigned int)KeyboardProcessor.Abs.X>>8);
                   1282:        IKBD_AddKeyToKeyboardBuffer((unsigned int)KeyboardProcessor.Abs.X&0xff);
                   1283:        IKBD_AddKeyToKeyboardBuffer((unsigned int)KeyboardProcessor.Abs.Y>>8);
                   1284:        IKBD_AddKeyToKeyboardBuffer((unsigned int)KeyboardProcessor.Abs.Y&0xff);
                   1285: 
1.1.1.15  root     1286:        LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_ReadAbsMousePos %d,%d 0x%X\n",
                   1287:                  KeyboardProcessor.Abs.X, KeyboardProcessor.Abs.Y, Buttons);
1.1       root     1288: }
                   1289: 
                   1290: 
1.1.1.12  root     1291: /*-----------------------------------------------------------------------*/
                   1292: /**
                   1293:  * LOAD MOUSE POSITION
                   1294:  *
                   1295:  * 0x0E
                   1296:  * 0x00      ; filler
                   1297:  * XMSB      ; X coordinate
                   1298:  * XLSB      ; (in scaled coordinate system)
                   1299:  * YMSB      ; Y coordinate
                   1300:  * YLSB
                   1301:  */
1.1.1.13  root     1302: static void IKBD_Cmd_SetInternalMousePos(void)
1.1.1.7   root     1303: {
1.1.1.12  root     1304:        /* Setting these do not clip internal position(this happens on next update) */
                   1305:        KeyboardProcessor.Abs.X = (((unsigned int)Keyboard.InputBuffer[2])<<8) | (unsigned int)Keyboard.InputBuffer[3];
                   1306:        KeyboardProcessor.Abs.Y = (((unsigned int)Keyboard.InputBuffer[4])<<8) | (unsigned int)Keyboard.InputBuffer[5];
1.1.1.13  root     1307: 
1.1.1.15  root     1308:        LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_SetInternalMousePos %d,%d\n",
                   1309:                  KeyboardProcessor.Abs.X, KeyboardProcessor.Abs.Y);
1.1       root     1310: }
                   1311: 
1.1.1.2   root     1312: 
                   1313: /*-----------------------------------------------------------------------*/
1.1.1.12  root     1314: /**
                   1315:  * SET Y=0 AT BOTTOM
                   1316:  *
                   1317:  * 0x0F
                   1318:  */
1.1.1.13  root     1319: static void IKBD_Cmd_SetYAxisDown(void)
1.1       root     1320: {
1.1.1.12  root     1321:        KeyboardProcessor.Mouse.YAxis = -1;
1.1.1.13  root     1322: 
1.1.1.15  root     1323:        LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_SetYAxisDown\n");
1.1       root     1324: }
                   1325: 
1.1.1.2   root     1326: 
                   1327: /*-----------------------------------------------------------------------*/
1.1.1.12  root     1328: /**
                   1329:  * SET Y=0 AT TOP
                   1330:  *
                   1331:  * 0x10
                   1332:  */
1.1.1.13  root     1333: static void IKBD_Cmd_SetYAxisUp(void)
1.1       root     1334: {
1.1.1.12  root     1335:        KeyboardProcessor.Mouse.YAxis = 1;
1.1.1.13  root     1336: 
1.1.1.15  root     1337:        LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_SetYAxisUp\n");
1.1       root     1338: }
                   1339: 
1.1.1.2   root     1340: 
                   1341: /*-----------------------------------------------------------------------*/
1.1.1.12  root     1342: /**
                   1343:  *  RESUME
                   1344:  *
                   1345:  * 0x11
                   1346:  */
1.1.1.13  root     1347: static void IKBD_Cmd_StartKeyboardTransfer(void)
1.1       root     1348: {
1.1.1.15  root     1349:        LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_StartKeyboardTransfer\n");
1.1       root     1350: }
                   1351: 
1.1.1.2   root     1352: 
                   1353: /*-----------------------------------------------------------------------*/
1.1.1.12  root     1354: /**
                   1355:  * DISABLE MOUSE
                   1356:  *
                   1357:  * 0x12
                   1358:  */
1.1.1.13  root     1359: static void IKBD_Cmd_TurnMouseOff(void)
1.1       root     1360: {
1.1.1.12  root     1361:        KeyboardProcessor.MouseMode = AUTOMODE_OFF;
1.1.1.15  root     1362:        bMouseDisabled = true;
1.1.1.13  root     1363: 
1.1.1.15  root     1364:        LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_TurnMouseOff\n");
1.1       root     1365: 
1.1.1.12  root     1366:        IKBD_CheckResetDisableBug();
1.1       root     1367: }
                   1368: 
1.1.1.2   root     1369: 
                   1370: /*-----------------------------------------------------------------------*/
1.1.1.12  root     1371: /**
                   1372:  * PAUSE OUTPUT
                   1373:  *
                   1374:  * 0x13
                   1375:  */
1.1.1.13  root     1376: static void IKBD_Cmd_StopKeyboardTransfer(void)
1.1       root     1377: {
1.1.1.15  root     1378:        LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_StopKeyboardTransfer\n");
1.1       root     1379: }
                   1380: 
1.1.1.2   root     1381: 
                   1382: /*-----------------------------------------------------------------------*/
1.1.1.12  root     1383: /**
                   1384:  * SET JOYSTICK EVENT REPORTING
                   1385:  *
                   1386:  * 0x14
                   1387:  */
1.1.1.13  root     1388: static void IKBD_Cmd_ReturnJoystickAuto(void)
1.1       root     1389: {
1.1.1.15  root     1390:        LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_ReturnJoystickAuto\n");
1.1.1.14  root     1391: 
1.1.1.12  root     1392:        KeyboardProcessor.JoystickMode = AUTOMODE_JOYSTICK;
                   1393:        KeyboardProcessor.MouseMode = AUTOMODE_OFF;
1.1.1.6   root     1394: 
1.1.1.14  root     1395:        /* If mouse was also enabled within time of a reset it isn't disabled now!
                   1396:         * (Used by the game Barbarian 1 by Psygnosis for example) */
                   1397:        if (bMouseEnabledDuringReset)
1.1.1.12  root     1398:        {
                   1399:                KeyboardProcessor.MouseMode = AUTOMODE_MOUSEREL;
1.1.1.15  root     1400:                bBothMouseAndJoy = true;
                   1401:                LOG_TRACE(TRACE_IKBD_ALL, "IKBD joystick and mouse "
                   1402:                          "enabled during RESET. Mouse not disabled!\n");
1.1.1.12  root     1403:        }
1.1.1.6   root     1404: 
1.1.1.13  root     1405:        /* This command resets the internally previously stored joystick states */
                   1406:        KeyboardProcessor.Joy.PrevJoyData[0] = KeyboardProcessor.Joy.PrevJoyData[1] = 0;
                   1407: 
                   1408:        /* This is a hack for the STE Utopos (=> v1.50) and Falcon Double Bubble
                   1409:         * 2000 games. They expect the joystick data to be sent within a certain
                   1410:         * amount of time after this command, without checking the ACIA control
                   1411:         * register first.
                   1412:         */
                   1413:        IKBD_GetJoystickData();
                   1414:        IKBD_SelAutoJoysticks();
1.1       root     1415: }
                   1416: 
1.1.1.2   root     1417: 
                   1418: /*-----------------------------------------------------------------------*/
1.1.1.12  root     1419: /**
                   1420:  * SET JOYSTICK INTERROGATION MODE
                   1421:  *
                   1422:  * 0x15
                   1423:  */
1.1.1.13  root     1424: static void IKBD_Cmd_StopJoystick(void)
1.1       root     1425: {
1.1.1.12  root     1426:        KeyboardProcessor.JoystickMode = AUTOMODE_OFF;
1.1.1.15  root     1427:        LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_StopJoystick\n");
1.1       root     1428: }
                   1429: 
1.1.1.2   root     1430: 
                   1431: /*-----------------------------------------------------------------------*/
1.1.1.12  root     1432: /**
                   1433:  * JOYSTICK INTERROGATE
                   1434:  *
                   1435:  * 0x16
                   1436:  */
1.1.1.13  root     1437: static void IKBD_Cmd_ReturnJoystick(void)
1.1       root     1438: {
1.1.1.17! root     1439:        /* The game "Downfall" continually issues this command during the
        !          1440:         * title screen - faster than processing the 3 bytes from the ACIA,
        !          1441:         * so it floods our Keyboard.Buffer ... in the end, we can not put the
        !          1442:         * whole packet into the buffer anymore, and the game hangs due to
        !          1443:         * these incomplete answers. To avoid this situation, only execute
        !          1444:         * this command if there is enough space left in our Keyboard.Buffer! */
        !          1445:        if (((Keyboard.BufferHead-1-Keyboard.BufferTail)&KEYBOARD_BUFFER_MASK) < 3)
        !          1446:        {
        !          1447:                LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_ReturnJoystick ignored - buffer is full!\n");
        !          1448:                return;
        !          1449:        }
        !          1450: 
        !          1451:        LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_ReturnJoystick\n");
        !          1452: 
1.1.1.13  root     1453:        IKBD_AddKeyToKeyboardBufferWithDelay(0xFD, 35000);
1.1.1.12  root     1454:        IKBD_AddKeyToKeyboardBuffer(Joy_GetStickData(0));
                   1455:        IKBD_AddKeyToKeyboardBuffer(Joy_GetStickData(1));
1.1       root     1456: }
                   1457: 
1.1.1.2   root     1458: 
                   1459: /*-----------------------------------------------------------------------*/
1.1.1.12  root     1460: /**
                   1461:  * SET JOYSTICK MONITORING
                   1462:  *
                   1463:  * 0x17
                   1464:  * rate      ; time between samples in hundreths of a second
                   1465:  *   Returns: (in packets of two as long as in mode)
                   1466:  *     %000000xy  where y is JOYSTICK1 Fire button
                   1467:  *         and x is JOYSTICK0 Fire button
                   1468:  *     %nnnnmmmm  where m is JOYSTICK1 state
                   1469:  *         and n is JOYSTICK0 state
                   1470:  */
1.1.1.13  root     1471: static void IKBD_Cmd_SetJoystickDuration(void)
1.1       root     1472: {
1.1.1.15  root     1473:        LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_SetJoystickDuration\n");
1.1       root     1474: }
                   1475: 
1.1.1.2   root     1476: 
                   1477: /*-----------------------------------------------------------------------*/
1.1.1.12  root     1478: /**
                   1479:  * SET FIRE BUTTON MONITORING
                   1480:  *
                   1481:  * 0x18
                   1482:  *   Returns: (as long as in mode)
                   1483:  *     %bbbbbbbb  ; state of the JOYSTICK1 fire button packed
                   1484:  *           ; 8 bits per byte, the first sample if the MSB
                   1485:  */
1.1.1.13  root     1486: static void IKBD_Cmd_SetJoystickFireDuration(void)
1.1       root     1487: {
1.1.1.15  root     1488:        LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_SetJoystickFireDuration\n");
1.1       root     1489: }
                   1490: 
1.1.1.2   root     1491: 
                   1492: /*-----------------------------------------------------------------------*/
1.1.1.12  root     1493: /**
                   1494:  * SET JOYSTICK KEYCODE MODE
                   1495:  *
                   1496:  * 0x19
                   1497:  * RX        ; length of time (in tenths of seconds) until
                   1498:  *         ; horizontal velocity breakpoint is reached
                   1499:  * RY        ; length of time (in tenths of seconds) until
                   1500:  *         ; vertical velocity breakpoint is reached
                   1501:  * TX        ; length (in tenths of seconds) of joystick closure
                   1502:  *         ; until horizontal cursor key is generated before RX
                   1503:  *         ; has elapsed
                   1504:  * TY        ; length (in tenths of seconds) of joystick closure
                   1505:  *         ; until vertical cursor key is generated before RY
                   1506:  *         ; has elapsed
                   1507:  * VX        ; length (in tenths of seconds) of joystick closure
                   1508:  *         ; until horizontal cursor keystokes are generated after RX
                   1509:  *         ; has elapsed
                   1510:  * VY        ; length (in tenths of seconds) of joystick closure
                   1511:  *         ; until vertical cursor keystokes are generated after RY
                   1512:  *         ; has elapsed
                   1513:  */
1.1.1.13  root     1514: static void IKBD_Cmd_SetCursorForJoystick(void)
1.1       root     1515: {
1.1.1.15  root     1516:        LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_SetCursorForJoystick\n");
1.1       root     1517: }
                   1518: 
1.1.1.2   root     1519: 
                   1520: /*-----------------------------------------------------------------------*/
1.1.1.12  root     1521: /**
                   1522:  * DISABLE JOYSTICKS
                   1523:  *
                   1524:  * 0x1A
                   1525:  */
1.1.1.13  root     1526: static void IKBD_Cmd_DisableJoysticks(void)
1.1       root     1527: {
1.1.1.12  root     1528:        KeyboardProcessor.JoystickMode = AUTOMODE_OFF;
1.1.1.15  root     1529:        bJoystickDisabled = true;
1.1.1.13  root     1530: 
1.1.1.15  root     1531:        LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_DisableJoysticks\n");
1.1       root     1532: 
1.1.1.12  root     1533:        IKBD_CheckResetDisableBug();
1.1       root     1534: }
                   1535: 
1.1.1.2   root     1536: 
                   1537: /*-----------------------------------------------------------------------*/
1.1.1.12  root     1538: /**
                   1539:  * TIME-OF-DAY CLOCK SET
                   1540:  *
                   1541:  * 0x1B
                   1542:  * YY        ; year (2 least significant digits)
                   1543:  * MM        ; month
                   1544:  * DD        ; day
                   1545:  * hh        ; hour
                   1546:  * mm        ; minute
                   1547:  * ss        ; second
                   1548:  */
1.1.1.13  root     1549: static void IKBD_Cmd_SetClock(void)
1.1       root     1550: {
1.1.1.15  root     1551:        LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_SetClock\n");
1.1.1.13  root     1552: }
                   1553: 
                   1554: 
                   1555: /*-----------------------------------------------------------------------*/
                   1556: /**
1.1.1.17! root     1557:  * Convert value to 2-digit BCD.
        !          1558:  * Note: TOS 2.0x requires BCD conversion with overflow, so the decade
        !          1559:  * is not calculated modulo 10, or it will end up in the year 2039
        !          1560:  * instead...
1.1.1.13  root     1561:  */
1.1.1.17! root     1562: static Uint8 IKBD_ConvertToBCD(Uint16 Value)
1.1.1.13  root     1563: {
1.1.1.17! root     1564:        return ((Value/10)<<4) | (Value%10);
1.1       root     1565: }
                   1566: 
1.1.1.2   root     1567: 
                   1568: /*-----------------------------------------------------------------------*/
1.1.1.12  root     1569: /**
                   1570:  * INTERROGATE TIME-OF-DAT CLOCK
                   1571:  *
                   1572:  * 0x1C
                   1573:  *   Returns:
                   1574:  *     0xFC  ; time-of-day event header
                   1575:  *     YY    ; year (2 least significant digits)
                   1576:  *     MM    ; month
                   1577:  *     DD    ; day
                   1578:  *     hh    ; hour
                   1579:  *     mm    ; minute
                   1580:  *     ss    ; second
                   1581:  */
1.1.1.13  root     1582: static void IKBD_Cmd_ReadClock(void)
1.1       root     1583: {
1.1.1.12  root     1584:        struct tm *SystemTime;
                   1585:        time_t nTimeTicks;
1.1       root     1586: 
1.1.1.12  root     1587:        /* Get system time */
                   1588:        nTimeTicks = time(NULL);
                   1589:        SystemTime = localtime(&nTimeTicks);
                   1590: 
                   1591:        /* Return packet */
1.1.1.13  root     1592:        IKBD_AddKeyToKeyboardBufferWithDelay(0xFC, 32000);
1.1.1.12  root     1593:        /* Return time-of-day clock as yy-mm-dd-hh-mm-ss as BCD */
1.1.1.13  root     1594:        IKBD_AddKeyToKeyboardBuffer(IKBD_ConvertToBCD(SystemTime->tm_year));  /* yy - year (2 least significant digits) */
                   1595:        IKBD_AddKeyToKeyboardBuffer(IKBD_ConvertToBCD(SystemTime->tm_mon+1)); /* mm - Month */
                   1596:        IKBD_AddKeyToKeyboardBuffer(IKBD_ConvertToBCD(SystemTime->tm_mday));  /* dd - Day */
                   1597:        IKBD_AddKeyToKeyboardBuffer(IKBD_ConvertToBCD(SystemTime->tm_hour));  /* hh - Hour */
                   1598:        IKBD_AddKeyToKeyboardBuffer(IKBD_ConvertToBCD(SystemTime->tm_min));   /* mm - Minute */
                   1599:        IKBD_AddKeyToKeyboardBuffer(IKBD_ConvertToBCD(SystemTime->tm_sec));   /* ss - Second */
                   1600: 
1.1.1.15  root     1601:        LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_ReadClock\n");
1.1       root     1602: }
                   1603: 
1.1.1.2   root     1604: 
                   1605: /*-----------------------------------------------------------------------*/
1.1.1.12  root     1606: /**
                   1607:  * MEMORY LOAD
                   1608:  *
                   1609:  * 0x20
                   1610:  * ADRMSB      ; address in controller
                   1611:  * ADRLSB      ; memory to be loaded
                   1612:  * NUM        ; number of bytes (0-128)
                   1613:  * { data }
                   1614:  */
1.1.1.13  root     1615: static void IKBD_Cmd_LoadMemory(void)
1.1       root     1616: {
1.1.1.15  root     1617:        LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_LoadMemory addr 0x%x count %d\n",
                   1618:                  (Keyboard.InputBuffer[1] << 8) + Keyboard.InputBuffer[2], Keyboard.InputBuffer[3]);
1.1.1.13  root     1619: 
                   1620:        MemoryLoadNbBytesTotal = Keyboard.InputBuffer[3];
                   1621:        MemoryLoadNbBytesLeft = MemoryLoadNbBytesTotal;
                   1622:        crc32_reset ( &MemoryLoadCrc );
1.1       root     1623: }
                   1624: 
1.1.1.2   root     1625: 
                   1626: /*-----------------------------------------------------------------------*/
1.1.1.12  root     1627: /**
                   1628:  * MEMORY READ
                   1629:  *
                   1630:  * 0x21
                   1631:  * ADRMSB        ; address in controller
                   1632:  * ADRLSB        ; memory to be read
                   1633:  *   Returns:
                   1634:  *     0xF6    ; status header
                   1635:  *     0x20    ; memory access
                   1636:  *     { data }  ; 6 data bytes starting at ADR
                   1637:  */
1.1.1.13  root     1638: static void IKBD_Cmd_ReadMemory(void)
1.1       root     1639: {
1.1.1.15  root     1640:        LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_ReadMemory\n");
1.1       root     1641: }
                   1642: 
1.1.1.2   root     1643: 
                   1644: /*-----------------------------------------------------------------------*/
1.1.1.12  root     1645: /**
                   1646:  * CONTROLLER EXECUTE
                   1647:  *
                   1648:  * 0x22
                   1649:  * ADRMSB      ; address of subroutine in
                   1650:  * ADRLSB      ; controller memory to be called
                   1651:  */
1.1.1.13  root     1652: static void IKBD_Cmd_Execute(void)
                   1653: {
1.1.1.17! root     1654:        LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_Execute addr 0x%x\n",
        !          1655:                (Keyboard.InputBuffer[1] << 8) + Keyboard.InputBuffer[2]);
1.1.1.13  root     1656: 
                   1657:        if ( pIKBD_CustomCodeHandler_Write )
                   1658:        {
1.1.1.15  root     1659:                LOG_TRACE(TRACE_IKBD_EXEC, "ikbd execute addr 0x%x using custom handler\n",
                   1660:                          (Keyboard.InputBuffer[1] << 8) + Keyboard.InputBuffer[2]);
1.1.1.13  root     1661: 
1.1.1.15  root     1662:                IKBD_ExeMode = true;                            /* turn 6301's custom mode ON */
1.1.1.13  root     1663:        }
                   1664:        else                                                    /* unknown code uploaded to ikbd RAM */
                   1665:        {
1.1.1.15  root     1666:                LOG_TRACE(TRACE_IKBD_EXEC, "ikbd execute addr 0x%x ignored, no custom handler found\n",
                   1667:                          (Keyboard.InputBuffer[1] << 8) + Keyboard.InputBuffer[2]);
1.1.1.13  root     1668:        }
                   1669: }
                   1670: 
                   1671: 
                   1672: /*-----------------------------------------------------------------------*/
                   1673: /**
                   1674:  * REPORT MOUSE BUTTON ACTION
                   1675:  *
                   1676:  * 0x87
                   1677:  */
                   1678: static void IKBD_Cmd_ReportMouseAction(void)
                   1679: {
1.1.1.15  root     1680:        LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_ReportMouseAction\n");
1.1.1.13  root     1681: 
                   1682:        IKBD_AddKeyToKeyboardBufferWithDelay(0xf6, 30000);
                   1683:        IKBD_AddKeyToKeyboardBuffer(7);
                   1684:        IKBD_AddKeyToKeyboardBuffer(KeyboardProcessor.Mouse.Action);
                   1685:        IKBD_AddKeyToKeyboardBuffer(0);
                   1686:        IKBD_AddKeyToKeyboardBuffer(0);
                   1687:        IKBD_AddKeyToKeyboardBuffer(0);
                   1688:        IKBD_AddKeyToKeyboardBuffer(0);
                   1689:        IKBD_AddKeyToKeyboardBuffer(0);
                   1690: }
                   1691: 
                   1692: 
                   1693: /*-----------------------------------------------------------------------*/
                   1694: /**
                   1695:  * REPORT MOUSE MODE
                   1696:  *
                   1697:  * 0x88 or 0x89 or 0x8A
                   1698:  */
                   1699: static void IKBD_Cmd_ReportMouseMode(void)
                   1700: {
1.1.1.15  root     1701:        LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_ReportMouseMode\n");
1.1.1.13  root     1702: 
                   1703:        IKBD_AddKeyToKeyboardBufferWithDelay(0xf6, 30000);
                   1704:        switch (KeyboardProcessor.MouseMode)
                   1705:        {
                   1706:         case AUTOMODE_MOUSEREL:
                   1707:                IKBD_AddKeyToKeyboardBuffer(8);
                   1708:                IKBD_AddKeyToKeyboardBuffer(0);
                   1709:                IKBD_AddKeyToKeyboardBuffer(0);
                   1710:                IKBD_AddKeyToKeyboardBuffer(0);
                   1711:                IKBD_AddKeyToKeyboardBuffer(0);
                   1712:                IKBD_AddKeyToKeyboardBuffer(0);
                   1713:                IKBD_AddKeyToKeyboardBuffer(0);
                   1714:                break;
                   1715:         case AUTOMODE_MOUSEABS:
                   1716:                IKBD_AddKeyToKeyboardBuffer(9);
                   1717:                IKBD_AddKeyToKeyboardBuffer(KeyboardProcessor.Abs.MaxX >> 8);
                   1718:                IKBD_AddKeyToKeyboardBuffer(KeyboardProcessor.Abs.MaxX);
                   1719:                IKBD_AddKeyToKeyboardBuffer(KeyboardProcessor.Abs.MaxY >> 8);
                   1720:                IKBD_AddKeyToKeyboardBuffer(KeyboardProcessor.Abs.MaxY);
                   1721:                IKBD_AddKeyToKeyboardBuffer(0);
                   1722:                IKBD_AddKeyToKeyboardBuffer(0);
                   1723:                break;
                   1724:         case AUTOMODE_MOUSECURSOR:
                   1725:                IKBD_AddKeyToKeyboardBuffer(10);
                   1726:                IKBD_AddKeyToKeyboardBuffer(KeyboardProcessor.Mouse.KeyCodeDeltaX);
                   1727:                IKBD_AddKeyToKeyboardBuffer(KeyboardProcessor.Mouse.KeyCodeDeltaY);
                   1728:                IKBD_AddKeyToKeyboardBuffer(0);
                   1729:                IKBD_AddKeyToKeyboardBuffer(0);
                   1730:                IKBD_AddKeyToKeyboardBuffer(0);
                   1731:                IKBD_AddKeyToKeyboardBuffer(0);
                   1732:                break;
                   1733:        }
                   1734: }
                   1735: 
                   1736: 
                   1737: /*-----------------------------------------------------------------------*/
                   1738: /**
                   1739:  * REPORT MOUSE THRESHOLD
                   1740:  *
                   1741:  * 0x8B
                   1742:  */
                   1743: static void IKBD_Cmd_ReportMouseThreshold(void)
                   1744: {
1.1.1.15  root     1745:        LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_ReportMouseThreshold\n");
1.1.1.13  root     1746: 
                   1747:        IKBD_AddKeyToKeyboardBufferWithDelay(0xf6, 30000);
                   1748:        IKBD_AddKeyToKeyboardBuffer(0x0B);
                   1749:        IKBD_AddKeyToKeyboardBuffer(KeyboardProcessor.Mouse.XThreshold);
                   1750:        IKBD_AddKeyToKeyboardBuffer(KeyboardProcessor.Mouse.YThreshold);
                   1751:        IKBD_AddKeyToKeyboardBuffer(0);
                   1752:        IKBD_AddKeyToKeyboardBuffer(0);
                   1753:        IKBD_AddKeyToKeyboardBuffer(0);
                   1754:        IKBD_AddKeyToKeyboardBuffer(0);
                   1755: }
                   1756: 
                   1757: 
                   1758: /*-----------------------------------------------------------------------*/
                   1759: /**
                   1760:  * REPORT MOUSE SCALE
                   1761:  *
                   1762:  * 0x8C
                   1763:  */
                   1764: static void IKBD_Cmd_ReportMouseScale(void)
                   1765: {
1.1.1.15  root     1766:        LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_ReportMouseScale\n");
1.1.1.13  root     1767: 
                   1768:        IKBD_AddKeyToKeyboardBufferWithDelay(0xf6, 30000);
                   1769:        IKBD_AddKeyToKeyboardBuffer(0x0C);
                   1770:        IKBD_AddKeyToKeyboardBuffer(KeyboardProcessor.Mouse.XScale);
                   1771:        IKBD_AddKeyToKeyboardBuffer(KeyboardProcessor.Mouse.YScale);
                   1772:        IKBD_AddKeyToKeyboardBuffer(0);
                   1773:        IKBD_AddKeyToKeyboardBuffer(0);
                   1774:        IKBD_AddKeyToKeyboardBuffer(0);
                   1775:        IKBD_AddKeyToKeyboardBuffer(0);
                   1776: }
                   1777: 
                   1778: 
                   1779: /*-----------------------------------------------------------------------*/
                   1780: /**
                   1781:  * REPORT MOUSE VERTICAL COORDINATES
                   1782:  *
                   1783:  * 0x8F and 0x90
                   1784:  */
                   1785: static void IKBD_Cmd_ReportMouseVertical(void)
                   1786: {
1.1.1.15  root     1787:        LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_ReportMouseVertical\n");
1.1.1.13  root     1788: 
                   1789:        IKBD_AddKeyToKeyboardBufferWithDelay(0xf6, 30000);
                   1790:        if (KeyboardProcessor.Mouse.YAxis == -1)
                   1791:                IKBD_AddKeyToKeyboardBuffer(0x0F);
                   1792:        else
                   1793:                IKBD_AddKeyToKeyboardBuffer(0x10);
                   1794:        IKBD_AddKeyToKeyboardBuffer(0);
                   1795:        IKBD_AddKeyToKeyboardBuffer(0);
                   1796:        IKBD_AddKeyToKeyboardBuffer(0);
                   1797:        IKBD_AddKeyToKeyboardBuffer(0);
                   1798:        IKBD_AddKeyToKeyboardBuffer(0);
                   1799:        IKBD_AddKeyToKeyboardBuffer(0);
                   1800: }
                   1801: 
                   1802: 
                   1803: /*-----------------------------------------------------------------------*/
                   1804: /**
                   1805:  * REPORT MOUSE AVAILABILITY
                   1806:  *
                   1807:  * 0x92
                   1808:  */
                   1809: static void IKBD_Cmd_ReportMouseAvailability(void)
                   1810: {
1.1.1.15  root     1811:        LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_ReportMouseAvailability\n");
1.1.1.13  root     1812: 
                   1813:        IKBD_AddKeyToKeyboardBufferWithDelay(0xf6, 30000);
                   1814:        if (KeyboardProcessor.MouseMode == AUTOMODE_OFF)
                   1815:                IKBD_AddKeyToKeyboardBuffer(0x12);
                   1816:        else
                   1817:                IKBD_AddKeyToKeyboardBuffer(0x00);
                   1818:        IKBD_AddKeyToKeyboardBuffer(0);
                   1819:        IKBD_AddKeyToKeyboardBuffer(0);
                   1820:        IKBD_AddKeyToKeyboardBuffer(0);
                   1821:        IKBD_AddKeyToKeyboardBuffer(0);
                   1822:        IKBD_AddKeyToKeyboardBuffer(0);
                   1823:        IKBD_AddKeyToKeyboardBuffer(0);
                   1824: }
                   1825: 
                   1826: 
                   1827: /*-----------------------------------------------------------------------*/
                   1828: /**
                   1829:  * REPORT JOYSTICK MODE
                   1830:  *
                   1831:  * 0x94 or 0x95 or 0x99
                   1832:  */
                   1833: static void IKBD_Cmd_ReportJoystickMode(void)
1.1       root     1834: {
1.1.1.15  root     1835:        LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_ReportJoystickMode\n");
1.1.1.13  root     1836: 
                   1837:        IKBD_AddKeyToKeyboardBufferWithDelay(0xf6, 30000);
                   1838:        switch (KeyboardProcessor.JoystickMode)
                   1839:        {
                   1840:         case AUTOMODE_JOYSTICK:
                   1841:                IKBD_AddKeyToKeyboardBuffer(0x14);
                   1842:                IKBD_AddKeyToKeyboardBuffer(0);
                   1843:                IKBD_AddKeyToKeyboardBuffer(0);
                   1844:                IKBD_AddKeyToKeyboardBuffer(0);
                   1845:                IKBD_AddKeyToKeyboardBuffer(0);
                   1846:                IKBD_AddKeyToKeyboardBuffer(0);
                   1847:                IKBD_AddKeyToKeyboardBuffer(0);
                   1848:                break;
                   1849:         default:    /* TODO: Joystick keycodes mode not supported yet! */
                   1850:                IKBD_AddKeyToKeyboardBuffer(0x15);
                   1851:                IKBD_AddKeyToKeyboardBuffer(0);
                   1852:                IKBD_AddKeyToKeyboardBuffer(0);
                   1853:                IKBD_AddKeyToKeyboardBuffer(0);
                   1854:                IKBD_AddKeyToKeyboardBuffer(0);
                   1855:                IKBD_AddKeyToKeyboardBuffer(0);
                   1856:                IKBD_AddKeyToKeyboardBuffer(0);
                   1857:                break;
                   1858:        }
                   1859: }
                   1860: 
                   1861: 
                   1862: /*-----------------------------------------------------------------------*/
                   1863: /**
                   1864:  * REPORT JOYSTICK AVAILABILITY
                   1865:  *
                   1866:  * 0x9A
                   1867:  */
                   1868: static void IKBD_Cmd_ReportJoystickAvailability(void)
                   1869: {
1.1.1.15  root     1870:        LOG_TRACE(TRACE_IKBD_CMDS, "IKBD_Cmd_ReportJoystickAvailability\n");
1.1.1.13  root     1871: 
                   1872:        IKBD_AddKeyToKeyboardBufferWithDelay(0xf6, 30000);
                   1873:        if (KeyboardProcessor.JoystickMode == AUTOMODE_OFF)
                   1874:                IKBD_AddKeyToKeyboardBuffer(0x1A);
                   1875:        else
                   1876:                IKBD_AddKeyToKeyboardBuffer(0x00);
                   1877:        IKBD_AddKeyToKeyboardBuffer(0);
                   1878:        IKBD_AddKeyToKeyboardBuffer(0);
                   1879:        IKBD_AddKeyToKeyboardBuffer(0);
                   1880:        IKBD_AddKeyToKeyboardBuffer(0);
                   1881:        IKBD_AddKeyToKeyboardBuffer(0);
                   1882:        IKBD_AddKeyToKeyboardBuffer(0);
1.1       root     1883: }
                   1884: 
                   1885: 
1.1.1.2   root     1886: /*-----------------------------------------------------------------------*/
1.1.1.12  root     1887: /**
                   1888:  * Send data to keyboard processor via ACIA by writing to address 0xfffc02.
                   1889:  * For our emulation we bypass the ACIA (I've yet to see anything check for this)
                   1890:  * and add the byte directly into the keyboard input buffer.
                   1891:  */
1.1.1.11  root     1892: static void IKBD_RunKeyboardCommand(Uint16 aciabyte)
1.1       root     1893: {
1.1.1.12  root     1894:        int i=0;
1.1       root     1895: 
1.1.1.12  root     1896:        /* Write into our keyboard input buffer */
                   1897:        Keyboard.InputBuffer[Keyboard.nBytesInInputBuffer++] = aciabyte;
1.1       root     1898: 
1.1.1.12  root     1899:        /* Now check bytes to see if we have a valid/in-valid command string set */
                   1900:        while (KeyboardCommands[i].Command!=0xff)
                   1901:        {
                   1902:                /* Found command? */
                   1903:                if (KeyboardCommands[i].Command==Keyboard.InputBuffer[0])
                   1904:                {
                   1905:                        /* Is string complete, then can execute? */
                   1906:                        if (KeyboardCommands[i].NumParameters==Keyboard.nBytesInInputBuffer)
                   1907:                        {
                   1908:                                CALL_VAR(KeyboardCommands[i].pCallFunction);
                   1909:                                Keyboard.nBytesInInputBuffer = 0;
                   1910:                        }
1.1       root     1911: 
1.1.1.12  root     1912:                        return;
                   1913:                }
1.1.1.7   root     1914: 
1.1.1.12  root     1915:                i++;
                   1916:        }
1.1       root     1917: 
1.1.1.12  root     1918:        /* Command not known, reset buffer(IKBD assumes a NOP) */
                   1919:        Keyboard.nBytesInInputBuffer = 0;
1.1       root     1920: }
                   1921: 
1.1.1.2   root     1922: 
                   1923: /*-----------------------------------------------------------------------*/
1.1.1.12  root     1924: /**
                   1925:  * Send byte to our keyboard processor, and execute
                   1926:  */
1.1.1.13  root     1927: static void IKBD_SendByteToKeyboardProcessor(Uint16 bl)
1.1       root     1928: {
1.1.1.13  root     1929:        /* If IKBD is executing custom code, send the byte to the function handling this code */
                   1930:        if ( IKBD_ExeMode && pIKBD_CustomCodeHandler_Write )
                   1931:        {
                   1932:                (*pIKBD_CustomCodeHandler_Write) ( (Uint8) bl );
                   1933:                return;
                   1934:        }
                   1935: 
                   1936:        if ( MemoryLoadNbBytesLeft == 0 )               /* No pending MemoryLoad command */
                   1937:                IKBD_RunKeyboardCommand ( bl );         /* check for known commands */
                   1938: 
                   1939:        else                                            /* MemoryLoad command is not finished yet */
                   1940:                IKBD_LoadMemoryByte ( (Uint8) bl );     /* process bytes sent to the ikbd RAM */
1.1       root     1941: }
                   1942: 
1.1.1.2   root     1943: 
                   1944: /*-----------------------------------------------------------------------*/
1.1.1.12  root     1945: /**
                   1946:  * The byte stored in the ACIA 'ACIAByte' has been read by the CPU by reading from
                   1947:  * address $fffc02. We clear the status flag and set the GPIP register to signal read.
                   1948:  */
1.1.1.11  root     1949: Uint16 IKBD_GetByteFromACIA(void)
1.1       root     1950: {
1.1.1.12  root     1951:        /* ACIA is now reset */
                   1952:        ACIAStatusRegister &= ~(ACIA_STATUS_REGISTER__RX_BUFFER_FULL | ACIA_STATUS_REGISTER__INTERRUPT_REQUEST | ACIA_STATUS_REGISTER__OVERRUN_ERROR);
1.1       root     1953: 
1.1.1.12  root     1954:        /* GPIP I4 - General Purpose Pin Keyboard/MIDI interrupt */
                   1955:        MFP_GPIP |= 0x10;
                   1956:        return ACIAByte;  /* Return byte from keyboard */
1.1       root     1957: }
                   1958: 
1.1.1.2   root     1959: 
                   1960: /*-----------------------------------------------------------------------*/
1.1.1.12  root     1961: /**
1.1.1.17! root     1962:  * This interrupt handler is used to simulate a correct number of CPU cycles
        !          1963:  * when sending a byte from the ACIA to the ikdb or when receiving a byte
        !          1964:  * from the ikbd to the ACIA (because ACIA serial transfers are running
        !          1965:  * at 7812.5 bps, bytes should not be available immediatly as it would break
        !          1966:  * some programs)
        !          1967:  * - Byte received in the ACIA from the keyboard processor : store byte for read
        !          1968:  *   from $fffc02 and schedule MFP interrupt to be triggered just a few cycles after.
        !          1969:  * - Byte sent from the ACIA to the keyboard processor : pass the byte to
        !          1970:  *   IKBD_SendByteToKeyboardProcessor and set TX_BUFFER_EMPTY in status register.
1.1.1.12  root     1971:  */
1.1       root     1972: void IKBD_InterruptHandler_ACIA(void)
                   1973: {
1.1.1.12  root     1974:        /* Remove this interrupt from list and re-order */
1.1.1.16  root     1975:        CycInt_AcknowledgeInterrupt();
1.1       root     1976: 
1.1.1.17! root     1977:        if ( bByteInTransitToACIA )
        !          1978:        {
        !          1979:                /* Copy keyboard byte, ready for read from $fffc02 */
        !          1980:                ACIAByte = Keyboard.Buffer[Keyboard.BufferHead++];
        !          1981:                Keyboard.BufferHead &= KEYBOARD_BUFFER_MASK;
        !          1982: 
        !          1983:                /* Did we get an over-run? Ie byte has arrived from keyboard processor BEFORE CPU has read previous one from ACIA */
        !          1984:                if (ACIAStatusRegister&ACIA_STATUS_REGISTER__RX_BUFFER_FULL)
        !          1985:                        ACIAStatusRegister |= ACIA_STATUS_REGISTER__OVERRUN_ERROR;  /* Set over-run */
        !          1986: 
        !          1987:                /* ACIA buffer is now full */
        !          1988:                ACIAStatusRegister |= ACIA_STATUS_REGISTER__RX_BUFFER_FULL;
        !          1989:                /* Signal interrupt pending */
        !          1990:                ACIAStatusRegister |= ACIA_STATUS_REGISTER__INTERRUPT_REQUEST;
        !          1991: 
        !          1992:                /* GPIP I4 - General Purpose Pin Keyboard/MIDI interrupt */
        !          1993:                /* NOTE: GPIP will remain low(0) until keyboard data is read from $fffc02. */
        !          1994:                MFP_GPIP &= ~0x10;
        !          1995: 
        !          1996:                /* There seems to be a small gap on a real ST between the point in time
        !          1997:                * the ACIA_STATUS_REGISTER__RX_BUFFER_FULL bit is set and the MFP
        !          1998:                * interrupt is triggered - for example the "V8 music system" demo
        !          1999:                * depends on this behaviour. To emulate this, we simply start another
        !          2000:                * Int which triggers the MFP interrupt later: */
        !          2001:                CycInt_AddRelativeInterrupt(18, INT_CPU_CYCLE, INTERRUPT_IKBD_MFP);
        !          2002:        }
        !          2003: 
        !          2004:        if ( bByteInTransitFromACIA )
        !          2005:        {
        !          2006:                IKBD_SendByteToKeyboardProcessor(ACIATxDataRegister);           /* Pass the byte to the keyboard processor */
        !          2007:                ACIAStatusRegister |= ACIA_STATUS_REGISTER__TX_BUFFER_EMPTY;    /* TX buffer is now empty */
        !          2008:                bByteInTransitFromACIA = false;                                 /* ready to send another byte */
        !          2009:        }
1.1.1.13  root     2010: }
                   2011: 
                   2012: 
                   2013: /**
                   2014:  * Start MFP interrupt after byte has been received in the ACIA.
                   2015:  */
                   2016: void IKBD_InterruptHandler_MFP(void)
                   2017: {
                   2018:        /* Remove this interrupt from list and re-order */
1.1.1.16  root     2019:        CycInt_AcknowledgeInterrupt();
1.1.1.13  root     2020: 
1.1.1.12  root     2021:        /* Acknowledge in MFP circuit, pass bit,enable,pending */
                   2022:        MFP_InputOnChannel(MFP_ACIA_BIT, MFP_IERB, &MFP_IPRB);
                   2023: 
                   2024:        /* Clear flag so can allow another byte to be sent along serial line */
1.1.1.15  root     2025:        bByteInTransitToACIA = false;
1.1.1.13  root     2026: 
1.1.1.12  root     2027:        /* If another key is waiting, start sending from keyboard processor now */
                   2028:        if (Keyboard.BufferHead!=Keyboard.BufferTail)
1.1.1.13  root     2029:                IKBD_SendByteToACIA(ACIA_CYCLES);
1.1       root     2030: }
                   2031: 
                   2032: 
1.1.1.2   root     2033: /*-----------------------------------------------------------------------*/
1.1.1.12  root     2034: /**
                   2035:  * Send a byte from the keyboard buffer to the ACIA. On a real ST this takes some time to send
                   2036:  * so we must be as accurate in the timing as possible - bytes do not appear to the 68000 instantly!
                   2037:  * We do this via an internal interrupt - neat!
                   2038:  */
1.1.1.13  root     2039: static void IKBD_SendByteToACIA(int nAciaCycles)
1.1       root     2040: {
1.1.1.13  root     2041:        /* Transmit byte from keyboard processor to ACIA.
                   2042:         * This takes approx ACIA_CYCLES CPU clock cycles to complete */
1.1.1.12  root     2043:        if (!bByteInTransitToACIA)
                   2044:        {
                   2045:                /* Send byte to ACIA */
1.1.1.16  root     2046:                CycInt_AddRelativeInterrupt(nAciaCycles, INT_CPU_CYCLE, INTERRUPT_IKBD_ACIA);
1.1.1.12  root     2047:                /* Set flag so only transmit one byte at a time */
1.1.1.15  root     2048:                bByteInTransitToACIA = true;
1.1.1.12  root     2049:        }
1.1       root     2050: }
                   2051: 
1.1.1.2   root     2052: 
                   2053: /*-----------------------------------------------------------------------*/
1.1.1.12  root     2054: /**
1.1.1.13  root     2055:  * Add character to our internal keyboard buffer, with default ACIA_CYCLES
                   2056:  * timing.
                   2057:  */
                   2058: static void IKBD_AddKeyToKeyboardBuffer(Uint8 Data)
                   2059: {
                   2060:        if ( IKBD_ExeMode )                                     /* if IKBD is executing custom code, don't add */
                   2061:                return;                                         /* anything to the buffer */
                   2062: 
                   2063:        IKBD_AddKeyToKeyboardBuffer_Real(Data, ACIA_CYCLES);
                   2064: }
                   2065: 
                   2066: 
                   2067: /**
                   2068:  * Add character to our internal keyboard buffer, with additional delay.
                   2069:  * This is required for some keyboard commands like ReadAbsMousePos (0x0d)
                   2070:  * where it takes a little bit longer than the typical ACIA_CYCLES until
                   2071:  * the first byte arrives from the IKBD (for example the "Unlimited bobs"
                   2072:  * screen in the Dragonnels demo depends on this behaviour.
                   2073:  */
                   2074: static void IKBD_AddKeyToKeyboardBufferWithDelay(Uint8 Data, int nAciaCycles)
                   2075: {
                   2076:        if (IKBD_ExeMode)                               /* if IKBD is executing custom code, */
                   2077:                return;                                         /* don't add anything to the buffer */
                   2078: 
                   2079:        IKBD_AddKeyToKeyboardBuffer_Real(Data, nAciaCycles);
                   2080: }
                   2081: 
                   2082: 
                   2083: /**
                   2084:  * Add character to our internal keyboard buffer. These bytes are then sent
                   2085:  * one at a time to the ACIA. This is done via a delay to mimick the STs
                   2086:  * internal workings, as this is needed for games such as Carrier Command.
1.1.1.12  root     2087:  */
1.1.1.13  root     2088: static void IKBD_AddKeyToKeyboardBuffer_Real(Uint8 Data, int nAciaCycles)
1.1       root     2089: {
1.1.1.12  root     2090:        /* Is keyboard initialised yet? Ignore any bytes until it is */
                   2091:        if (!KeyboardProcessor.bReset)
                   2092:                return;
                   2093: 
                   2094:        /* Check we have space to add byte */
                   2095:        if (Keyboard.BufferHead!=((Keyboard.BufferTail+1)&KEYBOARD_BUFFER_MASK))
                   2096:        {
                   2097:                /* Add byte to our buffer */
                   2098:                Keyboard.Buffer[Keyboard.BufferTail++] = Data;
                   2099:                Keyboard.BufferTail &= KEYBOARD_BUFFER_MASK;
                   2100: 
                   2101:                /* We have character ready to transmit from the ACIA - see if can send it now */
1.1.1.13  root     2102:                IKBD_SendByteToACIA(nAciaCycles);
1.1.1.12  root     2103:        }
1.1.1.17! root     2104:        else
        !          2105:        {
        !          2106:                Log_Printf(LOG_ERROR, "IKBD buffer is full!\n");
        !          2107:        }
1.1       root     2108: }
                   2109: 
1.1.1.2   root     2110: 
                   2111: /*-----------------------------------------------------------------------*/
1.1.1.12  root     2112: /**
                   2113:  * When press/release key under host OS, execute this function.
                   2114:  */
1.1.1.13  root     2115: void IKBD_PressSTKey(Uint8 ScanCode, bool bPress)
1.1       root     2116: {
1.1.1.13  root     2117:        /* Store the state of each ST scancode : 1=pressed 0=released */
                   2118:        if ( bPress )           ScanCodeState[ ScanCode & 0x7f ] = 1;
                   2119:        else                    ScanCodeState[ ScanCode & 0x7f ] = 0;
                   2120: 
1.1.1.12  root     2121:        if (!bPress)
                   2122:                ScanCode |= 0x80;    /* Set top bit if released key */
                   2123:        IKBD_AddKeyToKeyboardBuffer(ScanCode);  /* And send to keyboard processor */
1.1       root     2124: }
1.1.1.10  root     2125: 
                   2126: 
                   2127: /*-----------------------------------------------------------------------*/
1.1.1.12  root     2128: /**
                   2129:  * Handle read from keyboard control ACIA register (0xfffc00)
                   2130:  */
1.1.1.10  root     2131: void IKBD_KeyboardControl_ReadByte(void)
                   2132: {
1.1.1.11  root     2133:        /* ACIA registers need wait states - but the value seems to vary in certain cases */
                   2134:        M68000_WaitState(8);
                   2135: 
1.1.1.13  root     2136:        IoMem[0xfffc00] = ACIAStatusRegister;
1.1.1.12  root     2137: 
1.1.1.15  root     2138:        if (LOG_TRACE_LEVEL(TRACE_IKBD_ACIA))
1.1.1.12  root     2139:        {
1.1.1.15  root     2140:                int FrameCycles, HblCounterVideo, LineCycles;
                   2141:                Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
                   2142:                LOG_TRACE_PRINT("ikbd read fffc00 ctrl=0x%x video_cyc=%d %d@%d pc=%x instr_cycle %d\n",
                   2143:                                IoMem[0xfffc00], FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC(), CurrentInstrCycles);
1.1.1.12  root     2144:        }
1.1.1.10  root     2145: }
                   2146: 
                   2147: /*-----------------------------------------------------------------------*/
1.1.1.12  root     2148: /**
                   2149:  * Handle read from keyboard data ACIA register (0xfffc02)
                   2150:  */
1.1.1.10  root     2151: void IKBD_KeyboardData_ReadByte(void)
                   2152: {
1.1.1.11  root     2153:        /* ACIA registers need wait states - but the value seems to vary in certain cases */
                   2154:        M68000_WaitState(8);
                   2155: 
1.1.1.13  root     2156:        /* If IKBD is executing custom code, call the function to update the byte read in $fffc02 */
                   2157:        if ( IKBD_ExeMode && pIKBD_CustomCodeHandler_Read )
                   2158:        {
                   2159:                (*pIKBD_CustomCodeHandler_Read) ();
                   2160:        }
                   2161: 
                   2162: 
1.1.1.10  root     2163:        IoMem[0xfffc02] = IKBD_GetByteFromACIA();  /* Return our byte from keyboard processor */
1.1.1.12  root     2164: 
1.1.1.15  root     2165:        if (LOG_TRACE_LEVEL(TRACE_IKBD_ACIA))
1.1.1.12  root     2166:        {
1.1.1.15  root     2167:                int FrameCycles, HblCounterVideo, LineCycles;
                   2168:                Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
                   2169:                LOG_TRACE_PRINT("ikbd read fffc02 data=0x%x video_cyc=%d %d@%d pc=%x instr_cycle %d\n",
                   2170:                                IoMem[0xfffc02], FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC(), CurrentInstrCycles);
1.1.1.12  root     2171:        }
1.1.1.10  root     2172: }
                   2173: 
                   2174: 
                   2175: /*-----------------------------------------------------------------------*/
1.1.1.12  root     2176: /**
                   2177:  * Handle write to keyboard control ACIA register (0xfffc00)
                   2178:  */
1.1.1.10  root     2179: void IKBD_KeyboardControl_WriteByte(void)
                   2180: {
1.1.1.11  root     2181:        /* ACIA registers need wait states - but the value seems to vary in certain cases */
                   2182:        M68000_WaitState(8);
                   2183: 
1.1.1.15  root     2184:        if (LOG_TRACE_LEVEL(TRACE_IKBD_ACIA))
1.1.1.12  root     2185:        {
1.1.1.15  root     2186:                int FrameCycles, HblCounterVideo, LineCycles;
                   2187:                Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
                   2188:                LOG_TRACE_PRINT("ikbd write fffc00 ctrl=0x%x video_cyc=%d %d@%d pc=%x instr_cycle %d\n",
                   2189:                                IoMem[0xfffc00], FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC(), CurrentInstrCycles);
1.1.1.12  root     2190:        }
                   2191: 
                   2192:        /* [NP] We only handle reset of the ACIA */
                   2193:        if ( ( IoMem[0xfffc00] & 0x03 ) == 0x03 )
                   2194:                ACIA_Reset();
                   2195: 
1.1.1.10  root     2196:        /* Nothing... */
                   2197: }
                   2198: 
                   2199: /*-----------------------------------------------------------------------*/
1.1.1.12  root     2200: /**
                   2201:  * Handle write to keyboard data ACIA register (0xfffc02)
                   2202:  */
1.1.1.10  root     2203: void IKBD_KeyboardData_WriteByte(void)
                   2204: {
1.1.1.11  root     2205:        /* ACIA registers need wait states - but the value seems to vary in certain cases */
                   2206:        M68000_WaitState(8);
                   2207: 
1.1.1.15  root     2208:        if (LOG_TRACE_LEVEL(TRACE_IKBD_ACIA))
1.1.1.12  root     2209:        {
1.1.1.15  root     2210:                int FrameCycles, HblCounterVideo, LineCycles;
                   2211:                Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
                   2212:                LOG_TRACE_PRINT("ikbd write fffc02 data=0x%x video_cyc=%d %d@%d pc=%x instr_cycle %d\n",
                   2213:                                IoMem[0xfffc02], FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC(), CurrentInstrCycles);
1.1.1.12  root     2214:        }
                   2215: 
1.1.1.13  root     2216: 
1.1.1.17! root     2217:        if ( bByteInTransitFromACIA == false )                  /* we're not already transfering a byte to the ikbd */
        !          2218:        {
        !          2219: //             IKBD_SendByteToKeyboardProcessor(IoMem[0xfffc02]);  /* Pass our byte to the keyboard processor */
        !          2220:                ACIATxDataRegister = IoMem[0xfffc02];           /* store the byte that we want to send to the ikbd */
        !          2221: 
        !          2222:                /* Delay the processing of the byte in IKBD_InterruptHandler_ACIA */
        !          2223:                /* The delay doesn't seem to be constant, so we add a small random number of max 40 cycles */
        !          2224:                /* (else some programs get stuck in an endless loop ('Pandemonium Demos' by Chaos) */
        !          2225: 
        !          2226:                // [NP] FIXME 2011/05/20 : if we use a delay of ACIA_CYCLES=7200, tos 1.02 and 1.04 are showing
        !          2227:                // a bug where addr $6122/$6124 are overwritten by the stack, preventing the desktop
        !          2228:                // to be restored at the correct resolution !
        !          2229:                // For now, use a delay of 1000 cycles ; need to do complete measures on a real ST for this
        !          2230:                //CycInt_AddRelativeInterrupt(ACIA_CYCLES+rand()%40, INT_CPU_CYCLE, INTERRUPT_IKBD_ACIA);
        !          2231: // delay cycles <=1560 ok, > 1570 bad for tos 1.02/1.04
        !          2232:                CycInt_AddRelativeInterrupt(1000+rand()%40, INT_CPU_CYCLE, INTERRUPT_IKBD_ACIA);
        !          2233: 
        !          2234:                /* Some games like USS John Young / FOF54 actually check whether the
        !          2235:                * transmit-buffer-empty bit is really cleared after writing a data
        !          2236:                * byte to the IKBD, so we have to temporarily clear this bit, too,
        !          2237:                * although the byte is send immediately to our virtual IKBD. */
        !          2238:                ACIAStatusRegister &= ~ACIA_STATUS_REGISTER__TX_BUFFER_EMPTY;           /* TX buffer is full */
        !          2239: 
        !          2240:                bByteInTransitFromACIA = true;
        !          2241:        }
1.1.1.10  root     2242: }
1.1.1.13  root     2243: 
                   2244: 
                   2245: /*************************************************************************/
                   2246: /**
                   2247:  * Below part is for emulating custom 6301 program sent to the ikbd RAM
                   2248:  * Specific read/write functions for each demo/game should be added here,
                   2249:  * after being defined in the CustomCodeDefinitions[] array.
                   2250:  *
                   2251:  * The 6301 has 256 bytes of RAM, but only 128 bytes are available to
                   2252:  * put a program (from $80 to $ff).
                   2253:  *
                   2254:  * Executing a program in the 6301 is a 2 steps process :
                   2255:  *     1) a very small program is sent to the RAM using the 0x20 command.
                   2256:  *        This is often loaded at address $b0.
                   2257:  *        This program will stop interruptions in the 6301 and will accept
                   2258:  *        a second small program that will relocate itself to $80.
                   2259:  *     2) the relocated program at address $80 will accept a third (main)
                   2260:  *        program and will execute it once reception is complete.
                   2261:  *
                   2262:  * Writes during step 1 are handled with the ExeBootHandler matching the
                   2263:  * LoadMemory CRC.
                   2264:  * ExeBootHandler will compute a 2nd CRC for the writes corresponding to
                   2265:  * the 2nd and 3rd programs sent to the 6301's RAM.
                   2266:  *
                   2267:  * If a match is found for this 2nd CRC, we will override default ikbd's behaviour
                   2268:  * for reading/writing to $fffc02 with ExeMainHandler_Read / ExeMainHandler_Write
                   2269:  * (once the Execute command 0x22 is received).
                   2270:  *
1.1.1.15  root     2271:  * When using custom program (ExeMode==true), we must ignore all keyboard/mouse/joystick
1.1.1.13  root     2272:  * events sent to IKBD_AddKeyToKeyboardBuffer. Only our functions can add bytes
                   2273:  * to the keyboard buffer.
                   2274:  *
                   2275:  * To exit 6301's execution mode, we can use the 68000 'reset' instruction.
                   2276:  * Some 6301's programs also handle a write to $fffc02 as an exit signal.
                   2277:  */
                   2278: 
                   2279: 
                   2280: /*-----------------------------------------------------------------------*/
                   2281: /**
                   2282:  * Handle writes to $fffc02 when loading bytes in the ikbd RAM.
                   2283:  * We compute a CRC of the bytes that are sent until MemoryLoadNbBytesLeft
                   2284:  * reaches 0.
                   2285:  * When all bytes are loaded, we look for a matching CRC ; if found, we
                   2286:  * use the ExeBootHandler defined for this CRC to process the next writes
                   2287:  * that will occur in $fffc02.
                   2288:  * LoadMemory is often used to load a small boot code into the 6301's RAM.
                   2289:  * This small program will be executed later using the command 0x22.
                   2290:  */
                   2291: 
                   2292: static void IKBD_LoadMemoryByte ( Uint8 aciabyte )
                   2293: {
                   2294:        unsigned int i;
                   2295: 
                   2296:        crc32_add_byte ( &MemoryLoadCrc , aciabyte );
                   2297: 
                   2298:        MemoryLoadNbBytesLeft--;
                   2299:        if ( MemoryLoadNbBytesLeft == 0 )                               /* all bytes were received */
                   2300:        {
                   2301:                /* Search for a match amongst the known custom routines */
                   2302:                for ( i = 0 ; i < sizeof ( CustomCodeDefinitions ) / sizeof ( CustomCodeDefinitions[0] ) ; i++ )
                   2303:                        if ( CustomCodeDefinitions[ i ].LoadMemCrc == MemoryLoadCrc )
                   2304:                                break;
                   2305: 
                   2306:                if ( i < sizeof ( CustomCodeDefinitions ) / sizeof ( CustomCodeDefinitions[0] ) )       /* found */
                   2307:                {
1.1.1.15  root     2308:                        LOG_TRACE(TRACE_IKBD_EXEC, "ikbd loadmemory %d bytes crc=0x%x matches <%s>\n",
                   2309:                                  MemoryLoadNbBytesTotal, MemoryLoadCrc, CustomCodeDefinitions[ i ].Name);
1.1.1.13  root     2310: 
                   2311:                        crc32_reset ( &MemoryLoadCrc );
                   2312:                        MemoryExeNbBytes = 0;
                   2313:                        pIKBD_CustomCodeHandler_Read = NULL;
                   2314:                        pIKBD_CustomCodeHandler_Write = CustomCodeDefinitions[ i ].ExeBootHandler;
                   2315:                }
                   2316: 
                   2317:                else                                                    /* unknown code uploaded to ikbd RAM */
                   2318:                {
1.1.1.15  root     2319:                        LOG_TRACE(TRACE_IKBD_EXEC, "ikbd loadmemory %d bytes crc=0x%x : unknown code\n",
                   2320:                                  MemoryLoadNbBytesTotal, MemoryLoadCrc);
1.1.1.13  root     2321: 
                   2322:                        pIKBD_CustomCodeHandler_Read = NULL;
                   2323:                        pIKBD_CustomCodeHandler_Write = NULL;
                   2324:                }
                   2325:        }
                   2326: }
                   2327: 
                   2328: 
                   2329: 
                   2330: /*-----------------------------------------------------------------------*/
                   2331: /**
                   2332:  * Handle writes to $fffc02 when executing custom code in the ikbd RAM.
                   2333:  * This is used to send the small ikdb program that will handle keyboard/mouse/joystick
                   2334:  * input.
                   2335:  * We compute a CRC of the bytes that are sent until we found a match
                   2336:  * with a known custom ikbd program.
                   2337:  */
                   2338: 
                   2339: static void IKBD_CustomCodeHandler_CommonBoot ( Uint8 aciabyte )
                   2340: {
                   2341:        unsigned int i;
                   2342: 
                   2343:        crc32_add_byte ( &MemoryLoadCrc , aciabyte );
                   2344:        MemoryExeNbBytes++;
                   2345: 
1.1.1.15  root     2346:        LOG_TRACE(TRACE_IKBD_EXEC, "ikbd custom exe common boot write 0x%02x count %d crc=0x%x\n",
                   2347:                  aciabyte, MemoryExeNbBytes, MemoryLoadCrc);
1.1.1.13  root     2348: 
                   2349:        /* Search for a match amongst the known custom routines */
                   2350:        for ( i = 0 ; i < sizeof ( CustomCodeDefinitions ) / sizeof ( CustomCodeDefinitions[0] ) ; i++ )
                   2351:                if ( ( CustomCodeDefinitions[ i ].MainProgNbBytes == MemoryExeNbBytes )
                   2352:                        && ( CustomCodeDefinitions[ i ].MainProgCrc == MemoryLoadCrc ) )
                   2353:                        break;
                   2354: 
                   2355:        if ( i < sizeof ( CustomCodeDefinitions ) / sizeof ( CustomCodeDefinitions[0] ) )       /* found */
                   2356:        {
1.1.1.15  root     2357:                LOG_TRACE(TRACE_IKBD_EXEC, "ikbd custom exe common boot, uploaded code matches <%s>\n",
                   2358:                          CustomCodeDefinitions[i].Name);
1.1.1.13  root     2359: 
                   2360:                pIKBD_CustomCodeHandler_Read = CustomCodeDefinitions[ i ].ExeMainHandler_Read;
                   2361:                pIKBD_CustomCodeHandler_Write = CustomCodeDefinitions[ i ].ExeMainHandler_Write;
                   2362: 
                   2363:                Keyboard.BufferHead = Keyboard.BufferTail = 0;  /* flush all queued bytes that would be read in $fffc02 */
                   2364:                (*pIKBD_CustomCodeHandler_Read) ();             /* initialize ACIAByte */
                   2365:        }
                   2366: 
                   2367:        /* If not found, we keep on accumulating bytes until we find a matching crc */
                   2368: }
                   2369: 
                   2370: 
                   2371: 
                   2372: /*----------------------------------------------------------------------*/
                   2373: /* Froggies Over The Fence menu.                                       */
                   2374: /* Returns 2 bytes with the mouse position, keyboard can be used too.  */
                   2375: /* Writing 0xff to $fffc02 will cause the 6301 to exit custom exe mode.        */
                   2376: /*----------------------------------------------------------------------*/
                   2377: 
                   2378: static void IKBD_CustomCodeHandler_FroggiesMenu_Read ( void )
                   2379: {
                   2380:        Uint8           res1 = 0;
                   2381:        Uint8           res2 = 0;
                   2382: 
                   2383:        if ( KeyboardProcessor.Mouse.DeltaX < 0 )       res1 = 0x7a;    /* mouse left */
                   2384:        if ( KeyboardProcessor.Mouse.DeltaX > 0 )       res1 = 0x06;    /* mouse right */
                   2385:        if ( KeyboardProcessor.Mouse.DeltaY < 0 )       res2 = 0x7a;    /* mouse up */
                   2386:        if ( KeyboardProcessor.Mouse.DeltaY > 0 )       res2 = 0x06;    /* mouse down */
                   2387:        if ( Keyboard.bLButtonDown & BUTTON_MOUSE )     res1 |= 0x80;   /* left mouse button */
                   2388: 
                   2389:        if ( ScanCodeState[ 0x4b ] )                    res1 |= 0x7a;   /* left */
                   2390:        if ( ScanCodeState[ 0x4d ] )                    res1 |= 0x06;   /* right */
                   2391:        if ( ScanCodeState[ 0x48 ] )                    res2 |= 0x7a;   /* up */
                   2392:        if ( ScanCodeState[ 0x50 ] )                    res2 |= 0x06;   /* down */
                   2393:        if ( ScanCodeState[ 0x70 ] )                    res1 |= 0x80;   /* keypad 0 */
                   2394: 
                   2395:        IKBD_AddKeyToKeyboardBuffer_Real(res1, ACIA_CYCLES);
                   2396:        IKBD_AddKeyToKeyboardBuffer_Real(res2, ACIA_CYCLES);
                   2397: }
                   2398: 
                   2399: static void IKBD_CustomCodeHandler_FroggiesMenu_Write ( Uint8 aciabyte )
                   2400: {
                   2401:        /* When writing 0xff to $fffc02, Froggies ikbd's program will terminate itself */
                   2402:        /* and leave Execution mode */
                   2403:        if ( aciabyte == 0xff )
                   2404:                IKBD_Reset_ExeMode ();
                   2405: }
                   2406: 
                   2407: 
                   2408: 
                   2409: /*----------------------------------------------------------------------*/
                   2410: /* Transbeauce II menu.                                                        */
                   2411: /* Returns 1 byte with the joystick position, keyboard can be used too.        */
                   2412: /*----------------------------------------------------------------------*/
                   2413: 
                   2414: static void IKBD_CustomCodeHandler_Transbeauce2Menu_Read ( void )
                   2415: {
                   2416:        Uint8           res = 0;
                   2417: 
                   2418:        /* keyboard emulation */
                   2419:        if ( ScanCodeState[ 0x48 ] )    res |= 0x01;            /* up */
                   2420:        if ( ScanCodeState[ 0x50 ] )    res |= 0x02;            /* down */
                   2421:        if ( ScanCodeState[ 0x4b ] )    res |= 0x04;            /* left */
                   2422:        if ( ScanCodeState[ 0x4d ] )    res |= 0x08;            /* right */
                   2423:        if ( ScanCodeState[ 0x62 ] )    res |= 0x40;            /* help */
                   2424:        if ( ScanCodeState[ 0x39 ] )    res |= 0x80;            /* space */
                   2425: 
                   2426:        /* joystick emulation (bit mapping is same as cursor above, with bit 7 = fire button */
                   2427:        res |= ( Joy_GetStickData(1) & 0x8f ) ;                 /* keep bits 0-3 and 7 */
                   2428: 
                   2429:        IKBD_AddKeyToKeyboardBuffer_Real(res, ACIA_CYCLES);
                   2430: }
                   2431: 
                   2432: static void IKBD_CustomCodeHandler_Transbeauce2Menu_Write ( Uint8 aciabyte )
                   2433: {
                   2434:   /* Ignore write */
                   2435: }
                   2436: 
                   2437: 
                   2438: 
                   2439: /*----------------------------------------------------------------------*/
                   2440: /* Dragonnels demo menu.                                               */
                   2441: /* Returns 1 byte with the Y position of the mouse.                    */
                   2442: /*----------------------------------------------------------------------*/
                   2443: 
                   2444: static void IKBD_CustomCodeHandler_DragonnelsMenu_Read ( void )
                   2445: {
                   2446:        Uint8           res = 0;
                   2447: 
                   2448:        if ( KeyboardProcessor.Mouse.DeltaY < 0 )       res = 0xfc;     /* mouse up */
                   2449:        if ( KeyboardProcessor.Mouse.DeltaY > 0 )       res = 0x04;     /* mouse down */
                   2450: 
                   2451:        if ( Keyboard.bLButtonDown & BUTTON_MOUSE )     res = 0x80;     /* left mouse button */
                   2452: 
                   2453:        IKBD_AddKeyToKeyboardBuffer_Real(res, ACIA_CYCLES);
                   2454: }
                   2455: 
                   2456: static void IKBD_CustomCodeHandler_DragonnelsMenu_Write ( Uint8 aciabyte )
                   2457: {
                   2458:   /* Ignore write */
                   2459: }
                   2460: 
1.1.1.17! root     2461: 
        !          2462: 
        !          2463: /*----------------------------------------------------------------------*/
        !          2464: /* Chaos A.D. protection's decoder                                     */
        !          2465: /* This custom program reads bytes, decode them and send back the result*/
        !          2466: /* to the 68000.                                                       */
        !          2467: /* The program first returns $fe to indicate it's ready to receive the */
        !          2468: /* encoded bytes.                                                      */
        !          2469: /* The program then receives the 8 bytes used to decode the data and   */
        !          2470: /* store them in $f0 - $f7 (KeyBuffer is already initialized, so we    */
        !          2471: /* ignore those 8 bytes).                                              */
        !          2472: /* Then for any received byte a XOR is made with one of the byte in the        */
        !          2473: /* 8 bytes buffer, by incrementing an index in this buffer.            */
        !          2474: /* The decoded byte is written to addr $13 (TDR) to be received by ACIA        */
        !          2475: /*----------------------------------------------------------------------*/
        !          2476: 
        !          2477: static void IKBD_CustomCodeHandler_ChaosAD_Read ( void )
        !          2478: {
        !          2479:        static bool     FirstCall = true;
        !          2480: 
        !          2481:        if ( FirstCall == true )
        !          2482:                IKBD_AddKeyToKeyboardBuffer_Real ( 0xfe , ACIA_CYCLES );
        !          2483: 
        !          2484:        FirstCall = false;
        !          2485: }
        !          2486: 
        !          2487: static void IKBD_CustomCodeHandler_ChaosAD_Write ( Uint8 aciabyte )
        !          2488: {
        !          2489:        static int      IgnoreNb = 8;
        !          2490:        Uint8           KeyBuffer[] = { 0xca , 0x0a , 0xbc , 0x00 , 0xde , 0xde , 0xfe , 0xca };
        !          2491:        static int      Index = 0;
        !          2492:        static int      Count = 0;
        !          2493: 
        !          2494:        /* We ignore the first 8 bytes we received (they're already in KeyBuffer) */
        !          2495:        if ( IgnoreNb > 0 )
        !          2496:        {
        !          2497:                IgnoreNb--;
        !          2498:                return;
        !          2499:        }
        !          2500: 
        !          2501:        if ( Count <= 6080 )                                            /* there're 6081 bytes to decode */
        !          2502:        {
        !          2503:                Count++;
        !          2504:                
        !          2505:                aciabyte ^= KeyBuffer[ Index ];
        !          2506:                Index++;
        !          2507:                Index &= 0x07;
        !          2508: 
        !          2509:                IKBD_AddKeyToKeyboardBuffer_Real ( aciabyte , ACIA_CYCLES );
        !          2510:        }
        !          2511: 
        !          2512:        else
        !          2513:        {
        !          2514:                /* When all bytes were decoded if 0x08 is written to $fffc02 */
        !          2515:                /* the program will terminate itself and leave Execution mode */
        !          2516:                if ( aciabyte == 0x08 )
        !          2517:                        IKBD_Reset_ExeMode ();
        !          2518:        }
        !          2519: }
        !          2520: 

unix.superglobalmegacorp.com

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