;********************************************************************** ; ; Enhanced GBA multiboot smart cable ; ; Revision History ; ------------------------------------------------------------- ; First release, Version 0.1.0, Jan 1, 2003 (Happy new year!) ; Bug fix, Version 0.1.1, May 5, 2003 (Fix fail to start bug) ; ; - Compiled by Tuna (by hand... ) ; - Origional C code from godmaze.org ; - You can use this code for watever you wish, but I take no ; responsability for any injury, damage to property or copywrite ; breaches. ; ; - 100% compatable to the software from godsmaze.org ; - Extended function includes: ; - EEprom read/write ; - External FLASH read/write ; - 10 bits ADC ; - Debug serial port output, 57600 baud ; - The external dataFLASH are from Atmel, the code is tested ; with the 2-mbit device (AT45DB021B) ; ; Connection: ; Device tested: PIC16F872 ; Device that might work: PIC16F87X (X = 3, 4, 6, 7) ; PortB 0: Printer D0 (pin 2) through 500Ohm resistor ; PortB 1: Printer D1 (pin 3) through 500Ohm resistor ; PortB 2: Printer D2 (pin 4) through 500Ohm resistor ; PortB 3: Printer D3 (pin 5) through 500Ohm resistor ; PortB 4: Printer (pin 11) through 100Ohm resistor ; PortB 5: Printer (pin 16) through 2.2kOhm resistor ; PortB 6: Printer (pin 17) through 2.2kOhm resistor ; PortB 7: Debug port, connect to RX of serial port ; though MAX232 (Optional) ; - Pulling the Debug port to Vcc though 10Kohm resistor start the ; processor in slave mode, waiting command from computer. ; - Pulling the Debug port to GND though 10Kohm resistor start the ; processor in mastor mode, sending the stored program to GBA ; ; PortA 0: Analog port, accept any analog input (Optional) ; PortA 1: GBA Pin 3 ; PortA 2: GBA Pin 2 ; PortA 3: Analog V+ reference port, can not be used when ; communicating with GBA. (Optional) ; PortA 4: GBA Pin 5 ; PortA 5: GBA Pin 4 ; ; GBA Pin 1 - Vcc (3.3V) connected to the Vcc of the entire circuit ; The entire system power is supplied by GBA ; GBA Pin 6 - System ground. (GND) ; ; PortC 3: to /CS pin of the dataFLASH ; PortC 4: to /SO pin of the dataFLASH (Data Input) ; PortC 5: to /SI pin of the dataFLASH (Data Output) ; PortC 6: to /CLK pin of the dataFLASH (Serial Clock) ; ; PortC 0,1,2,7 Not used, maybe someone will find a use for them ; System clock: 3.6864Mhz, same as the design from godsmaze.org ; ;********************************************************************** list p=16F872 ; list directive to define processor include ; processor specific variable definitions __CONFIG _CP_OFF & _WDT_OFF & _PWRTE_ON & _XT_OSC & _LVP_OFF & _BODEN_OFF ;********************************************************************** #define _DEBUG PORTB,7 #define _CMD PORTB,6 #define _HSi PORTB,5 #define _HSo PORTB,4 ; Reserv PORTA,0 and PORTA,1 for analog signals #define _SO PORTA,1 #define _SI PORTA,2 #define _SC PORTA,4 #define _SD PORTA,5 #define _CS PORTC,6 ;********************************************************************** Variable Command EQU 0x20 Nibble0 EQU 0x21 Nibble1 EQU 0x22 Nibble2 EQU 0x23 Nibble3 EQU 0x24 _Data EQU 0x25 Delay EQU 0x26 sendBy EQU 0x27 eeAddr EQU 0x28 Loop EQU 0x29 DF_ADDR_H EQU 0x2A DF_ADDR_L EQU 0x2B Loop2 EQU 0x2C WordH EQU 0x22 ; Overlap Nibble1 WordL EQU 0x24 ; Overlap Nibble3 pAddr EQU 0x2D Wtemp EQU 0x2E Var1L EQU 0x30 LengthH EQU 0x31 LengthM EQU 0x32 LengthL EQU 0x33 Var8L EQU 0x34 VarCH EQU 0x35 VarCL EQU 0x36 PosH EQU 0x37 PosM EQU 0x38 PosL EQU 0x39 CRC32H EQU 0x3b CRC32L EQU 0x3c Var30 EQU 0x3f SeedA EQU 0x40 SeedB EQU 0x41 SeedC EQU 0x42 SeedD EQU 0x43 TempA EQU 0x44 TempB EQU 0x45 TempC EQU 0x46 TempD EQU 0x47 DataH EQU 0x48 DataL EQU 0x49 DebugD EQU 0x4a DebugL EQU 0x4b ;********************************************************************** ORG 0x000 ; processor reset vector goto main ; go to beginning of program ORG 0x004 ; interrupt vector location ;********************************************************************** Main main: clrf INTCON clrf PORTB bsf STATUS, RP0 movlw b'10101000' movwf OPTION_REG clrf PIE1 clrf PIE2 movlw b'10001110' ; Analog channel setup movwf ADCON1 bsf PORTA, 0 ; Analog input bsf PORTA, 3 ; Analog input ; GBA signals bcf _SO ; O bsf _SI ; I bsf _SD ; I bsf _SC ; I bsf _HSi ; I bsf _CMD ; I bcf _HSo ; O bsf _DEBUG ; I Use as mode select when starting bcf STATUS, RP0 bcf _DEBUG ; Debug is inactive low movlw b'01000000' ; Analog converter off, Fosc/8 as clock movwf ADCON0 bsf _SO ; Idle high ;************ DEBUG here! ;goto chip_id ;************ END DEBUG JP PT ;************************************************************ Receive a command from computer get_cmd: bsf STATUS, RP0 bcf _DEBUG ; Return to output bcf STATUS, RP0 movlw '1' call Send_Debug ; Stage 1 movlw 's' call Send_Debug ; Stage 1 movlw ':' call Send_Debug ; Stage 1 bsf _HSo bsf STATUS, RP0 movlw 0x0f iorwf TRISB, F ; Set portB[0:3] to input bsf _DEBUG ; Because the send MB routine set the bcf STATUS, RP0 ; Debug to output, it has to be set to ; input again. 5/5/03 wait_cmd: btfss _DEBUG goto send_mb_image btfss _CMD goto wait_cmd movfw PORTB andlw 0x0f movwf Command bcf _HSo wait_cmd_done: btfss _DEBUG goto send_mb_image btfsc _CMD goto wait_cmd_done bsf STATUS, RP0 bcf _DEBUG ; Return to output bcf STATUS, RP0 movlw '3' call Send_Debug ; Stage 3 movlw 'r' call Send_Debug ; Stage 3 movlw ':' call Send_Debug ; Stage 3 movfw Command addwf PCL, f goto get_cmd ; CMD 0 - Reserved goto cmd_xfer ; CMD 1 - Transfer goto chip_id ; CMD 2 - Standard ID goto get_cmd ; CMD 3 - Reserved goto get_cmd ; CMD 4 - Reserved goto get_cmd ; CMD 5 - Reserved goto get_cmd ; CMD 6 - Reserved goto get_cmd ; CMD 7 - Reserved goto ee_read ; CMD 8 - EEprom read goto ee_write ; CMD 9 - EEprom write goto spi_read ; CMD A - SPI read goto spi_write ; CMD B - SPI write goto adc_read ; CMD C - ADC read goto get_cmd ; CMD D - Reserved goto get_cmd ; CMD E - Reserved goto EXT_id ; CMD F - Extended ID goto get_cmd ;************************************************************ ; CMD 0 - Transfer ; cmd_xfer: bsf STATUS,RP0 bcf _SO ; Output bsf _SI ; Input bsf _SD ; Input bsf _SC ; Input bcf STATUS,RP0 call get_nibbles ; Get a word from the computer waitbh: btfss _SC goto waitbh btfss _SD goto waitbh bsf STATUS,RP0 bcf _SD ; Output bcf _SC ; Output bcf STATUS,RP0 call send_bits ; send 16bits to GBA call recv_bits ; receive 16bits from GBA call put_nibbles ; put the 16bits to the computer goto cmd_xfer ; Loop forever goto get_cmd ; Waste catcher ;************************************************************ ; CMD 1 - Chip ID - Return 0x636100 ; chip_id: bsf STATUS,RP0 movfw TRISB andlw 0xf0 ;PORTB[0:3] AS OUTPUTS movwf TRISB bcf STATUS,RP0 bsf _DEBUG ; Inactive high movlw 0x06 call put_nibble_wH movlw 0x03 call put_nibble_wL movlw 0x06 call put_nibble_wH movlw 0x01 call put_nibble_wL movlw 0x00 call put_nibble_wH movlw 0x00 call put_nibble_wL movlw 'a' call Send_Debug goto get_cmd ;************************************************************ ; CMD 8 - EEProm data read ; ee_read: bsf STATUS, RP0 movlw 0xf0 andwf TRISB, F ; PORTB[0:3] AS OUTPUTS bcf STATUS, RP0 movlw 0x40 movwf Loop movlw 0x00 movwf eeAddr read_loop: bsf STATUS, RP1 ; Bank 2 movfw eeAddr movwf EEADR bsf STATUS, RP0 ; Bank 3 bcf EECON1, EEPGD ; Data bsf EECON1, RD ; Read bcf STATUS, RP0 ; Bank 2 movfw EEDATA bcf STATUS, RP1 ; Bank 0 call par_send_byte incf eeAddr, F decfsz Loop, F goto read_loop goto get_cmd ;************************************************************ ; CMD A - EEProm data write ; ee_write: call par_read_byte ; Read address first movwf eeAddr call par_read_byte ; Read data next movwf _Data bsf STATUS, RP1 ; Bank 2 movfw eeAddr movwf EEADR ; Address movfw _Data movwf EEDATA ; Data bsf STATUS, RP0 ; Bank 3 bcf EECON1, EEPGD bsf EECON1, WREN bcf INTCON, GIE movlw 0x55 movwf EECON2 movlw 0xAA movwf EECON2 bsf EECON1, WR ; Start writing ;bsf INTCON, GIE ; Don't need it at this point bcf EECON1, WREN bcf STATUS, RP0 bcf STATUS, RP1 ; Bank 0 Write_loop: btfss PIR2, EEIF goto Write_loop bcf PIR2, EEIF goto get_cmd ;************************************************************ ; CMD A - SPI DataFLASH read ; Receive a 2 byte block address ; Always send out a block of data, for 2Mbit ; chip, it is 264 bytes spi_read: bsf STATUS, RP0 bcf PORTC, 3 ; SCK set to output bsf PORTC, 4 ; SDI set to input bcf PORTC, 5 ; SDO set to output bcf _CS ; CS set to output bsf SSPSTAT, CKE ; DataFLASH Sample on falling cycle bcf SSPSTAT, SMP ; PIC sample on falling cycle bcf STATUS, RP0 movlw b'00100000' ; SPI master Fosc/4 movwf SSPCON ; SPI clock Idle low bsf _CS ; CS idle high call par_read_byte ; Read address first movwf DF_ADDR_H call par_read_byte ; Read data next movwf DF_ADDR_L ;*********************** Finished setting up SPI port bsf STATUS, RP0 movlw 0xf0 andwf TRISB, F ; PORTB[0:3] AS OUTPUTS bcf STATUS, RP0 call read_df_setup movlw 2 movwf Loop2 movlw 8 movwf Loop SPI_read_loop2: call Read_Next call par_send_byte decfsz Loop, F goto SPI_read_loop2 decfsz Loop2, F goto SPI_read_loop2 bsf _CS goto get_cmd ;************************************************************ ; CMD B - SPI DataFLASH write spi_write: bsf STATUS, RP0 bcf PORTC, 3 ; SCK set to output bsf PORTC, 4 ; SDI set to input bcf PORTC, 5 ; SDO set to output bcf _CS ; CS set to output bsf SSPSTAT, CKE ; DataFLASH Sample on falling cycle bcf SSPSTAT, SMP ; PIC sample on falling cycle bcf STATUS, RP0 movlw b'00100000' ; SPI master Fosc/4 movwf SSPCON ; SPI clock Idle low bsf _CS ; CS idle high call par_read_byte ; Read address first movwf DF_ADDR_H call par_read_byte ; Read data next movwf DF_ADDR_L spi_test: ;*********************** Finished setting up SPI port bsf _DEBUG bcf _DEBUG bcf _CS movlw 0x82 ; Buffer 1 write movwf SSPBUF bcf STATUS, C ; 1 rlf DF_ADDR_L, F ; 2 rlf DF_ADDR_H, F ; 3 nop ; 4 nop ; 5 nop ; 6 nop ; 7 nop ; 8 nop ; 9 movfw DF_ADDR_H ; 10 movwf SSPBUF ; High Address nop nop nop nop nop nop nop nop nop ; 9 movfw DF_ADDR_L ; 10 movwf SSPBUF ; Low Address nop nop nop nop nop nop nop nop movlw 0 ; 6 call Send_SPI_d ; Empty address, no addr within page nop nop movlw 2 movwf Loop2 movlw 8 movwf Loop SPI_write_loop: call par_read_byte movwf SSPBUF ; Send the data out decfsz Loop, F goto SPI_write_loop decfsz Loop2, F goto SPI_write_loop nop nop nop nop nop nop ; Last byte delay bsf _CS bcf _HSo ; Set _HSo low to indicate busy SPI_write_wait: bsf _CS bcf _CS movlw 0xd7 call Send_SPI_d nop movlw 0 call Send_SPI_d ; Read status nop nop nop nop movfw SSPBUF andlw 0x80 ; 7th bit is BUSY/READY btfss STATUS, Z goto SPI_write_wait bsf _HSo ; High indicate ready, same as get_cmd Deadlock: bsf _CS goto Deadlock ; Stall the process, goto get_cmd ; must use a hard reset to exit ; Required for the computer to sense ; HSo correctly ;************************************************************ ; CMD C - ADC read ; adc_read: bsf STATUS, RP0 movlw 0xf0 andwf TRISB, F ; PORTB[0:3] AS OUTPUTS bcf STATUS, RP0 movlw 0xc7 andwf ADCON0, F ; Select channel 0 bsf ADCON0, ADON call long_delay ; Wait at least 20uS for 5V bsf ADCON0, GO Wait_ADC: btfsc ADCON0, GO goto Wait_ADC movf ADRESH, W call par_send_byte bsf STATUS, RP0 movf ADRESL, W bcf STATUS, RP0 call par_send_byte bcf ADCON0, ADON ; ADC off goto get_cmd ;************************************************************ ; CMD F - Extended Chip ID - Return 0x0001 ; EXT_id: bsf STATUS,RP0 movfw TRISB andlw 0xf0 ;PORTB(0-3) AS OUTPUTS movwf TRISB bcf STATUS,RP0 movlw 0x0 call put_nibble_wH movlw 0x0 call put_nibble_wL movlw 0x0 call put_nibble_wH movlw 0x1 call put_nibble_wL goto get_cmd ;************************************************************ ; Boot up mode: send MB image from FLASH to GBA ; send_mb_image: bsf STATUS, RP0 ; Setup DataFLASH first bcf PORTC, 3 ; SCK set to output bsf PORTC, 4 ; SDI set to input bcf PORTC, 5 ; SDO set to output bcf _CS ; CS set to output bsf SSPSTAT, CKE ; DataFLASH Sample on falling cycle bcf SSPSTAT, SMP ; PIC sample on falling cycle bcf _DEBUG ; Return to output bcf STATUS, RP0 movlw b'00100000' ; SPI master Fosc/4 movwf SSPCON ; SPI clock Idle low bsf _CS ; CS idle high bsf _DEBUG ; Inactive high Use as serial out call long_delay movlw 'S' call Send_Debug ; Mark Starting point movlw ':' call Send_Debug ; Again... movlw 0x62 ; Send 0x6202, Attention movwf WordH movlw 0x02 movwf WordL ; Get GBA attention call xfer_word ; Check if returning 0x7202 movf WordH, W call Send_Debug movf WordL, W call Send_Debug ; Send out debug movlw 0x72 xorwf WordH, F btfss STATUS, Z goto get_cmd ; Error, try again movlw 0x02 xorwf WordL, F btfss STATUS, Z goto get_cmd ; Error, try again movlw 0x61 ; Send 0x6100, header data movwf WordH clrf WordL call xfer_word movlw 0x60 movwf Loop ; Send 60 words of data clrf DF_ADDR_H clrf DF_ADDR_L ; Start from 1st page call read_df_setup nop nop nop nop ; Wait for the first byte to be ready nop nop load_loop1: call Read_Next movwf WordL ;call Send_Debug ; Also debug call Read_Next movwf WordH ;call Send_Debug ; Send out debug call xfer_word decfsz Loop, F goto load_loop1 movlw 0x62 ; Sending command movwf WordH movlw 0x02 movwf WordL call xfer_word ;movf WordH, W ;call Send_Debug ;movf WordL, W ;call Send_Debug ; Send out debug movlw 0x63 ; Send encryption value movwf WordH movlw 0xc1 movwf WordL call xfer_word ;movf WordH, W ;call Send_Debug ;movf WordL, W ;call Send_Debug ; Send out debug movlw 0x63 ; Get encryption value movwf WordH movlw 0xc1 movwf WordL call xfer_word ;movf WordH, W ;call Send_Debug ;movf WordL, W ;call Send_Debug ; Send out debug movf WordL, W movwf SeedC ; Seed of encryption movlw 0xc1 movwf SeedD movlw 0xff movwf SeedB ; Setup the Encryption seed with 0xFFFFxxC1 movwf SeedA ; Note, xx is given by GBA movf WordL, W addlw 0x0F movwf Var1L movlw 0x64 movwf WordH movf Var1L, W movwf WordL call xfer_word ; Send back Var1L | 0x6400 ;*********************** Read the length of the program bsf STATUS, RP1 ; Bank 2 movlw 0x00 movwf EEADR bsf STATUS, RP0 ; Bank 3 bcf EECON1, EEPGD ; Data bsf EECON1, RD ; Read bcf STATUS, RP0 ; Bank 2 movlw LengthH movwf FSR movf EEDATA, W ; LengthH movwf INDF incf EEADR, F bsf STATUS, RP0 ; Bank 3 bcf EECON1, EEPGD ; Data bsf EECON1, RD ; Read bcf STATUS, RP0 ; Bank 2 incf FSR, F movf EEDATA, W ; LengthM movwf INDF incf EEADR, F bsf STATUS, RP0 ; Bank 3 bcf EECON1, EEPGD ; Data bsf EECON1, RD ; Read bcf STATUS, RP0 ; Bank 2 incf FSR, F movf EEDATA, W ; LengthL movwf INDF bcf STATUS, RP1 ; Bank 0 movf LengthL, W movwf TempD movf LengthM, W movwf TempC movf LengthH, W movwf TempB movlw 0xc0 subwf TempD, F btfsc STATUS, C goto SkipDecCarry movf TempC, F btfsc STATUS, Z decf TempB, F decf TempC, F ; Length - 0xc0 SkipDecCarry: bcf STATUS, C rrf TempB, F rrf TempC, F rrf TempD, F bcf STATUS, C rrf TempB, F rrf TempC, F rrf TempD, F ; Length >> 2 movlw 0x34 subwf TempD, W movwf WordL movf TempC, W btfss STATUS, C decf TempC, W movwf WordH ; Length - 0x34 call xfer_word movf WordL, W movwf Var8L movlw 0xff movwf VarCH movlw 0xf8 movwf VarCL movlw 0xc0 movwf PosL clrf PosM clrf PosH ;---------------------------------------------------- Send_data_loop: call Read_Next movwf DataL movwf CRC32L call Read_Next movwf DataH movwf CRC32H ;movf DataL, W ;call Send_Debug ;movf DataH, W ;call Send_Debug ; Send out debug call Do_CRC ;movf SeedA, W ;call Send_Debug ;movf SeedB, W ;call Send_Debug ; Send out debug ;movf SeedC, W ;call Send_Debug ;movf SeedD, W ;call Send_Debug ; Send out debug btfsc PosL, 1 goto Skip_Encrypt ;Compute Encryption seed, which is ; (seed * 0x6F64573) + 1 bcf STATUS, C rlf SeedD, W movwf TempD rlf SeedC, W movwf TempC rlf SeedB, W movwf TempB rlf SeedA, W movwf TempA call AddM ; Bit 0 and 1 call Shift call Shift call Shift call AddM ; Bit 4 call Shift call AddM ; Bit 5 call Shift call AddM ; Bit 6 call Shift call Shift call AddM1 ; Bit 8 call Shift call Shift call AddM1 ; Bit 10 call Shift call Shift call Shift call AddM1 ; Bit 13 call Shift call AddM1 ; Bit 14 call Shift call Shift call Shift call Shift call AddM2 ; Bit 18 call Shift call Shift call Shift call AddM2 ; Bit 21 call Shift call AddM2 ; Bit 22 call Shift call Shift call AddM2 ; Bit 24 call Shift call AddM3 ; Bit 25 call Shift call AddM3 ; Bit 26 call Shift call AddM3 ; Bit 27 call Shift call Shift call AddM3 ; Bit 29 call Shift call AddM3 ; Bit 30 incf SeedD, F btfsc STATUS, Z incf SeedC, F btfsc STATUS, Z incf SeedB, F btfsc STATUS, Z incf SeedA, F ; Increase Seed by 1 comf PosL, W movwf WordL comf PosM, W movwf WordH comf PosH, W ; Use temp B & A for the client_pos movwf TempB ; of next xfer movlw 0xfd ; ~0x20 movwf TempA incf WordL, F btfsc STATUS, Z incf WordH, F btfsc STATUS, Z incf TempB, F btfsc STATUS, Z incf TempA, F ; ~client_pos+1 movf SeedD, W xorwf DataL, W xorlw 0x6f xorwf WordL, F movf SeedC, W xorwf DataH, W xorlw 0x64 xorwf WordH, F goto Send_data_16 Skip_Encrypt: movf TempB, W xorwf SeedB, W xorwf DataL, W xorlw 0x65 movwf WordL movf TempA, W xorwf SeedA, W xorwf DataH, W xorlw 0x64 movwf WordH Send_data_16: call xfer_word ; Send out the computed data movlw 0x02 addwf PosL, F ; client_pos += 2 btfsc STATUS, C incf PosM, F btfsc STATUS, Z incf PosH, F movf PosL, W xorwf LengthL, W btfss STATUS, Z goto Send_data_loop movf PosM, W xorwf LengthM, W btfss STATUS, Z goto Send_data_loop movf PosH, W xorwf LengthH, W btfss STATUS, Z goto Send_data_loop movlw 'D' call Send_Debug movlw ':' call Send_Debug ; Send out debug Wait_for_ack: movlw 0x65 movwf WordL clrf WordH call xfer_word ; End of transfer movf WordH, W call Send_Debug movf WordL, W call Send_Debug ; Send out debug movlw 0x75 xorwf WordL, W btfss STATUS, Z goto Wait_for_ack ; Wait for GBA to ack movlw 0x66 movwf WordL clrf WordH call xfer_word movf VarCH, W call Send_Debug movf VarCL, W call Send_Debug ; Send out debug movf Var8L, W movwf CRC32H movf Var1L, W movwf CRC32L call Do_CRC movlw 0xff movwf CRC32H movwf CRC32L call Do_CRC movf VarCL, W movwf WordL movf VarCH, W movwf WordH call xfer_word ; Send CRC out movf WordH, W call Send_Debug movf WordL, W call Send_Debug ; Send out debug movf VarCH, W call Send_Debug movf VarCL, W call Send_Debug ; Send out debug movf Var8L, W ; Final CRC value for debug call Send_Debug movf Var1L, W call Send_Debug ; Send out debug goto get_cmd Shift: bcf STATUS, C rlf TempD, F rlf TempC, F rlf TempB, F rlf TempA, F return AddM: movf TempD, W addwf SeedD, F bcf STATUS, Z ; If incf is not executed, btfsc STATUS, C ; Make sure carry does not goes on incf SeedC, F btfsc STATUS, Z incf SeedB, F btfsc STATUS, Z incf SeedA, F ; Byte D AddM1: movf TempC, W addwf SeedC, F bcf STATUS, Z btfsc STATUS, C incf SeedB, F btfsc STATUS, Z incf SeedA, F ; Byte C AddM2: movf TempB, W addwf SeedB, F btfsc STATUS, C incf SeedA, F AddM3: movf TempA, W addwf SeedA, F bcf STATUS, C return Do_CRC: ;******* Compute CRC movlw 0x10 movwf Loop ; Process 16 bits CRCLoop: movf VarCL, W xorwf CRC32L, W movwf Var30 ; var_30 = var_C^CRCTemp bcf STATUS, C rrf VarCH, F rrf VarCL, F ; Var_C = Var_C >> 1 bcf STATUS, C rrf CRC32H, F rrf CRC32L, F ; CRCTemp = CRCTemp >> 1 btfss Var30, 0 goto Skip_reset movlw 0xa5 xorwf VarCH, F movlw 0x17 xorwf VarCL, F Skip_reset: decfsz Loop, F goto CRCLoop return ;************************************************************ ; subroutine: send nibble bits to GBA, ; send_nibble_bits: btfss INDF,0 ;6 ;38 goto Set0_Lo ;7 ;39 bsf _SD ;8 ;40 (*) goto Set1 ;9 ;41 Set0_Lo: bcf _SD ;9 (**) <-- ;41 nop ;10 ;42 Set1: btfss INDF,1 ;11 <-- ;43 goto Set1_Lo ;12 ;44 nop ;13 ;45 nop ;14 ;46 nop ;15 ;47 bsf _SD ;16 (*) ;48 goto Set2 ;17 ;49 Set1_Lo: nop ;14 <-- ;46 nop ;15 ;47 bcf _SD ;16 (*) ;48 nop ;17 nop ;18 Set2: btfss INDF,2 ;19 <-- goto Set2_Lo ;20 nop ;21 nop ;22 nop ;23 bsf _SD ;24 (*) ;56 goto Set3 ;25 Set2_Lo: nop ;22 <-- nop ;23 bcf _SD ;24 (*) ;56 nop ;25 nop ;26 Set3: btfss INDF,3 ;27 <-- goto Set3_Lo ;28 nop ;29 nop ;30 nop ;31 bsf _SD ;32 (*) ;64 return ;33 Set3_Lo: nop ;30 <-- nop ;31 bcf _SD ;32 (*) ;64 return ;33 ;************************************************************ ; subroutine: send a 16 bit word to GBA, stored in Nibble ; send_bits: movlw Nibble3 movwf FSR movfw PORTA andlw B'11001111' ; raise SC & SD (Active low) movwf PORTA ; SC- Clock, SD- Data nop nop nop nop nop ;3 -2 call send_nibble_bits ;4 decf FSR,f ;35 call send_nibble_bits ;36 decf FSR,f ;67 call send_nibble_bits ;68 decf FSR,f ;99 call send_nibble_bits ;100 ;131 nop ;(3) nop ;(4) keep the last bit nop ;(5) nop ;(6) nop ;(7) bsf _SD ;(8) STOP bit return ;************************************************************ ; subroutine: send and receive a 16 bit word to GBA, ; stored in Word xfer_word: bsf STATUS,RP0 bcf _SO ; Output bsf _SI ; Input bsf _SD ; Input bsf _SC ; Input bcf STATUS,RP0 swapf Nibble3, W ; [4:7] Word L movwf Nibble2 swapf Nibble1, W ; [8:11] Word H movwf Nibble0 waitbh_W: btfss _SC goto waitbh_W btfss _SD goto waitbh_W bsf STATUS,RP0 bcf _SD ; Output bcf _SC ; Output bcf STATUS,RP0 call send_bits ; send 16bits to GBA call recv_bits ; receive 16bits from GBA return ;************************************************************ ; subroutine: receive nibble bits, ; recv_nibble_bits: btfss _SD ;9 ;38 goto rSet0_Lo ;7 ;39 bsf INDF,0 ;8 ;40 (*) goto rSet1 ;9 ;41 rSet0_Lo: bcf INDF,0 ;9 (**) <-- ;41 nop ;10 ;42 rSet1: btfss _SD ;11 <-- ;43 goto rSet1_Lo ;12 ;44 nop ;13 ;45 nop ;14 ;46 nop ;15 ;47 bsf INDF,1 ;16 (*) ;48 goto rSet2 ;17 ;49 rSet1_Lo: nop ;14 <-- ;46 nop ;15 ;47 bcf INDF,1 ;16 (*) ;48 nop ;17 nop ;18 rSet2: btfss _SD ;19 <-- goto rSet2_Lo ;20 nop ;21 nop ;22 nop ;23 bsf INDF,2 ;24 (*) ;56 goto rSet3 ;25 rSet2_Lo: nop ;22 <-- nop ;23 bcf INDF,2 ;24 (*) ;56 nop ;25 nop ;26 rSet3: btfss _SD ;27 <-- goto rSet3_Lo ;28 nop ;29 nop ;30 nop ;31 bsf INDF,3 ;32 (*) ;64 return ;33 rSet3_Lo: nop ;30 <-- nop ;31 bcf INDF,3 ;32 (*) ;64 return ;33 ;************************************************************ ; subroutine: receive 16 bit word from GBA, stored in Nibble ; recv_bits: bsf STATUS,RP0 bsf _SD ;SD as input bcf STATUS,RP0 movlw Nibble3 movwf FSR bcf _SO ;ask for 16bits wait_for_start: btfsc _SD ;0 goto wait_for_start ;1 nop ;2 nop ;3 nop ;4 nop ;5 nop ;6 nop ;-------centering waveform ;P nop nop nop nop call recv_nibble_bits ;7 decf FSR,f call recv_nibble_bits decf FSR,f call recv_nibble_bits decf FSR,f call recv_nibble_bits movlw 0x0f ; Steal 5 cycle to use andwf Nibble0, F andwf Nibble1, F andwf Nibble2, F andwf Nibble3, F ; stop bit -5 swapf Nibble2, W ; Steal 4 more cycle to assemble the 16bit word iorwf Nibble3, F swapf Nibble0, W bsf _SO ; SO high as ACK iorwf Nibble1, F wait_ack: btfsc _SI goto wait_ack wait_nack btfss _SI goto wait_nack bsf _SC ;put _SC high ; EOT return ;************************************************************ ; subroutine: write a byte into parallel port, data in W par_send_byte: movwf sendBy swapf sendBy, W call put_nibble_wH movfw sendBy call put_nibble_wL return ;************************************************************ ; subroutine: read a byte from parallel port, place in W par_read_byte: call get_nibble_wH movwf sendBy call get_nibble_wL movlw 0x0f andwf _Data, F swapf sendBy, W andlw 0xf0 iorwf _Data, W return ;************************************************************ ; subroutine: Read from parallel port - 4 nibbles ; get_nibbles: bsf STATUS, RP0 movlw 0x0f ; PortB[0,3] as input iorwf TRISB, F bcf STATUS, RP0 call get_nibble_wH ; [15,12] movwf Nibble0 call get_nibble_wL ; [11, 8] movwf Nibble1 call get_nibble_wH ; [ 7, 4] movwf Nibble2 call get_nibble_wL ; [ 3, 0] movwf Nibble3 return ;************************************************************ ; subroutine: Write to parallel port - 4 nibbles ; put_nibbles: bsf STATUS, RP0 movlw 0xf0 andwf TRISB, F bcf STATUS, RP0 movfw Nibble0 call put_nibble_wH movfw Nibble1 call put_nibble_wL movfw Nibble2 call put_nibble_wH movfw Nibble3 call put_nibble_wL return ;************************************************************ ; subroutine: Get nibble from parallel port get_nibble_wH: btfss _HSi ; Wait for_HSi high goto get_nibble_wH Call GetBits bsf _HSo ; Set _HSo high return get_nibble_wL: btfsc _HSi ; Wait for _HSi low goto get_nibble_wL Call GetBits ; both W and _Data contain the data bcf _HSo ; set _HSo low return ;************************************************************ ; subroutine: Put nibble to parallel port put_nibble_wH: movwf _Data Call PutBits bsf _HSo pn_wH: btfss _HSi ;Wait for_HSi high goto pn_wH return put_nibble_wL: movwf _Data Call PutBits bcf _HSo pn_wL: btfsc _HSi ; Wait for_HSi low goto pn_wL return ;************************************************************ ; subroutine: Put/get data on/to the parallel port PutBits: movlw 0xf0 andwf PORTB, F movfw _Data andlw 0x0f iorwf PORTB, F return GetBits: movlw 0x0f andwf PORTB, W movwf _Data return ;************************************************************ ; subroutine: Delay, 255 cycles 830uS for 3.684Mhz clock long_delay: decfsz Delay, F goto long_delay return ;************************************************************ ; subroutine: Setup DataFlash for transfer at address ; specified in DF_ADDR. ; read_df_setup: bsf _CS ; Reset for next transfer bcf _CS movlw 0xd2 ; Main memory read 0xd2 movwf SSPBUF bcf STATUS, C ; 1 nop ; 2 nop ; 3 nop ; 4 nop ; 5 nop ; 6 nop ; 7 nop ; 8 rlf DF_ADDR_L, W ; 9 rlf DF_ADDR_H, W ; 10 movwf SSPBUF ; High Address nop nop nop nop nop nop nop bcf STATUS, C rlf DF_ADDR_L, W ; 9 nop ; 10 movwf SSPBUF ; Low Address nop nop nop nop nop nop nop nop movlw 0 ; 6 call Send_SPI_d ; Empty address, no addr within page nop nop call Send_SPI_d ; 4 don't care bytes nop nop call Send_SPI_d nop nop call Send_SPI_d nop nop call Send_SPI_d nop movf SSPBUF, W ; EMPTY out buffer call Send_SPI_d ; Init receving clrf pAddr ; Clear address pt return ;************************************************************ ; subroutine: Read the next byte from DataFLASH Read_Next: movf SSPBUF, W clrf SSPBUF ; Start the next transfer incf pAddr, F ; Point to next byte nop nop btfss STATUS, Z return ; Read the next page incf DF_ADDR_L, F btfsc STATUS, Z incf DF_ADDR_H, F movwf Wtemp call read_df_setup movf Wtemp, W return ;************************************************************ ; subroutine: SendSPI with delay Send_SPI_d: ; Call need 2 cycles movwf SSPBUF nop ; Total 9 cycles, leaving 1 cycle to load data nop ; nop nop return ; return need 2 cycles ;************************************************************ ; subroutine: SendSPI with delay, roughly 57600 baud Send_Debug: movwf DebugD movlw 0x08 movwf DebugL bcf _DEBUG ; Start bit, always low nop nop nop nop nop nop nop nop nop nop nop DebugLoop: rrf DebugD, F btfss STATUS, C goto BitSetLow nop bsf _DEBUG goto BitFinish BitSetLow: bcf _DEBUG nop nop BitFinish: nop nop nop nop nop nop decfsz DebugL, F goto DebugLoop nop nop nop nop nop bsf _DEBUG ; Stop bit, always high return ;************************************************************ End end