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

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

unix.superglobalmegacorp.com

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