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

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

unix.superglobalmegacorp.com

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