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

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

unix.superglobalmegacorp.com

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