; Pinball Bus snooper ; By Joel Jordan, SigArch @ ACM, UIUC ; http://www.acm.uiuc.edu/sigarch/ ; ; 3/07/04 ; connect to Bally Star Trek Pinball 6800 processor ; to monitor game score ; History ; 3/08/04 v0.1 ; Reads 4 scores from pinball machine reliably ; 3/11/04 v0.2 ; Reads 4 scores realiably (again) and also current ; ball. ; How does this work? Basically, we have some combinational logic ; external to the PIC which creates an interrupt whenever there ; is a write to either RAM chip in the pinball machine. The ; interrupt handler has a lookup table which tells it whether to ; ignore the address or where to store the data in the PIC's ; memory. Our pinball controller board then polls us periodically ; over I2C, and we respond by dumping the contents of the score ; memory. ; Note that I've commented out one of the interrupt routines. ; This corresponds to the 8-bit SRAM in the system. The problem ; is that, even at 40MHz, we can't handle the timing requirements ; of a 16-bit write, which takes something like 2us. So instead, ; we just ignore the 8-bit SRAM and focus on the 6101 nybble RAM ; which has the scores in it. This means that we don't know ; certain things, like which player is currently playing. LIST P=18F452 #include ; constants #define READ_RAM0 #undefine READ_RAM0 #define RAM0CS PORTB, 0 #define RAM1CS PORTB, 1 #define A05 PORTB #define A0 PORTB, 2 #define A1 PORTB, 3 #define A2 PORTB, 4 #define A3 PORTB, 5 #define A4 PORTB, 6 #define A5 PORTB, 7 #define A67 PORTE #define A6 PORTE, 0 #define A7 PORTE, 1 #define D07 PORTD #define D0 PORTD, 0 #define D1 PORTD, 1 #define D2 PORTD, 2 #define D3 PORTD, 3 #define D4 PORTD, 4 #define D5 PORTD, 5 #define D6 PORTD, 6 #define D7 PORTD, 7 #define ScoreAddr 0x03 #define IDLE 0x00 #define RECV 0x01 #define XMIT 0x02 #define WAIT_BUF 0x03 #define NewDataFlag flags, 0 IFSR macro Address,Offset lfsr 2, Address movf Offset, w addwf FSR2L, f btfsc STATUS, C incf FSR2H, f endm ; variables cblock 0x000 StatusSave WSave BSRSave CharBuf NumChars flags BufferEnd I2CAddr ; address associated with last I2C event I2CRXBuf:0x10 ; RX buffer for I2C I2CRXLength I2CTXLength ; user counter I2CTXBuf:0x40 ; TX buffer for I2C I2CTXIndex ; used from ISR I2CState ; status I2CTXFill ; flag ready to fill TX buffer I2CTXFull ; flag whether TX buf full Temp RAMAddrL ; low bits of address on bus RAMAddrH ; high bits of address on bus RAMData ; 6800 data bus contents BCDTemp DataLocation FSR2LSave FSR2HSave endc cblock 0x100 ReadBuffer:d'37' endc cblock 0x200 Score1:6 Score2:6 Score3:6 Score4:6 CurrentBall CurrentPlayer LastAddr ; dummy for end address offset endc ; code org 0x00000 ; Begininning of Program EEPROM goto Start org 0x00008 ; high-priority interrupt Interrupt1 goto BusInterrupt org 0x00018 ; low-priority interrupt goto I2CInterrupt BusInterrupt ; This interrupt uses FSR1, so don't use it anywhere in the program ; where interrupts will be enabled movff A05, RAMAddrL ; store these values while they're movff A67, RAMAddrH ; still valid on the MPU bus movff D07, RAMData rrcf RAMAddrH,F ; reconstruct 8 bit address from rrcf RAMAddrL,F ; 6 and 2 from different IO ports rrcf RAMAddrH,F rrcf RAMAddrL,F movlw 0xFF ; default value, do nothing btfsc RAMAddrL, 7 ; for now, ignore writes to the top half of goto BusInterruptDone ; RAM1, since we don't have an elegant way to ; handle them anyway ; the "handlers" take the address and return an index into ; our variable storage at 0x200. 0xFF means ignore btfsc INTCON, INT0IF ; check for RAM0 call RAM0Handler ; btfsc INTCON3, INT1IF ; check for RAM1 call RAM1Handler ; movwf DataLocation ; save returned value xorlw 0xFF ; check for ignored values bz BusInterruptDone ; and retfie if necessary lfsr FSR1, 0x200 ; index into our variable storage movf DataLocation, w ; addwf FSR1L, F movff RAMData, INDF1 ; and store the value we read bsf NewDataFlag ; tell the main routine that it ; has new data waiting for it BusInterruptDone retfie FAST I2CInterrupt ; This routine handles all I2C transfers in the background ; to send something, put it in the I2CTXBuf with the first ; byte as the length (including itself) and ; execute 'bsf I2CTXFull, 0' to send the data the next time ; this node is polled. MOVWF WSave ; save processor state MOVFF STATUS, StatusSave MOVFF BSR, BSRSave MOVFF FSR2L, FSR2LSave MOVFF FSR2H, FSR2HSave btfss PIR1, SSPIF, 0 ; interrupt on I2C event? goto I2CInterruptDone ; break out if not call service_I2C ; and service I2C event I2CInterruptDone MOVFF FSR2LSave, FSR2L ; restore processor state MOVFF FSR2HSave, FSR2H MOVFF BSRSave, BSR MOVF WSave, W MOVFF StatusSave, STATUS retfie ; ------------------------------------------------------ ; Service routine for I2C interrupts ; adapted from AN734 ; ------------------------------------------------------ service_I2C movf SSPSTAT, w, 0 ; get SSP status andlw b'00101101' ; and mask out bits not used to determine state movwf Temp State1 ; Receiving, last byte was an address, movlw b'00001001' ; buffer full xorwf Temp,w bnz State2 movlw RECV ; mark that we're in the recv state movwf I2CState clrf I2CRXLength movf SSPBUF,w,0 ; dummy read to get address bsf SSPCON1,CKP,0 ; release clock bcf PIR1, SSPIF, 0 ; we're done, clear SSPIF return State2 movlw b'00101001' ; Receiving, last byte was data, xorwf Temp,w ; buffer is full bnz State3 IFSR I2CRXBuf,I2CRXLength movf SSPBUF,w,0 movwf INDF2 incf I2CRXLength,F movf I2CRXLength,w andlw 0x0f ; test buffer overflow btfsc STATUS,Z,0 clrf I2CRXLength bsf SSPCON1,CKP,0 ; release clock bcf PIR1, SSPIF, 0 ; we're done, clear SSPIF return State3 ; Transmitting, last byte was an movlw b'00001100' ; address, buffer is empty xorwf Temp,w bnz State4 movlw XMIT ; mark that we're in the xmit state movwf I2CState clrf I2CTXIndex lfsr FSR2, I2CTXBuf movlw 0x00 btfsc I2CTXFull, 0 movf INDF2, w, 0 call WriteI2C incf I2CTXIndex,f,0 bcf PIR1, SSPIF, 0 ; we're done, clear SSPIF return State4 ; Transmitting, last byte was data, movlw b'00101100' ; buffer is empty xorwf Temp,w bnz State5 IFSR I2CTXBuf, I2CTXIndex movlw 0x00 btfsc I2CTXFull, 0 movf INDF2,w,0 call WriteI2C incf I2CTXIndex,F movf I2CTXIndex,w andlw 0x3f ; test buffer overflow btfsc STATUS,Z clrf I2CTXIndex bcf PIR1, SSPIF, 0 ; we're done, clear SSPIF return State5 ; NACK received movlw b'00101000' xorwf Temp,w bnz I2CError movlw IDLE ; mark that we're in the idle state movwf I2CState bcf I2CTXFull, 0 bcf PIR1, SSPIF, 0 ; we're done, clear SSPIF return I2CError ; otherwise, hang and wait for WDT return ; ------------------------------------------------------ ; WriteI2C ; ------------------------------------------------------ WriteI2C btfsc SSPSTAT,BF,0 ; buffer full? goto $-2 ; wait for it to empty write bcf SSPCON1,WCOL,0 movwf SSPBUF,0 btfsc SSPCON1,WCOL,0 ; write collision? goto write bsf SSPCON1,CKP,0 ; release clock return ; ------------------------------------------------------ ; Set up I2C slave mode ; I2CAddress - address to assume ; ------------------------------------------------------ I2C_slave_setup clrf I2CState clrf I2CTXFill movlw b'00011000' ; set TRISC<3:4> to be inputs iorwf TRISC, f, 0 movlw b'00110110' ; set slave mode, enable MSSP, movwf SSPCON1, 0 bsf SSPCON2, SEN, 0 ; enable clock stretching on send/recv movff I2CAddr, SSPADD ; set address clrf SSPSTAT, 0 clrf PIR1, 0 ; clear current interrupt status bcf IPR1, SSPIP, 0 ; set low interrupt priority bsf PIE1, SSPIE, 0 ; enable I2C interrupts return ; ------------------------------------------------------ ; Main program begins here ; ------------------------------------------------------ Start MOVLW 0x07 ; Configure A/D MOVWF ADCON1 ; for digital inputs setf TRISB ; make B all inputs setf TRISD ; make D all inputs movlw b'00000011' ; make some E inputs movwf TRISE ; and disable PSP bsf RCON, IPEN ; enable interrupt priorities ; bsf INTCON, INT0IE ; enable INT0 interrupt bsf INTCON3, INT1IE ; enable INT1 interrupt ClearScoreBuffer LFSR FSR0, Score1 ; initialize the score buffer to ; all zeros ClearBufferLoop CLRF POSTINC0 MOVLW (LastAddr)&0xFF ; load end pointer CPFSEQ FSR0L GOTO ClearBufferLoop ; set up I2C movlw ScoreAddr ; assume address TestAddr movwf I2CAddr ; and configure for slave mode call I2C_slave_setup bcf NewDataFlag bsf INTCON, GIEL, 0 ; enable low priority interrupts bsf INTCON, GIEH, 0 ; enable high priority interrupts bcf I2CTXFull, 0 MainLoop btfss NewDataFlag goto MainLoop ; when we have new data, copy it into the I2C buffer ; and tell the I2C routines that it's there SendBuffer ; wait until buffer is empty BTFSC I2CTXFull, 0 GOTO SendBuffer ; wait until we're not transmitting MOVLW XMIT XORWF I2CState, W BZ SendBuffer FillTXBuffer ; copy score buffer into I2C BCF NewDataFlag ; write buffer LFSR FSR0, Score1 ; reset to beginning of buffer LFSR FSR2, I2CTXBuf CLRF I2CTXLength CLRF POSTINC2 ; save a byte for length data MOVLW "S" ; indicates score data follows MOVWF POSTINC2 INCF I2CTXLength, F FillBufferLoop MOVF POSTINC0, W ; get each character CALL BcdToAscii ; convert to ASCII MOVWF POSTINC2 INCF I2CTXLength, F ; accumulate size info MOVLW (LastAddr - 1)&0xFF ; all but last address CPFSEQ FSR0L GOTO FillBufferLoop ; last address is BCD packed in low nybble instead of high MOVF POSTINC0, W CALL BcdToAsciiLow ; so convert it MOVWF POSTINC2 INCF I2CTXLength, F ; accumulate size info MOVLW d'13' ; CR MOVWF POSTINC2 INCF I2CTXLength, F MOVLW d'10' ; LF MOVWF POSTINC2 INCF I2CTXLength, F INCF I2CTXLength, F ; not sure why i need this... LFSR FSR2, I2CTXBuf ; put length byte at beginning MOVFF I2CTXLength, INDF2 ; of I2C buffer BSF I2CTXFull, 0 ; set flag so ISR knows to send GOTO MainLoop ; repeat indefinitely BcdToAscii: ; convert upper-nybble BCD andlw 0xF0 ; numbers into ASCII movwf BCDTemp rrncf BCDTemp,f rrncf BCDTemp,f rrncf BCDTemp,f rrncf BCDTemp,f movf BCDTemp,w BcdToAsciiLow: andlw 0x0F addlw 0x30 return org 0x2F4 RAM0Handler bcf INTCON, INT0IF ; clear interrupt condition #ifdef READ_RAM0 movlw 0x3 ; set correct page so computed movwf PCLATH ; goto works correctly rlncf RAMAddrL, w ; multiply offset by 2 since instructions andlw 0xFE ; are 2 bytes long. mask out LSb addwf PCL, F ; jump ; addr function retlw 0xFF ; 0x00 (unknown) retlw 0xFF ; 0x01 (unknown) retlw 0xFF ; 0x02 (unknown) retlw 0xFF ; 0x03 (unknown) retlw 0xFF ; 0x04 (unknown) retlw 0xFF ; 0x05 (unknown) retlw 0xFF ; 0x06 (unknown) retlw 0xFF ; 0x07 (unknown) retlw 0xFF ; 0x08 (unknown) retlw 0xFF ; 0x09 (unknown) retlw 0xFF ; 0x0A (unknown) retlw 0xFF ; 0x0B (unknown) retlw 0xFF ; 0x0C (unknown) retlw 0xFF ; 0x0D (unknown) retlw 0xFF ; 0x0E (unknown) retlw 0xFF ; 0x0F (unknown) retlw 0xFF ; 0x10 (unknown) retlw 0xFF ; 0x11 (unknown) retlw 0xFF ; 0x12 (unknown) retlw 0xFF ; 0x13 (unknown) retlw (CurrentPlayer)&0xFF ; 0x14 (unknown) retlw 0xFF ; 0x15 (unknown) retlw 0xFF ; 0x16 (unknown) retlw 0xFF ; 0x17 (unknown) retlw 0xFF ; 0x18 (unknown) retlw 0xFF ; 0x19 (unknown) retlw 0xFF ; 0x1A (unknown) retlw 0xFF ; 0x1B (unknown) retlw 0xFF ; 0x1C (unknown) retlw 0xFF ; 0x1D (unknown) retlw 0xFF ; 0x1E (unknown) retlw 0xFF ; 0x1F (unknown) retlw 0xFF ; 0x20 (unknown) retlw 0xFF ; 0x21 (unknown) retlw 0xFF ; 0x22 (unknown) retlw 0xFF ; 0x23 (unknown) retlw 0xFF ; 0x24 (unknown) retlw 0xFF ; 0x25 (unknown) retlw 0xFF ; 0x26 (unknown) retlw 0xFF ; 0x27 (unknown) retlw 0xFF ; 0x28 (unknown) retlw 0xFF ; 0x29 (unknown) retlw 0xFF ; 0x2A (unknown) retlw 0xFF ; 0x2B (unknown) retlw 0xFF ; 0x2C (unknown) retlw 0xFF ; 0x2D (unknown) retlw 0xFF ; 0x2E (unknown) retlw 0xFF ; 0x2F (unknown) retlw 0xFF ; 0x30 (unknown) retlw 0xFF ; 0x31 (unknown) retlw 0xFF ; 0x32 (unknown) retlw 0xFF ; 0x33 (unknown) retlw 0xFF ; 0x34 (unknown) retlw 0xFF ; 0x35 (unknown) retlw 0xFF ; 0x36 (unknown) retlw 0xFF ; 0x37 (unknown) retlw 0xFF ; 0x38 (unknown) retlw 0xFF ; 0x39 (unknown) retlw 0xFF ; 0x3A (unknown) retlw 0xFF ; 0x3B (unknown) retlw 0xFF ; 0x3C (unknown) retlw 0xFF ; 0x3D (unknown) retlw 0xFF ; 0x3E (unknown) retlw 0xFF ; 0x3F (unknown) retlw 0xFF ; 0x40 (unknown) retlw 0xFF ; 0x41 (unknown) retlw 0xFF ; 0x42 (unknown) retlw 0xFF ; 0x43 (unknown) retlw 0xFF ; 0x44 (unknown) retlw 0xFF ; 0x45 (unknown) retlw 0xFF ; 0x46 (unknown) retlw 0xFF ; 0x47 (unknown) retlw 0xFF ; 0x48 (unknown) retlw 0xFF ; 0x49 (unknown) retlw 0xFF ; 0x4A (unknown) retlw 0xFF ; 0x4B (unknown) retlw 0xFF ; 0x4C (unknown) retlw 0xFF ; 0x4D (unknown) retlw 0xFF ; 0x4E (unknown) retlw 0xFF ; 0x4F (unknown) retlw 0xFF ; 0x50 (unknown) retlw 0xFF ; 0x51 (unknown) retlw 0xFF ; 0x52 (unknown) retlw 0xFF ; 0x53 (unknown) retlw 0xFF ; 0x54 (unknown) retlw 0xFF ; 0x55 (unknown) retlw 0xFF ; 0x56 (unknown) retlw 0xFF ; 0x57 (unknown) retlw 0xFF ; 0x58 (unknown) retlw 0xFF ; 0x59 (unknown) retlw 0xFF ; 0x5A (unknown) retlw 0xFF ; 0x5B (unknown) retlw 0xFF ; 0x5C (unknown) retlw 0xFF ; 0x5D (unknown) retlw 0xFF ; 0x5E (unknown) retlw 0xFF ; 0x5F (unknown) retlw 0xFF ; 0x60 (unknown) retlw 0xFF ; 0x61 (unknown) retlw 0xFF ; 0x62 (unknown) retlw 0xFF ; 0x63 (unknown) retlw 0xFF ; 0x64 (unknown) retlw 0xFF ; 0x65 (unknown) retlw 0xFF ; 0x66 (unknown) retlw 0xFF ; 0x67 (unknown) retlw 0xFF ; 0x68 (unknown) retlw 0xFF ; 0x69 (unknown) retlw 0xFF ; 0x6A (unknown) retlw 0xFF ; 0x6B (unknown) retlw 0xFF ; 0x6C (unknown) retlw 0xFF ; 0x6D (unknown) retlw 0xFF ; 0x6E (unknown) retlw 0xFF ; 0x6F (unknown) retlw 0xFF ; 0x70 (unknown) retlw 0xFF ; 0x71 (unknown) retlw 0xFF ; 0x72 (unknown) retlw 0xFF ; 0x73 (unknown) retlw 0xFF ; 0x74 (unknown) retlw 0xFF ; 0x75 (unknown) retlw 0xFF ; 0x76 (unknown) retlw 0xFF ; 0x77 (unknown) retlw 0xFF ; 0x78 (unknown) retlw 0xFF ; 0x79 (unknown) retlw 0xFF ; 0x7A (unknown) retlw 0xFF ; 0x7B (unknown) retlw 0xFF ; 0x7C (unknown) retlw 0xFF ; 0x7D (unknown) retlw 0xFF ; 0x7E (unknown) retlw 0xFF ; 0x7F (unknown) #else retlw 0xFF #endif org 0x4F4 RAM1Handler ; This routine is broken for addresses greater than 128 or so! movlw 0x5 ; set correct page so computed movwf PCLATH ; goto works correctly bcf INTCON3, INT1IF ; clear the interrupt condition rlncf RAMAddrL, w ; multiply offset by 2 since instructions andlw 0xFE ; are 2 bytes long. mask out LSb addwf PCL, F ; jump ; addr function retlw 0xFF ; 0x00 (unknown) retlw 0xFF ; 0x01 (unknown) retlw 0xFF ; 0x02 (unknown) retlw 0xFF ; 0x03 (unknown) retlw 0xFF ; 0x04 (unknown) retlw 0xFF ; 0x05 (unknown) retlw 0xFF ; 0x06 (unknown) retlw 0xFF ; 0x07 (unknown) retlw 0xFF ; 0x08 (unknown) retlw 0xFF ; 0x09 (unknown) retlw 0xFF ; 0x0A (unknown) retlw 0xFF ; 0x0B (unknown) retlw 0xFF ; 0x0C (unknown) retlw 0xFF ; 0x0D (unknown) retlw 0xFF ; 0x0E (unknown) retlw 0xFF ; 0x0F (unknown) retlw 0xFF ; 0x10 (unknown) retlw 0xFF ; 0x11 (unknown) retlw 0xFF ; 0x12 (unknown) retlw 0xFF ; 0x13 (unknown) retlw 0xFF ; 0x14 (unknown) retlw 0xFF ; 0x15 (unknown) retlw 0xFF ; 0x16 (unknown) retlw 0xFF ; 0x17 (unknown) retlw 0xFF ; 0x18 (unknown) retlw 0xFF ; 0x19 (unknown) retlw 0xFF ; 0x1A (unknown) retlw 0xFF ; 0x1B (unknown) retlw 0xFF ; 0x1C (unknown) retlw 0xFF ; 0x1D (unknown) retlw (Score1+5)&0xFF ; 0x1E Score 1 Nybble 5 retlw (Score1+4)&0xFF ; 0x1F Score 1 Nybble 4 retlw (Score1+3)&0xFF ; 0x20 Score 1 Nybble 3 retlw (Score1+2)&0xFF ; 0x21 Score 1 Nybble 2 retlw (Score1+1)&0xFF ; 0x22 Score 1 Nybble 1 retlw (Score1+0)&0xFF ; 0x23 Score 1 Nybble 0 retlw (Score2+5)&0xFF ; 0x24 Score 2 Nybble 5 retlw (Score2+4)&0xFF ; 0x25 Score 2 Nybble 4 retlw (Score2+3)&0xFF ; 0x26 Score 2 Nybble 3 retlw (Score2+2)&0xFF ; 0x27 Score 2 Nybble 2 retlw (Score2+1)&0xFF ; 0x28 Score 2 Nybble 1 retlw (Score2+0)&0xFF ; 0x29 Score 2 Nybble 0 retlw (Score3+5)&0xFF ; 0x2A Score 3 Nybble 5 retlw (Score3+4)&0xFF ; 0x2B Score 3 Nybble 4 retlw (Score3+3)&0xFF ; 0x2C Score 3 Nybble 3 retlw (Score3+2)&0xFF ; 0x2D Score 3 Nybble 2 retlw (Score3+1)&0xFF ; 0x2E Score 3 Nybble 1 retlw (Score3+0)&0xFF ; 0x2F Score 3 Nybble 0 retlw (Score4+5)&0xFF ; 0x30 Score 4 Nybble 5 retlw (Score4+4)&0xFF ; 0x31 Score 4 Nybble 4 retlw (Score4+3)&0xFF ; 0x32 Score 4 Nybble 3 retlw (Score4+2)&0xFF ; 0x33 Score 4 Nybble 2 retlw (Score4+1)&0xFF ; 0x34 Score 4 Nybble 1 retlw (Score4+0)&0xFF ; 0x35 Score 4 Nybble 0 retlw (CurrentBall)&0xFF ; 0x36 Current Ball retlw 0xFF ; 0x37 (unknown) retlw 0xFF ; 0x38 (unknown) retlw 0xFF ; 0x39 (unknown) retlw 0xFF ; 0x3A (unknown) retlw 0xFF ; 0x3B (unknown) retlw 0xFF ; 0x3C (unknown) retlw 0xFF ; 0x3D (unknown) retlw 0xFF ; 0x3E (unknown) retlw 0xFF ; 0x3F (unknown) retlw 0xFF ; 0x40 (unknown) retlw 0xFF ; 0x41 (unknown) retlw 0xFF ; 0x42 (unknown) retlw 0xFF ; 0x43 (unknown) retlw 0xFF ; 0x44 (unknown) retlw 0xFF ; 0x45 (unknown) retlw 0xFF ; 0x46 (unknown) retlw 0xFF ; 0x47 (unknown) retlw 0xFF ; 0x48 (unknown) retlw 0xFF ; 0x49 (unknown) retlw 0xFF ; 0x4A (unknown) retlw 0xFF ; 0x4B (unknown) retlw 0xFF ; 0x4C (unknown) retlw 0xFF ; 0x4D (unknown) retlw 0xFF ; 0x4E (unknown) retlw 0xFF ; 0x4F (unknown) retlw 0xFF ; 0x50 (unknown) retlw 0xFF ; 0x51 (unknown) retlw 0xFF ; 0x52 (unknown) retlw 0xFF ; 0x53 (unknown) retlw 0xFF ; 0x54 (unknown) retlw 0xFF ; 0x55 (unknown) retlw 0xFF ; 0x56 (unknown) retlw 0xFF ; 0x57 (unknown) retlw 0xFF ; 0x58 (unknown) retlw 0xFF ; 0x59 (unknown) retlw 0xFF ; 0x5A (unknown) retlw 0xFF ; 0x5B (unknown) retlw 0xFF ; 0x5C (unknown) retlw 0xFF ; 0x5D (unknown) retlw 0xFF ; 0x5E (unknown) retlw 0xFF ; 0x5F (unknown) retlw 0xFF ; 0x60 (unknown) retlw 0xFF ; 0x61 (unknown) retlw 0xFF ; 0x62 (unknown) retlw 0xFF ; 0x63 (unknown) retlw 0xFF ; 0x64 (unknown) retlw 0xFF ; 0x65 (unknown) retlw 0xFF ; 0x66 (unknown) retlw 0xFF ; 0x67 (unknown) retlw 0xFF ; 0x68 (unknown) retlw 0xFF ; 0x69 (unknown) retlw 0xFF ; 0x6A (unknown) retlw 0xFF ; 0x6B (unknown) retlw 0xFF ; 0x6C (unknown) retlw 0xFF ; 0x6D (unknown) retlw 0xFF ; 0x6E (unknown) retlw 0xFF ; 0x6F (unknown) retlw 0xFF ; 0x70 (unknown) retlw 0xFF ; 0x71 (unknown) retlw 0xFF ; 0x72 (unknown) retlw 0xFF ; 0x73 (unknown) retlw 0xFF ; 0x74 (unknown) retlw 0xFF ; 0x75 (unknown) retlw 0xFF ; 0x76 (unknown) retlw 0xFF ; 0x77 (unknown) retlw 0xFF ; 0x78 (unknown) retlw 0xFF ; 0x79 (unknown) retlw 0xFF ; 0x7A (unknown) retlw 0xFF ; 0x7B (unknown) retlw 0xFF ; 0x7C (unknown) retlw 0xFF ; 0x7D (unknown) retlw 0xFF ; 0x7E (unknown) retlw 0xFF ; 0x7F (unknown) END