#include processor p16f630 ; --------------------------------------------------------------------- ; Code hacked to work with the super NT by Kevtris ; 073117 ; ; Changes: ; ; * = change ; ; ,-----_-----. ; +5V (27,58) [18] |1 14| GND (5,36) [9] ; CIC clk in (56) [7] |2 A5 A0 13| * Programming ; D4 out |3 A4 A1 12| * Programming ; /RST * |4 A3 A2 11| host reset out [10] ; Region in * |5 C5 C0 10| CIC data i/o 0 (55) [1] / {50/60Hz in} ; Disable Link Mode * |6 C4 C1 9| CIC data i/o 1 (24) [2] / {D4 in} ; Key Detect * |7 C3 C2 8| CIC slave reset out (25) [11] ; `-----------' ; ; (4) /RST: ; --------- ; Low = reset input ; ; (5) Region in: ; -------------- ; Low = 60Hz, High = 50Hz. This is set to the system's selected region. ; ; (6) Disable Link Mode: ; ---------------------- ; High = disable link mode. ; ; (7) Key Detect: ; --------------- ; High = Key in cart is connected and working ; ; (12, 13) Programming: ; --------------------- ; Used for programming so we don't use these for anything. ; ; The newer version of MPASM changes how banksel works. This really was a huge pain, because I didn't know it. ; Comparing the hex files between the zip and my assembled version revealed that the assembled version was quite a bit smaller. ; Further inspection shows that it has two instructions for every banksel, because the assembler was buggy. It was emitting a BCF for the upper ; bank bit on the status register, but the 630 does not have two bank bits, it only has one. The later version of the assembler fixes this., ; I have added NOPs to each banksel to fix this. ; ; Changes are denoted by *K*. ; ; This is a horrible hack. I have very little time to clean it up. I got it working properly for the project so that's what I am going with. It has been ; tested with NTSC games, PAL games, and SA-1 games. ; --------------------------------------------------------------------- ; feature enhanced auto region switching SNES CIC clone ; for PIC Microcontrollers (lock mode) ; ; Copyright (C) 2010 by Maximilian Rehkopf (ikari_01) ; This software is part of the sd2snes project. ; ; Based on reverse engineering work and disassembly by segher. ; http://hackmii.com/2010/01/the-weird-and-wonderful-cic/ ; ; This program is free software; you can redistribute it and/or modify ; it under the terms of the GNU General Public License as published by ; the Free Software Foundation; version 2 of the License only. ; ; This program is distributed in the hope that it will be useful, ; but WITHOUT ANY WARRANTY; without even the implied warranty of ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ; GNU General Public License for more details. ; ; You should have received a copy of the GNU General Public License ; along with this program; if not, write to the Free Software ; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ; ; --------------------------------------------------------------------- ; ; pin configuration: (cartridge slot pin) [original 18-pin SMD lock CIC pin] ; {alternative pin function in pair mode} ; ; ,-----_-----. ; +5V (27,58) [18] |1 14| GND (5,36) [9] ; CIC clk in (56) [7] |2 A5 A0 13| CIC lock reset in [8] ; D4 out |3 A4 A1 12| 50/60Hz out ; REG_TIMEOUT in |4 A3 A2 11| host reset out [10] ; LED out (grn) |5 C5 C0 10| CIC data i/o 0 (55) [1] / {50/60Hz in} ; LED out (red) |6 C4 C1 9| CIC data i/o 1 (24) [2] / {D4 in} ; LED_TYPE in |7 C3 C2 8| CIC slave reset out (25) [11] ; `-----------' ; ; pin 8 connected to key CIC pin 7 (or clone CIC pin 5) ; pin 9 connected to key CIC pin 1 (or clone CIC pin 6) ; pin 10 connected to key CIC pin 2 (or clone CIC pin 7) ; pin 11 connected to key CIC pin 9 (SNES /reset line) ; pin 12 connected to PPU1 pin 24 & PPU2 pin 30 (both isolated from mainboard) ; pin 13 connected to reset button ; ; LED_TYPE sets the output mode for the LED pins (must be tied to either level): ; low = common cathode ; high = common anode (output inverted) ; ; D4 out is always switched to the autodetected region and is not user ; overridable except in SuperCIC pair mode or when no key CIC is detected. ; It can be used, by adding an address decoder and a latch, to override ; bit 4 of the $213f register (used by games to detect the console region). ; ; REG_TIMEOUT in (Pin 4) enables a ~9 sec timeout before switching ; to the forced region. If D4 is not used, the REG_TIMEOUT pin should be ; connected to Vcc. ; ; Host reset out behaves as follows: ; After powerup it is held low for a couple of ms to allow the components ; to power-up properly. ; It is then asserted a high level even if the CIC "auth" should fail at ; any point, thus enabling homebrew or other cartridges without a CIC or ; CIC clone to be run properly while maintaining compatibility with ; cartridges requiring a CIC, like S-DD1 or SA-1 games. ; The type of key CIC (411/413) is detected automatically. ; ; This implementation supports automatic 50/60Hz switching based on the ; detected key CIC in the game cartridge. Also the 50/60Hz setting can be ; overridden by the user via the reset button. ; ; Reset / Mode switch behaves as follows: ; Reset is pressed for < 586ms -> reset console upon release ; Reset is pressed for >= 586ms -> enter mode switch cycle, no reset ; Modes are cycled every 586ms as shown in Fig.1 as long as the reset button ; is held down. ; The currently selected mode is indicated by the color of the power LED ; (see Table 3). ; The mode is finally selected by releasing the reset button while the ; desired LED color is shown. The selected mode will then become effective ; and will be saved to EEPROM. Mode switching does not reset the console. ; ; Note that in case a valid CIC is detected in the game cartridge, video mode ; will be forced to its corresponding region for the first ~9 seconds after ; reset or powerup if the REG_TIMEOUT enable pin is high. ; This is an attempt to trick the region detection on most games. See Table 1. ; In case no CIC is present in the game cartridge, or REG_TIMEOUT is low, the ; user setting is applied immediately. ; ; SuperCIC pair mode: when a SuperCIC lock and SuperCIC key detect each other ; they both switch both of the data pins to inputs. The lock then passes ; through data i/o 0 to SNES 50/60Hz and data i/o 1 to an optional D4 output ; (for overriding the 213f register using additional hardware). This makes it ; possible to switch 50/60Hz and D4 from the cartridge slot, e.g. by ; connecting an additional MCU to the CIC data lines. Of course, they have to ; be tristated for normal (non-passthrough) operation. ; ; Table 1. 50/60Hz output behavior according to user setting and key CIC type. ; SuperCIC key CIC "region" ; ------------------------------------------------------ ; 60Hz D/F413 50Hz for ~9 sec, then 60Hz ; 60Hz D/F411 60Hz permanent ; 60Hz none 60Hz permanent ; ; 50Hz D/F413 50Hz permanent ; 50Hz D/F411 60Hz for ~9 sec, then 50Hz ; 50Hz none 50Hz permanent ; ; Auto D/F413 50Hz permanent ; Auto D/F411 60Hz permanent ; Auto none 60Hz permanent ; ; Table 2. D4 output behavior according to key CIC type ; key CIC output ; ----------------------------------------------- ; D/F413 1 (PAL) ; D/F411 0 (NTSC) ; none same as user setting (NTSC if Auto) ; ; Fig.1. SuperCIC mode cycle. ; ,->60Hz--->50Hz--->Auto->. ; `-------<--------<-------' ; ; Table 3. LED color according to user setting. ; mode LED color ; --------------------- ; 60Hz red ; 50Hz green ; Auto orange ; ; Table 4. memory usage. ; -------------------basic CIC functions-------------------- ; 0x20 buffer for seed calc and transfer ; 0x21 - 0x2f seed area (lock seed) ; 0x30 buffer for seed calc ; 0x31 - 0x3f seed area (key seed; 0x31 filled in by lock) ; 0x40 - 0x41 buffer for seed calc ; 0x42 input buffer ; 0x43 variable for key detect ; 0x44 "direction" buffer ; 0x4d buffer for eeprom access ; 0x4e loop variable for longwait ; 0x4f loop variable for wait ; -------------------SuperCIC extensions-------------------- ; 0x50 power LED state (no bits except 4 and 5 must be set!!) ; 0x51 last reset button state ; 0x52 mode dirty flag ; 0x53 tmr overflow counter ; 0x54 region output (0: 60Hz, 2: 50Hz) ; 0x55 final mode setting ; 0x56 temp LED state ; 0x57 detected region (0: 60Hz, 2: 50Hz) ; 0x58 forced region (0: 60Hz, 2: 50Hz) ; 0x59 detected D4 (0: 60Hz, 16: 50Hz) ; 0x5e SuperCIC pair mode detect (phase 1) ; 0x5f SuperCIC pair mode detect (phase 2) ; ; --------------------------------------------------------------------- ; ----------------------------------------------------------------------- __CONFIG _EC_OSC & _WDT_OFF & _PWRTE_OFF & _MCLRE_OFF & _CP_OFF & _CPD_OFF ; ----------------------------------------------------------------------- ; code memory org 0x0000 nop nop nop goto init trap movlw 0x3 xorwf PORTC, f goto trap rst ; we jump here after powerup or RC0=1 bcf PORTC, 0 ; clear stream i/o bcf PORTC, 1 ; clear stream i/o bcf PORTC, 2 ; disable slave reset bcf PORTC, 3 ; *K* disable "lockout detected" bcf PORTA, 2 ; hold the SNES in reset movlw 0x30 ; prescaler 1:8 movwf T1CON ; clrf PIR1 rst_loop btfss PORTA, 3 ; *K* reset moved and inverted stay in "reset" as long as RA0=1 goto rst_loop clrf 0x44 ; clear dir buffer clrf 0x51 ; clear reset button state clrf 0x52 ; clear modechange flag clrf 0x53 clrf 0x54 ; clear user mode clrf 0x57 ; clear key mode clrf 0x59 ; clear D4 clrf 0x5e ; clrf 0x5f ; banksel EEADR ; fetch current mode from EEPROM ;nop ; *K* remove this ;clrf EEADR ; address 0 ;bsf EECON1, RD ; ;movf EEDAT, w ; banksel PORTA movlw h'01' ; *K* set the default region from pin state btfsc PORTC, 5 movlw h'02' nop movwf 0x55 ; store saved mode in mode var movwf 0x56 ; and temp LED movwf 0x58 ; and forced region andlw 0x03 ; mask ;btfsc PORTC, 3 ; invert LEDs? ;xorlw 0x03 ; then make it so ;movwf 0x50 ; and store ;swapf 0x50, f ; and nibbleswap for actual output nop nop nop clrf 0x50 ; *K* clear this ;btfss PORTA, 3 ; if D4 mode is disabled: ;bsf 0x53, 4 ; simulate region timeout->immediate region chg nop ; *K* removed nop movlw 0x2 andwf 0x58, f clrf PIR1 ; reset overflow bit clrf TMR1L ; reset counter clrf TMR1H bsf T1CON, 0 ; start the timer goto main ; go go go init ; PORTA: in out in out out in ; PORTC: out out in out out in banksel PORTA nop clrf PORTA movlw 0x07 ; GPIO2..0 are digital I/O (not connected to comparator) movwf CMCON movlw 0x00 ; disable all interrupts movwf INTCON banksel TRISA nop ;movlw 0x29 ; in out in out out in ;movwf TRISA ;movlw 0x09 ; out out in out out in ;movwf TRISC movlw 0x2b ; *K* in out in out in in movwf TRISA movlw 0x31 ; *K* in in out out out in movwf TRISC movlw 0x00 ; no pullups movwf WPUA movlw 0x80 ; global pullup disable movwf OPTION_REG banksel PORTA nop bcf PORTA, 2 ; hold SNES in reset goto rst main movlw 0x40 ; wait a bit before initializing the slave + console call longwait nop bsf PORTC, 2 ; trigger the slave nop nop bcf PORTC, 2 banksel TRISC nop bcf TRISC, 0 bsf TRISC, 1 banksel PORTC nop ; --------INIT LOCK SEED (what we must send)-------- movlw 0xb movwf 0x21 movlw 0x1 movwf 0x22 movlw 0x4 movwf 0x23 movlw 0xf movwf 0x24 movlw 0x4 movwf 0x25 movlw 0xb movwf 0x26 movlw 0x5 movwf 0x27 movlw 0x7 movwf 0x28 movlw 0xf movwf 0x29 movlw 0xd movwf 0x2a movlw 0x6 movwf 0x2b movlw 0x1 movwf 0x2c movlw 0xe movwf 0x2d movlw 0x9 movwf 0x2e movlw 0x8 movwf 0x2f ; --------INIT KEY SEED (what the key sends)-------- movlw 0xf ; we always request the same stream for simplicity movwf 0x31 movlw 0x0 ; this is filled in by key autodetect movwf 0x32 movlw 0xa movwf 0x33 movlw 0x1 movwf 0x34 movlw 0x8 movwf 0x35 movlw 0x5 movwf 0x36 movlw 0xf movwf 0x37 movlw 0x1 movwf 0x38 movwf 0x39 movlw 0xe movwf 0x3a movlw 0x1 movwf 0x3b movlw 0x0 movwf 0x3c movlw 0xd movwf 0x3d movlw 0xe movwf 0x3e movlw 0xc movwf 0x3f ; --------wait before sending stream ID-------- movlw 0xba call wait ; --------lock sends stream ID. 15 cycles per bit-------- btfsc 0x31, 3 ; read stream select bit bsf PORTC, 0 ; send bit nop nop bcf PORTC, 0 movlw 0x1 ; wait=3*0+7 call wait ; burn 10 cycles in total nop nop btfsc 0x31, 0 ; read stream select bit bsf PORTC, 0 ; send bit nop nop bcf PORTC, 0 movlw 0x1 ; wait=3*0+7 call wait ; burn 10 cycles in total nop nop btfsc 0x31, 1 ; read stream select bit bsf PORTC, 0 ; send bit nop nop bcf PORTC, 0 movlw 0x1 ; wait=3*0+7 call wait ; burn 10 cycles in total nop nop btfsc 0x31, 2 ; read stream select bit bsf PORTC, 0 ; send bit nop nop bcf PORTC, 0 movlw 0x1 ; wait=3*0+7 call wait ; burn 10 cycles in total banksel TRISC nop bsf TRISC, 0 bcf TRISC, 1 banksel PORTC nop movlw 0x23 ; call wait ; wait 109 movlw 0x1 ; 'first time' bit movwf 0x43 ; for key detection ; --------main loop-------- loop movlw 0x1 loop0 addlw 0x20 ; lock stream movwf FSR ; store in index reg loop1 nop movf INDF, w ; load seed value andlw 0x01 ; mask LSB movwf 0x20 btfsc 0x20, 0 ; copy from bit 0 bsf 0x20, 1 ; (if set) ;movf 0x50, w ; get LED state ;iorwf 0x20, f ; combine with data i/o ;movf 0x20, w movf 0x20, w ; changed how this works iorwf 0x50, w nop movwf PORTC nop movf PORTC, w ; read input movwf 0x42 ; store input movf 0x50, w ; get LED state movwf PORTC ; reset GPIO call checkkey btfsc 0x44, 0 ; check "direction" rrf 0x42, f ; shift received bit into place bsf FSR, 4 ; goto other stream movf INDF, w ; read xorwf 0x42, f ; xor received + calculated bcf FSR, 4 ; back to our own stream btfsc 0x42, 0 ; equal? then continue bsf 0x43, 1 ; else mark key invalid btfss 0x43, 1 ; if key invalid: goto main_skipinval1 ; bcf 0x57, 1 ; set det.region=60Hz bsf 0x53, 4 ; simulate region timeout->immediate region chg clrf 0x59 ; clear D4 output btfsc 0x54, 1 ; use effective region for D4 output bsf 0x59, 4 ;nop bcf 0x50, 3 ; lockout is not working main_skipinval2 call checkrst incf FSR, f ; next one movlw 0xf andwf FSR, w btfss STATUS, Z goto loop1 call mangle call mangle call mangle movf 0x37, w movwf 0x44 nop nop nop nop btfsc 0x37, 0 goto swap banksel TRISC nop bsf TRISC, 0 bcf TRISC, 1 goto swapskip swap banksel TRISC nop bcf TRISC, 0 bsf TRISC, 1 nop swapskip banksel PORTA nop bsf 0x54, 2 ; run the console movf 0x54, w ; read resolved mode iorwf 0x59, w ; get D4 value movwf PORTA bcf 0x43, 0 ; don't check key region anymore movf 0x37, w andlw 0xf btfss STATUS, Z goto loop0 goto loop main_skipinval1 bsf 0x50, 3 ;nop nop nop goto main_skipinval2 ; --------calculate new seeds-------- ; had to be unrolled because PIC has an inefficient way of handling ; indirect access, no post increment, no swap, etc. mangle call mangle_lock nop nop mangle_key movf 0x2f, w movwf 0x20 mangle_key_loop addlw 0x1 addwf 0x21, f movf 0x22, w movwf 0x40 movf 0x21, w addwf 0x22, f incf 0x22, f comf 0x22, f movf 0x23, w movwf 0x41 ; store 23 to 41 movlw 0xf andwf 0x23, f movf 0x40, w ; add 40(22 old)+23+#1 and skip if carry andlw 0xf addwf 0x23, f incf 0x23, f btfsc 0x23, 4 goto mangle_key_withskip mangle_key_withoutskip movf 0x41, w ; restore 23 addwf 0x24, f ; add to 24 movf 0x25, w movwf 0x40 ; save 25 to 40 movf 0x24, w addwf 0x25, f movf 0x26, w movwf 0x41 ; save 26 to 41 movf 0x40, w ; restore 25 andlw 0xf ; mask nibble addlw 0x8 ; add #8 to HIGH nibble movwf 0x40 btfss 0x40, 4 ; skip if carry to 5th bit addwf 0x26, w movwf 0x26 movf 0x41, w ; restore 26 addlw 0x1 ; inc addwf 0x27, f ; add to 27 movf 0x27, w ; addlw 0x1 ; inc addwf 0x28, f ; add to 28 movf 0x28, w ; addlw 0x1 ; inc addwf 0x29, f ; add to 29 movf 0x29, w ; addlw 0x1 ; inc addwf 0x2a, f ; add to 2a movf 0x2a, w ; addlw 0x1 ; inc addwf 0x2b, f ; add to 2b movf 0x2b, w ; addlw 0x1 ; inc addwf 0x2c, f ; add to 2c movf 0x2c, w ; addlw 0x1 ; inc addwf 0x2d, f ; add to 2d movf 0x2d, w ; addlw 0x1 ; inc addwf 0x2e, f ; add to 2e movf 0x2e, w ; addlw 0x1 ; inc addwf 0x2f, f ; add to 2f movf 0x20, w ; restore original 0xf andlw 0xf addlw 0xf movwf 0x20 nop nop nop nop nop nop nop nop nop btfss 0x20, 4 ; skip if half-byte carry goto mangle_return ; +2 cycles in return nop goto mangle_key_loop ; 69 when goto, 69 when return ; CIC has 78 -> 9 nops mangle_key_withskip movf 0x41, w ; restore 23 addwf 0x23, f ; add to 23 movf 0x24, w movwf 0x40 ; save 24 to 40 movf 0x23, w addwf 0x24, f movf 0x25, w movwf 0x41 ; save 25 to 41 movf 0x40, w ; restore 24 andlw 0xf ; mask nibble addlw 0x8 ; add #8 to HIGH nibble movwf 0x40 btfss 0x40, 4 ; skip if carry to 5th bit addwf 0x25, w movwf 0x25 movf 0x41, w ; restore 25 addlw 0x1 ; inc addwf 0x26, f ; add to 26 movf 0x26, w ; addlw 0x1 ; inc addwf 0x27, f ; add to 27 movf 0x27, w ; addlw 0x1 ; inc addwf 0x28, f ; add to 28 movf 0x28, w ; addlw 0x1 ; inc addwf 0x29, f ; add to 29 movf 0x29, w ; addlw 0x1 ; inc addwf 0x2a, f ; add to 2a movf 0x2a, w ; addlw 0x1 ; inc addwf 0x2b, f ; add to 2b movf 0x2b, w ; addlw 0x1 ; inc addwf 0x2c, f ; add to 2c movf 0x2c, w ; addlw 0x1 ; inc addwf 0x2d, f ; add to 2d movf 0x2d, w ; addlw 0x1 ; inc addwf 0x2e, f ; add to 2e movf 0x2e, w ; addlw 0x1 ; inc addwf 0x2f, f ; add to 2f movf 0x20, w ; restore original 0xf andlw 0xf addlw 0xf movwf 0x20 bsf PORTC, 1 movf PORTC, w movwf 0x5e nop bcf PORTC, 1 movf PORTC, w movwf 0x5f nop nop nop nop btfss 0x20, 4 ; skip if half-byte carry goto mangle_return ; +2 cycles in return movf 0x20, w ; restore w (previously destroyed) goto mangle_key_loop mangle_return return ; 73 when goto, 73 when return ; CIC has 84 -> 11 nops mangle_lock movf 0x3f, w movwf 0x30 mangle_lock_loop addlw 0x1 addwf 0x31, f movf 0x32, w movwf 0x40 movf 0x31, w addwf 0x32, f incf 0x32, f comf 0x32, f movf 0x33, w movwf 0x41 ; store 33 to 41 movlw 0xf andwf 0x33, f movf 0x40, w ; add 40(32 old)+33+#1 and skip if carry andlw 0xf addwf 0x33, f incf 0x33, f btfsc 0x33, 4 goto mangle_lock_withskip mangle_lock_withoutskip movf 0x41, w ; restore 33 addwf 0x34, f ; add to 34 movf 0x35, w movwf 0x40 ; save 35 to 40 movf 0x34, w addwf 0x35, f movf 0x36, w movwf 0x41 ; save 36 to 41 movf 0x40, w ; restore 35 andlw 0xf ; mask nibble addlw 0x8 ; add #8 to HIGH nibble movwf 0x40 btfss 0x40, 4 ; skip if carry to 5th bit addwf 0x36, w movwf 0x36 movf 0x41, w ; restore 36 addlw 0x1 ; inc addwf 0x37, f ; add to 37 movf 0x37, w ; addlw 0x1 ; inc addwf 0x38, f ; add to 38 movf 0x38, w ; addlw 0x1 ; inc addwf 0x39, f ; add to 39 movf 0x39, w ; addlw 0x1 ; inc addwf 0x3a, f ; add to 3a movf 0x3a, w ; addlw 0x1 ; inc addwf 0x3b, f ; add to 3b movf 0x3b, w ; addlw 0x1 ; inc addwf 0x3c, f ; add to 3c movf 0x3c, w ; addlw 0x1 ; inc addwf 0x3d, f ; add to 3d movf 0x3d, w ; addlw 0x1 ; inc addwf 0x3e, f ; add to 3e movf 0x3e, w ; addlw 0x1 ; inc addwf 0x3f, f ; add to 3f movf 0x30, w ; restore original 0xf andlw 0xf addlw 0xf movwf 0x30 nop nop nop nop nop nop nop nop nop btfss 0x30, 4 ; skip if half-byte carry goto mangle_return nop goto mangle_lock_loop ; 69 when goto, 69 when return ; CIC has 78 -> 9 nops mangle_lock_withskip movf 0x41, w ; restore 33 addwf 0x33, f ; add to 33 movf 0x34, w movwf 0x40 ; save 34 to 40 movf 0x33, w addwf 0x34, f movf 0x35, w movwf 0x41 ; save 35 to 41 movf 0x40, w ; restore 34 andlw 0xf ; mask nibble addlw 0x8 ; add #8 to HIGH nibble movwf 0x40 btfss 0x40, 4 ; skip if carry to 5th bit addwf 0x35, w movwf 0x35 movf 0x41, w ; restore 35 addlw 0x1 ; inc addwf 0x36, f ; add to 36 movf 0x36, w ; addlw 0x1 ; inc addwf 0x37, f ; add to 37 movf 0x37, w ; addlw 0x1 ; inc addwf 0x38, f ; add to 38 movf 0x38, w ; addlw 0x1 ; inc addwf 0x39, f ; add to 39 movf 0x39, w ; addlw 0x1 ; inc addwf 0x3a, f ; add to 3a movf 0x3a, w ; addlw 0x1 ; inc addwf 0x3b, f ; add to 3b movf 0x3b, w ; addlw 0x1 ; inc addwf 0x3c, f ; add to 3c movf 0x3c, w ; addlw 0x1 ; inc addwf 0x3d, f ; add to 3d movf 0x3d, w ; addlw 0x1 ; inc addwf 0x3e, f ; add to 3e movf 0x3e, w ; addlw 0x1 ; inc addwf 0x3f, f ; add to 3f movf 0x30, w ; restore original 0xf andlw 0xf addlw 0xf movwf 0x30 btfsc 0x5e, 0 goto scic_pair_skip1 btfss 0x5f, 0 goto scic_pair_skip2 goto supercic_pairmode scic_pair_skip1 nop nop scic_pair_skip2 nop nop nop nop nop nop ; *K* removed to account for the btfss btfss 0x30, 4 ; skip if half-byte carry goto mangle_return nop goto mangle_lock_loop ; 73 when goto, 73 when return ; CIC has 84 -> 11 nops ; --------wait: 3*(W-1)+7 cycles (including call+return). W=0 -> 256!-------- wait movwf 0x4f wait0 decfsz 0x4f, f goto wait0 return ; --------wait long: 8+(3*(w-1))+(772*w). W=0 -> 256!-------- longwait movwf 0x4e clrw longwait0 call wait decfsz 0x4e, f goto longwait0 return ; --------die (do nothing, wait for reset)-------- die btfss PORTA, 3 ; *K* moved and inverted goto rst goto die ; --------check the key input and change "region" when appropriate-------- ; --------requires 20 cycles (incl. call+return) checkkey btfss 0x43, 0 ; first time? goto checkkey_nocheck; if not, just burn some cycles movlw 0x22 ; are we at the correct stream offset? xorwf FSR, w btfss STATUS, Z ; if not equal: goto checkkey_nocheck2; burn some cycles less. ; if equal do the check btfss 0x42, 0 ; if value from slave is set it's a 411 goto checkkey_413 checkkey_411 nop ; to compensate for untaken branch bcf 0x57, 1 ; set detected mode (60Hz) bcf 0x59, 4 ; set detected D4 mode (60Hz) bcf 0x54, 1 ; set output mode (60Hz) movlw 0x9 goto checkkey_save checkkey_413 bsf 0x57, 1 ; set detected mode (50Hz) bsf 0x59, 4 ; set detected D4 mode (50Hz) bsf 0x54, 1 ; set output mode (50Hz) movlw 0x6 goto checkkey_save checkkey_nocheck nop nop nop nop checkkey_nocheck2 nop nop nop nop nop nop nop goto checkkey_done checkkey_save movwf 0x32 checkkey_done return ; -------- check reset button, update status LEDs, etc. checkrst ; 4 ;movf PORTA, w ;btfss 0x51, 0 btfss PORTA, 3 goto rst goto checkrst_0 nop checkrst_1 ; 4 movwf 0x51 btfsc 0x51, 0 goto checkrst_1_1 nop checkrst_1_0 ; 26 ; if modechange flag is set: clear modechange flag, set mode, save, restart timer ; else reset btfss 0x52, 0 goto rst2 ; modechange flag is not set, reset. timing is irrelevant clrf 0x52 ; clear modechange flag movf 0x56, w ; get temp mode movwf 0x55 ; set final mode movwf 0x58 ; set forced mode banksel EEADR ; save to EEPROM. note: banksels take two cycles each! nop movwf EEDAT bsf EECON1,WREN movlw 0x55 movwf EECON2 movlw 0xaa movwf EECON2 bsf EECON1, WR banksel PORTA ; two cycles again nop movlw 0x2 andwf 0x58, f ; cleanup forced mode bcf T1CON, 0 ; stop the timer clrf PIR1 ; reset overflow bit clrf TMR1L ; reset counter clrf TMR1H bsf T1CON, 0 ; restart the timer return ; shortcut (no goto checkrst_end) checkrst_1_1 ; 24 ; check TMR overflow ; if overflow, change LED, reset TMR+overflow, set modechange flag ; else do nothing nop nop nop nop btfss PIR1, 0 goto checkrst_end_plus17 bcf T1CON, 0 ; stop the timer clrf PIR1 ; reset overflow bit clrf TMR1L ; reset counter clrf TMR1H bsf T1CON, 0 ; restart the timer incf 0x56, f ; change tmp LED/mode movlw 0x5 btfsc 0x56, 2 ; if 4: xorwf 0x56, f ; change back to 1 movf 0x56, w andlw 0x03 ; mask btfsc PORTC, 3 ; invert LEDs? xorlw 0x03 ; then make it so ;movwf 0x50 ;swapf 0x50, f ; adjust for GPIO pins nop nop ; *K* remove this bsf 0x52, 0 ; set modechange flag goto checkrst_end checkrst_0 ; 4 movwf 0x51 btfsc 0x51, 0 goto checkrst_0_1 nop checkrst_0_0 ; 24 nop nop nop nop nop nop ; count some overflows, change region from detected to forced unless auto btfsc 0x53, 4 ; past delay? goto checkrst_0_0_setregion_plus5 btfss PIR1, 0 goto checkrst_end_plus13 clrf PIR1 incf 0x53, f ; increment overflow counter btfss 0x53, 4 ; 0x10 reached? goto checkrst_end_plus9 checkrst_0_0_setregion movlw 0x3 xorwf 0x55, w ; mode=auto? btfss STATUS, Z goto checkrst_0_0_setregion_forced checkrst_0_0_setregion_auto movf 0x57, w ; get detected region goto checkrst_0_0_setregion_save checkrst_0_0_setregion_forced movf 0x58, w ; get forced region nop checkrst_0_0_setregion_save movwf 0x54 ; set to output goto checkrst_end checkrst_0_1 ; 24 ; reset + start TMR, reset TMR overflow clrf TMR1L ; reset timer register clrf TMR1H clrf PIR1 ; clear overflow bit bsf T1CON, 0 goto checkrst_end_plus18 checkrst_end ; 2 return checkrst_end_plus18 nop checkrst_end_plus17 nop nop nop nop checkrst_end_plus13 nop nop nop nop checkrst_end_plus9 nop nop nop nop nop nop nop goto checkrst_end checkrst_0_0_setregion_plus5 nop nop nop goto checkrst_0_0_setregion supercic_pairmode banksel TRISC nop bsf TRISC, 0 ; tristate both bsf TRISC, 1 ; data lines banksel PORTC btfss PORTC, 4 ; *K* skip link mode if we don't want it goto die nop supercic_pairmode_loop clrf 0x5d bsf 0x5d, 2 btfsc PORTC, 0 ;bsf 0x5d, 1 nop ; we don't worry about this btfsc PORTC, 1 bsf 0x5d, 4 btfss PORTA, 3 goto rst ; exit pair mode ;bcf 0x5d, 2 movf PORTA, w ; dorkulate the port andlw h'ef' iorwf 0x5d, w movwf PORTA goto supercic_pairmode_loop ; *K* jump around the entire loop, we are updating D4 so we're good. ; btfss PORTC, 0 goto supercic_pairmode_led_60 supercic_pairmode_led_50 movlw 0x20 btfsc PORTC, 3 xorlw 0x30 movwf PORTC goto supercic_pairmode_loop supercic_pairmode_led_60 movlw 0x10 btfsc PORTC, 3 xorlw 0x30 movwf PORTC goto supercic_pairmode_loop rst2 bcf PORTA, 2 ; hold the SNES in reset bcf T1CON, 0 ; stop the timer clrf TMR1L ; reset timer register clrf TMR1H clrf PIR1 ; clear overflow bit bsf T1CON, 0 clrf 0x51 ; clear reset button state rst2_loop1 btfss PORTA, 3 ; if reset button is pressed goto rst ; *K* invert and move ;bsf 0x51, 0 ; set reset flag btfss PIR1, 0 ; break if timeout goto rst2_loop1 btfss 0x51, 0 ; if no 2nd reset button press occured: goto rst ; just reset normally clrf 0x53 ; else keep resetting some more bcf T1CON, 0 ; stop the timer clrf TMR1L ; reset timer register clrf TMR1H clrf PIR1 ; clear overflow bit bsf T1CON, 0 rst2_loop2 btfss PIR1, 0 goto rst2_loop2 clrf PIR1 incf 0x53, f movlw 0x0a xorwf 0x53, w btfss STATUS, Z ; 10 overflows ~= 5.86s goto rst2_loop2 goto rst ; finally reset ; ----------------------------------------------------------------------- ; eeprom data DEEPROM CODE de 0x01 ;current mode (default: 60Hz) end ; ------------------------------------------------------------------------