supercic-lock.asm 24 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102
  1. #include <p16f630.inc>
  2. processor p16f630
  3. ; ---------------------------------------------------------------------
  4. ; feature enhanced auto region switching SNES CIC clone
  5. ; for PIC Microcontrollers (lock mode)
  6. ;
  7. ; Copyright (C) 2010 by Maximilian Rehkopf (ikari_01) <otakon@gmx.net>
  8. ; This software is part of the sd2snes project.
  9. ;
  10. ; This program is free software; you can redistribute it and/or modify
  11. ; it under the terms of the GNU General Public License as published by
  12. ; the Free Software Foundation; version 2 of the License only.
  13. ;
  14. ; This program is distributed in the hope that it will be useful,
  15. ; but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. ; GNU General Public License for more details.
  18. ;
  19. ; You should have received a copy of the GNU General Public License
  20. ; along with this program; if not, write to the Free Software
  21. ; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  22. ;
  23. ; ---------------------------------------------------------------------
  24. ;
  25. ; pin configuration: (cartridge slot pin) [original 18-pin SMD lock CIC pin]
  26. ; {alternative pin function in pair mode}
  27. ;
  28. ; ,-----_-----.
  29. ; +5V (27,58) [18] |1 14| GND (5,36) [9]
  30. ; CIC clk in (56) [7] |2 A5 A0 13| CIC lock reset in [8]
  31. ; D4 out |3 A4 A1 12| 50/60Hz out
  32. ; REG_TIMEOUT in |4 A3 A2 11| host reset out [10]
  33. ; LED out (grn) |5 C5 C0 10| CIC data i/o 0 (55) [1] / {50/60Hz in}
  34. ; LED out (red) |6 C4 C1 9| CIC data i/o 1 (24) [2] / {D4 in}
  35. ; LED_TYPE in |7 C3 C2 8| CIC slave reset out (25) [11]
  36. ; `-----------'
  37. ;
  38. ; pin 8 connected to key CIC pin 7 (or clone CIC pin 5)
  39. ; pin 9 connected to key CIC pin 1 (or clone CIC pin 6)
  40. ; pin 10 connected to key CIC pin 2 (or clone CIC pin 7)
  41. ; pin 11 connected to key CIC pin 9 (SNES /reset line)
  42. ; pin 12 connected to PPU1 pin 24 & PPU2 pin 30 (both isolated from mainboard)
  43. ; pin 13 connected to reset button
  44. ;
  45. ; LED_TYPE sets the output mode for the LED pins (must be tied to either level):
  46. ; low = common cathode
  47. ; high = common anode (output inverted)
  48. ;
  49. ; D4 out is always switched to the autodetected region and is not user
  50. ; overridable except in SuperCIC pair mode or when no key CIC is detected.
  51. ; It can be used, by adding an address decoder and a latch, to override
  52. ; bit 4 of the $213f register (used by games to detect the console region).
  53. ;
  54. ; REG_TIMEOUT in (Pin 4) enables a ~9 sec timeout before switching
  55. ; to the forced region. If D4 is not used, the REG_TIMEOUT pin should be
  56. ; connected to Vcc.
  57. ;
  58. ; Host reset out behaves as follows:
  59. ; After powerup it is held low for a couple of ms to allow the components
  60. ; to power-up properly.
  61. ; It is then asserted a high level even if the CIC "auth" should fail at
  62. ; any point, thus enabling homebrew or other cartridges without a CIC or
  63. ; CIC clone to be run properly while maintaining compatibility with
  64. ; cartridges requiring a CIC, like S-DD1 or SA-1 games.
  65. ; The type of key CIC (411/413) is detected automatically.
  66. ;
  67. ; This implementation supports automatic 50/60Hz switching based on the
  68. ; detected key CIC in the game cartridge. Also the 50/60Hz setting can be
  69. ; overridden by the user via the reset button.
  70. ;
  71. ; Reset / Mode switch behaves as follows:
  72. ; Reset is pressed for < 586ms -> reset console upon release
  73. ; Reset is pressed for >= 586ms -> enter mode switch cycle, no reset
  74. ; Modes are cycled every 586ms as shown in Fig.1 as long as the reset button
  75. ; is held down.
  76. ; The currently selected mode is indicated by the color of the power LED
  77. ; (see Table 3).
  78. ; The mode is finally selected by releasing the reset button while the
  79. ; desired LED color is shown. The selected mode will then become effective
  80. ; and will be saved to EEPROM. Mode switching does not reset the console.
  81. ;
  82. ; Note that in case a valid CIC is detected in the game cartridge, video mode
  83. ; will be forced to its corresponding region for the first ~9 seconds after
  84. ; reset or powerup if the REG_TIMEOUT enable pin is high.
  85. ; This is an attempt to trick the region detection on most games. See Table 1.
  86. ; In case no CIC is present in the game cartridge, or REG_TIMEOUT is low, the
  87. ; user setting is applied immediately.
  88. ;
  89. ; SuperCIC pair mode: when a SuperCIC lock and SuperCIC key detect each other
  90. ; they both switch both of the data pins to inputs. The lock then passes
  91. ; through data i/o 0 to SNES 50/60Hz and data i/o 1 to an optional D4 output
  92. ; (for overriding the 213f register using additional hardware). This makes it
  93. ; possible to switch 50/60Hz and D4 from the cartridge slot, e.g. by
  94. ; connecting an additional MCU to the CIC data lines. Of course, they have to
  95. ; be tristated for normal (non-passthrough) operation.
  96. ;
  97. ; Table 1. 50/60Hz output behavior according to user setting and key CIC type.
  98. ; SuperCIC key CIC "region"
  99. ; ------------------------------------------------------
  100. ; 60Hz D/F413 50Hz for ~9 sec, then 60Hz
  101. ; 60Hz D/F411 60Hz permanent
  102. ; 60Hz none 60Hz permanent
  103. ;
  104. ; 50Hz D/F413 50Hz permanent
  105. ; 50Hz D/F411 60Hz for ~9 sec, then 50Hz
  106. ; 50Hz none 50Hz permanent
  107. ;
  108. ; Auto D/F413 50Hz permanent
  109. ; Auto D/F411 60Hz permanent
  110. ; Auto none 60Hz permanent
  111. ;
  112. ; Table 2. D4 output behavior according to key CIC type
  113. ; key CIC output
  114. ; -----------------------------------------------
  115. ; D/F413 1 (PAL)
  116. ; D/F411 0 (NTSC)
  117. ; none same as user setting (NTSC if Auto)
  118. ;
  119. ; Fig.1. SuperCIC mode cycle.
  120. ; ,->60Hz--->50Hz--->Auto->.
  121. ; `-------<--------<-------'
  122. ;
  123. ; Table 3. LED color according to user setting.
  124. ; mode LED color
  125. ; ---------------------
  126. ; 60Hz red
  127. ; 50Hz green
  128. ; Auto orange
  129. ;
  130. ; Table 4. memory usage.
  131. ; -------------------basic CIC functions--------------------
  132. ; 0x20 buffer for seed calc and transfer
  133. ; 0x21 - 0x2f seed area (lock seed)
  134. ; 0x30 buffer for seed calc
  135. ; 0x31 - 0x3f seed area (key seed; 0x31 filled in by lock)
  136. ; 0x40 - 0x41 buffer for seed calc
  137. ; 0x42 input buffer
  138. ; 0x43 variable for key detect
  139. ; 0x44 "direction" buffer
  140. ; 0x4d buffer for eeprom access
  141. ; 0x4e loop variable for longwait
  142. ; 0x4f loop variable for wait
  143. ; -------------------SuperCIC extensions--------------------
  144. ; 0x50 power LED state (no bits except 4 and 5 must be set!!)
  145. ; 0x51 last reset button state
  146. ; 0x52 mode dirty flag
  147. ; 0x53 tmr overflow counter
  148. ; 0x54 region output (0: 60Hz, 2: 50Hz)
  149. ; 0x55 final mode setting
  150. ; 0x56 temp LED state
  151. ; 0x57 detected region (0: 60Hz, 2: 50Hz)
  152. ; 0x58 forced region (0: 60Hz, 2: 50Hz)
  153. ; 0x59 detected D4 (0: 60Hz, 16: 50Hz)
  154. ; 0x5e SuperCIC pair mode detect (phase 1)
  155. ; 0x5f SuperCIC pair mode detect (phase 2)
  156. ;
  157. ; ---------------------------------------------------------------------
  158. ; -----------------------------------------------------------------------
  159. __CONFIG _EC_OSC & _WDT_OFF & _PWRTE_OFF & _MCLRE_OFF & _CP_OFF & _CPD_OFF
  160. ; -----------------------------------------------------------------------
  161. ; code memory
  162. org 0x0000
  163. nop
  164. nop
  165. nop
  166. goto init
  167. trap
  168. movlw 0x3
  169. xorwf PORTC, f
  170. goto trap
  171. rst ; we jump here after powerup or RC0=1
  172. bcf PORTC, 0 ; clear stream i/o
  173. bcf PORTC, 1 ; clear stream i/o
  174. bcf PORTC, 2 ; disable slave reset
  175. bcf PORTA, 2 ; hold the SNES in reset
  176. movlw 0x30 ; prescaler 1:8
  177. movwf T1CON ;
  178. clrf PIR1
  179. rst_loop
  180. btfsc PORTA, 0 ; stay in "reset" as long as RA0=1
  181. goto rst_loop
  182. clrf 0x44 ; clear dir buffer
  183. clrf 0x51 ; clear reset button state
  184. clrf 0x52 ; clear modechange flag
  185. clrf 0x53
  186. clrf 0x54 ; clear user mode
  187. clrf 0x57 ; clear key mode
  188. clrf 0x59 ; clear D4
  189. clrf 0x5e ;
  190. clrf 0x5f ;
  191. banksel EEADR ; fetch current mode from EEPROM
  192. clrf EEADR ; address 0
  193. bsf EECON1, RD ;
  194. movf EEDAT, w ;
  195. banksel PORTA
  196. movwf 0x55 ; store saved mode in mode var
  197. movwf 0x56 ; and temp LED
  198. movwf 0x58 ; and forced region
  199. andlw 0x03 ; mask
  200. btfsc PORTC, 3 ; invert LEDs?
  201. xorlw 0x03 ; then make it so
  202. movwf 0x50 ; and store
  203. swapf 0x50, f ; and nibbleswap for actual output
  204. btfss PORTA, 3 ; if D4 mode is disabled:
  205. bsf 0x53, 4 ; simulate region timeout->immediate region chg
  206. movlw 0x2
  207. andwf 0x58, f
  208. clrf PIR1 ; reset overflow bit
  209. clrf TMR1L ; reset counter
  210. clrf TMR1H
  211. bsf T1CON, 0 ; start the timer
  212. goto main ; go go go
  213. init
  214. ; PORTA: in out in out out in
  215. ; PORTC: out out in out out in
  216. banksel PORTA
  217. clrf PORTA
  218. movlw 0x07 ; GPIO2..0 are digital I/O (not connected to comparator)
  219. movwf CMCON
  220. movlw 0x00 ; disable all interrupts
  221. movwf INTCON
  222. banksel TRISA
  223. movlw 0x29 ; in out in out out in
  224. movwf TRISA
  225. movlw 0x09 ; out out in out out in
  226. movwf TRISC
  227. movlw 0x00 ; no pullups
  228. movwf WPUA
  229. movlw 0x80 ; global pullup disable
  230. movwf OPTION_REG
  231. banksel PORTA
  232. bcf PORTA, 2 ; hold SNES in reset
  233. goto rst
  234. main
  235. movlw 0x40 ; wait a bit before initializing the slave + console
  236. call longwait
  237. nop
  238. bsf PORTC, 2 ; trigger the slave
  239. nop
  240. nop
  241. bcf PORTC, 2
  242. banksel TRISC
  243. bcf TRISC, 0
  244. bsf TRISC, 1
  245. banksel PORTC
  246. ; --------INIT LOCK SEED (what we must send)--------
  247. movlw 0xb
  248. movwf 0x21
  249. movlw 0x1
  250. movwf 0x22
  251. movlw 0x4
  252. movwf 0x23
  253. movlw 0xf
  254. movwf 0x24
  255. movlw 0x4
  256. movwf 0x25
  257. movlw 0xb
  258. movwf 0x26
  259. movlw 0x5
  260. movwf 0x27
  261. movlw 0x7
  262. movwf 0x28
  263. movlw 0xf
  264. movwf 0x29
  265. movlw 0xd
  266. movwf 0x2a
  267. movlw 0x6
  268. movwf 0x2b
  269. movlw 0x1
  270. movwf 0x2c
  271. movlw 0xe
  272. movwf 0x2d
  273. movlw 0x9
  274. movwf 0x2e
  275. movlw 0x8
  276. movwf 0x2f
  277. ; --------INIT KEY SEED (what the key sends)--------
  278. movlw 0xf ; we always request the same stream for simplicity
  279. movwf 0x31
  280. movlw 0x0 ; this is filled in by key autodetect
  281. movwf 0x32
  282. movlw 0xa
  283. movwf 0x33
  284. movlw 0x1
  285. movwf 0x34
  286. movlw 0x8
  287. movwf 0x35
  288. movlw 0x5
  289. movwf 0x36
  290. movlw 0xf
  291. movwf 0x37
  292. movlw 0x1
  293. movwf 0x38
  294. movwf 0x39
  295. movlw 0xe
  296. movwf 0x3a
  297. movlw 0x1
  298. movwf 0x3b
  299. movlw 0x0
  300. movwf 0x3c
  301. movlw 0xd
  302. movwf 0x3d
  303. movlw 0xe
  304. movwf 0x3e
  305. movlw 0xc
  306. movwf 0x3f
  307. ; --------wait before sending stream ID--------
  308. movlw 0xba
  309. call wait
  310. ; --------lock sends stream ID. 15 cycles per bit--------
  311. btfsc 0x31, 3 ; read stream select bit
  312. bsf PORTC, 0 ; send bit
  313. nop
  314. nop
  315. bcf PORTC, 0
  316. movlw 0x1 ; wait=3*0+7
  317. call wait ; burn 10 cycles in total
  318. nop
  319. nop
  320. btfsc 0x31, 0 ; read stream select bit
  321. bsf PORTC, 0 ; send bit
  322. nop
  323. nop
  324. bcf PORTC, 0
  325. movlw 0x1 ; wait=3*0+7
  326. call wait ; burn 10 cycles in total
  327. nop
  328. nop
  329. btfsc 0x31, 1 ; read stream select bit
  330. bsf PORTC, 0 ; send bit
  331. nop
  332. nop
  333. bcf PORTC, 0
  334. movlw 0x1 ; wait=3*0+7
  335. call wait ; burn 10 cycles in total
  336. nop
  337. nop
  338. btfsc 0x31, 2 ; read stream select bit
  339. bsf PORTC, 0 ; send bit
  340. nop
  341. nop
  342. bcf PORTC, 0
  343. movlw 0x1 ; wait=3*0+7
  344. call wait ; burn 10 cycles in total
  345. banksel TRISC
  346. bsf TRISC, 0
  347. bcf TRISC, 1
  348. banksel PORTC
  349. movlw 0x23 ;
  350. call wait ; wait 109
  351. movlw 0x1 ; 'first time' bit
  352. movwf 0x43 ; for key detection
  353. ; --------main loop--------
  354. loop
  355. movlw 0x1
  356. loop0
  357. addlw 0x20 ; lock stream
  358. movwf FSR ; store in index reg
  359. loop1
  360. nop
  361. movf INDF, w ; load seed value
  362. andlw 0x01 ; mask LSB
  363. movwf 0x20
  364. btfsc 0x20, 0 ; copy from bit 0
  365. bsf 0x20, 1 ; (if set)
  366. movf 0x50, w ; get LED state
  367. iorwf 0x20, f ; combine with data i/o
  368. movf 0x20, w
  369. movwf PORTC
  370. nop
  371. movf PORTC, w ; read input
  372. movwf 0x42 ; store input
  373. movf 0x50, w ; get LED state
  374. movwf PORTC ; reset GPIO
  375. call checkkey
  376. btfsc 0x44, 0 ; check "direction"
  377. rrf 0x42, f ; shift received bit into place
  378. bsf FSR, 4 ; goto other stream
  379. movf INDF, w ; read
  380. xorwf 0x42, f ; xor received + calculated
  381. bcf FSR, 4 ; back to our own stream
  382. btfsc 0x42, 0 ; equal? then continue
  383. bsf 0x43, 1 ; else mark key invalid
  384. btfss 0x43, 1 ; if key invalid:
  385. goto main_skipinval1 ;
  386. bcf 0x57, 1 ; set det.region=60Hz
  387. bsf 0x53, 4 ; simulate region timeout->immediate region chg
  388. clrf 0x59 ; clear D4 output
  389. btfsc 0x54, 1 ; use effective region for D4 output
  390. bsf 0x59, 4
  391. nop
  392. main_skipinval2
  393. call checkrst
  394. incf FSR, f ; next one
  395. movlw 0xf
  396. andwf FSR, w
  397. btfss STATUS, Z
  398. goto loop1
  399. call mangle
  400. call mangle
  401. call mangle
  402. movf 0x37, w
  403. movwf 0x44
  404. nop
  405. nop
  406. nop
  407. nop
  408. btfsc 0x37, 0
  409. goto swap
  410. banksel TRISC
  411. bsf TRISC, 0
  412. bcf TRISC, 1
  413. goto swapskip
  414. swap
  415. banksel TRISC
  416. bcf TRISC, 0
  417. bsf TRISC, 1
  418. nop
  419. swapskip
  420. banksel PORTA
  421. bsf 0x54, 2 ; run the console
  422. movf 0x54, w ; read resolved mode
  423. iorwf 0x59, w ; get D4 value
  424. movwf PORTA
  425. bcf 0x43, 0 ; don't check key region anymore
  426. movf 0x37, w
  427. andlw 0xf
  428. btfss STATUS, Z
  429. goto loop0
  430. goto loop
  431. main_skipinval1
  432. nop
  433. nop
  434. nop
  435. goto main_skipinval2
  436. ; --------calculate new seeds--------
  437. ; had to be unrolled because PIC has an inefficient way of handling
  438. ; indirect access, no post increment, no swap, etc.
  439. mangle
  440. call mangle_lock
  441. nop
  442. nop
  443. mangle_key
  444. movf 0x2f, w
  445. movwf 0x20
  446. mangle_key_loop
  447. addlw 0x1
  448. addwf 0x21, f
  449. movf 0x22, w
  450. movwf 0x40
  451. movf 0x21, w
  452. addwf 0x22, f
  453. incf 0x22, f
  454. comf 0x22, f
  455. movf 0x23, w
  456. movwf 0x41 ; store 23 to 41
  457. movlw 0xf
  458. andwf 0x23, f
  459. movf 0x40, w ; add 40(22 old)+23+#1 and skip if carry
  460. andlw 0xf
  461. addwf 0x23, f
  462. incf 0x23, f
  463. btfsc 0x23, 4
  464. goto mangle_key_withskip
  465. mangle_key_withoutskip
  466. movf 0x41, w ; restore 23
  467. addwf 0x24, f ; add to 24
  468. movf 0x25, w
  469. movwf 0x40 ; save 25 to 40
  470. movf 0x24, w
  471. addwf 0x25, f
  472. movf 0x26, w
  473. movwf 0x41 ; save 26 to 41
  474. movf 0x40, w ; restore 25
  475. andlw 0xf ; mask nibble
  476. addlw 0x8 ; add #8 to HIGH nibble
  477. movwf 0x40
  478. btfss 0x40, 4 ; skip if carry to 5th bit
  479. addwf 0x26, w
  480. movwf 0x26
  481. movf 0x41, w ; restore 26
  482. addlw 0x1 ; inc
  483. addwf 0x27, f ; add to 27
  484. movf 0x27, w ;
  485. addlw 0x1 ; inc
  486. addwf 0x28, f ; add to 28
  487. movf 0x28, w ;
  488. addlw 0x1 ; inc
  489. addwf 0x29, f ; add to 29
  490. movf 0x29, w ;
  491. addlw 0x1 ; inc
  492. addwf 0x2a, f ; add to 2a
  493. movf 0x2a, w ;
  494. addlw 0x1 ; inc
  495. addwf 0x2b, f ; add to 2b
  496. movf 0x2b, w ;
  497. addlw 0x1 ; inc
  498. addwf 0x2c, f ; add to 2c
  499. movf 0x2c, w ;
  500. addlw 0x1 ; inc
  501. addwf 0x2d, f ; add to 2d
  502. movf 0x2d, w ;
  503. addlw 0x1 ; inc
  504. addwf 0x2e, f ; add to 2e
  505. movf 0x2e, w ;
  506. addlw 0x1 ; inc
  507. addwf 0x2f, f ; add to 2f
  508. movf 0x20, w ; restore original 0xf
  509. andlw 0xf
  510. addlw 0xf
  511. movwf 0x20
  512. nop
  513. nop
  514. nop
  515. nop
  516. nop
  517. nop
  518. nop
  519. nop
  520. nop
  521. btfss 0x20, 4 ; skip if half-byte carry
  522. goto mangle_return ; +2 cycles in return
  523. nop
  524. goto mangle_key_loop
  525. ; 69 when goto, 69 when return
  526. ; CIC has 78 -> 9 nops
  527. mangle_key_withskip
  528. movf 0x41, w ; restore 23
  529. addwf 0x23, f ; add to 23
  530. movf 0x24, w
  531. movwf 0x40 ; save 24 to 40
  532. movf 0x23, w
  533. addwf 0x24, f
  534. movf 0x25, w
  535. movwf 0x41 ; save 25 to 41
  536. movf 0x40, w ; restore 24
  537. andlw 0xf ; mask nibble
  538. addlw 0x8 ; add #8 to HIGH nibble
  539. movwf 0x40
  540. btfss 0x40, 4 ; skip if carry to 5th bit
  541. addwf 0x25, w
  542. movwf 0x25
  543. movf 0x41, w ; restore 25
  544. addlw 0x1 ; inc
  545. addwf 0x26, f ; add to 26
  546. movf 0x26, w ;
  547. addlw 0x1 ; inc
  548. addwf 0x27, f ; add to 27
  549. movf 0x27, w ;
  550. addlw 0x1 ; inc
  551. addwf 0x28, f ; add to 28
  552. movf 0x28, w ;
  553. addlw 0x1 ; inc
  554. addwf 0x29, f ; add to 29
  555. movf 0x29, w ;
  556. addlw 0x1 ; inc
  557. addwf 0x2a, f ; add to 2a
  558. movf 0x2a, w ;
  559. addlw 0x1 ; inc
  560. addwf 0x2b, f ; add to 2b
  561. movf 0x2b, w ;
  562. addlw 0x1 ; inc
  563. addwf 0x2c, f ; add to 2c
  564. movf 0x2c, w ;
  565. addlw 0x1 ; inc
  566. addwf 0x2d, f ; add to 2d
  567. movf 0x2d, w ;
  568. addlw 0x1 ; inc
  569. addwf 0x2e, f ; add to 2e
  570. movf 0x2e, w ;
  571. addlw 0x1 ; inc
  572. addwf 0x2f, f ; add to 2f
  573. movf 0x20, w ; restore original 0xf
  574. andlw 0xf
  575. addlw 0xf
  576. movwf 0x20
  577. bsf PORTC, 1
  578. movf PORTC, w
  579. movwf 0x5e
  580. nop
  581. bcf PORTC, 1
  582. movf PORTC, w
  583. movwf 0x5f
  584. nop
  585. nop
  586. nop
  587. nop
  588. btfss 0x20, 4 ; skip if half-byte carry
  589. goto mangle_return ; +2 cycles in return
  590. movf 0x20, w ; restore w (previously destroyed)
  591. goto mangle_key_loop
  592. mangle_return
  593. return
  594. ; 73 when goto, 73 when return
  595. ; CIC has 84 -> 11 nops
  596. mangle_lock
  597. movf 0x3f, w
  598. movwf 0x30
  599. mangle_lock_loop
  600. addlw 0x1
  601. addwf 0x31, f
  602. movf 0x32, w
  603. movwf 0x40
  604. movf 0x31, w
  605. addwf 0x32, f
  606. incf 0x32, f
  607. comf 0x32, f
  608. movf 0x33, w
  609. movwf 0x41 ; store 33 to 41
  610. movlw 0xf
  611. andwf 0x33, f
  612. movf 0x40, w ; add 40(32 old)+33+#1 and skip if carry
  613. andlw 0xf
  614. addwf 0x33, f
  615. incf 0x33, f
  616. btfsc 0x33, 4
  617. goto mangle_lock_withskip
  618. mangle_lock_withoutskip
  619. movf 0x41, w ; restore 33
  620. addwf 0x34, f ; add to 34
  621. movf 0x35, w
  622. movwf 0x40 ; save 35 to 40
  623. movf 0x34, w
  624. addwf 0x35, f
  625. movf 0x36, w
  626. movwf 0x41 ; save 36 to 41
  627. movf 0x40, w ; restore 35
  628. andlw 0xf ; mask nibble
  629. addlw 0x8 ; add #8 to HIGH nibble
  630. movwf 0x40
  631. btfss 0x40, 4 ; skip if carry to 5th bit
  632. addwf 0x36, w
  633. movwf 0x36
  634. movf 0x41, w ; restore 36
  635. addlw 0x1 ; inc
  636. addwf 0x37, f ; add to 37
  637. movf 0x37, w ;
  638. addlw 0x1 ; inc
  639. addwf 0x38, f ; add to 38
  640. movf 0x38, w ;
  641. addlw 0x1 ; inc
  642. addwf 0x39, f ; add to 39
  643. movf 0x39, w ;
  644. addlw 0x1 ; inc
  645. addwf 0x3a, f ; add to 3a
  646. movf 0x3a, w ;
  647. addlw 0x1 ; inc
  648. addwf 0x3b, f ; add to 3b
  649. movf 0x3b, w ;
  650. addlw 0x1 ; inc
  651. addwf 0x3c, f ; add to 3c
  652. movf 0x3c, w ;
  653. addlw 0x1 ; inc
  654. addwf 0x3d, f ; add to 3d
  655. movf 0x3d, w ;
  656. addlw 0x1 ; inc
  657. addwf 0x3e, f ; add to 3e
  658. movf 0x3e, w ;
  659. addlw 0x1 ; inc
  660. addwf 0x3f, f ; add to 3f
  661. movf 0x30, w ; restore original 0xf
  662. andlw 0xf
  663. addlw 0xf
  664. movwf 0x30
  665. nop
  666. nop
  667. nop
  668. nop
  669. nop
  670. nop
  671. nop
  672. nop
  673. nop
  674. btfss 0x30, 4 ; skip if half-byte carry
  675. goto mangle_return
  676. nop
  677. goto mangle_lock_loop
  678. ; 69 when goto, 69 when return
  679. ; CIC has 78 -> 9 nops
  680. mangle_lock_withskip
  681. movf 0x41, w ; restore 33
  682. addwf 0x33, f ; add to 33
  683. movf 0x34, w
  684. movwf 0x40 ; save 34 to 40
  685. movf 0x33, w
  686. addwf 0x34, f
  687. movf 0x35, w
  688. movwf 0x41 ; save 35 to 41
  689. movf 0x40, w ; restore 34
  690. andlw 0xf ; mask nibble
  691. addlw 0x8 ; add #8 to HIGH nibble
  692. movwf 0x40
  693. btfss 0x40, 4 ; skip if carry to 5th bit
  694. addwf 0x35, w
  695. movwf 0x35
  696. movf 0x41, w ; restore 35
  697. addlw 0x1 ; inc
  698. addwf 0x36, f ; add to 36
  699. movf 0x36, w ;
  700. addlw 0x1 ; inc
  701. addwf 0x37, f ; add to 37
  702. movf 0x37, w ;
  703. addlw 0x1 ; inc
  704. addwf 0x38, f ; add to 38
  705. movf 0x38, w ;
  706. addlw 0x1 ; inc
  707. addwf 0x39, f ; add to 39
  708. movf 0x39, w ;
  709. addlw 0x1 ; inc
  710. addwf 0x3a, f ; add to 3a
  711. movf 0x3a, w ;
  712. addlw 0x1 ; inc
  713. addwf 0x3b, f ; add to 3b
  714. movf 0x3b, w ;
  715. addlw 0x1 ; inc
  716. addwf 0x3c, f ; add to 3c
  717. movf 0x3c, w ;
  718. addlw 0x1 ; inc
  719. addwf 0x3d, f ; add to 3d
  720. movf 0x3d, w ;
  721. addlw 0x1 ; inc
  722. addwf 0x3e, f ; add to 3e
  723. movf 0x3e, w ;
  724. addlw 0x1 ; inc
  725. addwf 0x3f, f ; add to 3f
  726. movf 0x30, w ; restore original 0xf
  727. andlw 0xf
  728. addlw 0xf
  729. movwf 0x30
  730. btfsc 0x5e, 0
  731. goto scic_pair_skip1
  732. btfss 0x5f, 0
  733. goto scic_pair_skip2
  734. goto supercic_pairmode
  735. scic_pair_skip1
  736. nop
  737. nop
  738. scic_pair_skip2
  739. nop
  740. nop
  741. nop
  742. nop
  743. nop
  744. nop
  745. btfss 0x30, 4 ; skip if half-byte carry
  746. goto mangle_return
  747. nop
  748. goto mangle_lock_loop
  749. ; 73 when goto, 73 when return
  750. ; CIC has 84 -> 11 nops
  751. ; --------wait: 3*(W-1)+7 cycles (including call+return). W=0 -> 256!--------
  752. wait
  753. movwf 0x4f
  754. wait0 decfsz 0x4f, f
  755. goto wait0
  756. return
  757. ; --------wait long: 8+(3*(w-1))+(772*w). W=0 -> 256!--------
  758. longwait
  759. movwf 0x4e
  760. clrw
  761. longwait0
  762. call wait
  763. decfsz 0x4e, f
  764. goto longwait0
  765. return
  766. ; --------die (do nothing, wait for reset)--------
  767. die
  768. btfsc PORTA, 0
  769. goto rst
  770. goto die
  771. ; --------check the key input and change "region" when appropriate--------
  772. ; --------requires 20 cycles (incl. call+return)
  773. checkkey
  774. btfss 0x43, 0 ; first time?
  775. goto checkkey_nocheck; if not, just burn some cycles
  776. movlw 0x22 ; are we at the correct stream offset?
  777. xorwf FSR, w
  778. btfss STATUS, Z ; if not equal:
  779. goto checkkey_nocheck2; burn some cycles less.
  780. ; if equal do the check
  781. btfss 0x42, 0 ; if value from slave is set it's a 411
  782. goto checkkey_413
  783. checkkey_411
  784. nop ; to compensate for untaken branch
  785. bcf 0x57, 1 ; set detected mode (60Hz)
  786. bcf 0x59, 4 ; set detected D4 mode (60Hz)
  787. bcf 0x54, 1 ; set output mode (60Hz)
  788. movlw 0x9
  789. goto checkkey_save
  790. checkkey_413
  791. bsf 0x57, 1 ; set detected mode (50Hz)
  792. bsf 0x59, 4 ; set detected D4 mode (50Hz)
  793. bsf 0x54, 1 ; set output mode (50Hz)
  794. movlw 0x6
  795. goto checkkey_save
  796. checkkey_nocheck
  797. nop
  798. nop
  799. nop
  800. nop
  801. checkkey_nocheck2
  802. nop
  803. nop
  804. nop
  805. nop
  806. nop
  807. nop
  808. nop
  809. goto checkkey_done
  810. checkkey_save
  811. movwf 0x32
  812. checkkey_done
  813. return
  814. ; -------- check reset button, update status LEDs, etc.
  815. checkrst ; 4
  816. movf PORTA, w
  817. btfss 0x51, 0
  818. goto checkrst_0
  819. nop
  820. checkrst_1 ; 4
  821. movwf 0x51
  822. btfsc 0x51, 0
  823. goto checkrst_1_1
  824. nop
  825. checkrst_1_0 ; 26
  826. ; if modechange flag is set: clear modechange flag, set mode, save, restart timer
  827. ; else reset
  828. btfss 0x52, 0
  829. goto rst2 ; modechange flag is not set, reset. timing is irrelevant
  830. clrf 0x52 ; clear modechange flag
  831. movf 0x56, w ; get temp mode
  832. movwf 0x55 ; set final mode
  833. movwf 0x58 ; set forced mode
  834. banksel EEADR ; save to EEPROM. note: banksels take two cycles each!
  835. movwf EEDAT
  836. bsf EECON1,WREN
  837. movlw 0x55
  838. movwf EECON2
  839. movlw 0xaa
  840. movwf EECON2
  841. bsf EECON1, WR
  842. banksel PORTA ; two cycles again
  843. movlw 0x2
  844. andwf 0x58, f ; cleanup forced mode
  845. bcf T1CON, 0 ; stop the timer
  846. clrf PIR1 ; reset overflow bit
  847. clrf TMR1L ; reset counter
  848. clrf TMR1H
  849. bsf T1CON, 0 ; restart the timer
  850. return ; shortcut (no goto checkrst_end)
  851. checkrst_1_1 ; 24
  852. ; check TMR overflow
  853. ; if overflow, change LED, reset TMR+overflow, set modechange flag
  854. ; else do nothing
  855. nop
  856. nop
  857. nop
  858. nop
  859. btfss PIR1, 0
  860. goto checkrst_end_plus17
  861. bcf T1CON, 0 ; stop the timer
  862. clrf PIR1 ; reset overflow bit
  863. clrf TMR1L ; reset counter
  864. clrf TMR1H
  865. bsf T1CON, 0 ; restart the timer
  866. incf 0x56, f ; change tmp LED/mode
  867. movlw 0x5
  868. btfsc 0x56, 2 ; if 4:
  869. xorwf 0x56, f ; change back to 1
  870. movf 0x56, w
  871. andlw 0x03 ; mask
  872. btfsc PORTC, 3 ; invert LEDs?
  873. xorlw 0x03 ; then make it so
  874. movwf 0x50
  875. swapf 0x50, f ; adjust for GPIO pins
  876. bsf 0x52, 0 ; set modechange flag
  877. goto checkrst_end
  878. checkrst_0 ; 4
  879. movwf 0x51
  880. btfsc 0x51, 0
  881. goto checkrst_0_1
  882. nop
  883. checkrst_0_0 ; 24
  884. nop
  885. nop
  886. nop
  887. nop
  888. nop
  889. nop
  890. ; count some overflows, change region from detected to forced unless auto
  891. btfsc 0x53, 4 ; past delay?
  892. goto checkrst_0_0_setregion_plus5
  893. btfss PIR1, 0
  894. goto checkrst_end_plus13
  895. clrf PIR1
  896. incf 0x53, f ; increment overflow counter
  897. btfss 0x53, 4 ; 0x10 reached?
  898. goto checkrst_end_plus9
  899. checkrst_0_0_setregion
  900. movlw 0x3
  901. xorwf 0x55, w ; mode=auto?
  902. btfss STATUS, Z
  903. goto checkrst_0_0_setregion_forced
  904. checkrst_0_0_setregion_auto
  905. movf 0x57, w ; get detected region
  906. goto checkrst_0_0_setregion_save
  907. checkrst_0_0_setregion_forced
  908. movf 0x58, w ; get forced region
  909. nop
  910. checkrst_0_0_setregion_save
  911. movwf 0x54 ; set to output
  912. goto checkrst_end
  913. checkrst_0_1 ; 24
  914. ; reset + start TMR, reset TMR overflow
  915. clrf TMR1L ; reset timer register
  916. clrf TMR1H
  917. clrf PIR1 ; clear overflow bit
  918. bsf T1CON, 0
  919. goto checkrst_end_plus18
  920. checkrst_end ; 2
  921. return
  922. checkrst_end_plus18
  923. nop
  924. checkrst_end_plus17
  925. nop
  926. nop
  927. nop
  928. nop
  929. checkrst_end_plus13
  930. nop
  931. nop
  932. nop
  933. nop
  934. checkrst_end_plus9
  935. nop
  936. nop
  937. nop
  938. nop
  939. nop
  940. nop
  941. nop
  942. goto checkrst_end
  943. checkrst_0_0_setregion_plus5
  944. nop
  945. nop
  946. nop
  947. goto checkrst_0_0_setregion
  948. supercic_pairmode
  949. banksel TRISC
  950. bsf TRISC, 0 ; tristate both
  951. bsf TRISC, 1 ; data lines
  952. banksel PORTC
  953. supercic_pairmode_loop
  954. clrf 0x5d
  955. bsf 0x5d, 2
  956. btfsc PORTC, 0
  957. bsf 0x5d, 1
  958. btfsc PORTC, 1
  959. bsf 0x5d, 4
  960. btfsc PORTA, 0
  961. bcf 0x5d, 2
  962. movf 0x5d, w
  963. movwf PORTA
  964. btfss PORTC, 0
  965. goto supercic_pairmode_led_60
  966. supercic_pairmode_led_50
  967. movlw 0x20
  968. btfsc PORTC, 3
  969. xorlw 0x30
  970. movwf PORTC
  971. goto supercic_pairmode_loop
  972. supercic_pairmode_led_60
  973. movlw 0x10
  974. btfsc PORTC, 3
  975. xorlw 0x30
  976. movwf PORTC
  977. goto supercic_pairmode_loop
  978. rst2
  979. bcf PORTA, 2 ; hold the SNES in reset
  980. bcf T1CON, 0 ; stop the timer
  981. clrf TMR1L ; reset timer register
  982. clrf TMR1H
  983. clrf PIR1 ; clear overflow bit
  984. bsf T1CON, 0
  985. clrf 0x51 ; clear reset button state
  986. rst2_loop1
  987. btfsc PORTA, 0 ; if reset button is pressed
  988. bsf 0x51, 0 ; set reset flag
  989. btfss PIR1, 0 ; break if timeout
  990. goto rst2_loop1
  991. btfss 0x51, 0 ; if no 2nd reset button press occured:
  992. goto rst ; just reset normally
  993. clrf 0x53 ; else keep resetting some more
  994. bcf T1CON, 0 ; stop the timer
  995. clrf TMR1L ; reset timer register
  996. clrf TMR1H
  997. clrf PIR1 ; clear overflow bit
  998. bsf T1CON, 0
  999. rst2_loop2
  1000. btfss PIR1, 0
  1001. goto rst2_loop2
  1002. clrf PIR1
  1003. incf 0x53, f
  1004. movlw 0x0a
  1005. xorwf 0x53, w
  1006. btfss STATUS, Z ; 10 overflows ~= 5.86s
  1007. goto rst2_loop2
  1008. goto rst ; finally reset
  1009. ; -----------------------------------------------------------------------
  1010. ; eeprom data
  1011. DEEPROM CODE
  1012. de 0x01 ;current mode (default: 60Hz)
  1013. end
  1014. ; ------------------------------------------------------------------------