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

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

unix.superglobalmegacorp.com

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