diff options
23 files changed, 5382 insertions, 0 deletions
diff --git a/source/notes/pic-mcu/pic18.md b/source/notes/pic-mcu/pic18.md new file mode 100644 index 0000000..b76aa84 --- /dev/null +++ b/source/notes/pic-mcu/pic18.md @@ -0,0 +1,26 @@ +# PIC18 +Notes on the PIC18 family of chips. + +<a name="pic18f2550"> +# PIC18F2550 +</a> +[Datasheet](http://ww1.microchip.com/downloads/en/devicedoc/39632c.pdf) + +### Architecture +One working register, `W`. Most instructions read from/write to `W`, except `movff` which can move from a file (memory, ish) to a file. +* Even `movff` can read/write to memory through address `0xfe8` aka `WREG` + +Memory `0xf60` to `0xfff` are "Special Function Registers", described around page 68. Commonly seen SFRs: +#### `TBLPTR*` +Parts of the table pointer used in `tblrd`/`tblwr` instructions. +<a name="pic18f2550_fsr"> +#### `FSR0`, `FSR1`, `FSR2` +</a> +`FSR*` contain a 16-bit word typically used to indirectly reference memory. + +.. and the `INDF*`, `POSTINC*`, `POSTDEC*`, `PREINC*`, and `PLUSW*` registers. `*` for all of those can be `0`, `1`, or `2`, and all of these are used to indirectly access memory at `FSR0`, `FSR1`, or `FSR2`, respectively. `INDF` is a simple indirect access, while `POSTINC`, `POSTDEC`, and `PREINC` increment or decrement the appropriate `FSR`. `PLUSW*` is an indirect memory access to the selected `[FSR* + W]` as the name indicates. +#### `TRIS*` +`TRIS*` SFR control the state of pins mapped to ports `A`, `B`, and `C`. `0` indicates output ??? while `1` indicates input. +For example: `0xf6` being loaded into `TRISB` would set pins to `11110110`, making all pins inputs except pins 0 and 3, which would be set to output. +#### `PORT*` +`PORT*` SFR are the current state of the pins for ports `A`, `B`, and `C`. If `TRIS_X_` is set to be inputs for a port X, and `PORT_X_` is read, the value indicates if those pins are currently high or low. diff --git a/source/notes/pic-mcu/pic_index.md b/source/notes/pic-mcu/pic_index.md new file mode 100644 index 0000000..9a4cf0c --- /dev/null +++ b/source/notes/pic-mcu/pic_index.md @@ -0,0 +1,8 @@ +# [PICKit2](pickit2/index.html) +Notes, process, and tools for reverse engineering parts of the PICKit2 programmer +# [pk2cmd](pickit2/pk2cmd/index.html) +Notes on pk2cmd, which is PC-side software to drive PICKit2 programmers +# [L1 Demoboard](l1_demoboard/index.html) +Notes on programming the L1 demoboard. Eventually might actually have demoboard-specific thoughts. +# Celestron CPC +Notes on remotely controlling Celestron CPC mounts from a computer. Additionally, the handset freezes sometimes, and I'm going to figure out the cause and maybe fix it. diff --git a/source/notes/pic-mcu/pickit2/index.md b/source/notes/pic-mcu/pickit2/index.md new file mode 100644 index 0000000..2fff243 --- /dev/null +++ b/source/notes/pic-mcu/pickit2/index.md @@ -0,0 +1,7 @@ +# PICKit2 +* [Intro/Notes](pickit2_intro.html) +* [Options](pickit2.html#parameters) +* [Part list](pickit2.html#partlist) +* [PICKit2 Tools](pickit2.html#tools) +* [PK2DeviceFile.dat](pickit2.html#pk2devicefile) +* [Scripts](pickit2.html#scripts) diff --git a/source/notes/pic-mcu/pickit2/partlist_w_term b/source/notes/pic-mcu/pickit2/partlist_w_term new file mode 100644 index 0000000..e355378 --- /dev/null +++ b/source/notes/pic-mcu/pickit2/partlist_w_term @@ -0,0 +1,678 @@ +> sudo ./pk2cmd -?P + +Device File Version: 1.62.15 +Number of devices = 662 + +Device Name Device Family +----------- ------------- +PIC10F200 Baseline +PIC10F202 Baseline +PIC10F204 Baseline +PIC10F206 Baseline +PIC10F220 Baseline +PIC10F222 Baseline +PIC12F508 Baseline +PIC12F509 Baseline +PIC12F510 Baseline +PIC12F519 Baseline +PIC12F529 Baseline +PIC16F54 Baseline +PIC16F57 Baseline +PIC16F59 Baseline +PIC16F505 Baseline +PIC16F506 Baseline +PIC16F526 Baseline +PIC12F609 Midrange/Standard +PIC12F615 Midrange/Standard +PIC12F617 Midrange/Standard +PIC12F629 Midrange/Standard +PIC12F635 Midrange/Standard +PIC12F675 Midrange/Standard +PIC12F683 Midrange/Standard +PIC12F752 Midrange/Standard +PIC12HV609 Midrange/Standard +PIC12HV615 Midrange/Standard +PIC12HV752 Midrange/Standard +PIC16F72 Midrange/Standard +PIC16F73 Midrange/Standard +PIC16F74 Midrange/Standard +PIC16F76 Midrange/Standard +PIC16F77 Midrange/Standard +PIC16F84A Midrange/Standard +PIC16F87 Midrange/Standard +PIC16F88 Midrange/Standard +PIC16F610 Midrange/Standard +PIC16F616 Midrange/Standard +PIC16F627 Midrange/Standard +PIC16F627A Midrange/Standard +PIC16F628 Midrange/Standard +PIC16F628A Midrange/Standard +PIC16F630 Midrange/Standard +PIC16F631 Midrange/Standard +PIC16F636 (639) Midrange/Standard +PIC16F648A Midrange/Standard +PIC16F676 Midrange/Standard +PIC16F677 Midrange/Standard +PIC16F684 Midrange/Standard +PIC16F685 Midrange/Standard +PIC16F687 Midrange/Standard +PIC16F688 Midrange/Standard +PIC16F689 Midrange/Standard +PIC16F690 Midrange/Standard +PIC16F716 Midrange/Standard +PIC16F737 Midrange/Standard +PIC16F747 Midrange/Standard +PIC16F767 Midrange/Standard +PIC16F777 Midrange/Standard +PIC16F785 Midrange/Standard +PIC16F818 Midrange/Standard +PIC16F819 Midrange/Standard +PIC16F870 Midrange/Standard +PIC16F871 Midrange/Standard +PIC16F872 Midrange/Standard +PIC16F873 Midrange/Standard +PIC16F873A Midrange/Standard +PIC16F874 Midrange/Standard +PIC16F874A Midrange/Standard +PIC16F876 Midrange/Standard +PIC16F876A Midrange/Standard +PIC16F877 Midrange/Standard +PIC16F877A Midrange/Standard +PIC16F882 Midrange/Standard +PIC16F883 Midrange/Standard +PIC16F884 Midrange/Standard +PIC16F886 Midrange/Standard +PIC16F887 Midrange/Standard +PIC16F913 Midrange/Standard +PIC16F914 Midrange/Standard +PIC16F916 Midrange/Standard +PIC16F917 Midrange/Standard +PIC16F946 Midrange/Standard +PIC16HV610 Midrange/Standard +PIC16HV616 Midrange/Standard +PIC16HV785 Midrange/Standard +PIC10F320 Midrange/1.8V Min +PIC10F322 Midrange/1.8V Min +PIC10LF320 Midrange/1.8V Min +PIC10LF322 Midrange/1.8V Min +PIC12F1822 Midrange/1.8V Min +PIC12F1840 Midrange/1.8V Min +PIC12LF1822 Midrange/1.8V Min +PIC12LF1840 Midrange/1.8V Min +PIC16F707 Midrange/1.8V Min +PIC16F720 Midrange/1.8V Min +PIC16F721 Midrange/1.8V Min +PIC16F722 Midrange/1.8V Min +PIC16F722A Midrange/1.8V Min +PIC16F723 Midrange/1.8V Min +PIC16F723A Midrange/1.8V Min +PIC16F724 Midrange/1.8V Min +PIC16F726 Midrange/1.8V Min +PIC16F727 Midrange/1.8V Min +PIC16F1503 Midrange/1.8V Min +PIC16F1507 Midrange/1.8V Min +PIC16F1508 Midrange/1.8V Min +PIC16F1509 Midrange/1.8V Min +PIC16F1516 Midrange/1.8V Min +PIC16F1517 Midrange/1.8V Min +PIC16F1518 Midrange/1.8V Min +PIC16F1519 Midrange/1.8V Min +PIC16F1526 Midrange/1.8V Min +PIC16F1527 Midrange/1.8V Min +PIC16F1782 Midrange/1.8V Min +PIC16F1783 Midrange/1.8V Min +PIC16F1823 Midrange/1.8V Min +PIC16F1824 Midrange/1.8V Min +PIC16F1825 Midrange/1.8V Min +PIC16F1826 Midrange/1.8V Min +PIC16F1827 Midrange/1.8V Min +PIC16F1828 Midrange/1.8V Min +PIC16F1829 Midrange/1.8V Min +PIC16F1847 Midrange/1.8V Min +PIC16F1933 Midrange/1.8V Min +PIC16F1934 Midrange/1.8V Min +PIC16F1936 Midrange/1.8V Min +PIC16F1937 Midrange/1.8V Min +PIC16F1938 Midrange/1.8V Min +PIC16F1939 Midrange/1.8V Min +PIC16F1946 Midrange/1.8V Min +PIC16F1947 Midrange/1.8V Min +PIC16LF707 Midrange/1.8V Min +PIC16LF720 Midrange/1.8V Min +PIC16LF721 Midrange/1.8V Min +PIC16LF722 Midrange/1.8V Min +PIC16LF722A Midrange/1.8V Min +PIC16LF723 Midrange/1.8V Min +PIC16LF723A Midrange/1.8V Min +PIC16LF724 Midrange/1.8V Min +PIC16LF726 Midrange/1.8V Min +PIC16LF727 Midrange/1.8V Min +PIC16LF1503 Midrange/1.8V Min +PIC16LF1507 Midrange/1.8V Min +PIC16LF1508 Midrange/1.8V Min +PIC16LF1509 Midrange/1.8V Min +PIC16LF1516 Midrange/1.8V Min +PIC16LF1517 Midrange/1.8V Min +PIC16LF1518 Midrange/1.8V Min +PIC16LF1519 Midrange/1.8V Min +PIC16LF1526 Midrange/1.8V Min +PIC16LF1527 Midrange/1.8V Min +PIC16LF1782 Midrange/1.8V Min +PIC16LF1783 Midrange/1.8V Min +PIC16LF1823 Midrange/1.8V Min +PIC16LF1824 Midrange/1.8V Min +PIC16LF1825 Midrange/1.8V Min +PIC16LF1826 Midrange/1.8V Min +PIC16LF1827 Midrange/1.8V Min +PIC16LF1828 Midrange/1.8V Min +PIC16LF1829 Midrange/1.8V Min +PIC16LF1847 Midrange/1.8V Min +PIC16LF1902 Midrange/1.8V Min +PIC16LF1903 Midrange/1.8V Min +PIC16LF1904 Midrange/1.8V Min +PIC16LF1906 Midrange/1.8V Min +PIC16LF1907 Midrange/1.8V Min +PIC16LF1933 Midrange/1.8V Min +PIC16LF1934 Midrange/1.8V Min +PIC16LF1936 Midrange/1.8V Min +PIC16LF1937 Midrange/1.8V Min +PIC16LF1938 Midrange/1.8V Min +PIC16LF1939 Midrange/1.8V Min +PIC16LF1946 Midrange/1.8V Min +PIC16LF1947 Midrange/1.8V Min +PIC18F242 PIC18F +PIC18F248 PIC18F +PIC18F252 PIC18F +PIC18F258 PIC18F +PIC18F442 PIC18F +PIC18F448 PIC18F +PIC18F452 PIC18F +PIC18F458 PIC18F +PIC18F1220 PIC18F +PIC18F1230 PIC18F +PIC18F1320 PIC18F +PIC18F1330 PIC18F +PIC18F1330-ICD PIC18F +PIC18F2220 PIC18F +PIC18F2221 PIC18F +PIC18F2320 PIC18F +PIC18F2321 PIC18F +PIC18F2331 PIC18F +PIC18F2410 PIC18F +PIC18F2420 PIC18F +PIC18F2423 PIC18F +PIC18F2431 PIC18F +PIC18F2450 PIC18F +PIC18F2455 PIC18F +PIC18F2458 PIC18F +PIC18F2480 PIC18F +PIC18F2510 PIC18F +PIC18F2515 PIC18F +PIC18F2520 PIC18F +PIC18F2523 PIC18F +PIC18F2525 PIC18F +PIC18F2550 PIC18F +PIC18F2553 PIC18F +PIC18F2580 PIC18F +PIC18F2585 PIC18F +PIC18F2610 PIC18F +PIC18F2620 PIC18F +PIC18F2680 PIC18F +PIC18F2682 PIC18F +PIC18F2685 PIC18F +PIC18F4220 PIC18F +PIC18F4221 PIC18F +PIC18F4320 PIC18F +PIC18F4321 PIC18F +PIC18F4331 PIC18F +PIC18F4410 PIC18F +PIC18F4420 PIC18F +PIC18F4423 PIC18F +PIC18F4431 PIC18F +PIC18F4450 PIC18F +PIC18F4455 PIC18F +PIC18F4458 PIC18F +PIC18F4480 PIC18F +PIC18F4510 PIC18F +PIC18F4515 PIC18F +PIC18F4520 PIC18F +PIC18F4523 PIC18F +PIC18F4525 PIC18F +PIC18F4550 PIC18F +PIC18F4553 PIC18F +PIC18F4580 PIC18F +PIC18F4585 PIC18F +PIC18F4610 PIC18F +PIC18F4620 PIC18F +PIC18F4680 PIC18F +PIC18F4682 PIC18F +PIC18F4685 PIC18F +PIC18F6310 PIC18F +PIC18F6390 PIC18F +PIC18F6393 PIC18F +PIC18F6410 PIC18F +PIC18F6490 PIC18F +PIC18F6493 PIC18F +PIC18F6520 PIC18F +PIC18F6525 PIC18F +PIC18F6527 PIC18F +PIC18F6585 PIC18F +PIC18F6620 PIC18F +PIC18F6621 PIC18F +PIC18F6622 PIC18F +PIC18F6627 PIC18F +PIC18F6628 PIC18F +PIC18F6680 PIC18F +PIC18F6720 PIC18F +PIC18F6722 PIC18F +PIC18F6723 PIC18F +PIC18F8310 PIC18F +PIC18F8390 PIC18F +PIC18F8393 PIC18F +PIC18F8410 PIC18F +PIC18F8490 PIC18F +PIC18F8493 PIC18F +PIC18F8520 PIC18F +PIC18F8525 PIC18F +PIC18F8527 PIC18F +PIC18F8585 PIC18F +PIC18F8620 PIC18F +PIC18F8621 PIC18F +PIC18F8622 PIC18F +PIC18F8627 PIC18F +PIC18F8628 PIC18F +PIC18F8680 PIC18F +PIC18F8720 PIC18F +PIC18F8722 PIC18F +PIC18F8723 PIC18F +PIC18LF6520 PIC18F +PIC18LF8520 PIC18F +PIC18F24J10 PIC18F_J_ +PIC18F24J11 PIC18F_J_ +PIC18F24J50 PIC18F_J_ +PIC18F25J10 PIC18F_J_ +PIC18F25J11 PIC18F_J_ +PIC18F25J50 PIC18F_J_ +PIC18F26J11 PIC18F_J_ +PIC18F26J50 PIC18F_J_ +PIC18F44J10 PIC18F_J_ +PIC18F44J11 PIC18F_J_ +PIC18F44J50 PIC18F_J_ +PIC18F45J10 PIC18F_J_ +PIC18F45J11 PIC18F_J_ +PIC18F45J50 PIC18F_J_ +PIC18F46J11 PIC18F_J_ +PIC18F46J50 PIC18F_J_ +PIC18F63J11 PIC18F_J_ +PIC18F63J90 PIC18F_J_ +PIC18F64J11 PIC18F_J_ +PIC18F64J90 PIC18F_J_ +PIC18F65J10 PIC18F_J_ +PIC18F65J11 PIC18F_J_ +PIC18F65J15 PIC18F_J_ +PIC18F65J50 PIC18F_J_ +PIC18F65J90 PIC18F_J_ +PIC18F66J10 PIC18F_J_ +PIC18F66J11 PIC18F_J_ +PIC18F66J15 PIC18F_J_ +PIC18F66J16 PIC18F_J_ +PIC18F66J50 PIC18F_J_ +PIC18F66J55 PIC18F_J_ +PIC18F66J60 PIC18F_J_ +PIC18F66J65 PIC18F_J_ +PIC18F66J90 PIC18F_J_ +PIC18F67J10 PIC18F_J_ +PIC18F67J11 PIC18F_J_ +PIC18F67J50 PIC18F_J_ +PIC18F67J60 PIC18F_J_ +PIC18F67J90 PIC18F_J_ +PIC18F83J11 PIC18F_J_ +PIC18F83J90 PIC18F_J_ +PIC18F84J11 PIC18F_J_ +PIC18F84J90 PIC18F_J_ +PIC18F85J10 PIC18F_J_ +PIC18F85J11 PIC18F_J_ +PIC18F85J15 PIC18F_J_ +PIC18F85J50 PIC18F_J_ +PIC18F85J90 PIC18F_J_ +PIC18F86J10 PIC18F_J_ +PIC18F86J11 PIC18F_J_ +PIC18F86J15 PIC18F_J_ +PIC18F86J16 PIC18F_J_ +PIC18F86J50 PIC18F_J_ +PIC18F86J55 PIC18F_J_ +PIC18F86J60 PIC18F_J_ +PIC18F86J65 PIC18F_J_ +PIC18F86J90 PIC18F_J_ +PIC18F87J10 PIC18F_J_ +PIC18F87J11 PIC18F_J_ +PIC18F87J50 PIC18F_J_ +PIC18F87J60 PIC18F_J_ +PIC18F87J90 PIC18F_J_ +PIC18F96J60 PIC18F_J_ +PIC18F96J65 PIC18F_J_ +PIC18F97J60 PIC18F_J_ +PIC18LF24J10 PIC18F_J_ +PIC18LF24J11 PIC18F_J_ +PIC18LF24J50 PIC18F_J_ +PIC18LF25J10 PIC18F_J_ +PIC18LF25J11 PIC18F_J_ +PIC18LF25J50 PIC18F_J_ +PIC18LF26J11 PIC18F_J_ +PIC18LF26J50 PIC18F_J_ +PIC18LF44J10 PIC18F_J_ +PIC18LF44J11 PIC18F_J_ +PIC18LF44J50 PIC18F_J_ +PIC18LF45J10 PIC18F_J_ +PIC18LF45J11 PIC18F_J_ +PIC18LF45J50 PIC18F_J_ +PIC18LF46J11 PIC18F_J_ +PIC18LF46J50 PIC18F_J_ +PIC18F13K22 PIC18F_K_ +PIC18F13K50 PIC18F_K_ +PIC18F14K22 PIC18F_K_ +PIC18F14K50 PIC18F_K_ +PIC18F14K50-ICD PIC18F_K_ +PIC18F23K20 PIC18F_K_ +PIC18F23K22 PIC18F_K_ +PIC18F24K20 PIC18F_K_ +PIC18F24K22 PIC18F_K_ +PIC18F25K20 PIC18F_K_ +PIC18F25K22 PIC18F_K_ +PIC18F26K20 PIC18F_K_ +PIC18F26K22 PIC18F_K_ +PIC18F26K80 PIC18F_K_ +PIC18F43K20 PIC18F_K_ +PIC18F43K22 PIC18F_K_ +PIC18F44K20 PIC18F_K_ +PIC18F44K22 PIC18F_K_ +PIC18F45K20 PIC18F_K_ +PIC18F45K22 PIC18F_K_ +PIC18F46K20 PIC18F_K_ +PIC18F46K22 PIC18F_K_ +PIC18LF13K22 PIC18F_K_ +PIC18LF13K50 PIC18F_K_ +PIC18LF14K22 PIC18F_K_ +PIC18LF14K50 PIC18F_K_ +PIC18LF14K50-ICD PIC18F_K_ +PIC18LF23K22 PIC18F_K_ +PIC18LF24K22 PIC18F_K_ +PIC18LF25K22 PIC18F_K_ +PIC18LF26K22 PIC18F_K_ +PIC18LF43K22 PIC18F_K_ +PIC18LF44K22 PIC18F_K_ +PIC18LF45K22 PIC18F_K_ +PIC18LF46K22 PIC18F_K_ +PIC24F04KA200 PIC24 +PIC24F04KA201 PIC24 +PIC24F08KA101 PIC24 +PIC24F08KA102 PIC24 +PIC24F16KA101 PIC24 +PIC24F16KA102 PIC24 +PIC24FJ16GA002 PIC24 +PIC24FJ16GA004 PIC24 +PIC24FJ32GA002 PIC24 +PIC24FJ32GA004 PIC24 +PIC24FJ32GA102 PIC24 +PIC24FJ32GA104 PIC24 +PIC24FJ32GB002 PIC24 +PIC24FJ32GB004 PIC24 +PIC24FJ48GA002 PIC24 +PIC24FJ48GA004 PIC24 +PIC24FJ64GA002 PIC24 +PIC24FJ64GA004 PIC24 +PIC24FJ64GA006 PIC24 +PIC24FJ64GA008 PIC24 +PIC24FJ64GA010 PIC24 +PIC24FJ64GA102 PIC24 +PIC24FJ64GA104 PIC24 +PIC24FJ64GB002 PIC24 +PIC24FJ64GB004 PIC24 +PIC24FJ64GB106 PIC24 +PIC24FJ64GB108 PIC24 +PIC24FJ64GB110 PIC24 +PIC24FJ96GA006 PIC24 +PIC24FJ96GA008 PIC24 +PIC24FJ96GA010 PIC24 +PIC24FJ128GA006 PIC24 +PIC24FJ128GA008 PIC24 +PIC24FJ128GA010 PIC24 +PIC24FJ128GA106 PIC24 +PIC24FJ128GA108 PIC24 +PIC24FJ128GA110 PIC24 +PIC24FJ128GB106 PIC24 +PIC24FJ128GB108 PIC24 +PIC24FJ128GB110 PIC24 +PIC24FJ192GA106 PIC24 +PIC24FJ192GA108 PIC24 +PIC24FJ192GA110 PIC24 +PIC24FJ192GB106 PIC24 +PIC24FJ192GB108 PIC24 +PIC24FJ192GB110 PIC24 +PIC24FJ256GA106 PIC24 +PIC24FJ256GA108 PIC24 +PIC24FJ256GA110 PIC24 +PIC24FJ256GB106 PIC24 +PIC24FJ256GB108 PIC24 +PIC24FJ256GB110 PIC24 +PIC24HJ12GP201 PIC24 +PIC24HJ12GP202 PIC24 +PIC24HJ16GP304 PIC24 +PIC24HJ32GP202 PIC24 +PIC24HJ32GP204 PIC24 +PIC24HJ32GP302 PIC24 +PIC24HJ32GP304 PIC24 +PIC24HJ64GP202 PIC24 +PIC24HJ64GP204 PIC24 +PIC24HJ64GP206 PIC24 +PIC24HJ64GP210 PIC24 +PIC24HJ64GP502 PIC24 +PIC24HJ64GP504 PIC24 +PIC24HJ64GP506 PIC24 +PIC24HJ64GP510 PIC24 +PIC24HJ128GP202 PIC24 +PIC24HJ128GP204 PIC24 +PIC24HJ128GP206 PIC24 +PIC24HJ128GP210 PIC24 +PIC24HJ128GP306 PIC24 +PIC24HJ128GP310 PIC24 +PIC24HJ128GP502 PIC24 +PIC24HJ128GP504 PIC24 +PIC24HJ128GP506 PIC24 +PIC24HJ128GP510 PIC24 +PIC24HJ256GP206 PIC24 +PIC24HJ256GP210 PIC24 +PIC24HJ256GP610 PIC24 +DSPIC33FJ06GS101 dsPIC33 +DSPIC33FJ06GS102 dsPIC33 +DSPIC33FJ06GS202 dsPIC33 +DSPIC33FJ12GP201 dsPIC33 +DSPIC33FJ12GP202 dsPIC33 +DSPIC33FJ12MC201 dsPIC33 +DSPIC33FJ12MC202 dsPIC33 +DSPIC33FJ16GP304 dsPIC33 +DSPIC33FJ16GS402 dsPIC33 +DSPIC33FJ16GS404 dsPIC33 +DSPIC33FJ16GS502 dsPIC33 +DSPIC33FJ16GS504 dsPIC33 +DSPIC33FJ16MC304 dsPIC33 +DSPIC33FJ32GP202 dsPIC33 +DSPIC33FJ32GP204 dsPIC33 +DSPIC33FJ32GP302 dsPIC33 +DSPIC33FJ32GP304 dsPIC33 +DSPIC33FJ32MC202 dsPIC33 +DSPIC33FJ32MC204 dsPIC33 +DSPIC33FJ32MC302 dsPIC33 +DSPIC33FJ32MC304 dsPIC33 +DSPIC33FJ64GP202 dsPIC33 +DSPIC33FJ64GP204 dsPIC33 +DSPIC33FJ64GP206(A) dsPIC33 +DSPIC33FJ64GP306(A) dsPIC33 +DSPIC33FJ64GP310(A) dsPIC33 +DSPIC33FJ64GP706(A) dsPIC33 +DSPIC33FJ64GP708(A) dsPIC33 +DSPIC33FJ64GP710(A) dsPIC33 +DSPIC33FJ64GP802 dsPIC33 +DSPIC33FJ64GP804 dsPIC33 +DSPIC33FJ64MC202 dsPIC33 +DSPIC33FJ64MC204 dsPIC33 +DSPIC33FJ64MC506 dsPIC33 +DSPIC33FJ64MC508 dsPIC33 +DSPIC33FJ64MC510 dsPIC33 +DSPIC33FJ64MC706 dsPIC33 +DSPIC33FJ64MC710 dsPIC33 +DSPIC33FJ64MC802 dsPIC33 +DSPIC33FJ64MC804 dsPIC33 +DSPIC33FJ128GP202 dsPIC33 +DSPIC33FJ128GP204 dsPIC33 +DSPIC33FJ128GP206(A) dsPIC33 +DSPIC33FJ128GP306(A) dsPIC33 +DSPIC33FJ128GP310(A) dsPIC33 +DSPIC33FJ128GP706(A) dsPIC33 +DSPIC33FJ128GP708(A) dsPIC33 +DSPIC33FJ128GP710(A) dsPIC33 +DSPIC33FJ128GP802 dsPIC33 +DSPIC33FJ128GP804 dsPIC33 +DSPIC33FJ128MC202 dsPIC33 +DSPIC33FJ128MC204 dsPIC33 +DSPIC33FJ128MC506 dsPIC33 +DSPIC33FJ128MC510 dsPIC33 +DSPIC33FJ128MC706 dsPIC33 +DSPIC33FJ128MC708 dsPIC33 +DSPIC33FJ128MC710 dsPIC33 +DSPIC33FJ128MC802 dsPIC33 +DSPIC33FJ128MC804 dsPIC33 +DSPIC33FJ256GP506 dsPIC33 +DSPIC33FJ256GP506A dsPIC33 +DSPIC33FJ256GP510 dsPIC33 +DSPIC33FJ256GP510A dsPIC33 +DSPIC33FJ256GP710 dsPIC33 +DSPIC33FJ256GP710A dsPIC33 +DSPIC33FJ256MC510 dsPIC33 +DSPIC33FJ256MC710 dsPIC33 +DSPIC30F2010 dsPIC30 +DSPIC30F2011 dsPIC30 +DSPIC30F2012 dsPIC30 +DSPIC30F3010 dsPIC30 +DSPIC30F3011 dsPIC30 +DSPIC30F3012 dsPIC30 +DSPIC30F3013 dsPIC30 +DSPIC30F3014 dsPIC30 +DSPIC30F4011 dsPIC30 +DSPIC30F4012 dsPIC30 +DSPIC30F4013 dsPIC30 +DSPIC30F5011 dsPIC30 +DSPIC30F5013 dsPIC30 +DSPIC30F5015 dsPIC30 +DSPIC30F5016 dsPIC30 +DSPIC30F6010A dsPIC30 +DSPIC30F6011A dsPIC30 +DSPIC30F6012A dsPIC30 +DSPIC30F6013A dsPIC30 +DSPIC30F6014A dsPIC30 +DSPIC30F6015 dsPIC30 +DSPIC30F1010 dsPIC30 SMPS +DSPIC30F2020 dsPIC30 SMPS +DSPIC30F2023 dsPIC30 SMPS +PIC32MX320F032H PIC32 +PIC32MX320F064H PIC32 +PIC32MX320F128H PIC32 +PIC32MX320F128L PIC32 +PIC32MX340F128H PIC32 +PIC32MX340F128L PIC32 +PIC32MX340F256H PIC32 +PIC32MX340F512H PIC32 +PIC32MX360F256L PIC32 +PIC32MX360F512L PIC32 +PIC32MX420F032H PIC32 +PIC32MX440F128H PIC32 +PIC32MX440F128L PIC32 +PIC32MX440F256H PIC32 +PIC32MX440F512H PIC32 +PIC32MX460F256L PIC32 +PIC32MX460F512L PIC32 +HCS200 KEELOQ® HCS +HCS201 KEELOQ® HCS +HCS300 KEELOQ® HCS +HCS301 KEELOQ® HCS +HCS320 KEELOQ® HCS +HCS360 KEELOQ® HCS +HCS361 KEELOQ® HCS +HCS362 KEELOQ® HCS +11LC010 EEPROMS/11LC +11LC020 EEPROMS/11LC +11LC040 EEPROMS/11LC +11LC080 EEPROMS/11LC +11LC160 EEPROMS/11LC +24LC00 EEPROMS/24LC +24LC01B EEPROMS/24LC +24LC02B EEPROMS/24LC +24LC04B EEPROMS/24LC +24LC08B EEPROMS/24LC +24LC16B EEPROMS/24LC +24LC32A EEPROMS/24LC +24LC64 EEPROMS/24LC +24LC128 EEPROMS/24LC +24LC256 EEPROMS/24LC +24LC512 EEPROMS/24LC +24LC1025 EEPROMS/24LC +25LC010A EEPROMS/25LC +25LC020A EEPROMS/25LC +25LC040A EEPROMS/25LC +25LC080A EEPROMS/25LC +25LC080B EEPROMS/25LC +25LC128 EEPROMS/25LC +25LC160A EEPROMS/25LC +25LC160B EEPROMS/25LC +25LC256 EEPROMS/25LC +25LC320A EEPROMS/25LC +25LC512 EEPROMS/25LC +25LC640A EEPROMS/25LC +25LC1024 EEPROMS/25LC +93LC46A (C X8) EEPROMS/93LCxA,C +93LC56A (C X8) EEPROMS/93LCxA,C +93LC66A (C X8) EEPROMS/93LCxA,C +93LC76A (C X8) EEPROMS/93LCxA,C +93LC86A (C X8) EEPROMS/93LCxA,C +93LC46B (C X16) EEPROMS/93LCxB,C +93LC56B (C X16) EEPROMS/93LCxB,C +93LC66B (C X16) EEPROMS/93LCxB,C +93LC76B (C X16) EEPROMS/93LCxB,C +93LC86B (C X16) EEPROMS/93LCxB,C +MCP25020 MCP250xx +MCP25025 MCP250xx +MCP25050 MCP250xx +MCP25055 MCP250xx +PIC24FJ64GA306 PIC24r2 +PIC24FJ64GA308 PIC24r2 +PIC24FJ64GA310 PIC24r2 +PIC24FJ64GC006 PIC24r2 +PIC24FJ64GC008 PIC24r2 +PIC24FJ64GC010 PIC24r2 +PIC24FJ128DA106 PIC24r2 +PIC24FJ128DA110 PIC24r2 +PIC24FJ128DA206 PIC24r2 +PIC24FJ128DA210 PIC24r2 +PIC24FJ128GA306 PIC24r2 +PIC24FJ128GA308 PIC24r2 +PIC24FJ128GA310 PIC24r2 +PIC24FJ128GB206 PIC24r2 +PIC24FJ128GB210 PIC24r2 +PIC24FJ128GC006 PIC24r2 +PIC24FJ128GC008 PIC24r2 +PIC24FJ128GC010 PIC24r2 +PIC24FJ256DA106 PIC24r2 +PIC24FJ256DA110 PIC24r2 +PIC24FJ256DA206 PIC24r2 +PIC24FJ256DA210 PIC24r2 +PIC24FJ256GB206 PIC24r2 +PIC24FJ256GB210 PIC24r2 + +NOTE: If the name contains a space with additional info in parentheses, Ex: + PIC16F636 (639) + 93LC46A (C X8) + then only the characters before the space are required for -P, Ex: + -pPIC16F636 + -p93LC46A + +Operation Succeeded diff --git a/source/notes/pic-mcu/pickit2/pickit2_firmware_notes.md b/source/notes/pic-mcu/pickit2/pickit2_firmware_notes.md new file mode 100644 index 0000000..f0c99aa --- /dev/null +++ b/source/notes/pic-mcu/pickit2/pickit2_firmware_notes.md @@ -0,0 +1,311 @@ +# PICKit2 Firmware + +Trying to make sense of [pk2cmd scripts](pk2cmd/pk2cmd_notes.html#scripts) lead me to needing to reverse engineer some of the firmware on the programmer, so here we are. + +## Recon + +The PICKit2 consists of a `PIC18F2550` and some supporting logic to program devices over ICSP. I have the `TODO: canakit, images` programmer which includes a ZIF socket, but seems to be functionally equivalent to connecting the same ICSP pins to the programmer. + +Hardware-wise, it's worth noting the LEDs are driven directly by the controller on the programmer, and of course that the USB connector is wired to the `PIC18F2550` as well. This is informative because in addition to programming and handling pk2cmd scripts, the microcontroller is responsible for USB traffic as well. + +## The Good Stuff + +The [firmware](PK2V023200.hex) that is freely available is distributd as an Intel HEX format file. An additional annoyance, Radare2 doesn't seem to have support for the PIC18F, PIC24, nor PIC16F I expect to see. + +So I wrote [an interactive disassembler](`TODO link to pydare`) to help keep track of notes as I walk through this firmware. + +Starting with the first few bytes of the firmware is as good as anywhere. As PIC18 instructions: + +<div class="codebox"><pre> +#eval python pk2cmd-stuff/pydare.py 'o pk2cmd-stuff/PK2V023200.hex' 'arch pic18' 'd 16 @ 0' 'q' | aha --no-header --stylesheet +</pre></div> + +`goto`s are interesting, as are the `BAD` - those are bytes that don't map to any PIC18 instruction. +The actual bytes there: + +<div class="codebox"><pre> +#eval python pk2cmd-stuff/pydare.py 'o pk2cmd-stuff/PK2V023200.hex' 'arch pic18' 'px 32 @ 0' 'q' +</pre></div> + +and comparing with the memory map in the datasheet for the `PIC18F2550`, reproduced partially in the table below: +``` +--------------------------------------- +0000h | Reset Vector +0002h | - +0004h | - +0006h | - +0008h | High Priority Interrupt Vector +000ah | - +.. +0018h | Low Priority Interrupt Vector +--------------------------------------- +``` + +Following the goto at the reset vector leads to more setup code: + +<div class="codebox"><pre> +#eval python pk2cmd-stuff/pydare.py 'o pk2cmd-stuff/PK2V023200.hex' 'loaddb pk2cmd-stuff/pk2cmd_firmware' 'd 8 @ 0xf0a' 'q' | aha --no-header --stylesheet +</pre></div> + +This loads [File Select Registers](../pic18.html#pic18f2550_fsr) 1 and 2 to defaults of 0x300, clears the table pointer, clears a bit, and calls some initialization functions. + +Continuing through initialization functions from here seemed problematic, and it wasn't immediately obvious how this even leads to reading USB traffic from pk2cmd. + +So while this eventually might lead to making sense of the firmware, at least trying to find USB accesses seems like a faster path to the script processing logic. The firmware is small, so disassembling the whole thing and searching for relevant SFR and instructions is quite tractable. From there it might be easy to reach the script interpreter, since that should be adjacent to the USB request handling logic. + +Searching for USB-relevant SFR like +[UIR](../pic18.html#pic18f2550_fsr_uir), +[UIE](../pic18.html#pic18f2550_fsr_uie), +or [UCON](../pic18.html#pic18f2550_fsr_ucon) leads to the code around 0xb2a (notes included for reference): + +<div class="codebox"><pre> +#eval python pk2cmd-stuff/pydare.py 'o pk2cmd-stuff/PK2V023200.hex' 'loaddb pk2cmd-stuff/pk2cmd_firmware' 'd 50 @ 0xb2a' 'q' | aha --no-header --stylesheet +</pre></div> + +In this code `UIE` and `UIR` are both tested to ensure that if an interrupt is seen by `UIR` it's also enabled in `UIE`. Then a call is made to the corresponding handler for the USB event that was seen. These handlers are all reasonable and mostly short. They also don't seem to provide much additional information on how data gets to the script interpreter, or where the script interpreter is. + +In the process, this leads to some USB controller setup, which is still interesting: + +<div class="codebox"><pre> +#eval python pk2cmd-stuff/pydare.py 'o pk2cmd-stuff/PK2V023200.hex' 'loaddb pk2cmd-stuff/pk2cmd_firmware' 'd 50 @ urstif_handler' 'q' | aha --no-header --stylesheet +</pre></div> + +Only really interesting to know how the USB controller is configured. Nothing that seems to be relevant for the script interpreter or code that stores and indexes scripts. + +Failing to find it through following USB processing logic, the next thought is to just look for what might be dispatch tables associated with the contiguous blocks of script command opcodes. + +As luck would have it, there are three sequences of unconditional branches at these addresses: +* `0x2334` +* `0x3b0a` +* `0x429e` + +These are good to keep in mind, and there's some logic that updates PC around them, which is a good sign these are in fact switch tables. + +Also seen, and may come in handy, is bit bang-looking logic around `0x525c`, through `LATA` 3 and somethig to do with `TRISA` 4: + +<div class="codebox"><pre> +#eval python pk2cmd-stuff/pydare.py 'o pk2cmd-stuff/PK2V023200.hex' 'loaddb pk2cmd-stuff/pk2cmd_firmware' 'd 40 @ 0x525c' 'q' | aha --no-header --stylesheet +</pre></div> + +With some good leads, it should be easy to correlate these tables with script command implementations as a sanity check. The simplest script commands seem like `SCMD_BUSY_LED_OFF` and `SCMD_BUSY_LED_ON`, which are `0xf4` and `0xf5` respectively. Following traces on the board, these should just map to setting a bit in the appropriate latch high or low. + +There are in fact several branch targets that seem like they would fill this role: everything between `0x3b60` and `0x3b92`: + +<div class="codebox"><pre> +#eval python pk2cmd-stuff/pydare.py 'o pk2cmd-stuff/PK2V023200.hex' 'arch pic18' 'd 26 @ 0x3b60' 'q' | aha --no-header --stylesheet +</pre></div> + +From looking at the board, it looks like the busy LED is pin 4 in `PORTB`. Searching `PORTB` yields a lot of `btfss` and `btfsc`, but searching `LATB` is entirely `bsf` and `bcf`. Further refining to `LATB, 4` yields 12 possibly interesting instructions. + +Because these operations would be the result of command dispatch, and are adjacent codes, the implementations are probably close together. The only close pairs: + +<div class="codebox"><pre> +#eval python pk2cmd-stuff/pydare.py 'o pk2cmd-stuff/PK2V023200.hex' 'loaddb pk2cmd-stuff/pk2cmd_firmware' 'd 6 @ 0x26ca' 'q' | aha --no-header --stylesheet +</pre></div> + +and + +<div class="codebox"><pre> +#eval python pk2cmd-stuff/pydare.py 'o pk2cmd-stuff/PK2V023200.hex' 'arch pic18' 'd 4 @ 0x3b60' 'q' | aha --no-header --stylesheet +</pre></div> + +Further reading around the jump tables, noticed some interesting constants before the first jump table: + +<div class="codebox"><pre> +#eval python pk2cmd-stuff/pydare.py 'o pk2cmd-stuff/PK2V023200.hex' 'arch pic18' 'd 7 @ 0x22ae' 'q' | aha --no-header --stylesheet +</pre></div> +This is immediately eyecatching on account of 0x42 being `FWCMD_ENTER_BOOTLOADER`. +The subsequent `xorlw #0x34` functionally results in `W == W_original ^ 0x42 ^ 0x34`. Because xor is associative that can be read as `W == W_original ^ (0x42 ^ 0x34)`, or `W == W_original ^ (0x76)`. `0x76` is, itself, also interesting, as that's the opcode for `FWCMD_FIRMWARE_VERSION`. +The third xor at `0x22b6` is equivalent to `W == W_original ^ (0x42 ^ 0x34 ^ 0x2c)` aka `W == W_original ^ (0x5a)`. 0x53 maps to `FWCMD_NO_OPERATION`, so at this point this is definitely the start of the command interpreter loop. + +At this point there's something to closely inspect, so it's worth investigating a structure seen many times in this firmware: + +<div class="codebox"><pre> +; a call target +0x222c: movff FSR2L, POSTINC1 +0x2230: movff FSR1L, FSR2L +; ^ what's up with this and why? +; and at the return... (different function) +0x7532: movf POSTDEC1, POSTDEC1 +0x7534: movff INDF1, FSR2L +0x7536: return +</pre></div> + +So at function entry the code stores the previous FSR2L to `[FSR1++]`, then `FSR1 => FSR2`. because the PIC18F2550 doesn't have a stack, this seems like a decent approximation of the same context-saving behavior. And of course, at return, context is restored. + +This provides some illumination on another interesting idiom: + +<div class="codebox"><pre> +#eval python pk2cmd-stuff/pydare.py 'o pk2cmd-stuff/PK2V023200.hex' 'arch pic18' 'd 6 @ 0x22d2' 'q' | aha --no-header --stylesheet +</pre></div> + +Again, FSR1 is being used akin to a stack to pass parameters. + +`setf POSTINC1` stores `0xFF` through `FSR1` and increments, the subsequent `movlw #0x4; movwf POSTINC1` provides a second argument, which aligns with the two `movf POSTDEC` after the call (undoing the increments to provide parameters) + +Returning to the jump table-style code, register 0x54 is compared with 0xb9 (in the range of opcodes, though well into `SCMD_` space), and if the opcode is less than 0xb9, a branch is taken to `0x2306`: + +<div class="codebox"><pre> +#eval python pk2cmd-stuff/pydare.py 'o pk2cmd-stuff/PK2V023200.hex' 'arch pic18' 'd 30 @ 0x2306' 'q' | aha --no-header --stylesheet +</pre></div> + +At `0x2306` the opcode is turned into an offset into the subsequent jump table and added to PC, implementing the switch by opcode. At this point it's pretty reasonable to add labels for the cases to indicate what command they correspond to. Out of an abundance of caution though, it's worthwhile verfiying at least a simple command. + +`FWCMD_RESET` gives us exactly that: + +<div class="codebox"><pre> +#eval python pk2cmd-stuff/pydare.py 'o pk2cmd-stuff/PK2V023200.hex' 'loaddb pk2cmd-stuff/pk2cmd_firmware' 'd 3 @ FWCMD_RESET' 'q' | aha --no-header --stylesheet +</pre></div> +This case is the "reset" instruction plus logic to advance to the next opcode in the script. Of course, that never gets reached because the chip has reset, but that's a clear artifact of compilation. + +#### FWCMD instructions to revisit +* `FWCMD_EXECUTE_SCRIPT`: this is relevant for programmer operation. all operations seem to be scripts. +* `FWCMD_RUN_SCRIPT`: how is this different from "execute"? +* `FWCMD_DOWNLOAD_SCRIPT`: this is the command to download a script to the programmer. can we read script memory? how many scripts can there be? what's their size? +* `FWCMD_DOWNLOAD_DATA`: seems interesting. download to programmer or to target? +* `FWCMD_UPLOAD_DATA`: same as above +* `FWCMD_END_OF_BUFFER`: might be interesting to know later + +Will come back to these in the future, now that there's a plausible starting point to find their logic. + +With `FWCMD` addressed, it's still not clear how `SCMD` commands are dispatched, which is probably a different table. Time to keep looking. Onward to the table around `0x3b0a`... + +<div class="codebox"><pre> +#eval python pk2cmd-stuff/pydare.py 'o pk2cmd-stuff/PK2V023200.hex' 'arch pic18' 'd 58 @ 0x3aec' 'q' | aha --no-header --stylesheet +</pre></div> + +At `0x3aec` the opcode (again in register `0x54`) is compared against `0xd5`. If the opcode is that or above, `0x3af0` branches to a different but similar switch on opcode value. Since then it's safe to assume the entries are in order from command `0xd5` up, script command names apply cleanly to each branch: +<div class="codebox"><pre> +#eval python pk2cmd-stuff/pydare.py 'o pk2cmd-stuff/PK2V023200.hex' 'loaddb pk2cmd-stuff/pk2cmd_firmware' 'd 58 @ 0x3aec' 'q' | aha --no-header --stylesheet +</pre></div> + +While if the opcode was below `0xd5`, the branch at `0x3af2` kicks in and takes us to... + +<div class="codebox"><pre> +#eval python pk2cmd-stuff/pydare.py 'o pk2cmd-stuff/PK2V023200.hex' 'arch pic18' 'd 54 @ 0x3af2' 'q' | aha --no-header --stylesheet +</pre></div> + +Again, very similar structure to other tables, but starts with `0xb3`. `0xb3` is not in the header file and is unknown, but the rest can be filled in. + +<div class="codebox"><pre> +#eval python pk2cmd-stuff/pydare.py 'o pk2cmd-stuff/PK2V023200.hex' 'loaddb pk2cmd-stuff/pk2cmd_firmware' 'd 54 @ 0x3af2' 'q' | aha --no-header --stylesheet +</pre></div> + +(note: at this point as i was keymashing i accidentally hit ctrl+c, which my script doesn't handle, and lost three hours of notes give or take. largely looking through the interpreter cases, and easy enough to rebuild, but beware sigint) + +With the script command dispatcher found and marked up, it's time to return to the original questions: +* What script opcodes take how many parameters? +* How does programming actually take place? + +## Script Opcodes +Easiest to start with obvious opcodes where the intended functionality is straightforward, to find unknown details about implementation. `SCMD_NOP24` is an obvious candidate here: functionally it *probably* does nothing, but does likely increment some pointers on the programmer side (current script opcode pointer, if such a thing exists), and possibly on the device side (to cause the target device to execute a no-op). + +### `SCMD_NOP24` + +<div class="codebox"><pre> +#eval python pk2cmd-stuff/pydare.py 'o pk2cmd-stuff/PK2V023200.hex' 'arch pic18' 'd 25 @ 0x4112' 'q' | aha --no-header --stylesheet +</pre></div> + +`SCMD_NOP24` makes four calls to the same function, with parameters that vary: +* `0x5066(4, 0)` +* `0x5066(8, 0)` +* `0x5066(8, 0)` +* `0x5066(8, 0)` + +the sequence of three calls with `(8, 0)` probably correspond to the bytes `00 00 00`, which decode under PIC24 to a NOP. So this seems sane! The remaining question if this is true, is why is there a call with arguments `(4, 0)`? + +The answer to that is a little further, at `0x5066`: +<div class="codebox"><pre> +#eval python pk2cmd-stuff/pydare.py 'o pk2cmd-stuff/PK2V023200.hex' 'arch pic18' 'd 53 @ 0x5066' 'q' | aha --no-header --stylesheet +</pre></div> + +This function reads two parameters, stores the second parameter to `0x54`, and the first to `0x55`. As the first parameter for these calls is either 8 or 4, and the latter parameter is all 0's, this continues to make sense. + +The function then tests if `0x2e1` > `0x2` and branches below if so. + +<div class="codebox"><pre> +#eval python pk2cmd-stuff/pydare.py 'o pk2cmd-stuff/PK2V023200.hex' 'arch pic18' 'd 12 @ 0x5084' 'q' | aha --no-header --stylesheet +</pre></div> + +This sequence of instructions is responsible for putting pin 2 of latch A into a high or low state. Bit 0 in `0x54` can only be 1 or 0, so exactly one of `btfss` or `btfcs` will result in a fallthrough. As a result, only one of `bcf LATA, 2; bsf LATA, 2` will be executed. Afterward, the `nop; bsf LATA, 3; nop; bcf LATA, 3`, which raises waits, then lowers another GPIO pin. This makes sense given that the programmer is responsible for directly driving clock signals on the remote chip in programming modes, so this is the logic that actually sends data to the target chip, one bit at a time. + +There is another region of this function that's similar save for one change. If the value in `0x2e1` was above 2, a different bit banging loop is reached, down at `0x509c`: + +<div class="codebox"><pre> +#eval python pk2cmd-stuff/pydare.py 'o pk2cmd-stuff/PK2V023200.hex' 'arch pic18' 'd 20 @ 0x509c' 'q' | aha --no-header --stylesheet +</pre></div> + +This loop is the same as above, as far as setting the data pin (LATA bit 2). The difference is that before alternating the clock three nops are used (rather than the earlier one nop), and those nops are executed in a loop. The loop repeats `[0x2e1]` times and functionally is the same bitbanging loop with longer periods between clock cycles. This may be relevant for some target devices that have different tolerances in serial programming, and makes sense to keep as a single "send these bits" abstraction. + +Back to the question of the two arguments, while one is sent one bit at a time, the other seems to count the number of bits to send: + +<div class="codebox"><pre> +#eval python pk2cmd-stuff/pydare.py 'o pk2cmd-stuff/PK2V023200.hex' 'arch pic18' 'd 2 @ 0x50c8' 'q' | aha --no-header --stylesheet +</pre></div> + +This function is noted down as `tx_bits` for later reference. + +So `(4, 0)` sends the bits `0000`, while `(8, 0)` sends `00000000`. Taken together `SCMD_NOP24` sends `0000b 000000`, and inferring from the PIC18 ICSP guide a leading `0000` prefix should indicate the following word is an instruction, yielding the expected `NOP` on the target device. + +### `SCMD_COREINST24` + +Moving on to `SCMD_COREINST24`, which functionally should send three user-specified bytes to the target... + +<div class="codebox"><pre> +#eval python pk2cmd-stuff/pydare.py 'o pk2cmd-stuff/PK2V023200.hex' 'arch pic18' 'define-function "tx_bits" @ 0x5066' 'd 2 @ 0x41b2' 'q' | aha --no-header --stylesheet +</pre></div> + +As expected, this calls the same transmit function, and passes 4 and 8 in the same places. The major difference is how the second parameter is provided, where this version involves a bit of an incantation: + +<div class="codebox"><pre> +#eval python pk2cmd-stuff/pydare.py 'o pk2cmd-stuff/PK2V023200.hex' 'arch pic18' 'define-function "tx_bits" @ 0x5066' 'd 14 @ 0x41c6' 'q' | aha --no-header --stylesheet +</pre></div> + +Since the three bytes for a pic24 instruction are part of the script (in fact, the three bytes after the `SCMD_COREINST24`), it stands to reason that the value passed is read out of the script buffer, tugging this thread should lead to the script buffer and eventually where it's selected. Interestingly, the logic appears to be: +* read the current script buffer offset (through `INDF2` at `0x41c6`) +* increment the offset (`0x41c8`) +* load the pointer to the script array (`0x41cc`-`0x41d4`) into `FRS0` - this comes from an argument! +* add the offset into the pointer (`0x41d8`) +* read that address (`0x41e0`) +* "push" the parameter (`0x41e2`) + +This confirms that for the various commands we can track `INDF2` modification to determine the number of parameters for the various commands! + +The first unknown script commands ones of interest: `SCMD_WRITE_BUFBYTE_W` and `SCMD_WRITE_BUFWORD_W` + +### `SCMD_WRITE_BUFWORD_W` + +``` +TODO: SCMD_WRITE_BUFWORD_W +``` + +this handler involves the same transmit function from earlier and also another function, `0x5006`. + +guessing from context it appears to read from a global address and return the byte in W. `SCMD_WRITE_BUFWORD_W` then uses that as bits to send down the wire. + +### `SCMD_WRITE_BUFBYTE_W` + +`SCMD_WRITE_BUFBYTE_W` does the same, but only reads one byte, the second value transmitted is a 0. + +### Miscellaneous Script Commands + +`SCMD_WRITE_BITS_LITERAL` takes two parameters, the number of bits and the pattern to send. +`SCMD_WRITE_BYTE_LITERAL` takes one parameter, the pattern, and assumes the number of bits to send is 8. +TODO: `SCMD_RD2_BYTE_BUFFER`. +TODO: `SCMD_READ_BYTE`. +TODO: `SCMD_VISI24`. (transmits (4, 1), (8, 0), then some unknown calls.) + +### `SCMD_DELAY_LONG` + +Passes the single byte parameter along to the function at `0x4966`, which... +<div class="codebox"><pre> +#eval python pk2cmd-stuff/pydare.py 'o pk2cmd-stuff/PK2V023200.hex' 'arch pic18' 'define-function "tx_bits" @ 0x5066' 'd 11 @ 0x4966' 'q' | aha --no-header --stylesheet +</pre></div> + +At `0x496e` the flag indicating `timer0` has fired is cleared (since it may have in the past), followed by multiplying the argument by `0xff` and loading the low byte of the result into `tmr0h`? This really has no result other than to negate it before setting the timer. From there, the timer is enabled and the controller spins until the timer fires (`0x497e`). + +`delay`. Dunno what else to have expected. + +### `SCMD_LOOP` + +TODO, eventually. diff --git a/source/notes/pic-mcu/pickit2/pickit2_intro.md b/source/notes/pic-mcu/pickit2/pickit2_intro.md new file mode 100644 index 0000000..54713e6 --- /dev/null +++ b/source/notes/pic-mcu/pickit2/pickit2_intro.md @@ -0,0 +1,17 @@ +This all started with wanting to program the [layerone demoboard](http://l1demo.org/). The demoboard is essentially a `PIC24FJ256DA206` with IO circuitry. it's a neat chip, and I already had a pickit2 programmer from a project long ago. + +![pickit2 EOL](...)\ + +it turns out the `PIC24FJ256DA206` was relesed after the pickit2 was end-of-life'd. This means that there is no official support to program the chip with this programmer or the pk2cmd control software. + +There is clearly support for other `PIC24` chips with this tool: +<div class="codebox"> +#eval cat partlist_w_term | aha --no-header --stylesheet +</div> +so I decided to see if I can sneak in support for the demoboard. + +Notes on sneaking support into pickit2 toolchains are with other notes on pk2cmd, [here](pk2cmd/pk2cmd_notes.html#adding_parts). + +Additionally, looking at pk2cmd lead to reverse engineering the firmware on pickit2 programmers. Notes on that are [here](pickit2_firmware_notes.html). + +There's another issue still TBD: it seems pickit2 programmers can be used, if the target circuit and chip support it, as a debugger. A nice to have but not terribly important goal is figuring out how to control debugging logic from pk2cmd or some other PC-side tool. diff --git a/source/notes/pic-mcu/pickit2/pk2cmd-stuff.zip b/source/notes/pic-mcu/pickit2/pk2cmd-stuff.zip Binary files differnew file mode 100644 index 0000000..ec7a748 --- /dev/null +++ b/source/notes/pic-mcu/pickit2/pk2cmd-stuff.zip diff --git a/source/notes/pic-mcu/pickit2/pk2cmd-stuff/PK2V023200.hex b/source/notes/pic-mcu/pickit2/pk2cmd-stuff/PK2V023200.hex new file mode 100644 index 0000000..8096b15 --- /dev/null +++ b/source/notes/pic-mcu/pickit2/pk2cmd-stuff/PK2V023200.hex @@ -0,0 +1,2071 @@ +:020000040000FA +:1000000085EF07F01200FFFF04EF10F01200FFFF72 +:10001000FFFFFFFFFFFFFFFF0CEF10F01200FFFFDD +:10002000FFFFFFFFFFFFFFFFFFFF00000401105174 +:10003000600BE842E842E842E842E842000901E099 +:1000400055D01151070A51E00B0A4FE0070A40E072 +:10005000010A2CE00B0A28E0020A26E0030A22E04B +:10006000080A12E0010A0EE00F0A0AE0030A01E0A2 +:100070003CD00001010EB06F0001040EB76F36D006 +:1000800036D834D090D832D00001010EB06F0001C4 +:10009000B90EB16F000EB26F0001B8930001010EEE +:1000A000B56F24D0A8D822D0F5D820D00001010EF9 +:1000B000B06F040114510001B16FB26BBA0EB127D9 +:1000C000000EB2230001B8930001010EB56F0ED0EF +:1000D0000001010EB06F04011451EA6ABA0FE96E13 +:1000E000000EEA2212C4EFFF01D000D01200800EF1 +:1000F0000401105D57E11351030A34E0010A10E0D6 +:10010000030A01E04DD00001010EB06F0001600E46 +:10011000B16F0C0EB26F120E0001B56FB66B40D00E +:100120000001010EB06F04011251F66EF76AD8900B +:10013000F636F7369E0EF6260D0EF7220900F5CF9D +:10014000B1F00A00F5CFB2F0020E0001F76AB12556 +:10015000F66EB251F7220900F5CFB5F00A00F5CFDF +:10016000B6F01ED00001010EB06F04011251F66E00 +:10017000F76AD890F636F736A20EF6260D0EF7225D +:100180000900F5CFB1F00A00F5CFB2F0B1C0F6FF2B +:10019000B2C0F7FF0800F5500001B56FB66B00D094 +:1001A0000001B88312000001010EB06F0F0EE66E61 +:1001B000710EE66E0F0EE66E1BEC06F0E552E55290 +:1001C000E552010EE66EBA0EE66E000EE66E1BEC10 +:1001D00006F0E552E552E55212C4B9F0040112519D +:1001E00004E10001050EB76F05D00001060EB76FE0 +:1001F000E7EC04F012000401186B196B04011051B4 +:100200001F0B020A15E0030A0FE0010A01E034D0D7 +:100210000001010EB06F02D0040118810001B8A1E5 +:1002200002D00401188328D00001010EB06F24D041 +:100230000001010EB06F040114510F0B080DF350B3 +:10024000016A000F006E040E01221451800B01E0C0 +:10025000010E040DF35000010024B36F000E0120C5 +:10026000B46FB3C0E9FFB4C0EAFFEF50040B03E082 +:100270000401010E186F00D00001B0050AE1000171 +:10028000180EB16F040EB26F0001B8930001020E98 +:10029000B56F12000401120510E110511F0B000987 +:1002A0000CE10001010EB06F030E0401115D03E1CA +:1002B0000001B88102D00001B891040112513AE165 +:1002C00010511F0B020836E114510F0B000932E0E8 +:1002D0000001010EB06F040114510F0B080DF35013 +:1002E000016A000F006E040E01221451800B01E020 +:1002F000010E040DF35000010024B36F000E012025 +:10030000B46F030E0401115D07E1840EB3C0E9FF71 +:10031000B4C0EAFFEF6E0ED014AF06D0B3C0E9FF51 +:10032000B4C0EAFFEF6A06D0880EB3C0E9FFB4C0DC +:10033000EAFFEF6E12006C500BE1040100513C0B20 +:10034000E842E8420D0802E108D801D03CD804D0C8 +:10035000040E6C5C01E147D81200D9CFE6FFE1CF73 +:10036000D9FFE6520001AF6BB06BB56BB66B16EC04 +:1003700000F0DF6ADF50006E016A010E005C000EC3 +:1003800001581BE20001B05101E017D0F76ADF34D9 +:10039000FE0BF736F66EAC0EF6260D0EF7220900B0 +:1003A000F5CF00F00800F5CF01F004D001C0FAFF4E +:1003B0000050F96EFBDFDF2ADDD7D5D8E552E552D4 +:1003C000E7CFD9FF1200020E0001AF5D0AE192D81B +:1003D000040100BD03D0C80E006F02D0880E006F6C +:1003E00001D007D91200040E0001B75D0AE112C462 +:1003F0006EFF6E50000803E2050EB76F02D0030EC9 +:10040000B76F0001AF050AE10BD8040104BD03D0AA +:10041000C80E046F02D0880E046F01D0EAD8120013 +:10042000D9CFE6FFE1CFD9FF020EE1260001080E89 +:10043000B55D000EB65905E2B5C0DEFFB6C0DDFF02 +:1004400003D0080EDE6EDD6A040104930491010EF0 +:10045000DB500413DFCF05F4000EDB500001B55F65 +:10046000010EDB50B65B180EB36F040EB46F0001C3 +:10047000B8A31ED0D9CFE9FFDACFEAFFEE50ED10D6 +:1004800016E0B1C0F6FFB2C0F7FF0800F550B3C0E8 +:10049000E9FFB4C0EAFFEF6E0001B32B000EB423F6 +:1004A000B12BB223DF06010E01E2DB06E3D71CD03D +:1004B000D9CFE9FFDACFEAFFEE50ED1015E0B1C079 +:1004C000E9FFB2C0EAFFEF50B3C0E9FFB4C0EAFFF2 +:1004D000EF6E0001B32B000EB423B12BB223DF0665 +:1004E000010E01E2DB06E4D7D9CFE1FFE552E7CF09 +:1004F000D9FF1200D9CFE6FFE1CFD9FF020EE126E6 +:10050000030E04010015E76E010EE7CFDBFF01C407 +:10051000DFFFDE500001B527DD50B623180EB16FA6 +:10052000040EB26FD9CFE9FFDACFEAFFEE50ED103B +:1005300014E0B1C0E9FFB2C0EAFFEF50B3C0E9FF79 +:10054000B4C0EAFFEF6EB32B000EB423B12BB2237D +:10055000DF06010E01E2DB06E5D7D9CFE1FFE55268 +:10056000E7CFD9FF12006D980001B0510CE10401F2 +:10057000080E016F100E026F040E036F840E006FE1 +:100580000401046F35D0040110AF22D00001B55131 +:100590000401165D0001B6510401175904E216C4A6 +:1005A000B5F017C4B6F03CDF0001010EAF6F0401D7 +:1005B000080E016F100E026F040E036F800E006FA5 +:1005C0000401180E066F040E076FC80E046F10D0DA +:1005D0000001020EAF6F0401056BC80E046F040129 +:1005E000080E016F180E026F040E036FC80E006F25 +:1005F00012000001AF6B0401080E016F100E026FB4 +:10060000040E036F880E006F0401046B1200550E78 +:10061000A76EAA0EA76EA68212000001420E6A6F94 +:10062000020E6B6F010E6C6F12000001606B665161 +:10063000605D1EE260C000F0016A026A675100243A +:10064000F36E68510120F46E69510220F86EF4CF08 +:10065000F7FFF3CFF6FF0800F5CF61F06051EA6ACB +:100660006A0FE96E000EEA2261C0EFFF602BDFD750 +:10067000F86A1200840EA66E0001606B6651605D20 +:1006800027E26051EA6A6A0FE96E000EEA22EFCFB4 +:1006900003F060C000F0016A026A67510024F36E43 +:1006A00068510120F46E69510220F86EF4CFF7FF13 +:1006B000F3CFF6FF03C0F5FF0C001F0E60151F08F7 +:1006C00003E06605605D01E1A2DF0001602BD6D783 +:1006D00012000001606B6651605D20E2940EA66E10 +:1006E0006051006E016A060ED89000360136E804AB +:1006F000FBE1026A01BE0268000167510024F36E4B +:1007000068510120F46E69510220F86EF4CFF7FFB2 +:10071000F3CFF6FF7CDF0001602BDDD7F86A120013 +:10072000A66A0001606B6651605D0EE2675160254C +:10073000A96EA6806051EA6A6A0FE96E000EEA228D +:10074000A8CFEFFF602BEFD712000001606B66515E +:10075000605D13E267516025A96E6051EA6A6A0F15 +:10076000E96E000EEA22EF50A86E040EA66E4FDF6F +:10077000A6B2FED70001602BEAD71200C40EA66E07 +:100780000001606B6651605D20E26051EA6A6A0FA9 +:10079000E96E000EEA22EFCF03F060C000F0016ABC +:1007A000026A67510024F36E68510120F46E6951AA +:1007B0000220F86EF4CFF7FFF3CFF6FF03C0F5FF8A +:1007C0000C0025DF0001602BDDD7F86A1200400E17 +:1007D000E66E650EE66E000EE66E36EC05F0E5524E +:1007E000E552E552000870E20001606B00016551BE +:1007F000FF0A57E0FA0A50E0010A3BE0070A34E03A +:10080000010A2DE0030A18E0070A16E0700A01E069 +:100810005AD003DF0001040E606F04010CBFFDD746 +:10082000400EE66E650EE66E000EE66EFCEC04F021 +:10083000E552E552E55248D0F8DE050E000160278A +:1008400004010CBFFDD7400EE66E650EE66E000E8D +:10085000E66EFCEC04F0E552E552E55235D00ADFD5 +:100860000001010E606F30D034DF0001010E606FB7 +:100870002BD056DF050E0001602704010CBFFDD709 +:10088000400EE66E650EE66E000EE66EFCEC04F0C1 +:10089000E552E552E55218D058DF0001010E606FB5 +:1008A00013D093EC05F00001636B646B00016307E8 +:1008B000000E645B00016351641103E0000000005E +:1008C000F5D7FF0001D000D01200040110511F0B1A +:1008D000010801E079D0145101E076D0060E115DD7 +:1008E0002EE11351230A28E0010A13E0030A01E074 +:1008F00024D00001020EB06F0001B90505E100012E +:10090000840EB16F0C0EB26F090E0001B56FB66B9D +:1009100014D00001020EB06F0001B90505E100011D +:10092000810EB16F0D0EB26F0001B90504E11D0E0D +:100930000001B56FB66B01D000D00001B88304018F +:100940001051600BE842E842E842E842E842010800 +:1009500001E03AD011510B0A31E0080A21E0090AFE +:1009600019E0080A09E00B0A05E0080A01E02CD0AA +:100970002CD82AD02BD828D00001020EB06F00014D +:10098000BB0EB16F000EB26F0001B8930001010EF3 +:10099000B56F1AD00001020EB06F13C4BBF014D0B3 +:1009A0000001020EB06F0001BC0EB16F000EB26FFD +:1009B0000001B8930001010EB56F06D00001020ED0 +:1009C000B06F12C4BCF000D012001200120000017F +:1009D000BD6B1E0E716E0401400E096F200E0A6F72 +:1009E000040E0B6F880E086F0401600E0E6F040E6C +:1009F0000F6F400E0C6F1200D9CFE6FFE1CFD9FF89 +:100A0000E652FC0EDB50400805E2400EF36EFC0E91 +:100A1000F3CFDBFFDF6AFC0EDB50DF5C19E2DF5057 +:100A2000E76EFD0EDBCFE9FFFE0EDBCFEAFFE750FE +:100A3000E926000EEA22EF50E66EDF50EA6A600F08 +:100A4000E96E040EEA22E552E750EF6EDF2AE3D7A3 +:100A5000FC0EDBCF0DF4400E04010C170C7D880E4C +:100A60000C13E552E552E7CFD9FF1200D9CFE6FFCC +:100A7000E1CFD9FF0001BD6B040108BF30D0FC0EEF +:100A8000DBCF00F00951D880005403E2FC0E09C40A +:100A9000DBFF0001BD6BFC0EDB50BD5D19E2BD51FB +:100AA000EA6A200FE96E040EEA22EF50E66EBD51AD +:100AB000E76EFD0EDBCFE9FFFE0EDBCFEAFFE7506E +:100AC000E926000EEA22E552E750EF6EBD2BE3D790 +:100AD0000401400E096F0817087D880E08130001F5 +:100AE000BD5100D0E552E7CFD9FF12006DA60FD857 +:100AF00002D06DB613D80001B70508E16DBA06D073 +:100B0000686A696A69806988020EB76F12006D6A47 +:100B1000696A6D860001010EB76F12006D6A696A1D +:100B20000001B76B12008EEF05F00001B75101E133 +:100B30003AD06850040B04E06950040B01E038D847 +:100B40006DB231D06850010B04E06950010B01E037 +:100B500050D86850100B04E06950100B01E024D805 +:100B60006850400B04E06950400B01E037D86850F2 +:100B7000200B04E06950200B01E032D86850020BD2 +:100B800004E06950020B01E032D8030E0001B75DAA +:100B900001E209D06850080B06E06950080B03E039 +:100BA0009BEC01F068961200698468986D821200CF +:100BB0006D926994689412000001B8A10ED0F8DF1C +:100BC0006D840001080EBE6F070EBF6FBE07000EDA +:100BD000BF5BBE51BF11FAE16D941200689C120018 +:100BE00070A003D0F9EC02F07090689A120068923D +:100BF00012006A6A686A9F0E6B6E7B0E696E6E6A7F +:100C00000F0EE66E710EE66E0F0EE66E14D8E5520C +:100C1000E552E552160E706E68A602D06896FCD7B3 +:100C20006D98F9EC02F00001B8910001B96B000178 +:100C3000030EB76F1200D9CFE6FFE1CFD9FFFD0E4B +:100C4000DBCFE9FFFE0EDBCFEAFFFC0EDB5004E05A +:100C5000EE6AFC0EDB06F9D7E552E7CFD9FF1200AA +:100C60001201000200000008D80433000100010254 +:100C70000302090229000101028032090400000276 +:100C800003000000092101000001221D0007058169 +:100C90000340000107050103400001090220000193 +:100CA000020480320904000002FF000000070581F1 +:100CB0000340000107050103400001040309043457 +:100CC000034D006900630072006F006300680069F3 +:100CD000007000200054006500630068006E006F23 +:100CE000006C006F0067007900200049006E00630F +:100CF000002E0048035000490043006B0069007457 +:100D0000002000320020004D006900630072006F77 +:100D10000063006F006E00740072006F006C006C66 +:100D200000650072002000500072006F00670072C2 +:100D30000061006D006D00650072001603500049EF +:100D400000430031003800460032003500350030E5 +:100D50000030035000490043006B0069007400201C +:100D6000003200200043006F006E006600670075CF +:100D70000072006100740069006F006E0020003294 +:100D8000000600FF0901A10119012940150026FFF5 +:100D900000750895408102190129409102C0720C2A +:100DA0009B0CBB0CBF0CF30C3B0D510DCA082A0E5B +:100DB000F66E000EF76E000EF86E00010900F55099 +:100DC000AA6F0900F550AB6F03E1AA6701D03DD0CF +:100DD0000900F550A56F0900F550A66F0900F55000 +:100DE000A76F09000900F550E96E0900F550EA6E99 +:100DF000090009000900F550A86F0900F550A96F16 +:100E000009000900F6CFACF0F7CFADF0F8CFAEF0A7 +:100E1000A5C0F6FFA6C0F7FFA7C0F8FF0001A853C2 +:100E200002E1A95307E00900F550EE6EA807F8E2C9 +:100E3000A907F9D7ACC0F6FFADC0F7FFAEC0F8FF09 +:100E40000001AA07000EAB5BBFD71200D9CFE6FFA7 +:100E5000E1CFD9FF030EE126938A818AF19E580ED5 +:100E6000E66E6EEC07F0E55281AA0DD0FE0EF66E2E +:100E70007F0EF76EF86A0800F550DF6E550EDF5CE6 +:100E800002E100EF10F018D822D8E7EC03F0D950B7 +:100E9000010FE96EDACFEAFFEE50ED1001E18B7041 +:100EA000010EDB06020E01E2DB06EED7D9CFE1FF31 +:100EB000E552E7CFD9FF1200140E6F6E0001B76B39 +:100EC0000001B86B0001B96B8B909490120076EC26 +:100ED00005F06FBE02D095EC05F01200FF0EE35056 +:100EE000076EEF0E01D0F30EE76EE72E75EF07F0F9 +:100EF0000C0E066EE76AE72E7BEF07F0062E7AEF00 +:100F000007F0072E73EF07F0120013EE00F023EE48 +:100F100000F0F86A059CD7EC06F026EC07F0FDD748 +:100F20001200FFFFFFFFFFFFFFFFFFFFFFFFFFFFBD +:100F3000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC1 +:100F4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB1 +:100F5000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA1 +:100F6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF91 +:100F7000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF81 +:100F8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF71 +:100F9000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF61 +:100FA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF51 +:100FB000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF41 +:100FC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF31 +:100FD000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF21 +:100FE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF11 +:100FF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF01 +:10100000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0 +:10101000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 +:10102000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD0 +:10103000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC0 +:10104000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB0 +:10105000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA0 +:10106000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF90 +:10107000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF80 +:10108000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF70 +:10109000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF60 +:1010A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF50 +:1010B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF40 +:1010C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF30 +:1010D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF20 +:1010E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF10 +:1010F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00 +:10110000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEF +:10111000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDF +:10112000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCF +:10113000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBF +:10114000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAF +:10115000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9F +:10116000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8F +:10117000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7F +:10118000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6F +:10119000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5F +:1011A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4F +:1011B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3F +:1011C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2F +:1011D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1F +:1011E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0F +:1011F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +:10120000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEE +:10121000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDE +:10122000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCE +:10123000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBE +:10124000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAE +:10125000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9E +:10126000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8E +:10127000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7E +:10128000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6E +:10129000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5E +:1012A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4E +:1012B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3E +:1012C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2E +:1012D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1E +:1012E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0E +:1012F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE +:10130000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED +:10131000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDD +:10132000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCD +:10133000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBD +:10134000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAD +:10135000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9D +:10136000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8D +:10137000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7D +:10138000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6D +:10139000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D +:1013A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4D +:1013B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3D +:1013C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2D +:1013D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1D +:1013E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0D +:1013F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD +:10140000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEC +:10141000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDC +:10142000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCC +:10143000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBC +:10144000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAC +:10145000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9C +:10146000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8C +:10147000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7C +:10148000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6C +:10149000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5C +:1014A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4C +:1014B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3C +:1014C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2C +:1014D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1C +:1014E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0C +:1014F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC +:10150000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEB +:10151000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDB +:10152000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCB +:10153000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBB +:10154000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAB +:10155000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9B +:10156000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8B +:10157000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7B +:10158000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6B +:10159000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5B +:1015A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4B +:1015B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3B +:1015C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2B +:1015D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1B +:1015E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0B +:1015F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB +:10160000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEA +:10161000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDA +:10162000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA +:10163000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBA +:10164000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAA +:10165000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9A +:10166000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8A +:10167000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7A +:10168000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6A +:10169000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5A +:1016A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4A +:1016B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3A +:1016C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2A +:1016D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1A +:1016E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0A +:1016F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA +:10170000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE9 +:10171000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD9 +:10172000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC9 +:10173000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB9 +:10174000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA9 +:10175000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF99 +:10176000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF89 +:10177000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF79 +:10178000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF69 +:10179000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF59 +:1017A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF49 +:1017B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF39 +:1017C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF29 +:1017D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF19 +:1017E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF09 +:1017F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9 +:10180000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE8 +:10181000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD8 +:10182000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC8 +:10183000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB8 +:10184000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA8 +:10185000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF98 +:10186000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF88 +:10187000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF78 +:10188000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF68 +:10189000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF58 +:1018A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF48 +:1018B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF38 +:1018C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF28 +:1018D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF18 +:1018E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF08 +:1018F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8 +:10190000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE7 +:10191000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD7 +:10192000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7 +:10193000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB7 +:10194000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA7 +:10195000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF97 +:10196000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF87 +:10197000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF77 +:10198000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF67 +:10199000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF57 +:1019A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF47 +:1019B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF37 +:1019C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF27 +:1019D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF17 +:1019E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF07 +:1019F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7 +:101A0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE6 +:101A1000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6 +:101A2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC6 +:101A3000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB6 +:101A4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA6 +:101A5000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF96 +:101A6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF86 +:101A7000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF76 +:101A8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF66 +:101A9000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF56 +:101AA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF46 +:101AB000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF36 +:101AC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF26 +:101AD000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF16 +:101AE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF06 +:101AF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6 +:101B0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE5 +:101B1000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD5 +:101B2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC5 +:101B3000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB5 +:101B4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA5 +:101B5000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF95 +:101B6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF85 +:101B7000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF75 +:101B8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF65 +:101B9000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF55 +:101BA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF45 +:101BB000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF35 +:101BC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF25 +:101BD000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF15 +:101BE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF05 +:101BF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5 +:101C0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE4 +:101C1000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD4 +:101C2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC4 +:101C3000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB4 +:101C4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA4 +:101C5000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF94 +:101C6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF84 +:101C7000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF74 +:101C8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF64 +:101C9000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF54 +:101CA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF44 +:101CB000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF34 +:101CC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF24 +:101CD000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF14 +:101CE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04 +:101CF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4 +:101D0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE3 +:101D1000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD3 +:101D2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC3 +:101D3000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB3 +:101D4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA3 +:101D5000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF93 +:101D6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF83 +:101D7000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF73 +:101D8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF63 +:101D9000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF53 +:101DA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF43 +:101DB000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF33 +:101DC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF23 +:101DD000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF13 +:101DE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF03 +:101DF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3 +:101E0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE2 +:101E1000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD2 +:101E2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC2 +:101E3000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB2 +:101E4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA2 +:101E5000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF92 +:101E6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF82 +:101E7000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF72 +:101E8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF62 +:101E9000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF52 +:101EA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF42 +:101EB000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF32 +:101EC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF22 +:101ED000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF12 +:101EE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF02 +:101EF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2 +:101F0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE1 +:101F1000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD1 +:101F2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC1 +:101F3000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB1 +:101F4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA1 +:101F5000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF91 +:101F6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF81 +:101F7000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF71 +:101F8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF61 +:101F9000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF51 +:101FA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF41 +:101FB000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF31 +:101FC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF21 +:101FD000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF11 +:101FE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF01 +:101FF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1 +:1020000083EF3EF0120000009DEF3AF01200000056 +:1020100000000000000000009DEF3AF012000000F8 +:10202000FFFFFFFFFFFFFFFFFFFFD9CFE6FFE1CF7D +:10203000D9FFE652030ED26EA194A08492809282C0 +:102040000D0EC16E030EC06E9284809489949286A8 +:102050008096899692888998899A929A8A96939678 +:102060008A889398938A818AF19E8A9493948B901C +:1020700094908B9294928B949494949C8B8C020E5B +:10208000DF6E0001030E016F0001090E026F0001F7 +:10209000040E036FF00EE66E55EC2AF0E5522308AD +:1020A00028E11E0EDF5C25E2DF50FE0BE842F00F58 +:1020B000E66E55EC2AF0E552E66EDF50EA6A000F54 +:1020C000E96E000EEA22E552E750EF6EDF28EA6A79 +:1020D000000FE96E000EEA22EF6ADF50EA6A000F95 +:1020E000E96E000EEA22EF5001E103D0020EDF2676 +:1020F000D8D7020EDF240001006F3E6A0001E76BB3 +:102100000001010EE86F0201030EE06F0201E16BB6 +:102110000201010EE26FD9EC19F0BBEC17F0B3EC41 +:1021200017F08DEC17F00001400ED880E355010E3A +:10213000E4550EE30001C00EE35D000EE45908E330 +:102140000001E651AF0804E3500E0001E65D09E22C +:102150000001E36B010EE46F0001E56B0001800EEE +:10216000E66F080ED56E040ECA6E4F0ECB6E0C0EC7 +:10217000BD6E1D0EBE6E0001400EE06F00013E0EF2 +:10218000E16F00013C0EE26F02017E0EFA6F020168 +:102190002D0EFB6F070EB46EB56AF28CF28E93ECC7 +:1021A0003BF0040EE66E55EC2AF0E552500828E1AB +:1021B000050EE66E55EC2AF0E5524B0821E1060EBD +:1021C000E66E55EC2AF0E55232081AE1070EE66E8B +:1021D00055EC2AF0E5523D6E020E3E6E546AE66AF8 +:1021E000110EE66E01EC16F0E552E552400EE66E79 +:1021F00026EC17F0E5520201FA6F0201890E006F1A +:10220000E552E552E7CFD9FF120004010CBFFDD71C +:10221000400EE66E400EE66E020EE66E18EC3AF0E8 +:10222000E552E552E55280EC3DF01200D9CFE6FFD1 +:10223000E1CFD9FF020EE126DF6A010EDB6A81BA27 +:1022400002D00001E78D400EE66E000EE66E020E33 +:10225000E66E54EC3AF0E552E552E552000803E22E +:10226000DE52010EDD6E3E0406E1010EDB5002E09F +:1022700087EC2FF00ED2020E3E5C09E1010EDB501E +:1022800004E0760E0201005D02E00DDA02D20001E8 +:10229000E8B383DA010EDB5001E1FBD1DF50EA6ADB +:1022A000000FE96E020EEA22EF50546E5450420ABB +:1022B00027E0340A05E02C0A01E025D0DF2AE5D129 +:1022C00031EC1DF0020E3E5C19E1080ED56E8A88D5 +:1022D0003E6AE668040EE66E33EC2AF0E552E552FB +:1022E000E668050EE66E33EC2AF0E552E552E66844 +:1022F000060EE66E33EC2AF0E552E552DF2AC5D130 +:10230000F9EC1CF0C2D1A00E545C03E2400EDF6E6B +:10231000BCD15450B90803E2400EDF6EB6D1A00E16 +:10232000545E549E5446080E5426F9505424D8B096 +:10233000FA2AF96E1AD03FD06BD06ED071D07AD015 +:1023400091D0B1D0B4D0BDD0C0D0C3D0C6D0C9D048 +:10235000CBD0CDD0D0D005D10DD115D11DD11FD12D +:1023600027D128D12FD17AD190D1DF28EA6A000F66 +:10237000E96E020EEA22EF50E66E020EDF24EA6AF0 +:10238000000FE96E020EEA22EF50E66E01EC16F045 +:10239000E552E552030EDF24EA6A000FE96E020EF1 +:1023A000EA22EF50E66E26EC17F0E5520201FA6FD2 +:1023B000040EDF26D9D7DF28EA6A000FE96E020E85 +:1023C000EA22EFCFE0F0020EDF24EA6A000FE96EA6 +:1023D000020EEA22EF50E66E26EC17F0E552010FEE +:1023E0000001E16F020E0001E15D0001E26F030EEA +:1023F000DF24EA6A000FE96E020EEA22EF50E66E71 +:1024000026EC17F0E5520201FB6F040EDF26ACD775 +:1024100011EC1DF0DF2AA8D76EEC18F0DF2AA4D744 +:10242000DF2AD9CFE6FFDACFE6FF73EC1AF0E552E8 +:10243000E5529AD7DF2ADF28EA6A000FE96E020E1A +:10244000EA22EF50E66EDF50EA6A000FE96E020EF4 +:10245000EA22EF50E66E88EC19F0E552E552020EE2 +:10246000DF2682D7DF2ADF50EA6A000FE96E020E0C +:10247000EA22EF50E66EDF28406A000F3F6E020E40 +:1024800040223FC0E6FF40C0E6FF3CEC1DF0E552B5 +:10249000E552E552DF50EA6A000FE96E020EEA22C9 +:1024A000EF28DF2661D7BBEC17F0DF2A5DD7DF2AE4 +:1024B000D9CFE6FFDACFE6FFF4EC19F0E552E552AA +:1024C00053D7B3EC17F0DF2A4FD7E7EC18F0DF2A29 +:1024D0004BD7D9EC19F0DF2A47D73AEC19F0DF2AAD +:1024E00043D7400EDF6E40D7FF00DF2A3DD7C3EC55 +:1024F00017F0DF2A39D7DF28EA6A000FE96E020EEB +:10250000EA22EF500001E36FE46B020EDF24EA6A77 +:10251000000FE96E020EEA22EFCF3FF0406A3FBEA5 +:1025200040683FC040F03F6A3F500001E327405001 +:102530000001E423030EDF24EA6A000FE96E020EB5 +:10254000EA22EFCFE5F0040EDF24EA6A000FE96E1D +:10255000020EEA22EFCFE6F06AEC17F0050EDF2656 +:1025600003D7DF2AD9CFE6FFDACFE6FFC8DAE55294 +:10257000E552FAD6DF2AD9CFE6FFDACFE6FF3FDA17 +:10258000E552E552F1D6DF2AD9CFE6FFDACFE6FFF2 +:1025900099D9E552E552E8D6DF2AE0D9E5D6DF2A17 +:1025A000DFCFE6FF27EC2FF0E552040EDF26DCD666 +:1025B000DF2ADAD6DF2ADFCFE6FF38D9E552400E30 +:1025C000DF6ED2D6DF2ADF50DF2AEA6A000FE96E1B +:1025D000020EEA22EF505F6EDF50DF2AEA6A000F38 +:1025E000E96E020EEA22EF50546EDF50DF2AEA6AEB +:1025F000000FE96E020EEA22EF50566EDF50DF2A1E +:10260000EA6A000FE96E020EEA22EF50586EDF50C0 +:10261000DF2AEA6A000FE96E020EEA22EF50596ED5 +:10262000DF50DF2AEA6A000FE96E020EEA22EF505D +:102630005A6EDF50DF2AEA6A000FE96E020EEA22C4 +:10264000EF285B6EDF50DF2AEA6A000FE96E020EA8 +:10265000EA22EF505E6ECFEC2DF086D6DF2ADF281F +:10266000EA6A000FE96E020EEA22EF50E66EDF50D2 +:10267000EA6A000FE96E020EEA22EF50E66E7ED99A +:10268000E552E552020EDF266FD6400EDF5C01E216 +:1026900005D6020EE15C02E2E16AE552E16EE55226 +:1026A000E7CFD9FF1200F29A870ED56EF2A429D097 +:1026B000D20ED76E3A0ED66EF294542A54500508B4 +:1026C00001E2546A040E545C06E2010E5414E8B0B0 +:1026D0008A88E8A08A98300E0001E71512E08A88FF +:1026E00081BAFED78F0E0001E717F00EE66E58ECA8 +:1026F0003EF0E55281AAFED7F00EE66E58EC3EF0B1 +:10270000E5520001E7AD47D08A882FEC31F08A8886 +:102710008A8681AAFED7546AE66A110EE66E71DADD +:10272000E552E552400EE66E91DBE5520201FA6F8A +:10273000300E0001E71502E081BAFED7FC0E000161 +:10274000E81506E0080EE66E6FEC36F0E55210D0A4 +:10275000390406E1040EE66E6FEC36F0E55208D05F +:102760003650371005E0060EE66E6FEC36F0E55297 +:10277000F00EE66E58EC3EF0E55281AAFED7F00E60 +:10278000E66E58EC3EF0E5528F0E0001E7170001AF +:10279000E86B0001E79D8B901200D9CFE6FFE1CFF7 +:1027A000D9FFE6523D501AE03D50DF6E3D6A3A5087 +:1027B000E66ECEEC27F0E552DF50010805E23B5013 +:1027C000E66ECEEC27F0E552DF50020805E23C5001 +:1027D000E66ECEEC27F0E5523D50E6E10201E55110 +:1027E000E61108E0A050020B05E103EC28F0396E79 +:1027F000A182A0828150100B14E1C250020B11E1A2 +:102800000201FA51C45C0AE20C0E0201FC5D03E114 +:102810008A948A8802D00201FC2B02D00201FC6B50 +:10282000C282E552E552E7CFD9FF1200D9CFE6FFC9 +:10283000E1CFD9FFFE0EDBCFE6FF45EC2FF0E552EE +:1028400000093CE0020E3E6E546AE66A110EE66E26 +:10285000D8D9E552E552400EE66EF8DAE5520201AB +:10286000FA6F500EE66E040EE66E33EC2AF0E55277 +:10287000E5524B0EE66E050EE66E33EC2AF0E5529D +:10288000E552320EE66E060EE66E33EC2AF0E552A5 +:10289000E552FE0EDB50030FEA6A000FE96E020EEE +:1028A000EA22EF503D6E3D50E66E070EE66E33ECC9 +:1028B0002AF0E552E5520201890E006FE552E7CF9A +:1028C000D9FF1200D9CFE6FFE1CFD9FFF29EA8ECE5 +:1028D0003BF0050EC26EC282FD0EDBCFE9FFFE0E9D +:1028E000DBCFEAFFEF50EF2AEA6A000FE96E020E33 +:1028F000EA22EF50346EFD0EDBCFE9FFFE0EDBCF98 +:10290000EAFFEF50EF2AEA6A000FE96E020EEA22B0 +:10291000EF50356E366A376A386A396A3A6A3D6A04 +:102920000001E88392968986928492888A94899A93 +:102930002E0EB46EA50EB56E0C0EE66E9FEC3EF03C +:10294000E5529D90A092910ECD6E910EB16EA19C1C +:10295000A08CF28EE552E7CFD9FF1200F29E000163 +:10296000E893A09C9D90A092CD6AB16A070EB46EC8 +:10297000B56A928693EC3BF0F28E1200D9CFE6FF57 +:10298000E1CFD9FF030EE126FD0EDB50416E426A16 +:1029900041C042F0416AFE0EDB50000141243F6E0F +:1029A000000E4220406E010E3FC0DBFF020E40C011 +:1029B000DBFFDF6ADF503F6E406AD890405004E68C +:1029C000800E3F5C000E405810E2010EDBCFE9FFA5 +:1029D000DB2A020EDBCFEAFF01E3DB2AEF50E66ED3 +:1029E000CEEC27F0E552DF2AE5D7030EE15C02E2E8 +:1029F000E16AE552E16EE552E7CFD9FF1200D9CF87 +:102A0000E6FFE1CFD9FF050EE126FD0EDBCFE9FFA2 +:102A1000FE0EDBCFEAFFEF50EF2AEA6A000FE96E05 +:102A2000020EEA22040EEFCFDBFFFD0EDBCFE9FF43 +:102A3000FE0EDBCFEAFFEF50EF2AEA6A000FE96EE5 +:102A4000020EEA22EF50E66ED950020FE96EDACF9D +:102A5000EAFFE552E750EE6EED6AD950020FE96EDB +:102A6000DACFEAFF200ED880EE54000EED5407E2D4 +:102A7000200EF36E020EF3CFDBFF030EDB6AD9509C +:102A8000020FE96EDACFEAFFEE50ED1001E12DD032 +:102A9000DE6ADD6ADECF3FF0DDCF40F0020EDBCF35 +:102AA00041F0030EDBCF42F041503F5C42504058B2 +:102AB0001AE2040EDBCFF3FFDB2AF350E66E55EC8F +:102AC0002AF0E552E66EDECFE9FFDDCFEAFF400EE9 +:102AD000E926020EEA22E552E750EF6EDF2A010EE8 +:102AE00001E3DB2AD7D705EC11F0050EE15C02E229 +:102AF000E16AE552E16EE552E7CFD9FF1200D9CF86 +:102B0000E6FFE1CFD9FF050EE126FD0EDBCFE9FFA1 +:102B1000FE0EDBCFEAFFEF50EF2AEA6A000FE96E04 +:102B2000020EEA22040EEFCFDBFFFD0EDBCFE9FF42 +:102B3000FE0EDBCFEAFFEF50EF2AEA6A000FE96EE4 +:102B4000020EEA22EF50E66ED950020FE96EDACF9C +:102B5000EAFFE552E750EE6EED6AD950020FE96EDA +:102B6000DACFEAFF200ED880EE54000EED5407E2D3 +:102B7000200EF36E020EF3CFDBFF030EDB6AD9509B +:102B8000020FE96EDACFEAFFEE50ED1001E12FD02F +:102B9000DE6ADD6ADECF3FF0DDCF40F0020EDBCF34 +:102BA00041F0030EDBCF42F041503F5C42504058B1 +:102BB0001EE2FD0EDBCFE9FFFE0EDBCFEAFFEF509A +:102BC000EF2AEA6A000FE96E020EEA22EF50E66E83 +:102BD000040EDBCFF3FFDB2AF350E66E33EC2AF072 +:102BE000E552E552DF2A010E01E3DB2AD3D7050EB9 +:102BF000E15C02E2E16AE552E16EE552E7CFD9FF1E +:102C00001200D9CFE6FFE1CFD9FF030EE126FE0E79 +:102C1000DB50426E436A42C043F0426AFD0EDB5015 +:102C2000000142243F6E000E4320406E416A40BEC8 +:102C300041683FC0DFFF010E40C0DBFF020E41C014 +:102C4000DBFFD9CFE9FFDACFEAFF060EE76ED890B7 +:102C5000020EEB32010EEB32EF32E706F8E1E5C08F +:102C60003FF0406A416A3FAE02D040684168D9CF28 +:102C7000E9FFDACFEAFF3F50EE264050EE22415006 +:102C8000EE22E6C03FF0406A416AD9CFE9FFDACFD1 +:102C9000EAFF3FC02CF040C02DF041C02EF0EECF37 +:102CA00027F0EECF28F0EFCF29F0A5EC3CF026C0BE +:102CB000EDFF25C0EDFF24C0EFFFD9CFE9FFDACF4C +:102CC000EAFFD890020EEB32010EEB32EF32080E23 +:102CD000426ED9CFE9FFDACFEAFF42501F0BEECFA9 +:102CE0003FF0EECF40F0EECF41F006E0D890413219 +:102CF00040323F32E806FAE13F50BE6ED9CFE9FFDD +:102D0000DACFEAFFEE52EE6AEE6ACF0EBD14426EE3 +:102D1000436A446A020E486ED9CFE9FFDACFEAFF70 +:102D200048501F0BEECF45F0EECF46F0EECF47F008 +:102D300006E0D890473246324532E806FAE1425082 +:102D400045103F6E43504610406E44504710416E50 +:102D50003F50BD6E030EE15C02E2E16AE552E16EB6 +:102D6000E552E7CFD9FF1200D9CFE6FFE1CFD9FF77 +:102D7000040EE126FD0EDBCF3FF0FE0EDBCF40F070 +:102D8000000E3FC0DBFF010E40C0DBFF020EDB6A1E +:102D9000030EDB6AE3C03FF0E4C040F0416A426AE0 +:102DA000D9CFE9FFDACFEAFF3FC02BF040C02CF0CB +:102DB00041C02DF042C02EF0EECF26F0EECF27F02E +:102DC000EECF28F0EFCF29F020EC3EF025C0EDFF4C +:102DD00024C0EDFF23C0EDFF22C0EFFFD9CFE9FFF4 +:102DE000DACFEAFF080EE76ED890030EEB32020E40 +:102DF000EB32010EEB32EF32E706F6E1D9CFE9FF15 +:102E0000DACFEAFFD880FF0EEE54FF0EEE54000E2C +:102E1000EE54000EEE5406E2DE68DE68DE6ADD6A1D +:102E2000DD52DD52DFCF3FF0010EDBCF40F03FC07F +:102E3000F3FF40C0F4FF00D0040EE15C02E2E16A5F +:102E4000E552E16EE552E7CFD9FF1200D9CFE6FF98 +:102E5000E1CFD9FF020EE126E3C03FF0E4C040F02D +:102E6000000ED8803F56020E40563FC0DEFF40C0E5 +:102E7000DDFFFE0EDB503F6E406AD9CFE9FFDACFAF +:102E8000EAFF3FC02DF040C02EF0EECF28F0EDCF8E +:102E900029F087EC3CF026C0EEFF27C0EDFFD9CF2C +:102EA000E9FFDACFEAFF080E0F0B06E0EC52D890EC +:102EB000ED32EF32E806FAE1DF5000D03F6E020E4D +:102EC000E15C02E2E16AE552E16E3F50E552E7CF94 +:102ED000D9FF1200E3C0E6FFE66A33EC2AF0E552C0 +:102EE000E552E4C03FF0406A3F50E66E010EE66EE8 +:102EF00033EC2AF0E552E552E5C0E6FF020EE66E3D +:102F000033EC2AF0E552E552E6C0E6FF030EE66E2A +:102F100033EC2AF0E552E5521200E66A55EC2AF04D +:102F2000E5520001E36FE46B010EE66E55EC2AF00A +:102F3000E5523F6E406A3FC040F03F6A3F5000019B +:102F4000E32740500001E423020EE66E55EC2AF020 +:102F5000E5520001E56F030EE66E55EC2AF0E552EE +:102F60000001E66F12000001E96B0001EA6B00014D +:102F7000EB6BEC6B12000201E36B0201E46B0201EC +:102F8000E56BE66B1200D9CFE6FFE1CFD9FF060E65 +:102F9000E126DE6ADD6A020EDB6A030EDB6A040EDE +:102FA000DB6A050EDB6A040EDB6A050EDB6A040EC3 +:102FB000DBCF3FF0050EDBCF40F0D890405004E669 +:102FC000200E3F5C000E40581EE2040EDBCFE9FFEE +:102FD000050EDBCFEAFF030EEA02F3CFEAFF030E92 +:102FE000E902F3CFE9FFF450EA26800EE926020E4B +:102FF000EA22EF50DE26000EDD22040EDB2A050E4B +:1030000001E3DB2AD4D7040EDB6A050EDB6A040E6B +:10301000DBCF3FF0050EDBCF40F0DECF41F0DDCF60 +:1030200042F040504218E8AE02D0423404D0415041 +:103030003F5C425040581EE2040EDB500001F42574 +:103040000F01E96E050EDB500001F5210F01EA6E5C +:10305000EF503F6E406AD950020FE96EDACFEAFFB7 +:103060003F50EE264050ED22040EDB2A050E01E310 +:10307000DB2ACDD7DECF3FF0DDCF40F03F5002015D +:10308000406FDECF3FF0DDCF40F040C03FF0406A00 +:103090003FC041F2FF0EE76E020EDBCF3FF0030EA2 +:1030A000DBCF40F0E7503F16406A3FC042F2020ECD +:1030B000DBCF3FF0030EDBCF40F040C03FF0406A73 +:1030C0003FC043F205EC11F0060EE15C02E2E16A5A +:1030D000E552E16EE552E7CFD9FF1200D9CFE6FF06 +:1030E000E1CFD9FF020EE126A8EC3BF0040EE66E1C +:1030F00060D8E552C450416E426A41C042F0416A14 +:10310000C350000141243F6E000E4220406E3FC07C +:10311000DEFF40C0DDFFDECFE6FFDDCFE6FF24DED1 +:10312000E552E552F3CFDEFFF4CFDDFFDFCF40F213 +:10313000DECF3FF0DDCF40F040C03FF0406A3FC0FF +:1031400041F2E66A36D8E552C450416E426A41C047 +:1031500042F0416AC350000141243F6E000E4220FC +:10316000406E3FC0DEFF40C0DDFFDECFE6FFDDCFBB +:10317000E6FFFADDE552E552F3CFDEFFF4CFDDFFE7 +:10318000DFCF42F2DECF3FF0DDCF40F040C03FF076 +:10319000406A3FC043F205EC11F093EC3BF0020EA5 +:1031A000E15C02E2E16AE552E16EE552E7CFD9FF68 +:1031B0001200D9CFE6FFE1CFD9FFFE0EDB28C26EA9 +:1031C000C282C2B2FED7E552E7CFD9FF1200D9CFF3 +:1031D000E6FFE1CFD9FF020EE126010EEBC0DBFFD7 +:1031E000010EDB503F0803E2DE523F0EDD6E010EA2 +:1031F000DBCF40F2010EDF6E010EDB50D880DF54D2 +:1032000023E30001EA51EA2BEA6A600FE96E000E3F +:10321000EA22EF50E66EDF50EA6A400FE96E020ED6 +:10322000EA22E552E750EF6E0001EA513F6E406A34 +:10323000D890405004E6800E3F5C000E405802E3F8 +:103240000001EA6BDF2AD8D7010EDB503F6E406ADF +:103250003F500001EB5F40500001EC5B05EC11F0CA +:10326000020EE15C02E2E16AE552E16EE552E7CF6F +:10327000D9FF1200D9CFE6FFE1CFD9FF020EE12638 +:10328000010EEBC0DBFF010EDB50400803E2DE5213 +:10329000400EDD6EDF6A010EDB50DF5C23E20001D1 +:1032A000EA51EA2BEA6A600FE96E000EEA22EF505B +:1032B000E66EDF50EA6A400FE96E020EEA22E5523E +:1032C000E750EF6E0001EA513F6E406AD8904050DF +:1032D00004E6800E3F5C000E405802E30001EA6BFA +:1032E000DF2AD9D7010EDB503F6E406A3F50000104 +:1032F000EB5F40500001EC5B05EC11F0020EE15C6D +:1033000002E2E16AE552E16EE552E7CFD9FF120031 +:10331000D9CFE6FFE1CFD9FF200EF36EFE0EDBCF53 +:10332000F4FFF350F45C0DE2FE0EDB50030DF3CF1F +:10333000E9FFF4CFEAFF800EE926020EEA22EF5001 +:1033400003E10001E88B31D0FE0EDB50030DF3CF1B +:10335000E9FFF4CFEAFF800EE926020EEA22EF50E1 +:10336000E66EFE0EDB50030DF3CFE9FFF4CFEAFF6C +:10337000800EE926020EEA22EE5200010001F4510D +:10338000EE243F6E00010001F551EE20406E3FC07B +:10339000E6FF40C0E6FF70DBE552E552E552FD0E68 +:1033A000DB06FD0EDB500008CFE3E552E7CFD9FF87 +:1033B0001200D9CFE6FFE1CFD9FFE652DF6A200E37 +:1033C000DF5C0DE2DF50030DF3CFE9FFF4CFEAFF3E +:1033D000800EE926020EEA22EF6ADF2AF0D7E552D4 +:1033E000E552E7CFD9FF1200D9CFE6FFE1CFD9FFF1 +:1033F000040EE126FD0EDBCFE9FFFE0EDBCFEAFF78 +:10340000EF50EF2AEA6A000FE96E020EEA22EF504F +:10341000E66ED950020FE96EDACFEAFFE552E750C7 +:10342000EE6EED6A020EDB500201E52500013F6EF3 +:10343000030EDB500201E6210001406E000ED88031 +:103440003F54010E405403E20001E88F42D0DE6A8F +:10345000DD6ADECF3FF0DDCF40F0020EDBCF41F082 +:10346000030EDBCF42F041503F5C4250405831E206 +:10347000FD0EDBCFE9FFFE0EDBCFEAFFEF50EF2AB8 +:10348000EA6A000FE96E020EEA22EF50E66E0201D0 +:10349000E351E32BEA6A000FE96E010EEA22E552DE +:1034A000E750EF6E0201E3513F6E406AD890405002 +:1034B00004E6000E3F5C010E405802E30201E36B9C +:1034C0000201E52B000EE623DF2A010E01E3DB2AD1 +:1034D000C0D7040EE15C02E2E16AE552E16EE5521A +:1034E000E7CFD9FF1200D9CFE6FFE1CFD9FF080E11 +:1034F000E126FD0EDBCFE9FFFE0EDBCFEAFFEF2872 +:10350000EA6A000FE96E020EEA22EFCF3FF0406A4E +:103510003FBE4068040E3FC0DBFF050E40C0DBFF2E +:10352000040EDBCF3FF0050EDBCF40F0403404E269 +:103530003F503D08000E405403E20001E88D4FD299 +:10354000FD0EDBCFE9FFFE0EDBCFEAFFEF50EA6AAC +:10355000000FE96E020EEA22EFCF3FF0406A3FBE55 +:103560004068060E3FC0DBFF070E40C0DBFF020EC7 +:10357000DB6A030EDB6ADE6ADD6ADECF3FF0DDCF99 +:1035800040F0D890405004E6200E3F5C000E4058BA +:1035900023E2DECFE9FFDDCFEAFF030EEA02F3CF3D +:1035A000EAFF030EE902F3CFE9FFF450EA26800EAA +:1035B000E926020EEA22EF503F6E406AD950020F10 +:1035C000E96EDACFEAFF3F50EE264050ED22DF2AC7 +:1035D000010E01E3DB2AD1D7060EDBCFE9FF070E90 +:1035E000DBCFEAFF030EEA02F3CFEAFF030EE902A4 +:1035F000F3CFE9FFF450EA26800EE926020EEA2214 +:10360000EF503F6E406AD950020FE96EDACFEAFF01 +:103610003F50EE5E4050ED5A040EDBCF3FF0050EFA +:10362000DBCF40F0020EDBCF41F0030EDBCF42F0E8 +:10363000000ED8804156030E425642504018E8AE64 +:1036400002D0403404D03F50415C4050425803E225 +:103650000001E88DC4D1060EDBCF3FF0070EDBCFB3 +:1036600040F0403404E23F501F08000E405403E293 +:103670000001E88DB4D1060EDBCFE9FF070EDBCFEA +:10368000EAFF030EEA02F3CFEAFF030EE902F3CFEB +:10369000E9FFF450EA26800EE926020EEA22EF50F6 +:1036A00001E106D1060EDBCFE9FF070EDBCFEAFF13 +:1036B000030EEA02F3CFEAFF030EE902F3CFE9FFBC +:1036C000F450EA26800EE926020EEA22EF503F6E01 +:1036D000406A000ED8803F56030E40563F06000E4B +:1036E000405A040E3FC0DBFF050E40C0DBFF060E54 +:1036F000DBCFE9FF070EDBCFEAFF030EEA02F3CFD1 +:10370000EAFF030EE902F3CFE9FFF450EA26800E48 +:10371000E926020EEA22EE52EECFDEFFEDCFDDFF0C +:10372000DECF3FF0DDCF40F0040EDBCF41F0050EE1 +:10373000DBCF42F040504218E8AE02D0423404D011 +:1037400041503F5C4250405835E2060EDBCFE9FF66 +:10375000070EDBCFEAFF030EEA02F3CFEAFF030E08 +:10376000E902F3CFE9FFF450EA26800EE926020EC3 +:10377000EA22EF500001406AF4253F6EF5514022E5 +:10378000DE503F24E96EDD504020EA6EEF50E66ED9 +:10379000DE500001F4250F01E96EDD500001F52136 +:1037A0000F01EA6EE552E750EF6EDF2A010E01E3EA +:1037B000DB2AB6D7DE6ADD6ADECF3FF0DDCF40F030 +:1037C000D890405004E6200E3F5C000E405870E256 +:1037D000DECFE9FFDDCFEAFF030EEA02F3CFEAFF17 +:1037E000030EE902F3CFE9FFF450EA26800EE92642 +:1037F000020EEA22EECF3FF0EECF40F0EFCF41F0E5 +:10380000060EDBCFE9FF070EDBCFEAFF030EEA026D +:10381000F3CFEAFF030EE902F3CFE9FFF450EA2603 +:10382000800EE926020EEA22EE52EECF42F0EFCFF2 +:1038300043F0000143504118E8AE02D0413404D0B7 +:103840004050425C415043582EE2060EDBCFE9FF68 +:10385000070EDBCFEAFF030EEA02F3CFEAFF030E07 +:10386000E902F3CFE9FFF450EA26800EE926020EC2 +:10387000EA22EF503F6E406ADECFE9FFDDCFEAFF7C +:10388000030EEA02F3CFEAFF030EE902F3CFE9FFEA +:10389000F450EA26800EE926020EEA22EE523F504C +:1038A000EE5E4050ED5ADF2A010E01E3DB2A84D799 +:1038B000FD0EDBCFE9FFFE0EDBCFEAFFEF28EA6A61 +:1038C000000FE96E020EEA22EF50E66E060EDBCF25 +:1038D000E9FF070EDBCFEAFF030EEA02F3CFEAFFB0 +:1038E000030EE902F3CFE9FFF450EA26800EE92641 +:1038F000020EEA22E552E750EF6E060EDBCFE9FF3B +:10390000070EDBCFEAFF030EEA02F3CFEAFF030E56 +:10391000E902F3CFE9FFF450EA26800EE926020E11 +:10392000EA22EE52020EDBCFEEFF030EDBCFEDFFFD +:10393000020E3F6EFD0EDBCFE9FFFE0EDBCFEAFF8E +:103940003F50EF26DE6ADD6ADECF3FF0DDCF40F08C +:10395000060EDBCFE9FF070EDBCFEAFF030EEA021C +:10396000F3CFEAFF030EE902F3CFE9FFF450EA26B2 +:10397000800EE926020EEA22EF50000140AE02D08E +:10398000D89003D03F5C000E405829E2FD0EDBCFFB +:10399000E9FFFE0EDBCFEAFFEF50EF2AEA6A000FE5 +:1039A000E96E020EEA22EF50E66E020EDB500001D5 +:1039B000F42500013F6E030EDB500001F5210001EC +:1039C000406EDE503F24E96EDD504020EA6EE55245 +:1039D000E750EF6EDF2A010E01E3DB2AB5D7080EB0 +:1039E000E15C02E2E16AE552E16EE552E7CFD9FF20 +:1039F0001200F29E7BEC3DF0840EA66EFE0EF66E7B +:103A00007F0EF76EF86AF56A0C00550EA76EAA0EC7 +:103A1000A76EA6824E0EE66E58EC3EF0E552FF0011 +:103A20001200F00E0001E71781A402D00001E78721 +:103A300080AA02D00001E78581B802D00001E783A7 +:103A400081A602D00001E781E7C040F2E8C041F260 +:103A50008F0E0001E7170001E86B8B9005EC11F069 +:103A600012000201020E406F0201200E416F02019E +:103A7000426B05EC11F01200D9CFE6FFE1CFD9FF80 +:103A80000D0EE126DF6A0B0EDB6A0C0EDB6AF29A82 +:103A9000070ED56EFC0EDB5004E0FC0EDB503D083B +:103AA00004E20001E88B84EF24F0FE0E0001E8152B +:103AB00002E084EF24F0FC0EDB50DF5C02E384EFD5 +:103AC00024F0DF50E76EFD0EDBCFE9FFFE0EDBCF0B +:103AD000EAFFE750E926000EEA22EF50546EB30EDB +:103AE000545C04E2FC0EDB50DF6EDFD7D50E545C75 +:103AF00001E2CAD3D50E545E549E5446080E542695 +:103B0000F9505424D8B0FA2AF96EA5D39AD3DFD24B +:103B100000D34FD31BD3D8D2D0D266D25DD248D2F5 +:103B20003FD2E6D118D2E0D1CBD192D15AD133D104 +:103B300045D1EED0DDD0C9D0B1D099D070D069D008 +:103B40005ED053D03CD026D023D020D01DD01AD068 +:103B500016D012D00FD00CD009D006D003D000D090 +:103B60008A9890D38A888ED38A868CD38A968AD371 +:103B70008A8488D38A9486D30C0EBA6E83D3BA6AA9 +:103B80008B9280D3898A7ED3899A7CD38B807AD397 +:103B90008B9078D3DF2ADF50E76EFD0EDBCFE9FF95 +:103BA000FE0EDBCFEAFFE750E926000EEA22EFCF58 +:103BB000E0F2E0C2E6FFA3EC28F0E55263D3DF2A8F +:103BC000080EE66EDF50E76EFD0EDBCFE9FFFE0E5E +:103BD000DBCFEAFFE750E926000EEA22EF50E66E5F +:103BE00033EC28F0E552E5524DD3080EE66E03ECB7 +:103BF00028F0E66E33EC28F0E552E55243D3080E88 +:103C0000E66E85EC27F0E552E66ECEEC27F0E55245 +:103C100039D3080EE66E85EC27F0E55233D3DF2A60 +:103C2000DF50E76EFD0EDBCFE9FFFE0EDBCFEAFFD4 +:103C3000E750E926000EEA22EF50E66EDF50E76E0D +:103C4000FD0EDBCFE9FFFE0EDBCFEAFFE750E926F2 +:103C5000000EEA22010EE926000EEA22EF50E66E7F +:103C600033EC28F0E552E552020EDF260CD3DF2AB2 +:103C7000DF50E76EFD0EDBCFE9FFFE0EDBCFEAFF84 +:103C8000E750E926000EEA22EF50E66E03EC28F03A +:103C9000E66E33EC28F0E552E552F4D2DF2ADF502D +:103CA000E76EFD0EDBCFE9FFFE0EDBCFEAFFE7504C +:103CB000E926000EEA22EF50E66E85EC27F0E55289 +:103CC000E66ECEEC27F0E552DDD2DF2ADF50E76E5C +:103CD000FD0EDBCFE9FFFE0EDBCFEAFFE750E92662 +:103CE000000EEA22EF50E66E85EC27F0E552CAD2CC +:103CF000DF2ADF50E76EFD0EDBCFE9FFFE0EDBCFE4 +:103D0000EAFFE750E926000EEA22EFCFE1F2BAD24D +:103D10000B0EDB500EE0040EDB06040EDB5005E15B +:103D20000B0EDB6A030EDF26AED2050EDB50DF6E14 +:103D3000AAD2010EF36E0B0EF3CFDBFFDF50E76E5E +:103D4000FD0EDBCFE9FFFE0EDBCFEAFFE750E926F1 +:103D5000000EEA22010EE926000EEA22EF50DF5C97 +:103D6000E76E050EE7CFDBFFDF50E76EFD0EDBCF22 +:103D7000E9FFFE0EDBCFEAFFE750E926000EEA225C +:103D8000020EE926000EEA22040EEFCFDBFF050E3D +:103D9000DB50DF6E78D2DF2ADF50E76EFD0EDBCF1F +:103DA000E9FFFE0EDBCFEAFFE750E926000EEA222C +:103DB000EF50E66E1DEC27F0E55264D2DF2ADF50AB +:103DC000E76EFD0EDBCFE9FFFE0EDBCFEAFFE7502B +:103DD000E926000EEA22EF50E66EB3EC24F0E5523D +:103DE00051D20001E905EA6A600FE96E000EEA228D +:103DF000010EEFCFDBFFDF50E76EFD0EDBCFE9FFFB +:103E0000FE0EDBCFEAFFE750E926000EEA22010EA4 +:103E1000E926000EEA22EF50F36E010EDB50F35C50 +:103E200014E1DF50E76EFD0EDBCFE9FFFE0EDBCFC6 +:103E3000EAFFE750E926000EEA22020EE926000E0C +:103E4000EA22EF50DF24DF6E02D0030EDF261BD202 +:103E50000001E905EA6A600FE96E000EEA22010E30 +:103E6000EFCFDBFF010EDBCF3FF0DF50E76EFD0E43 +:103E7000DBCFE9FFFE0EDBCFEAFFE750E926000EBD +:103E8000EA22010EE926000EEA22EF50D8803F54C4 +:103E900014E2DF50E76EFD0EDBCFE9FFFE0EDBCF55 +:103EA000EAFFE750E926000EEA22020EE926000E9C +:103EB000EA22EF50DF24DF6E02D0030EDF26E3D1CB +:103EC000DF50E76EFD0EDBCFE9FFFE0EDBCFEAFF32 +:103ED000E750E926000EEA22010EE926000EEA224A +:103EE000EF50DF24DF6ECFD1FC0EDB50DF6ECBD185 +:103EF000DF2ADF50DF2AE76EFD0EDBCFE9FFFE0E83 +:103F0000DBCFEAFFE750E926000EEA22EF50406AD5 +:103F1000000F3F6E0F0E4022090E3FC0DBFF0A0E5E +:103F200040C0DBFFDF50DF2AE76EFD0EDBCFE9FF8D +:103F3000FE0EDBCFEAFFE750E926000EEA22EF5043 +:103F4000E66E090EDBCFE9FF0A0EDBCFEAFFE55292 +:103F5000E750EF6E98D1DF2ADF50E76EFD0EDBCF22 +:103F6000E9FFFE0EDBCFEAFFE750E926000EEA226A +:103F7000EF50406A000F3F6E0F0E4022090E3FC007 +:103F8000DBFF0A0E40C0DBFF090EDBCFE9FF0A0EA4 +:103F9000DBCFEAFFEF50E66ECEEC27F0E55272D1B0 +:103FA000DF2A44EC25F0E66ECEEC27F0E5526BD12B +:103FB000DF2ADF50DF2AE76EFD0EDBCFE9FFFE0EC2 +:103FC000DBCFEAFFE750E926000EEA22EF50E66E6B +:103FD000C6EC24F0E55257D1DF2A03EC28F0E66E58 +:103FE000C6EC24F0E5524FD10C0EDB5016E0070E64 +:103FF000DB06080E01E2DB06D950070FE96EDACFC7 +:10400000EAFFEE50ED1005E10C0EDB6A020EDF2632 +:104010003AD1060EDB50DF6E36D1DF50E76EFD0E73 +:10402000DBCFE9FFFE0EDBCFEAFFE750E926000E0B +:10403000EA22010EE926000EEA22EF50DF5CE76E6D +:10404000060EE7CFDBFF03EC28F0E66ED950070F32 +:10405000E96EDACFEAFFE552E750EE6EED6A03EC67 +:1040600028F0416E426A286A010E296E41C02DF087 +:1040700042C02EF05AEC3CF026C03FF027C040F082 +:10408000D950070FE96EDACFEAFF3F50EE264050D5 +:10409000ED22D950070FE96EDACFEAFFEE50ED10AE +:1040A00003E1020EDF26EFD0010EF36E0C0EF3CF0C +:1040B000DBFF060EDB50DF6EE6D0C3EC28F0E66EC9 +:1040C000CEEC27F0E552DED003EC28F0DBD0040E76 +:1040D000E66E010EE66E33EC28F0E552E552080E6E +:1040E000E66EE66A33EC28F0E552E552080EE66E1D +:1040F0003CEC27F0E552E66ECEEC27F0E552080ED8 +:10410000E66E3CEC27F0E552E66ECEEC27F0E55289 +:10411000B9D0040EE66EE66A33EC28F0E552E552BB +:10412000080EE66EE66A33EC28F0E552E552080E1A +:10413000E66EE66A33EC28F0E552E552080EE66ECC +:10414000E66A33EC28F0E552E5529CD0DF2A040EF3 +:10415000E66EE66A33EC28F0E552E552080EE66EAC +:10416000DF50DF2AE76EFD0EDBCFE9FFFE0EDBCF6F +:10417000EAFFE750E926000EEA22EF50E66E33EC44 +:1041800028F0E552E552080EE66EDF50DF2AE76EB2 +:10419000FD0EDBCFE9FFFE0EDBCFEAFFE750E9269D +:1041A000000EEA22EF50E66E33EC28F0E552E552BD +:1041B0006AD0DF2A040EE66EE66A33EC28F0E55298 +:1041C000E552080EE66EDF50DF2AE76EFD0EDBCF0C +:1041D000E9FFFE0EDBCFEAFFE750E926000EEA22F8 +:1041E000EF50E66E33EC28F0E552E552080EE66E2D +:1041F000DF50DF2AE76EFD0EDBCFE9FFFE0EDBCFDF +:10420000EAFFE750E926000EEA22EF50E66E33ECB3 +:1042100028F0E552E552080EE66EDF50DF2AE76E21 +:10422000FD0EDBCFE9FFFE0EDBCFEAFFE750E9260C +:10423000000EEA22EF50E66E33EC28F0E552E5522C +:1042400022D0080EE66E3CEC27F0E552E66ECEEC8E +:1042500027F0E55217D0DF2ADF50E76EFD0EDBCFE7 +:10426000E9FFFE0EDBCFEAFFE750E926000EEA2267 +:10427000EF50E66E3CEC27F0E552E66ECEEC27F010 +:10428000E55200D0DF2A11D4B30E545E549E54463A +:10429000080E5426F9505424D8B0FA2AF96E6AD27E +:1042A00070D227D3C6D216D3C7D273D250D23CD243 +:1042B00013D2D7D1ACD185D17ED16AD163D157D1B8 +:1042C0003FD135D12DD119D10ED104D1FCD0E8D0B8 +:1042D000E4D0E0D0D8D0C2D0AAD081D06ED001D066 +:1042E00035D0DF2A040EE66EE66A33EC28F0E5529C +:1042F000E552040EE66EDF50E76EFD0EDBCFE9FF00 +:10430000FE0EDBCFEAFFE750E926000EEA22EF506F +:10431000E66E33EC28F0E552E552080EE66E03EC4B +:1043200028F0E66E33EC28F0E552E552080EE66E12 +:10433000E66A33EC28F0E552E552040EE66E020E12 +:10434000E66E33EC28F0E552E5529CD7DF2A040EE6 +:10435000E66EE66A33EC28F0E552E552040EE66EAE +:10436000DF50E76EFD0EDBCFE9FFFE0EDBCFEAFF8D +:10437000E750E926000EEA22EF50E66E33EC28F013 +:10438000E552E552080EE66E03EC28F0E66E33ECDB +:1043900028F0E552E552080EE66E03EC28F0E66ED2 +:1043A00033EC28F0E552E552040EE66E020EE66E9E +:1043B00033EC28F0E552E55265D7DF2ADF50E76E8F +:1043C000FD0EDBCFE9FFFE0EDBCFEAFFE750E9266B +:1043D000000EEA22EF50E66EA1DAE55253D7DF2A4B +:1043E000DF50E76EFD0EDBCFE9FFFE0EDBCFEAFF0D +:1043F000E750E926000EEA22EF50E66EDF50E76E46 +:10440000FD0EDBCFE9FFFE0EDBCFEAFFE750E9262A +:10441000000EEA22010EE926000EEA22EF50E66EB7 +:104420006BEC28F0E552E552020EDF262CD7DF2A8E +:10443000DF50E76EFD0EDBCFE9FFFE0EDBCFEAFFBC +:10444000E750E926000EEA22EF50E66E03EC28F072 +:10445000E66E6BEC28F0E552E55214D7DF2ADF5008 +:10446000E76EFD0EDBCFE9FFFE0EDBCFEAFFE75084 +:10447000E926000EEA22EFCFE2F2E2C2E6FFD6EC36 +:1044800028F0E552FFD6EAEC28F0E66ECEEC27F0F5 +:10449000E552F8D6FBEC28F0F5D610EC29F0F2D670 +:1044A000DF2ADF50E76EFD0EDBCFE9FFFE0EDBCF2C +:1044B000EAFFE750E926000EEA22EF50E66E25EC0F +:1044C00029F0E552DFD603EC28F0E66E25EC29F062 +:1044D000E552D8D6E66A8EEC29F0E552E66ECEECCF +:1044E00027F0E552CFD60F0EE66E8EEC29F0E5529E +:1044F000E66ECEEC27F0E552C5D6DF2ADF50E76E38 +:10450000FD0EDBCFE9FFFE0EDBCFEAFFE750E92629 +:10451000000EEA22EF50E66EF5EC29F0E552B2D635 +:1045200003EC28F0E66EF5EC29F0E552ABD6E66A2E +:10453000F5EC29F0E552E66ECEEC27F0E552A2D676 +:10454000DF2ADF50E76EFD0EDBCFE9FFFE0EDBCF8B +:10455000EAFFE750E926000EEA22EF50E66EF5EC9E +:1045600029F0E552E66ECEEC27F0E5528BD603EC4F +:1045700028F0E66EF5EC29F0E552E66ECEEC27F079 +:10458000E55280D67ADBE66ECEEC27F0E5527AD69D +:10459000DF2ADF50DF2AE76EFD0EDBCFE9FFFE0EDC +:1045A000DBCFEAFFE750E926000EEA22EF50E66E85 +:1045B000DCDAE55268D603EC28F0E66ED6DAE5528E +:1045C00061D6CEDB020EF3CFDBFF030EF4CFDBFFB1 +:1045D000FF0EE76E020EDBCF3FF0030EDBCF40F0A5 +:1045E000E7503F16406A3F50E66ECEEC27F0E552AA +:1045F000020EDBCF3FF0030EDBCF40F040C03FF0B8 +:10460000406A3F50E66ECEEC27F0E5523BD6DF2AFB +:10461000E66ADF50E76EFD0EDBCFE9FFFE0EDBCF73 +:10462000EAFFE750E926000EEA22010EE926000E15 +:10463000EA22EF50E66EDF50E76EFD0EDBCFE9FFBA +:10464000FE0EDBCFEAFFE750E926000EEA22EF502C +:10465000E66E64EC2AF0E552E552E552020EDF26E2 +:1046600012D6DF2ADF50E76EFD0EDBCFE9FFFE0E2C +:10467000DBCFEAFFE750E926000EEA22020EE92628 +:10468000000EEA22EF50E66EDF50E76EFD0EDBCF44 +:10469000E9FFFE0EDBCFEAFFE750E926000EEA2233 +:1046A000010EE926000EEA22EF50E66EDF50E76EBB +:1046B000FD0EDBCFE9FFFE0EDBCFEAFFE750E92678 +:1046C000000EEA22EF50E66E64EC2AF0E552E55265 +:1046D000E552030EDF26D7D5DF2ADF50E76EFD0E49 +:1046E000DBCFE9FFFE0EDBCFEAFFE750E926000E45 +:1046F000EA22010EE926000EEA22EF50E66EDF50B4 +:10470000E76EFD0EDBCFE9FFFE0EDBCFEAFFE750E1 +:10471000E926000EEA22EF50E66EB9EC2BF0E552E6 +:10472000E552020EDF26AFD5DF2ADF50E76EFD0E21 +:10473000DBCFE9FFFE0EDBCFEAFFE750E926000EF4 +:10474000EA22EF50E66EFDEC2BF0E5529BD5DF2A16 +:10475000DF50E76EFD0EDBCFE9FFFE0EDBCFEAFF99 +:10476000E750E926000EEA22EF50E66E1EEC2CF030 +:10477000E55288D5E66AE66A81EC2DF0E552E5520D +:1047800081D5010EE66EE66A81EC2DF0E552E55228 +:1047900079D5DF2A010EE66EDF50E76EFD0EDBCF26 +:1047A000E9FFFE0EDBCFEAFFE750E926000EEA2222 +:1047B000EF50E66EDF50E76EFD0EDBCFE9FFFE0E39 +:1047C000DBCFEAFFE750E926000EEA22010EE926D8 +:1047D000000EEA22EF50E66EDF50E76EFD0EDBCFF3 +:1047E000E9FFFE0EDBCFEAFFE750E926000EEA22E2 +:1047F000020EE926000EEA22EF50E66EDF50E76E69 +:10480000FD0EDBCFE9FFFE0EDBCFEAFFE750E92626 +:10481000000EEA22030EE926000EEA22EF50E66EB1 +:104820004EEC2CF03F6E050EE15E3F50040EDF268D +:104830002AD530EC2DF026D5DF2ADF50E76EFD0EAD +:10484000DBCFE9FFFE0EDBCFEAFFE750E926000EE3 +:10485000EA22EF50E66EDF50E76EFD0EDBCFE9FF98 +:10486000FE0EDBCFEAFFE750E926000EEA22010E3A +:10487000E926000EEA22EF50E66EDF50E76EFD0EED +:10488000DBCFE9FFFE0EDBCFEAFFE750E926000EA3 +:10489000EA22020EE926000EEA22EF50E66EDF5011 +:1048A000E76EFD0EDBCFE9FFFE0EDBCFEAFFE75040 +:1048B000E926000EEA22030EE926000EEA22EF5056 +:1048C000E66EDFEC2CF0E552E552E552E552040EBF +:1048D000DF26D9D498DBE66E96DBE66E94DBE66ED7 +:1048E00092DBE66EDFEC2CF0E552E552E552E55244 +:1048F000C9D4010EE66E010EE66E81EC2DF0E55294 +:10490000E552C0D455EF1DF00D0EE15C02E2E16A04 +:10491000E552E16EE552E7CFD9FF1200D9CFE6FFAD +:10492000E1CFD9FF0201E351E32BEA6A000FE96E00 +:10493000010EEA22FE0EDBCFEFFF0201E3513F6ED4 +:10494000406AD890405004E6000E3F5C010E40588B +:1049500002E30201E36B0201E52B000EE623E552C0 +:10496000E7CFD9FF1200D9CFE6FFE1CFD9FFF2940C +:10497000FE0EDB50FF0DF350D76ED66AD58EF2A433 +:10498000FED7D59EE552E7CFD9FF1200D9CFE6FF7B +:10499000E1CFD9FFF29ECD90A40ED76E730ED66EE6 +:1049A000F294D58E8050080B04E1F250040B01E123 +:1049B000F9D7F2B45DD089949294600EE66E91ECD2 +:1049C0003EF0E55289848050080B04E0F250040B5D +:1049D00001E1F9D7F2B44CD0FE0EDB50546EF2B6C2 +:1049E00046D080A6FCD7899454BE898480B6FED771 +:1049F000F2B63DD080A6FCD7899454BC898480B699 +:104A0000FED7F2B634D080A6FCD7899454BA8984F4 +:104A100080B6FED7F2B62BD080A6FCD7899454B8C6 +:104A2000898480B6FED7F2B622D080A6FCD78994BE +:104A300054B6898480B6FED7F2B619D080A6FCD7CA +:104A4000899454B4898480B6FED7F2B610D080A67B +:104A5000FCD7899454B2898480B6FED7F2B607D0C9 +:104A600080A6FCD7899454B0898480B6FED7000014 +:104A7000F2A402D00001E885D59EF28ECD8000D050 +:104A8000E552E7CFD9FF1200CD90F29EA40ED76E6B +:104A9000730ED66EF294D58E8050080B04E1F2505E +:104AA000040B01E1F9D7F2B454D089949294600ECA +:104AB000E66E91EC3EF0E55289848050080B04E0EC +:104AC000F250040B01E1F9D79284F2B442D0546A57 +:104AD000F2B63ED080A6FCD780B6FED780B4548E06 +:104AE000F2B636D080A6FCD780B6FED780B4548C00 +:104AF000F2B62ED080A6FCD780B6FED780B4548AFA +:104B0000F2B626D080A6FCD780B6FED780B45488F3 +:104B1000F2B61ED080A6FCD780B6FED780B45486ED +:104B2000F2B616D080A6FCD780B6FED780B45484E7 +:104B3000F2B60ED080A6FCD780B6FED780B45482E1 +:104B4000F2B606D080A6FCD780B6FED780B45480DB +:104B5000000089849294F2A402D00001E885D59ED9 +:104B6000F28ECD80545000D01200D9CFE6FFE1CFB5 +:104B7000D9FFF29ECD90A40ED76E730ED66EF2942E +:104B8000D58E92848050040B04E0F250040B01E1B6 +:104B9000F9D7F2B45FD092968986600EE66E91ECFA +:104BA0003EF0E55289968050040B04E1F250040B6C +:104BB00001E1F9D792869294F2B44CD0FE0EDB500C +:104BC000546EF2B646D080A6FCD7899454BE898430 +:104BD00080B6FED7F2B63DD080A6FCD7899454BCEF +:104BE000898480B6FED7F2B634D080A6FCD78994EB +:104BF00054BA898480B6FED7F2B62BD080A6FCD7F3 +:104C0000899454B8898480B6FED7F2B622D080A6A3 +:104C1000FCD7899454B6898480B6FED7F2B619D0F1 +:104C200080A6FCD7899454B4898480B6FED7F2B6A6 +:104C300010D080A6FCD7899454B2898480B6FED760 +:104C4000F2B607D080A6FCD7899454B0898480B688 +:104C5000FED70000F2A402D00001E885600EE66EE7 +:104C600091EC3EF0E552D59EF28ECD8092849296E4 +:104C700000D0E552E7CFD9FF1200CD90F29EA40EEE +:104C8000D76E730ED66EF294D58E92848050040B3C +:104C900004E0F250040B01E1F9D7F2B455D092963A +:104CA0008986600EE66E91EC3EF0E5528996805062 +:104CB000040B04E1F250040B01E1F9D792849286CF +:104CC000F2B442D0546AF2B63ED080A6FCD780B689 +:104CD000FED780B4548EF2B636D080A6FCD780B60C +:104CE000FED780B4548CF2B62ED080A6FCD780B606 +:104CF000FED780B4548AF2B626D080A6FCD780B600 +:104D0000FED780B45488F2B61ED080A6FCD780B6F9 +:104D1000FED780B45486F2B616D080A6FCD780B6F3 +:104D2000FED780B45484F2B60ED080A6FCD780B6ED +:104D3000FED780B45482F2B606D080A6FCD780B6E7 +:104D4000FED780B454800000F2A402D00001E885B0 +:104D5000D59E92849296F28ECD80545000D012004F +:104D6000D9CFE6FFE1CFD9FF030EE126DF6AF29447 +:104D7000800ED76ED66AD58EF2AE02D0010EDF6EEF +:104D8000F29E80A40AD0F2A407D0D59EDF0401E1F0 +:104D9000F28EF36AF46A47D0F4D780B40AD0F2A452 +:104DA00007D0D59EDF0401E1F28EF36AF46A3BD0AE +:104DB000F4D7800ED76ED66AF29480A40AD0F2A4FB +:104DC00007D0D59EDF0401E1F28EF368F4682BD0A2 +:104DD000F4D7D59EDF0401E1F28ED650E66ED950AD +:104DE000010FE96EDACFEAFFE552E750EE6EED6AA9 +:104DF0007F0ED7143F6E406A3FC040F03F6AD950E3 +:104E0000010FE96EDACFEAFF3F50EE264050ED2267 +:104E1000010EDBCF3FF0020EDBCF40F03FC0F3FFCF +:104E200040C0F4FF00D0030EE15C02E2E16AE5520B +:104E3000E16EE552E7CFD9FF1200D9CFE6FFE1CF0F +:104E4000D9FFF294D768080EE66E9FEC3EF0E5526B +:104E5000FE0EDB0402E10CD002D0FE0EDB06FE0EDD +:104E6000DB50FF0DF350D66ED58EF2A4FED7D59E43 +:104E7000E552E7CFD9FF1200D9CFE6FFE1CFD9FF46 +:104E8000E6529284546AFE0EDB50556E020E020109 +:104E9000E15D0CE280B454808986000000000000CF +:104EA000899600005442552EF5D718D00201E1052D +:104EB000566E565080B45480898600000000000071 +:104EC00000000000E82EFBD7899656500000000035 +:104ED0000000E82EFBD75442552EEBD7FE0EDBCF59 +:104EE000E6FF080EE552D880E754070B04E0544271 +:104EF000549EE806FCE10201E0A39294545000D0D5 +:104F0000E552E552E7CFD9FF1200D9CFE6FFE1CF56 +:104F1000D9FFE6529284546AFE0EDB50556E020EA3 +:104F20000201E15D0CE2898600000000000080B40F +:104F30005480899600005442552EF5D718D00201AE +:104F4000E105566E89860000000056500000000002 +:104F50000000E82EFBD780B454808996565000009C +:104F600000000000E82EFBD75442552EEBD7FE0E72 +:104F7000DBCFE6FF080EE552D880E754070B04E0CC +:104F80005442549EE806FCE10201E0A3929454507E +:104F900000D0E552E552E7CFD9FF1200D9CFE6FFA6 +:104FA000E1CFD9FF010E0001406AEB253F6EEC51C5 +:104FB0004022800ED8803F54000E405403E200018E +:104FC000E8871DD00001E951E92BEA6A600FE96E1C +:104FD000000EEA22FE0EDBCFEFFF0001E9513F6E2B +:104FE000406AD890405004E6800E3F5C000E405866 +:104FF00002E30001E96B0001EB2B000EEC23E5520C +:10500000E7CFD9FF1200D9CFE6FFE1CFD9FFE652B3 +:105010000201E551E61104E10001E889000E1ED00D +:105020000201E451E42BEA6A000FE96E010EEA2264 +:10503000EFCFDFFF0201E507000EE65B0201E4515E +:105040003F6E406AD890405004E6000E3F5C010E6F +:10505000405802E30201E46BDF5000D0E552E55214 +:10506000E7CFD9FF1200D9CFE6FFE1CFD9FFE65253 +:10507000FE0EDB50546EFD0EDB50556E020E02012B +:10508000E15D0CE254A0899454B0898400008986C3 +:10509000000089965442552EF5D718D00201E1053B +:1050A000566E54A0899454B0898456500000000074 +:1050B0000000E82EFBD78986565000000000000053 +:1050C000E82EFBD789965442552EEBD7E552E55290 +:1050D000E7CFD9FF1200D9CFE6FFE1CFD9FFE652E3 +:1050E000FE0EDB50546EFD0EDB50556E020E0201BB +:1050F000E15D0CE254A0899454B089848986000053 +:10510000899600005442552EF5D718D00201E105CA +:10511000566E54A0899454B08984565089860000F4 +:1051200000000000E82EFBD78996565000000000D2 +:105130000000E82EFBD75442552EEBD7E552E5523E +:10514000E7CFD9FF1200D9CFE6FFE1CFD9FFFE0E9E +:10515000DBA402D0898601D08996FE0EDBA602D0A0 +:10516000898401D08994FE0EDBA002D0928601D002 +:105170009296FE0EDBA202D0928401D09294E55268 +:10518000E7CFD9FF1200D9CFE6FFE1CFD9FFE65232 +:10519000DF6A80B4DF8280A602D0000EDB80DF50A1 +:1051A00000D0E552E552E7CFD9FF1200D9CFE6FF94 +:1051B000E1CFD9FFFE0EDBA202D0898801D0899809 +:1051C000FE0EDBA002D0928801D09298E552E7CF84 +:1051D000D9FF1200D9CFE6FFE1CFD9FFE652DF6A4F +:1051E00080A802D0000EDB80DF5000D0E552E552EF +:1051F000E7CFD9FF12008986060EE66E9FEC3EF0DF +:10520000E55289989298060EE66E9FEC3EF0E552C4 +:105210008996060EE66E9FEC3EF0E55292881200EB +:105220008996060EE66E9FEC3EF0E55289989298BC +:10523000060EE66E9FEC3EF0E5528986060EE66E9F +:105240009FEC3EF0E55292881200D9CFE6FFE1CF05 +:10525000D9FFFE0EDB50546E080E556E8998020E73 +:105260000201E15D23E254AE929854BE928800D0D0 +:1052700000D000D08986000000D000D000D000D03F +:105280008996000000D000D05446552EECD7928865 +:1052900000D000D000D000D000D08986000000D01F +:1052A00000D000D080B8558089962FD00201E151FE +:1052B000E824FF0F566E54AE929854BE9288565012 +:1052C000000000D000D000D0E82EFAD789865650D2 +:1052D00000D000D000D0E82EFDD7899600005446BB +:1052E000552EE9D79288565000D000D0000000D04B +:1052F00000D000D0E82EFAD78986565000D000D0D2 +:10530000E82EFDD780B8558089965550000802E2F6 +:105310000001E885E552E7CFD9FF1200D9CFE6FFBB +:10532000E1CFD9FF546A080E556E010E566E928871 +:10533000020E0201E15D14E2544600D000D000D01C +:1053400000D00000898600D000D000D0000080B8D6 +:105350005480899600D000D000D0552EEDD725D0AE +:105360000201E151E824FF0F566E5446000000D0C0 +:10537000565000D000D000D00000E82EFAD7898621 +:10538000565000D000D0E82EFDD780B854808996C2 +:1053900000D0552EEAD70000565000D000D000D0E3 +:1053A00000D000D00000E82EFAD78998FE0EDB501E +:1053B00001E19298565000D000D000D000D000D02B +:1053C0000000E82EFAD78986565000D000D0E82E8B +:1053D000FDD700D0899600D000000000928854507C +:1053E00000D0E552E7CFD9FF1200D9CFE6FFE1CFD9 +:1053F000D9FFE652FE0EDB50546E080E556E020EBB +:105400000201E15D0DE254AE899854BE8988898617 +:105410005446549080B454808996552EF4D71BD0AE +:105420000201E105566E54AE899854BE89885650E3 +:10543000000000000000E82EFBD7898654465490F7 +:1054400080B454805650000000000000E82EFBD7C6 +:105450008996552EE8D78998545000D0E552E552E8 +:10546000E7CFD9FF1200D9CFE6FFE1CFD9FFE6524F +:10547000DF6AFE0EDB50A96EFD0EDB50A86EA66A39 +:10548000A684F2AE02D0010EDF6EF29E550EA76E1C +:10549000AA0EA76EA682DF0401E1F28EA6B2FED7A5 +:1054A000E552E552E7CFD9FF1200D9CFE6FFE1CFB1 +:1054B000D9FFFE0EDB50A96EA66AA680A85000D0C8 +:1054C000E552E7CFD9FF1200D9CFE6FFE1CFD9FFF0 +:1054D000040EE126DF6A010EDB6A0201E1510108D8 +:1054E00008E2120E566E0F0EF36E030EF3CFDBFFC3 +:1054F00007D0C60E566E030EF36E030EF3CFDBFF1E +:1055000089889298180EE66E9FEC3EF0E552020EE6 +:105510003F6EFD0EDBCFE7FF3F50E726FD0EE7CFE6 +:10552000DBFF480ED56E550E546E8998D66AF294FC +:10553000D58EF2AE02D0010EDF6EF29EFD0EDB06BE +:10554000020EDB6A020EDBCF3FF0080EE76E3F185B +:10555000E8AE02D0E73402D0E7503F5C21E2895048 +:10556000EF0B54AE1009F2A4FED7896E5650D62622 +:105570009298F294549E54468950556EFD0EDB501D +:1055800005E1FC0EDB5002E1558801D05598F2A4EC +:10559000FED789785650D626F294020EDB2AD2D74F +:1055A0005550F2A4FED7896E5650D626F294010EBD +:1055B000DB5007E0FD0EDB50000803E224DD546EF3 +:1055C00003D0FE0EDB50546EF2A4FED789785650FD +:1055D000D626F294F2A4FED792885650D626F2949C +:1055E000030EDBCFE6FF9FEC3EF0E552010EDB50F1 +:1055F00009E08050100B06E00001E885FD0EDB6A33 +:10560000FC0EDB6AF2A4FED700005650D626F294B8 +:10561000030EDBCFE6FF9FEC3EF0E552010EDB50C0 +:1056200009E08050100B06E10001E885FD0EDB6A01 +:10563000FC0EDB6ADE52010EDD6EFD0EDB50000853 +:1056400001E27CD7FC0EDBCFF3FFDB06F350000852 +:1056500001E37FD0546A020EDB6A020EDBCF3FF01B +:10566000080EE76E3F18E8AE02D0E73402D0E750EC +:105670003F5C30E2F2A4FED70000D66AF294895073 +:10568000556EFC0EDB5002E1558801D05598030E93 +:10569000DB04E66E9FEC3EF0E55280B807D0F2B432 +:1056A00002D080A8FCD75650D66E06D0F2B402D0F5 +:1056B00080B8FCD75650D66EF294030EDBCFE6FFCF +:1056C0009FEC3EF0E552549E544680B8542A020E98 +:1056D000DB2AC3D75550F2A4FED7896E5650D62682 +:1056E0009298F2945450E66E59DCE552F2A4FED73B +:1056F00089785650D626F294F2A4FED79288565056 +:10570000D626F294030EDBCFE6FF9FEC3EF0E55287 +:10571000010EDB5007E08050100B04E00001E8852B +:10572000FC0EDB6AF2A4FED700005650D626F29497 +:10573000030EDBCFE6FF9FEC3EF0E552010EDB509F +:1057400007E08050100B04E10001E885FC0EDB6AE5 +:1057500079D7DF0401E1F28E070ED56E9288040E30 +:10576000E15C02E2E16AE552E16EE552E7CFD9FF82 +:105770001200D9CFE6FFE1CFD9FFE652FE0EDB5093 +:1057800001E10FD0546AFD0EDB50556EDF6AFE0E4C +:10579000DB50DF5C06E247EC38F055905542DF2ADB +:1057A000F6D7E552E552E7CFD9FF1200D9CFE6FF91 +:1057B000E1CFD9FFE652FE0EDB5002E1000E18D019 +:1057C000FD0EDB50546EFC0EDB50556E566ADF6AE0 +:1057D000FE0EDB50DF5C0AE25690564247EC38F092 +:1057E0005490544255905542DF2AF2D7565000D07B +:1057F000E552E552E7CFD9FF1200D9CFE6FFE1CF5E +:10580000D9FF030EE66E040EE66EB3DFE552E552F5 +:10581000100EE66EFE0EDBCFE6FF050EE66EC6DF6F +:10582000E552E552E552010EE66E020EE66EA1DF8C +:10583000E552E552E552E7CFD9FF1200D9CFE6FF96 +:10584000E1CFD9FFE652DF6A010EE66E030EE66E87 +:1058500090DFE552E55256AE02D0010EDF6E800EAB +:10586000E66EFE0EDBCFE6FF080EE66E9FDFE5522A +:10587000E552E5525650E824DF12DFCFE6FFCEECCA +:1058800027F0E552010EE66E020EE66E72DFE5527B +:10589000E552E552E552E7CFD9FF1200D9CFE6FF36 +:1058A000E1CFD9FF020EE126DF6A010EDB6A010EAD +:1058B000E66E030EE66E5DDFE552E55256AE02D0AF +:1058C000010EDF6EE66AFB0EDBCFE6FF080EE66E2A +:1058D0006DDFE552E552E5525650E824DF12FA0E2C +:1058E000DB5005E0DFCFE6FFCEEC27F0E552DF6AC4 +:1058F00056AE02D0010EDF6EE66AFC0EDBCFE6FF8D +:10590000080EE66E53DFE552E552E5525650E824A4 +:10591000DF12FA0EDB5005E0DFCFE6FFCEEC27F01A +:10592000E552DF6A56AE02D0010EDF6EE66AFD0E6A +:10593000DBCFE6FF080EE66E39DFE552E552E552B1 +:105940005650E824DF12FA0EDB5005E0DFCFE6FF09 +:10595000CEEC27F0E552010EDFCFDBFFDF6A56AE5B +:1059600002D0010EDF6E800EE66EFE0EDBCFE6FF8C +:10597000080EE66E1BDFE552E552E5525650E8246C +:10598000DF12FA0EDB5005E0DFCFE6FFCEEC27F0AA +:10599000E552010EE66E020EE66EEBDEE552E552D2 +:1059A000010EDB5000D03F6E020EE15C02E2E16AC4 +:1059B000E552E16E3F50E552E7CFD9FF1200D9CF53 +:1059C000E6FFE1CFD9FF010EE66E030EE66ED1DEF3 +:1059D000E552E55256BE0AD01F0EE66E050EE66E83 +:1059E000C8DEE552E5520001E88536D0E66A010ED0 +:1059F000E66EBFDEE552E552E66AFB0EDBCFE6FF60 +:105A0000080EE66ED3DEE552E552E552E66AFC0E7C +:105A1000DBCFE6FF080EE66EC9DEE552E552E55241 +:105A2000E66AFD0EDBCFE6FF080EE66EBFDEE5524E +:105A3000E552E552800EE66EFE0EDBCFE6FF080E65 +:105A4000E66EB4DEE552E552E552010EE66E020E58 +:105A5000E66E8FDEE552E552E552E7CFD9FF120040 +:105A6000D9CFE6FFE1CFD9FFE652D76AD66AF294E2 +:105A7000D58E0A0EE66EC1DEE552E66AE66AD00E03 +:105A8000E66E040EE66EE66A09DF3F6E050EE15E25 +:105A90003F50DF6E040EDF1403E1F250040BEDE023 +:105AA000F2A404D00001E885D59E26D0090EE66E4A +:105AB000A4DEE552E66A03EC28F0E66E03EC28F07B +:105AC000E66E03EC28F0E66E03EC28F0E66EE6DE08 +:105AD0003F6E050EE15E3F500A0EE66E8EDEE55229 +:105AE000E66AE66AC00EE66EE66AE66AD7DE3F6EF2 +:105AF000050EE15E3F50D59EE552E552E7CFD9FF56 +:105B00001200D9CFE6FFE1CFD9FFE652D76AD66AB5 +:105B1000F294D58E0A0EE66E70DEE552E66AE66A0B +:105B2000D00EE66E040EE66EE66AB8DE3F6E050E37 +:105B3000E15E3F50DF6E040EDF1403E1F250040B10 +:105B4000EDE0F2A404D00001E885D59E23D0090E33 +:105B5000E66E53DEE552FE0EDBCFE6FFE66AE66A4E +:105B6000E66AE66A9BDE3F6E050EE15E3F50FD0E83 +:105B7000DB500FE00A0EE66E40DEE552E66AE66AAA +:105B8000C00EE66EE66AE66A89DE3F6E050EE15EED +:105B90003F50D59EE552E552E7CFD9FF1200D9CF4D +:105BA000E6FFE1CFD9FF020EE126F29EA8EC3BF022 +:105BB000928492869288D9EC19F08B80E950DF6E3E +:105BC000010EEACFDBFF5F5002E05F6A02D058505F +:105BD0005F6E5DEC38F05E50000803E2E5EC38F0F3 +:105BE00007D05F5003E0AAEC38F002D06FEC38F039 +:105BF000DF50E96E010EDB50EA6E8B9093EC3BF0C8 +:105C0000F28E54C040F255C041F205EC11F0020E84 +:105C1000E15C02E2E16AE552E16EE552E7CFD9FFCD +:105C200012000100567D0000F40000000200000098 +:105C3000D9CFE6FFE1CFD9FFE6520401B06B0401F2 +:105C4000B16BB26B396AC56AC76A280EC66E1F0E81 +:105C5000C86EC584C5B4FED7E552E552E7CFD9FF7B +:105C60001200D9CFE6FFE1CFD9FFE6528B9C67D86F +:105C70000401B06B9E960401B051B02BEA6AC00FCC +:105C8000E96E040EEA22EF50C96E9EA6FED7C5BC8F +:105C9000C584400E0401B05DEDE3C584C5B4FED7F4 +:105CA000060EE66E58EC3EF0E5520401B06B0401BE +:105CB000B12B000EB2238B8CE552E552E7CFD9FF12 +:105CC0001200D9CFE6FFE1CFD9FFE65238D801095B +:105CD000DF6EC582C5B2FED79E96DF50C96E9EA606 +:105CE000FED7C5BCC5840401B06B9E96C5869EA632 +:105CF000FED70401B051B02BEA6AC00FE96E040E62 +:105D0000EA22C9CFEFFF400E0401B05D02E1C58A6F +:105D100001D0C59AC588C5B8FED7400E0401B05D54 +:105D2000E4E3C584C5B4FED70401B06B0401B12B14 +:105D3000000EB223E552E552E7CFD9FF1200D9CFCA +:105D4000E6FFE1CFD9FF020EE126DE52A00EDD6EA6 +:105D50003D5007E10401B251040B02E0010EDB8269 +:105D60000CD00401B251080B02E0010EDB820401E9 +:105D7000B251040B02E0010EDB86C580C5B0FED730 +:105D80009E96010EDB50C96EB1C43FF0B2C440F024 +:105D9000D89040323F32D89040323F323F50DF6E91 +:105DA0009EA6FED7C5BCC5849E96DF50C96EB1C401 +:105DB0003FF0B2C440F0060ED8903F364036E804BB +:105DC000FBE13F50DF6E9EA6FED7C5BCC5849E9604 +:105DD000DF50C96E9EA6FED7C5BCC584010EDB5040 +:105DE00000D03F6E020EE15C02E2E16AE552E16E34 +:105DF0003F50E552E7CFD9FF1200D9CFE6FFE1CF00 +:105E0000D9FF0401B051B02BEA6AC00FE96E040E4D +:105E1000EA22FE0EDBCFEFFF0401B0513F0801E2A2 +:105E200020DFE552E7CFD9FF12000401B0513F084F +:105E300003E247DF0401B06B0401B051B02BEA6A02 +:105E4000C00FE96E040EEA22EF5000D01200D9CF45 +:105E5000E6FFE1CFD9FF3E6AFE0EDBCFE6FF15D8A5 +:105E6000E55200090EE0FE0EDB50030FEA6A000F58 +:105E7000E96E020EEA22EF503D6E010E3E6ED8DE54 +:105E80008B80E552E7CFD9FF1200D9CFE6FFE1CFF3 +:105E9000D9FFFE0EDBCFF3FFDB2AF350EA6A000FD7 +:105EA000E96E020EEA22EF50500802E0000E20D008 +:105EB000FE0EDBCFF3FFDB2AF350EA6A000FE96E38 +:105EC000020EEA22EF504B0802E0000E11D0FE0E47 +:105ED000DBCFF3FFDB2AF350EA6A000FE96E020E14 +:105EE000EA22EF50320802E0000E02D0010E00D08C +:105EF000E552E7CFD9FF1200AD0EE66E7EDFE55228 +:105F00000401B0510008F8E33E6A8B901200D9CF2B +:105F1000E6FFE1CFD9FF020EE126DF6A010EDB6A60 +:105F2000DF50EA6A000FE96E020EEA22EF50840A9F +:105F300001E14ED1210A01E129D1270A01E126D14F +:105F4000010A01E123D1040A01E120D1070A01E19C +:105F50001DD1010A01E11AD1230A01E115D1010A7B +:105F600001E112D10D0A01E10FD1010A01E10CD1C9 +:105F7000080A01E1FDD00E0A01E1FAD0030A01E1AD +:105F8000F7D0010A01E1F4D0070A01E1F1D0290AB2 +:105F900001E1EED0030A01E1EBD02E0A01E1BCD011 +:105FA0000E0A01E18DD0020A54E0140A4FE0100AF3 +:105FB00020E0010A1EE0130A19E0030A0CE0070AB8 +:105FC00006E01B0A01E03CD1400EDF6E3AD1400EE4 +:105FD000DF6E92DF36D1020EDF26DF50EA6A000F55 +:105FE000E96E020EEA22EF28DF262BD1030EDF2610 +:105FF00028D1DF50DF2AEA6A000FE96E020EEA229A +:10600000EF50E66EFADEE552DF50DF2AEA6A000F53 +:10601000E96E020EEA22EF50E66EEFDEE552DF5047 +:10602000DF2AEA6A000FE96E020EEA22EF50E66EFE +:10603000E4DEE552DF50DF2AEA6A000FE96E020E65 +:10604000EA22EF50E66ED9DEE552FBD0050EDF26E0 +:10605000F8D0DF50DF2AEA6A000FE96E020EEA226A +:10606000EF50E66ECADEE552DF50DF2AEA6A000F23 +:10607000E96E020EEA22EF50E66EBFDEE552DF5017 +:10608000DF2AEA6A000FE96E020EEA22010EEFCF64 +:10609000DBFF010EDBCFE6FFB0DEE552DF50DF2A8B +:1060A000EA6A000FE96E020EEA22EF50E66EA5DE04 +:1060B000E552010EDB06010EDB500008EFE3C1D014 +:1060C000DF50DF2AEA6A000FE96E020EEA22EF5083 +:1060D000E66E93DEE552DF50DF2AEA6A000FE96ED2 +:1060E000020EEA22010EEFCFDBFF010EDBCFE6FF4F +:1060F00084DEE552DF50DF2AEA6A000FE96E020E05 +:10610000EA22EF50E66E79DEE552010EDB06010E63 +:10611000DB500008EFE395D0DF50DF2AEA6A000F7A +:10612000E96E020EEA22EF50E66E67DEE552DF50BE +:10613000DF2AEA6A000FE96E020EEA22010EEFCFB3 +:10614000DBFF010EDBCFE6FF58DEE552DF50DF2A32 +:10615000EA6A000FE96E020EEA22EF50E66E4DDEAB +:10616000E552010EDB06010EDB500008EFE369D0BB +:10617000DF50DF2AEA6A000FE96E020EEA22EF50D2 +:10618000E66E3BDEE5525DD0DF2A5BD0DF50DF2AD2 +:10619000EA6A000FE96E020EEA22EF50E66E2DDE8B +:1061A000E552DF50DF2AEA6A000FE96E020EEA22AA +:1061B000EF50E66E22DEE552DF50DF2AEA6A000F7A +:1061C000E96E020EEA22EF50E66E17DEE55239D094 +:1061D000DF50DF2AEA6A000FE96E020EEA22EF5072 +:1061E000E66E0BDEE552DF50DF2AEA6A000FE96E49 +:1061F000020EEA22EF50E66E00DEE552DF50DF2AA3 +:10620000EA6A000FE96E020EEA22EF50E66EF5DD53 +:10621000E552DF50DF2AEA6A000FE96E020EEA2239 +:10622000EF50E66EEADDE552DF50DF2AEA6A000F42 +:10623000E96E020EEA22EF50E66EDFDDE55201D094 +:10624000DF2A400EDF5C01E26BD6020EE15C02E267 +:10625000E16AE552E16EE552E7CFD9FF1200D9CFEE +:10626000E6FFE1CFD9FF020EE126E2DC0401400E99 +:10627000B06FDBDDDF6EDF50AB0A01E1D1D0070A82 +:1062800001E1CCD0060A01E1C9D0030A01E1C3D083 +:10629000010A01E1BDD00F0A01E1B7D0010A01E115 +:1062A0009CD0030A01E18AD0010A01E185D0050AE8 +:1062B0006BE0010A53E0FA0A50E0DC0A4CE0030A02 +:1062C00048E0010A36E0070A2BE0040A25E0050A47 +:1062D00021E0030A11E0010A01E0A5D0A6DDE76E86 +:1062E000010EE7CFDBFFA1DDE66E010EDBCFE6FF9F +:1062F00060D9E552E55299D098DDE76E010EE7CFFF +:10630000DBFF93DDE66E010EDBCFE6FFB0D9E55291 +:10631000E5528BD0366A376A88DD386E86DD85D0E7 +:10632000361C366E371C376E80DD361A7EDD371A26 +:106330007CD07BDD586E79DD596E77DD5A6E75DD68 +:106340005B6E81D8000904E1010E396EAD0EDF6E7F +:106350006CD003D96AD021D968D067D066DDE76EEA +:10636000010EE7CFDBFF010EDBCFE6FF5EDDE66E61 +:1063700001EC16F0E552E55258DDE66E26EC17F01A +:10638000E5520201FA6F51D050DD0001E06F4DDDA2 +:10639000E66E26EC17F0E552010F0001E16F020EE8 +:1063A0000001E15D0001E26F40DDE66E26EC17F0D2 +:1063B000E5520201FB6F39D0B6D937D036DDE76E32 +:1063C000010EE7CFDBFF31DDE66E010EDBCFE6FF2E +:1063D00088EC19F0E552E55228D027DDE76E010E72 +:1063E000E7CFDBFF010EDBCFE6FFEBEC35F0E5524C +:1063F000010EDBCFE6FF000EE66E020EE66E3CEC11 +:106400001DF0E552E552E55210D0BBEC17F00DD06F +:1064100008EC36F00AD0B3EC17F007D04ED805D010 +:10642000D9EC19F002D0AD0EDF6EAD0EDF5C01E0ED +:1064300020D7020EE15C02E2E16AE552E16EE5522C +:10644000E7CFD9FF1200B3EC17F0010EE66EE66A53 +:1064500088EC19F0E552E552010EE66E020EE66E8A +:1064600088EC19F0E552E552010EE66E010EE66E7B +:1064700088EC19F0E552E5520001EA51EA2BEA6A8C +:10648000600FE96E000EEA22EF5058160001EA5143 +:10649000EA2BEA6A600FE96E000EEA22EF50591605 +:1064A000B3EC17F05A50585C05E15B50595C02E1BF +:1064B000010E02D0000E00D01200D9CFE6FFE1CFCE +:1064C000D9FF040EE126360EDE6E000EDD6E020EE2 +:1064D000DB6A020EDBCF3FF00001EB513F5C000EA8 +:1064E000EC552FE20001EA51EA2BEA6A600FE96EEF +:1064F000000EEA22030EEFCFDBFF385013E0020E4E +:10650000DBA00ED038A003D0030EDB9E08D0030E14 +:10651000DB92DB94DB96DB98DB9ADB9CDB9E02D084 +:10652000030EDB90030EDB503F6E406ADECFE9FFC7 +:10653000DDCFEAFF3F50EE264050ED22020EDB2A6F +:10654000C8D7B3EC17F0040EE15C02E2E16AE55251 +:10655000E16EE552E7CFD9FF1200B3EC17F0010E60 +:10656000E66EE66A88EC19F0E552E552010EE66E39 +:106570000D0EE66E88EC19F0E552E552010EE66E5E +:10658000010EE66E88EC19F0E552E552600E00014E +:1065900061153A6EB3EC17F012003A500101011385 +:1065A000010EE66E0F0EE66E88EC19F0E552E5522C +:1065B0001200D9CFE6FFE1CFD9FFBBEC17F0B3EC67 +:1065C00017F00201E351E32BEA6A000FE96E010EB6 +:1065D000EA22FE0EDBCFEFFF0201E351E32BEA6A72 +:1065E000000FE96E010EEA22FD0EDBCFEFFF020184 +:1065F000E351E32BEA6A000FE96E010EEA22EF6A2B +:10660000030E0201E527000E0201E623010EE66EED +:10661000E66A88EC19F0E552E552010EE66E140EBA +:10662000E66E88EC19F0E552E552010EE66E010EB9 +:10663000E66E88EC19F0E552E5520001EA51EA2BCA +:10664000EA6A600FE96E000EEA22EF50346E000134 +:10665000EA51EA2BEA6A600FE96E000EEA22EF5077 +:10666000356EB3EC17F0E552E7CFD9FF1200D9CF62 +:10667000E6FFE1CFD9FFBBEC17F0B3EC17F0020156 +:10668000E351E32BEA6A000FE96E010EEA22FE0EE7 +:10669000DBCFEFFF0201E351E32BEA6A000FE96E63 +:1066A000010EEA22FD0EDBCFEFFF0201E351E32BE7 +:1066B000EA6A000FE96E010EEA22EF6A0201E35175 +:1066C000E32BEA6A000FE96E010EEA2234C0EFFF05 +:1066D0000201E351E32BEA6A000FE96E010EEA22A0 +:1066E00035C0EFFF050E0201E527000E0201E6238B +:1066F000010EE66EE66A88EC19F0E552E552010EED +:10670000E66E150EE66E88EC19F0E552E552010EC4 +:10671000E66E010EE66E88EC19F0E552E552E552A0 +:10672000E7CFD9FF1200D9CFE6FFE1CFD9FF0A0E9C +:10673000E12615EC2FF0E66ED950060FE96EDACFA0 +:10674000EAFFE552E750EE6EED6A15EC2FF0E66ECB +:10675000D950040FE96EDACFEAFFE552E750EE6E4A +:10676000ED6A040EDBCF28F0050EDBCF29F0080E12 +:1067700028C0DBFF090E29C0DBFF040EDBCF3FF092 +:10678000050EDBCF40F0403404E23F503D08000EE0 +:10679000405403E20001E88D14D2020EDB6A030EBE +:1067A000DB6ADE6ADD6ADECF3FF0DDCF40F0D890F5 +:1067B000405004E6200E3F5C000E405823E2DECF3E +:1067C000E9FFDDCFEAFF030EEA02F3CFEAFF030E93 +:1067D000E902F3CFE9FFF450EA26800EE926020E23 +:1067E000EA22EF503F6E406AD950020FE96EDACFCD +:1067F000EAFF3F50EE264050ED22DF2A010E01E372 +:10680000DB2AD1D7060EDBCFE9FF070EDBCFEAFF8D +:10681000030EEA02F3CFEAFF030EE902F3CFE9FF2A +:10682000F450EA26800EE926020EEA22EF503F6E6F +:10683000406AD950020FE96EDACFEAFF3F50EE5EB0 +:106840004050ED5A040EDBCF3FF0050EDBCF40F099 +:10685000020EDBCF41F0030EDBCF42F0000ED880FA +:106860004156030E425642504018E8AE02D0403422 +:1068700004D03F50415C4050425803E20001E88D93 +:10688000A0D1060EDBCF3FF0070EDBCF40F0403447 +:1068900004E23F501F08000E405403E20001E88D5F +:1068A00090D1060EDBCFE9FF070EDBCFEAFF030E28 +:1068B000EA02F3CFEAFF030EE902F3CFE9FFF45057 +:1068C000EA26800EE926020EEA22EF5001E106D107 +:1068D000060EDBCFE9FF070EDBCFEAFF030EEA026D +:1068E000F3CFEAFF030EE902F3CFE9FFF450EA2603 +:1068F000800EE926020EEA22EF503F6E406A000E3B +:10690000D8803F56030E40563F06000E405A040EF4 +:106910003FC0DBFF050E40C0DBFF060EDBCFE9FF0B +:10692000070EDBCFEAFF030EEA02F3CFEAFF030E06 +:10693000E902F3CFE9FFF450EA26800EE926020EC1 +:10694000EA22EE52EECFDEFFEDCFDDFFDECF3FF0ED +:10695000DDCF40F0040EDBCF41F0050EDBCF42F07F +:1069600040504218E8AE02D0423404D041503F5C5F +:106970004250405835E2060EDBCFE9FF070EDBCF71 +:10698000EAFF030EEA02F3CFEAFF030EE902F3CFB8 +:10699000E9FFF450EA26800EE926020EEA22EF50C3 +:1069A0000001406AF4253F6EF5514022DE503F243D +:1069B000E96EDD504020EA6EEF50E66EDE500001D9 +:1069C000F4250F01E96EDD500001F5210F01EA6E9B +:1069D000E552E750EF6EDF2A010E01E3DB2AB6D75E +:1069E000DE6ADD6ADECF3FF0DDCF40F0D890405068 +:1069F00004E6200E3F5C000E405870E2DECFE9FF57 +:106A0000DDCFEAFF030EEA02F3CFEAFF030EE9024D +:106A1000F3CFE9FFF450EA26800EE926020EEA22BF +:106A2000EECF3FF0EECF40F0EFCF41F0060EDBCFE0 +:106A3000E9FF070EDBCFEAFF030EEA02F3CFEAFF1E +:106A4000030EE902F3CFE9FFF450EA26800EE926AF +:106A5000020EEA22EE52EECF42F0EFCF43F00001F9 +:106A600043504118E8AE02D0413404D04050425C5B +:106A7000415043582EE2060EDBCFE9FF070EDBCF75 +:106A8000EAFF030EEA02F3CFEAFF030EE902F3CFB7 +:106A9000E9FFF450EA26800EE926020EEA22EF50C2 +:106AA0003F6E406ADECFE9FFDDCFEAFF030EEA0268 +:106AB000F3CFEAFF030EE902F3CFE9FFF450EA2631 +:106AC000800EE926020EEA22EE523F50EE5E405062 +:106AD000ED5ADF2A010E01E3DB2A84D7060EDBCF55 +:106AE000E9FF070EDBCFEAFF030EEA02F3CFEAFF6E +:106AF000030EE902F3CFE9FFF450EA26800EE926FF +:106B0000020EEA22080EDBCFEFFF060EDBCFE9FF15 +:106B1000070EDBCFEAFF030EEA02F3CFEAFF030E14 +:106B2000E902F3CFE9FFF450EA26800EE926020ECF +:106B3000EA22EE52020EDBCFEEFF030EDBCFEDFFBB +:106B4000DE6ADD6ADECF3FF0DDCF40F0060EDBCF40 +:106B5000E9FF070EDBCFEAFF030EEA02F3CFEAFFFD +:106B6000030EE902F3CFE9FFF450EA26800EE9268E +:106B7000020EEA22EF50000140AE02D0D89003D0BE +:106B80003F5C000E40581DE215EC2FF0E66E020E41 +:106B9000DB500001F42500013F6E030EDB500001C5 +:106BA000F5210001406EDE503F24E96EDD504020AB +:106BB000EA6EE552E750EF6EDF2A010E01E3DB2AB1 +:106BC000C1D70A0EE15C02E2E16AE552E16EE552EC +:106BD000E7CFD9FF1200D9CFE6FFE1CFD9FFE652C8 +:106BE000DF6AFE0EDB50DF5C0EE215EC2FF0E66E86 +:106BF000DF50EA6A000FE96E020EEA22E552E75022 +:106C0000EF6EDF2AEED7E552E552E7CFD9FF12004B +:106C1000D9CFE6FFE1CFD9FF040EE12615EC2FF026 +:106C2000E66ED950020FE96EDACFEAFFE552E7507F +:106C3000EE6EED6A020EDB500201E52500013F6EAB +:106C4000030EDB500201E6210001406E000ED880E9 +:106C50003F54010E405403E20001E88F36D0DE6A53 +:106C6000DD6ADECF3FF0DDCF40F0020EDBCF41F03A +:106C7000030EDBCF42F041503F5C4250405825E2CA +:106C800015EC2FF0E66E0201E351E32BEA6A000FE8 +:106C9000E96E010EEA22E552E750EF6E0201E35180 +:106CA0003F6E406AD890405004E6000E3F5C010EF3 +:106CB000405802E30201E36B0201E52B000EE623DC +:106CC000DF2A010E01E3DB2ACCD7040EE15C02E2ED +:106CD000E16AE552E16EE552E7CFD9FF1200D9CF64 +:106CE000E6FFE1CFD9FFE652DF6A81AA14D0FE0E9B +:106CF000DB50D880DF5408E3DF50DF2A010BE8B017 +:106D00008B80E8A08B9001D0DF6AF00EE66E58EC25 +:106D10003EF0E552EAD7E552E552E7CFD9FF12003F +:106D20006C500CE16896040100513C0BE842E842CB +:106D30000D0802E10ED801D04BD808D0040E6C5CCF +:106D400003E1689657D802D0000E02D0010E00D0A1 +:106D50001200D9CFE6FFE1CFD9FFE652040104AF1C +:106D600002D00401046B0201F96B0201F16B020114 +:106D7000F26B0201F76BF86BAEEC3BF0DF6ADF50B1 +:106D80003F6E406A010E3F5C000E40581BE202015C +:106D9000F25101E017D0F76ADF34FE0BF736F66EDA +:106DA000DE0EF6267A0EF7220900F5CF3FF0080036 +:106DB000F5CF40F004D040C0FAFF3F50F96EFBDF42 +:106DC000DF2ADDD705D9E552E552E7CFD9FF12001A +:106DD000020E0201F15D0CE1B9D8040100BD04D03E +:106DE0000401C80E006F03D00401880E006F01D0AB +:106DF0003ED91200040E0001ED5D0CE112C46EFFDD +:106E00006E50000804E20001050EED6F03D0000192 +:106E1000030EED6F0201F10514E115D8020E020117 +:106E2000F95D04E10401840E046F0AD0040104BD7D +:106E300004D00401C80E046F03D00401880E046F4F +:106E400001D015D91200D9CFE6FFE1CFD9FF020E4C +:106E5000E1260201080EF75D000EF85912E2F7C2B2 +:106E6000DEFFF8C2DDFF0201F95104E10201010E6B +:106E7000F96F06D00201F90503E10201020EF96F74 +:106E800003D0080EDE6EDD6A040104930401049150 +:106E9000010EDB5004010413DFCF05F4000EDB50BC +:106EA0000201F75F010EDB500201F85B0201180ED0 +:106EB000F56F040EF66F0001EEA320D0D9CFE9FFE5 +:106EC000DACFEAFFEE50ED1018E0F3C2F6FFF4C29D +:106ED000F7FF0800F550F5C2E9FFF6C2EAFFEF6ED2 +:106EE0000201F52B000EF6230201F32B000EF42312 +:106EF000DF06010E01E2DB06E1D71ED0D9CFE9FFA4 +:106F0000DACFEAFFEE50ED1017E0F3C2E9FFF4C26A +:106F1000EAFFEF50F5C2E9FFF6C2EAFFEF6E0201A9 +:106F2000F52B000EF6230201F32B000EF423DF06EF +:106F3000010E01E2DB06E2D7020EE15C02E2E16A49 +:106F4000E552E16EE552E7CFD9FF1200D9CFE6FF57 +:106F5000E1CFD9FF020EE126030E04010015E76E12 +:106F6000010EE7CFDBFF01C4DFFFDE500201F72790 +:106F7000DD500201F8230201180EF36F040EF46FC6 +:106F8000D9CFE9FFDACFEAFFEE50ED1017E0F3C2F8 +:106F9000E9FFF4C2EAFFEF50F5C2E9FFF6C2EAFFEB +:106FA000EF6E0201F52B000EF6230201F32B000E0B +:106FB000F423DF06010E01E2DB06E2D7020EE15CFC +:106FC00002E2E16AE552E16EE552E7CFD9FF120035 +:106FD0006D980201F2510FE10401080E016F0401E6 +:106FE000100E026F040E036F0401840E006F040183 +:106FF000840E046F3BD0040110AF25D00201F7517D +:107000000401165D0201F8510401175904E216C487 +:10701000F7F217C4F8F217DF0201010EF16F040155 +:10702000080E016F0401100E026F040E036F0401BD +:10703000800E006F0401180E066F040E076F040126 +:10704000C80E046F13D00201020EF16F0401056B2C +:107050000401C80E046F0401080E016F0401180E2C +:10706000026F040E036F0401C80E006F12000201CC +:10707000F16B0401080E016F0401100E026F040E83 +:10708000036F04018C0E006F0401046B12008986EB +:10709000899454B0898492940000899655A089946B +:1070A000898655B08984569E899689869284899668 +:1070B000898680B4568E899612005438556E56389B +:1070C000576E5AC05CF05BC05DF0FE0E5A6E040E47 +:1070D0005B6E06EE00F0EE6AEAA6FDD7120007EE40 +:1070E000FFF0BAD85CC05AF05DC05BF08038ED129A +:1070F0005D6EEA8200D000D000D00ED081AAA9D067 +:107100008038ED12EA825D6E551457181EE15C500E +:1071100058140EE1594EAAD08050EF6E5C6E541494 +:10712000561816E15D385814E9E1592EE9D7AAD06E +:1071300000008050EF6E5C6E5414561809E15D3803 +:107140005814DCE1592EDCD79DD081AA82D0E4D737 +:107150000000D4D707EEFFF07FD85CC05AF05DC0C6 +:107160005BF08038ED125D6EEA8200D000D000D076 +:107170000ED081AA6ED08038ED12EA825D6E551471 +:1071800057181EE15C5058140EE0594E6FD08050D5 +:10719000EF6E5C6E5414561816E15D385814E9E031 +:1071A000592EE9D76FD000008050EF6E5C6E5414FA +:1071B000561809E15D385814DCE0592EDCD762D04E +:1071C00081AA47D0E4D70000D4D707EEFFF044D817 +:1071D0005CC05AF05DC05BF07DD800008038ED12D5 +:1071E0005D6EEA8200D000D000D0000010D081AAED +:1071F00030D070D88038ED12EA825D6E5514571881 +:1072000023E15C5058145F1810E1594E2FD062D81A +:107210008050EF6E5C6E5414561819E15D385814A6 +:107220005F18E5E1592EE5D72DD0000053D88050E6 +:10723000EF6E5C6E541456180AE15D3858145F18EE +:10724000D6E1592ED6D71ED081AA03D0E0D700D0E0 +:10725000CED7400E556E12008050EF6E00D000D099 +:1072600000D000005E5227E035D825D08050EF6E68 +:10727000E9CF54F0EA508009556E00D05E521BE011 +:1072800029D819D08038ED12EA82E9CF54F0EACF3C +:1072900055F000D05E5202E01DD800D08050EF6E55 +:1072A00000005A2E15D05B4E1200000000005E5206 +:1072B00002E010D800D08038ED12EA825A2E09D0B0 +:1072C0005B4E1200000000005E52E8E003D8E6D7F3 +:1072D000EDD7F9D75E5000D000D00000E84E120084 +:1072E00000D00000F8D700EE00F00F0EEE6AEA6260 +:1072F000FDD71200040110511F0B010801E07DD0E1 +:107300000401145101E079D0060E0401115D2FE152 +:1073100004011351230A28E0010A13E0030A01E0E3 +:1073200024D00201020EF26F0001EF0505E1020117 +:10733000000EF36F7A0EF46F090E0201F76FF86B0F +:1073400014D00201020EF26F0001EF0505E1020107 +:10735000B70EF36F7A0EF46F0001EF0504E11D0E16 +:107360000201F76FF86B01D000D00001EE83040139 +:107370001051600BE842E842E842E842E842010866 +:1073800001E03BD0040111510B0A31E0080A21E071 +:10739000090A19E0080A09E00B0A05E0080A01E0F9 +:1073A0002CD02CD82AD02BD828D00201020EF26F74 +:1073B0000201F10EF36F000EF46F0001EE93020173 +:1073C000010EF76F1AD00201020EF26F13C4F1F032 +:1073D00014D00201020EF26F0201F20EF36F000EE2 +:1073E000F46F0001EE930201010EF76F06D0020167 +:1073F000020EF26F12C4F2F000D01200120012005E +:107400000001F36B1E0E716E0401400E096F040142 +:10741000200E0A6F040E0B6F0401880E086F040122 +:10742000600E0E6F040E0F6F0401400E0C6F120001 +:10743000D9CFE6FFE1CFD9FFE652FC0EDB50400882 +:1074400005E2400EF36EFC0EF3CFDBFFDF6AFC0EAD +:10745000DB50DF5C19E2DF50E76EFD0EDBCFE9FFAA +:10746000FE0EDBCFEAFFE750E926000EEA22EF50DE +:10747000E66EDF50EA6A600FE96E040EEA22E5521A +:10748000E750EF6EDF2AE3D7FC0EDBCF0DF4400EA2 +:1074900004010C1704010C7D880E04010C13E55245 +:1074A000E552E7CFD9FF1200D9CFE6FFE1CFD9FFF0 +:1074B0000001F36B040108BF39D0FC0EDBCF3FF0B5 +:1074C00004010951D8803F5403E2FC0E09C4DBFFDC +:1074D0000001F36BFC0EDB500001F35D1CE20001C8 +:1074E000F351EA6A200FE96E040EEA22EF50E66ECD +:1074F0000001F351E76EFD0EDBCFE9FFFE0EDBCF9F +:10750000EAFFE750E926000EEA22E552E750EF6E67 +:107510000001F32BDFD70401400E096F400E040178 +:1075200008170401087D880E040108130001F351B7 +:1075300000D0E552E7CFD9FF1200D8CFE4FFE0CF6B +:10754000E4FFE46EDACFE4FFE2CFDAFFE6520001B7 +:10755000E8A37CD0A150400B1DE0A050400B1AE0E6 +:10756000B4BE17D0A09CCD983550CF6E480E3424B1 +:10757000496E4A6A000E4A224A3404E24950FF0822 +:10758000000E4A5401E2CF2A480E3424CE6E9E905B +:107590009D80A19C9E50010B31E09D50010B2EE07F +:1075A0003550CF6E3450CE6E9E9036500AE1CD8865 +:1075B000B4AE04D09D90A19CA08C02D08B80362AC2 +:1075C0001DD03650080815E2B4AE0DD03DA003D052 +:1075D00037503B6E07D03DA203D037503C6E02D0EF +:1075E00037503A6E3D2A8B90366A9D90A19CA08CB4 +:1075F00005D037903742B4BE378E362AA150020BE1 +:1076000024E0A050020B21E03550B36E3450B26E2E +:10761000A192385004E18996382A8B8016D0090E41 +:10762000385C03E18986382A10D03850090804E212 +:10763000386AA0928B9009D0010E3914E8B089867F +:10764000E8A08996382A3990394262D09EA035D078 +:107650009E90FA0ECF6E380ECE6E8150100B10E158 +:107660000201FA51C45C0CE20C0E0201FC5D05E162 +:107670008A948A880001E78902D00201FC2B02D09B +:107680000201FC6B300E0001E71512E00201FEC2A0 +:1076900049F0FFC24AF0FE2B000EFF239B0ED8805C +:1076A0004954020E4A5404E28B700201FE6BFF6BD8 +:1076B0009E9C010EC26E9D8CC2829EAC29D09E9C67 +:1076C0000C0EBA5C21E10001E151D880C45401E202 +:1076D000BB6A0001E251C45C02E2E0C0BBFF815022 +:1076E000040B10E00201FB51C45C0CE20C0E020121 +:1076F000FD5D05E18A948A880001E78B02D00201D2 +:10770000FD2B02D00201FD6B050EC26E9D9CC28254 +:10771000A1B4FF00E552E5CFDAFFE550E5CFE0FF89 +:10772000E5CFD8FF10000201FC6B0201FD6B800E5B +:10773000CD6EFA0ECF6E380ECE6E9E909D80CD80AF +:107740009E9C9D9C260EC06E050EC26EC2821200CB +:107750009D90CD90C26A9E9C9D9C12000401105188 +:10776000600BE842E842E842E842E842000901E0F2 +:10777000A0D004011151080A01E18CD0010A01E1F5 +:1077800077D00F0A0AE0030A01E092D00201010E4D +:10779000F26F0001040EED6F8CD00201010EF26F4A +:1077A000040113050AE10201DC0EF36F790EF46F98 +:1077B000120E0201F76FF86B58D0020E0401135D30 +:1077C0001FE104011251F66EF76AD890F636F736CB +:1077D000D40EF6267A0EF7220900F5CFF3F20A004E +:1077E000F5CFF4F2020E0201F76AF325F66EF451BA +:1077F000F7220900F5CFF7F20A00F5CFF8F235D0FD +:10780000030E0401135D2FE1030E0401125D10E16C +:107810000201000EF36F000EF46FF3C2E9FFF4C231 +:10782000EAFFEF500201F76FF86B0001EE9341D0D1 +:1078300004011251F66EF76AD890F636F736D80E74 +:10784000F6267A0EF7220900F5CFF3F20A00F5CFFB +:10785000F4F2F3C2F6FFF4C2F7FF0800F55002019C +:10786000F76FF86B02D00201F26B0001EE8321D0BA +:107870000201010EF26F12C4EFF00401125104E193 +:107880000001050EED6F05D00001060EED6F00EC56 +:107890003AF00FD00201010EF26F0201EF0EF36F0A +:1078A000000EF46F0001EE930201010EF76F01D09C +:1078B00000D0120029C033F028C032F028502D0229 +:1078C000F4CF27F0F3CF26F029502E02F4CF29F081 +:1078D000F3CF28F02D02F3502726F4502822E86A2F +:1078E000292232502E02F3502726F4502822E86A2B +:1078F00029222EAE80EF3CF03250285E3350295AB8 +:1079000033AE000C2D50285E2E50295A000C28C092 +:1079100032F028502D02F4CF27F0F3CF26F0295073 +:107920002E02F4CF29F0F3CF28F02D02F3502726B2 +:10793000F4502822E86A292232502E02F3502726DA +:10794000F4502822E86A2922000C29C033F028C00C +:1079500032F027C031F027502C02F4CF25F0F3CFBE +:1079600024F028502D02F4CF27F0F3CF26F02C027C +:10797000F3502526F4502622E86A272231502D02A2 +:10798000F3502526F4502622E86A272229502C029B +:10799000F3502626F450272229502D02286AE86A3F +:1079A0002822F3502726F450282231502E02F3507B +:1079B0002626F4502722296AE86A282229223250F2 +:1079C0002E02F3502726F4502822E86A2922335049 +:1079D0002E02F3502826F4502922000C1201000236 +:1079E00000000008D804330002000102030209026B +:1079F0002900010102803209040000020300000096 +:107A0000092101000001221D00070581034000013A +:107A10000705010340000109022000010204803231 +:107A20000904000002FF0000000705810340000177 +:107A3000070501034000010403090434034D0069F4 +:107A400000630072006F006300680069007000202E +:107A50000054006500630068006E006F006C006FEA +:107A60000067007900200049006E0063002E004886 +:107A7000035000490043006B00690074002000328D +:107A80000020004D006900630072006F0063006F0A +:107A9000006E00740072006F006C006C0065007274 +:107AA000002000500072006F006700720061006DDE +:107AB000006D00650072000600FF0901A1011901B7 +:107AC0002940150026FF00750895408102190129FB +:107AD000409102C0EE79177A377A3B7A6F7AF47266 +:107AE000080E6D6E6DBAFED7686A110E696E0001E0 +:107AF000020EED6F12006D6A696A0001ED6B1200F3 +:107B00006850040B09E06950040B06E06D9269941B +:107B100068A402D06894FCD76850010B04E0695057 +:107B2000010B01E025D86850200B06E06950200BBE +:107B300003E070B07090689A030E0001ED5D01E201 +:107B400016D00001F66B040E0001F65D10E26850DD +:107B5000080B09E06950080B06E090EC36F00009CC +:107B600001E1689601D003D00001F62BECD712009A +:107B7000686A7B0E696E6E6A160E706E68A608D013 +:107B80006896000000000000000000000000F6D72A +:107B90006D9837EC38F00001EF6B0001030EED6FCC +:107BA0001200220EF66E5C0EF76E000EF86E0201E9 +:107BB0000900F550EC6F0900F550ED6F03E1EC673B +:107BC00001D03DD00900F550E76F0900F550E86F8E +:107BD0000900F550E96F09000900F550E96E090048 +:107BE000F550EA6E090009000900F550EA6F090036 +:107BF000F550EB6F09000900F6CFEEF2F7CFEFF288 +:107C0000F8CFF0F2E7C2F6FFE8C2F7FFE9C2F8FFEB +:107C10000201EA5302E1EB5307E00900F550EE6E72 +:107C2000EA07F8E2EB07F9D7EEC2F6FFEFC2F7FF7B +:107C3000F0C2F8FF0201EC07000EED5BBFD71200A7 +:107C400026502B02F3CF22F0F4CF23F02C02F35076 +:107C50002326000EF420246E26502D02F3502426F5 +:107C6000000EF420256E26502E02F35025262750B4 +:107C70002B02F3502326F4502422000E25222750F5 +:107C80002C02F3502426F450252227502D02F350C5 +:107C9000252628502B02F3502426F4502522285064 +:107CA0002C02F350252629502B02F35025261200D2 +:107CB000FF0EE3504C6EEF0E01D0F30EE76EE72E91 +:107CC0005FEF3EF00C0E4B6EE76AE72E65EF3EF07D +:107CD0004B2E64EF3EF04C2E5DEF3EF0120006D8C6 +:107CE00080EC3DF016EC11F0FBD71200140E6F6E15 +:107CF0000001ED6B0001EE6B0001EF6B15EC10F075 +:107D000070EC3DF0120013EE00F023EE00F0F86A84 +:107D1000219CD1EC3DF0AAEC3EF06FEC3EF0FBD79D +:107D20001200FF0EE3504C6E1B0E00D001D0200E4F +:107D3000E76EE72EFED74C2EFAD700D01200FF0ECA +:107D4000E350E84E1200000000D000D000D0E82E32 +:107D5000FAD7120012000005FFFFFFFFFFFFFFFF31 +:107D6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF23 +:107D7000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF13 +:107D8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF03 +:107D9000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3 +:107DA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE3 +:107DB000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD3 +:107DC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC3 +:107DD000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB3 +:107DE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA3 +:107DF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF93 +:107E0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF82 +:107E1000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF72 +:107E2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF62 +:107E3000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF52 +:107E4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF42 +:107E5000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF32 +:107E6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF22 +:107E7000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF12 +:107E8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF02 +:107E9000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2 +:107EA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE2 +:107EB000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD2 +:107EC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC2 +:107ED000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB2 +:107EE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA2 +:107EF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF92 +:107F0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF81 +:107F1000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF71 +:107F2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF61 +:107F3000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF51 +:107F4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF41 +:107F5000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF31 +:107F6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF21 +:107F7000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF11 +:107F8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF01 +:107F9000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1 +:107FA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE1 +:107FB000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD1 +:107FC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC1 +:107FD000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB1 +:107FE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA1 +:107FF000FFFFFFFFFFFFFFFFFFFFFFFFFFFF5555E5 +:0200000400F00A +:100000000001FA83FFFFFF01FFFFFFFFFFFFFFFF7C +:10001000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0 +:10002000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 +:10003000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD0 +:10004000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC0 +:10005000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB0 +:10006000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA0 +:10007000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF90 +:10008000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF80 +:10009000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF70 +:1000A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF60 +:1000B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF50 +:1000C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF40 +:1000D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF30 +:1000E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF20 +:1000F000234F6C486F737300000000000000000085 +:020000040030CA +:0E000000240E391E000181000FC00EA00F401B +:020000040020DA +:08000000FFFFFFFFFFFFFFFF00 +:00000001FF diff --git a/source/notes/pic-mcu/pickit2/pk2cmd-stuff/PK2V023200.hex.nrt b/source/notes/pic-mcu/pickit2/pk2cmd-stuff/PK2V023200.hex.nrt new file mode 160000 +Subproject 1511337ad63e4166069adccc25743533edb36bb diff --git a/source/notes/pic-mcu/pickit2/pk2cmd-stuff/hexdisasm.py b/source/notes/pic-mcu/pickit2/pk2cmd-stuff/hexdisasm.py new file mode 100644 index 0000000..0c86592 --- /dev/null +++ b/source/notes/pic-mcu/pickit2/pk2cmd-stuff/hexdisasm.py @@ -0,0 +1,71 @@ +import pic24 +import pic18 +import pic16 +import sys + +arch = "pic18" + +hexfile = '../pk2cmd/pk2cmd/PK2V023200.hex' + +if len(sys.argv) > 1: + hexfile = sys.argv[1] + + if len(sys.argv) > 2: + arch = sys.argv[2] + +if arch == "pic24": + arch = pic24 +elif arch == "pic18": + arch = pic18 +elif arch == "pic16": + arch = pic16 +else: + raise Exception("Invalid arch " + arch) + +lines = open(hexfile).readlines() + +def read_hex(lines): + regions = { 0: [0] * 0x10000 } + curr_region = regions[0] + + for line in lines: + if not line.startswith(':'): + continue +# raise Exception("invalid hex line, needs to start with a ':', but was: " + line) + bytecount = int(line[1:3], 16) + addr = int(line[3:7], 16) + rec_type = int(line[7:9], 16) + data_end = bytecount * 2 + 9 + data = line[9:data_end] + # ignoring checksum because lazy + + if rec_type == 4: + ext_linear_addr = int(data, 16) + if ext_linear_addr not in regions: + regions[ext_linear_addr] = [0] * 0x10000 + + curr_region = regions[ext_linear_addr] + elif rec_type == 0: + for i in range(bytecount): + curr_region[addr + i] = int(data[i*2:i*2 + 2], 16) + elif rec_type == 1: + print("Read HEX file") + return regions + else: + raise Exception("Unsupported record type: " + str(rec_type)) + + +memory_regions = read_hex(lines) + +i = 0 + +coderegion = memory_regions[0] + +while i < len(coderegion): + (i, instr) = arch.disassemble(coderegion, i) + if "Unknown instr" in instr: + print(instr) + elif 'op' not in instr: + print(instr['mnemonic']) + else: + print("{} {}".format(instr['mnemonic'], instr['op'])) diff --git a/source/notes/pic-mcu/pickit2/pk2cmd-stuff/pic16.py b/source/notes/pic-mcu/pickit2/pk2cmd-stuff/pic16.py new file mode 100644 index 0000000..e543cda --- /dev/null +++ b/source/notes/pic-mcu/pickit2/pk2cmd-stuff/pic16.py @@ -0,0 +1,154 @@ +def render(instr): + if 'op' in instr: + return "{} {}".format(instr['mnemonic'], instr['op']) + else: + return instr['mnemonic'] + +def disassemble(blob, offset): + instr = {} + instr['length'] = 1 + instrbytes = blob[offset:offset + 2] +# instrbytes.reverse() + print("Decoding {}{}...".format(hex(instrbytes[0])[2:], hex(instrbytes[1])[2:])) + + if instrbytes[0] == 0x00: + print(hex(instrbytes[1])) + # there's a few instructions here... + if instrbytes[1] == 0xff: + instr['mnemonic'] = 'reset' + else: + instr['mnemonic'] = [ + 'nop', + 'BAD', + 'BAD', + 'sleep', + 'clrwdt', + 'push', + 'pop', + 'daw', + 'tblrd*', + 'tblrd*+', + 'tblrd*-', + 'tblrd+*', + 'tblwr*', + 'tblwr*+', + 'tblwr*-', + 'tblwr+*', + 'retfie', + 'retfie fast', + 'return', + 'return fast', + 'callw*'][instrbytes[1]] + if instrbytes[0] == 0x01: + if instrbytes[1] > 0xf: + instr['mnemonic'] = 'BAD' + else: + instr['mnemonic'] = 'movlb' + instr['op'] = "#" + str(instrbytes[1]) + elif instrbytes[0] == 0x02 or instrbytes[0] == 0x03: + instr['mnemonic'] = 'mulwf' + instr['op'] = 'TODO' + elif instrbytes[0] == 0x04 or instrbytes[0] == 0x05 or instrbytes[0] == 0x06 or instrbytes[0] == 0x07: + instr['mnemonic'] = 'decf' + instr['op'] = 'TODO' + elif instrbytes[0] == 0x08: + instr['mnemonic'] = 'sublw' + instr['op'] = '#' + hex(instrbytes[1]) + elif instrbytes[0] == 0x09: + instr['mnemonic'] = 'iorlw' + instr['op'] = '#' + hex(instrbytes[1]) + elif instrbytes[0] == 0x0a: + instr['mnemonic'] = 'xorlw' + instr['op'] = '#' + hex(instrbytes[1]) + elif instrbytes[0] == 0x0b: + instr['mnemonic'] = 'andlw' + instr['op'] = '#' + hex(instrbytes[1]) + elif instrbytes[0] == 0x0c: + instr['mnemonic'] = 'retlw' + instr['op'] = '#' + hex(instrbytes[1]) + elif instrbytes[0] == 0x0d: + instr['mnemonic'] = 'mullw' + instr['op'] = '#' + hex(instrbytes[1]) + elif instrbytes[0] == 0x0e: + instr['mnemonic'] = 'movlw' + instr['op'] = '#' + hex(instrbytes[1]) + elif instrbytes[0] == 0x0f: + instr['mnemonic'] = 'addlw' + instr['op'] = '#' + hex(instrbytes[1]) + elif instrbytes[0] >= 0x20 and instrbytes[0] <= 0x5f: + mnemonicSel = instrbytes[0] >> 2 + instr['mnemonic'] = [ + 'iorwf', + 'andwf', + 'xorwf', + 'comf', + 'addwfc', + 'addwf', + 'incf', + 'decfsz', + 'rrcf', + 'rlcf', + 'swapf', + 'incfsz', + 'rrncf', + 'rlncf', + 'infsnz', + 'dcfsnz', + 'movf', + 'subwfb', + 'subwfb', + 'subwf' + ][mnemonicSel] + instr['op'] = 'TODO' + elif instrbytes[0] >= 0x60 and instrbytes[0] < 0x70: + mnemonicSel = instrbytes[0] >> 1 + instr['mnemonic'] = [ + 'cpfslt', + 'cpfseq', + 'cpfsgt', + 'tstfsz', + 'setf', + 'clrf', + 'negf', + 'movwf' + ][mnemonicSel] + instr['op'] = 'TODO' + elif instrbytes[0] >= 0x70 and instrbytes[0] < 0xc0: + mnemonicSel = instrbytes[0] >> 4 + instr['mnemonic'] = [ + 'BAD', 'BAD', 'BAD', 'BAD', 'BAD', 'BAD', 'BAD', + 'BTG', + 'BSF', + 'BCF', + 'BTFSS', + 'BTFSC' + ][mnemonicSel] + instr['op'] = 'TODO' + elif instrbytes[0] >= 0xc0 and instrbytes[0] < 0xd0: + instr['mnemonic'] = 'MOVFF' + instr['op'] = 'TODO' + elif instrbytes[0] >= 0xd0 and instrbytes[0] < 0xd8: + instr['mnemonic'] = 'BRA' + instr['op'] = 'TODO' + elif instrbytes[0] >= 0xd8 and instrbytes[0] < 0xe0: + instr['mnemonic'] = 'RCALL' + instr['op'] = 'TODO' + elif instrbytes[0] >= 0xf0 and instrbytes[0] <= 0xff: + instr['mnemonic'] = 'MOVFF' + instr['op'] = 'TODO' + elif instrbytes[0] == 0xec or instrbytes[0] == 0xed: + instr['mnemonic'] = 'CALL' + instr['op'] = 'TODO' + instr['length'] = 2 + elif instrbytes[0] == 0xee: + instr['mnemonic'] = 'LFSR' + instr['op'] = 'TODO' + instr['length'] = 2 + elif instrbytes[0] == 0xef: + instr['mnemonic'] = 'GOTO' + instr['op'] = 'TODO' + instr['length'] = 2 + else: + instr['mnemonic'] = 'TODO' + + return (offset + instr['length'] * 2, instr) diff --git a/source/notes/pic-mcu/pickit2/pk2cmd-stuff/pic16.pyc b/source/notes/pic-mcu/pickit2/pk2cmd-stuff/pic16.pyc Binary files differnew file mode 100644 index 0000000..285d3ba --- /dev/null +++ b/source/notes/pic-mcu/pickit2/pk2cmd-stuff/pic16.pyc diff --git a/source/notes/pic-mcu/pickit2/pk2cmd-stuff/pic18.py b/source/notes/pic-mcu/pickit2/pk2cmd-stuff/pic18.py new file mode 100644 index 0000000..15c2791 --- /dev/null +++ b/source/notes/pic-mcu/pickit2/pk2cmd-stuff/pic18.py @@ -0,0 +1,526 @@ +def render(instr): + if 'ops' in instr: + optexts = [] + for op in instr['ops']: + if isinstance(op, dict) and 'type' in op: + optext = op['text'] if 'text' in op else hex(op['value']) + optexts.append(optext) + else: + optexts.append(str(op)) + return "{} {}".format(instr['mnemonic'], ', '.join(optexts)) + else: + return instr['mnemonic'] + +def sext(number, bit): + mask = 1 << bit + if number & mask > 0: + return - ((~number & (mask - 1)) + 1) + else: + return number + +NAMES = { + 0xF60: '_ZERO_', + 0xF61: '_ZERO_', + 0xF62: 'SPPDATA', + 0xF63: 'SPPCFG', + 0xF64: 'SPPEPS', + 0xF65: 'SPPCON', + 0xF66: 'UFRML', + 0xF67: 'UFRMH', + 0xF68: 'UIR', + 0xF69: 'UIE', + 0xF6A: 'UEIR', + 0xF6B: 'UEIE', + 0xF6C: 'USTAT', + 0xF6D: 'UCON', + 0xF6E: 'UADDR', + 0xF6F: 'UCFG', + 0xF70: 'UEP0', + 0xF71: 'UEP1', + 0xF72: 'UEP2', + 0xF73: 'UEP3', + 0xF74: 'UEP4', + 0xF75: 'UEP5', + 0xF76: 'UEP6', + 0xF77: 'UEP7', + 0xF78: 'UEP8', + 0xF79: 'UEP9', + 0xF7A: 'UEP10', + 0xF7B: 'UEP11', + 0xF7C: 'UEP12', + 0xF7D: 'UEP13', + 0xF7E: 'UEP14', + 0xF7F: 'UEP15', + 0xF80: 'PORTA', + 0xF81: 'PORTB', + 0xF82: 'PORTC', + 0xF83: 'PORTD', + 0xF84: 'PORTE', + 0xF85: '_ZERO_', + 0xF86: '_ZERO_', + 0xF87: '_ZERO_', + 0xF88: '_ZERO_', + 0xF89: 'LATA', + 0xF8A: 'LATB', + 0xF8B: 'LATC', + 0xF8C: 'LATD', + 0xF8D: 'LATE', + 0xF8E: '_ZERO_', + 0xF8F: '_ZERO_', + 0xF90: '_ZERO_', + 0xF91: '_ZERO_', + 0xF92: 'TRISA', + 0xF93: 'TRISB', + 0xF94: 'TRISC', + 0xF95: 'TRISD', + 0xF96: 'TRISE', + 0xF97: '_ZERO_', + 0xF98: '_ZERO_', + 0xF99: '_ZERO_', + 0xF9A: '_ZERO_', + 0xF9B: 'OSCTUNE', + 0xF9C: '_ZERO_', + 0xF9D: 'PIE1', + 0xF9E: 'PIR1', + 0xF9F: 'IPR1', + 0xFA0: 'PIE2', + 0xFA1: 'PIR2', + 0xFA2: 'IPR2', + 0xFA3: '_ZERO_', + 0xFA4: '_ZERO_', + 0xFA5: '_ZERO_', + 0xFA6: 'EECON1', + 0xFA7: 'EECON2', + 0xFA8: 'EEDATA', + 0xFA9: 'EEADR', + 0xFAA: '_ZERO_', + 0xFAB: 'RCSTA', + 0xFAC: 'TXSTA', + 0xFAD: 'TXREG', + 0xFAE: 'RCREG', + 0xFAF: 'SPBRG', + 0xFB0: 'SPBRGH', + 0xFB1: 'T3CON', + 0xFB2: 'TMR3L', + 0xFB3: 'TMR3H', + 0xFB4: 'CMCON', + 0xFB5: 'CVRCON', + 0xFB6: 'ECCP1AS', + 0xFB7: 'ECCP1DEL', + 0xFB8: 'BAUDCON', + 0xFB9: '_ZERO_', + 0xFBA: 'CCP2CON', + 0xFBB: 'CCPR2L', + 0xFBC: 'CCPR2H', + 0xFBD: 'CCP1CON', + 0xFBE: 'CCPR1L', + 0xFBF: 'CCPR1H', + 0xFC0: 'ADCON2', + 0xFC1: 'ADCON1', + 0xFC2: 'ADCON0', + 0xFC3: 'ADRESL', + 0xFC4: 'ADRESH', + 0xFC5: 'SSPCON2', + 0xFC6: 'SSPCON1', + 0xFC7: 'SSPSTAT', + 0xFC8: 'SSPADD', + 0xFC9: 'SSPBUF', + 0xFCA: 'T2CON', + 0xFCB: 'PR2', + 0xFCC: 'TMR2', + 0xFCD: 'T1CON', + 0xFCE: 'TMR1L', + 0xFCF: 'TMR1H', + 0xFD0: 'RCON', + 0xFD1: 'WDTCON', + 0xFD2: 'HLVDCON', + 0xFD3: 'OSCCON', + 0xFD4: '_ZERO_', + 0xFD5: 'T0CON', + 0xFD6: 'TMR0L', + 0xFD7: 'TMR0H', + 0xFD8: 'STATUS', + 0xFD9: 'FSR2L', + 0xFDA: 'FSR2H', + 0xFDB: 'PLUSW2', + 0xFDC: 'PREINC2', + 0xFDD: 'POSTDEC2', + 0xFDE: 'POSTINC2', + 0xFDF: 'INDF2', + 0xFE0: 'BSR', + 0xFE1: 'FSR1L', + 0xFE2: 'FSR1H', + 0xFE3: 'PLUSW1', + 0xFE4: 'PREINC1', + 0xFE5: 'POSTDEC1', + 0xFE6: 'POSTINC1', + 0xFE7: 'INDF1', + 0xFE8: 'WREG', + 0xFE9: 'FSR0L', + 0xFEA: 'FSR0H', + 0xFEB: 'PLUSW0', + 0xFEC: 'PREINC0', + 0xFED: 'POSTDEC0', + 0xFEE: 'POSTINC0', + 0xFEF: 'INDF0', + 0xFF0: 'INTCON3', + 0xFF1: 'INTCON2', + 0xFF2: 'INTCON', + 0xFF3: 'PRODL', + 0xFF4: 'PRODH', + 0xFF5: 'TABLAT', + 0xFF6: 'TBLPTRL', + 0xFF7: 'TBLPTRH', + 0xFF8: 'TBLPTRU', + 0xFF9: 'PCL', + 0xFFA: 'PCLATH', + 0xFFB: 'PCLATU', + 0xFFC: 'STKPTR', + 0xFFD: 'TOSL', + 0xFFE: 'TOSH', + 0xFFF: 'TOSU' +} + +def reg_name(number): + if number in NAMES: + return NAMES[number] + else: + return None + +def disassemble(blob, offset): + instr = {} + instr['length'] = 1 + instrbytes = blob[offset:offset + 2] + instrbytes.reverse() +# instrbytes.reverse() +# print("Decoding {:02x}{:02x}...".format(instrbytes[0], instrbytes[1])) + + if instrbytes[0] == 0x00: + # there's a few instructions here... + if instrbytes[1] == 0xff: + instr['mnemonic'] = 'reset' + else: + mnemonicmap = [ + 'nop', + 'BAD', + 'BAD', + 'sleep', + 'clrwdt', + 'push', + 'pop', + 'daw', + 'tblrd*', + 'tblrd*+', + 'tblrd*-', + 'tblrd+*', + 'tblwr*', + 'tblwr*+', + 'tblwr*-', + 'tblwr+*', + 'retfie', + 'retfie fast', + 'return', + 'return fast', + 'callw*'] + + if instrbytes[1] > len(mnemonicmap): + instr['mnemonic'] = 'BAD' + else: + instr['mnemonic'] = mnemonicmap[instrbytes[1]] + elif instrbytes[0] == 0x01: + if instrbytes[1] > 0xf: + instr['mnemonic'] = 'BAD' + else: + instr['mnemonic'] = 'movlb' + instr['ops'] = ["#" + str(instrbytes[1])] + elif instrbytes[0] == 0x02 or instrbytes[0] == 0x03: + instr['mnemonic'] = 'mulwf' + instr['ops'] = ['TODO'] + elif instrbytes[0] >= 0x04 and instrbytes[0] < 0x08: + instr['mnemonic'] = 'decf' + d = (instrbytes[0] >> 1) & 1 + a = instrbytes[0] & 1 + f = instrbytes[1] + if a == 0: + # "Access Bank" + f_physical = f if f < 0x60 else 0xf00 + f + source = { + 'type': 'register', + 'value': f_physical + } + else: + source = { + 'type': 'banked-register', + 'value': f + } + + if d == 0: + dest = { 'type': 'register', + 'value': 'W' } + else: + dest = source + + if a == 0: + instr['ops'] = [ source, dest ] + else: + instr['ops'] = [ source, dest, 'banked' ] + + elif instrbytes[0] >= 0x08 and instrbytes[0] < 0x10: + code = instrbytes[0] & 0x7 + + instr['mnemonic'] = [ + 'sublw', + 'iorlw', + 'xorlw', + 'andlw', + 'retlw', + 'mullw', + 'movlw', + 'addlw' + ][code] + instr['ops'] = ['#' + hex(instrbytes[1])] + elif instrbytes[0] >= 0x10 and instrbytes[0] < 0x20: + code = (instrbytes[0] >> 2) & 0x3 + instr['mnemonic'] = [ + 'iorwf', + 'andwf', + 'xorwf', + 'comf' + ][code] + d = (instrbytes[0] >> 1) & 1 + a = instrbytes[0] & 1 + f = instrbytes[1] + + if a == 0: + # "Access Bank" + f_physical = f if f < 0x60 else 0xf00 + f + source = { + 'type': 'register', + 'value': f_physical + } + else: + source = { + 'type': 'banked-register', + 'value': f + } + + if d == 0: + dest = { 'type': 'register', + 'value': 'W' } + else: + dest = source + + if a == 0: + instr['ops'] = [ source, dest ] + else: + instr['ops'] = [ source, dest, 'banked' ] + + elif instrbytes[0] >= 0x20 and instrbytes[0] < 0x60: + mnemonicSel = instrbytes[0] >> 2 + instr['mnemonic'] = [ + 'mulwf (TODO)', #000000 + 'decf', #000001 + 'BAD', 'BAD', #00001X + 'iorwf', #000100 + 'andwf', #000101 + 'xorwf', #000110 + 'comf', #000111 + 'addwfc', #001000 + 'addwf', #001001 + 'incf', #001010 + 'decfsz', #001011 + 'rrcf', #001100 + 'rlcf', #001101 + 'swapf', #001110 + 'incfsz', #001111 + 'rrncf', #010000 + 'rlncf', #010001 + 'infsnz', #010010 + 'dcfsnz', #010011 + 'movf', #010100 + 'subwfb', #010101 + 'subwfb', #000000 + 'subwf' #000000 + ][mnemonicSel] + d = (instrbytes[0] >> 1) & 1 + a = instrbytes[0] & 1 + f = instrbytes[1] + + if a == 0: + # "Access Bank" + f_physical = f if f < 0x60 else 0xf00 + f + source = { + 'type': 'register', + 'value': f_physical + } + else: + source = { + 'type': 'banked-register', + 'value': f + } + + if d == 0: + dest = { 'type': 'register', + 'value': 'W' } + else: + dest = source + + if a == 0: + instr['ops'] = [ source, dest ] + else: + instr['ops'] = [ source, dest, 'banked' ] + + elif instrbytes[0] >= 0x60 and instrbytes[0] < 0x70: + mnemonicSel = (instrbytes[0] >> 1) & 0x7 + instr['mnemonic'] = [ + 'cpfslt', + 'cpfseq', + 'cpfsgt', + 'tstfsz', + 'setf', + 'clrf', + 'negf', + 'movwf' + ][mnemonicSel] + a = instrbytes[0] & 1 + f = instrbytes[1] + if a == 0: + # "Access Bank" + f_physical = f if f < 0x60 else 0xf00 + f + instr['ops'] = [ + { 'type': 'register', + 'value': f_physical } + ] + else: + instr['ops'] = [ + { 'type': 'banked-register', + 'value': f }, + "banked" + ] + elif instrbytes[0] >= 0x70 and instrbytes[0] < 0xc0: + mnemonicSel = instrbytes[0] >> 4 + instr['mnemonic'] = [ + 'BAD', 'BAD', 'BAD', 'BAD', 'BAD', 'BAD', 'BAD', + 'btg', + 'bsf', + 'bcf', + 'btfss', + 'btfsc' + ][mnemonicSel] + bit = (instrbytes[0] >> 1) & 0x7 + a = instrbytes[0] & 1 + f = instrbytes[1] + if a == 0: + # "Access Bank" + f_physical = f if f < 0x60 else 0xf00 + f + instr['ops'] = [ + { 'type': 'register', + 'value': f_physical }, + bit + ] + else: + instr['ops'] = [ + { 'type': 'banked-register', + 'value': f }, + bit, + "banked" + ] + elif instrbytes[0] >= 0xc0 and instrbytes[0] < 0xd0: + instr['mnemonic'] = 'movff' + instr['length'] = 2 + fs = ((instrbytes[0] & 0xf) << 8) | instrbytes[1] + followingbytes = blob[offset + 2:offset + 4] + followingbytes.reverse() + if followingbytes[0] < 0xf0: + instr['mnemonic'] = 'movff (BAD)' + else: + fd = ((followingbytes[0] & 0xf) << 8) | followingbytes[1] + instr['ops'] = [ + { 'type': 'register', + 'value': fs }, + { 'type': 'register', + 'value': fd } + ] + elif instrbytes[0] >= 0xd0 and instrbytes[0] < 0xd8: + instr['mnemonic'] = 'bra' + n = ((instrbytes[0] & 0x7) << 8) | instrbytes[1] + n = sext(n, 10) + instr['ops'] = [{ + 'type': 'relpostdest', + 'value': n << 1 + }] + elif instrbytes[0] >= 0xd8 and instrbytes[0] < 0xe0: + instr['mnemonic'] = 'rcall' + n = ((instrbytes[0] & 0x7) << 8) | instrbytes[1] + instr['ops'] = [{ + 'type': 'relpostdest', + 'value': n << 1 + }] + elif instrbytes[0] >= 0xe0 and instrbytes[0] <= 0xe8: + code = instrbytes[0] & 0x7 + instr['mnemonic'] = [ + 'bz', + 'bnz', + 'bc', + 'bnc', + 'bov', + 'bnov', + 'bn', + 'bnn' + ][code] + n = instrbytes[1] + n = sext(n, 7) + instr['ops'] = [{ + 'type': 'relpostdest', + 'value': n << 1 + }] + elif instrbytes[0] >= 0xf0 and instrbytes[0] <= 0xff: + instr['mnemonic'] = 'BAD (misdecode)' + elif instrbytes[0] == 0xea: + instr['mnemonic'] = 'push' + instr['ops'] = [instrbytes[1]] + elif instrbytes[0] == 0xec or instrbytes[0] == 0xed: + instr['mnemonic'] = 'call' + s = instrbytes[0] & 1 + instr['length'] = 2 + lowbits = instrbytes[1] + followingbytes = blob[offset + 2:offset + 4] + followingbytes.reverse() + if followingbytes[0] < 0xf0: + instr['mnemonic'] = 'CALL (BAD)' + else: + k = (((followingbytes[0] & 0x0f) << 16) | (followingbytes[1] << 8) | lowbits) + instr['ops'] = [{ + 'type': 'absolutedest', + 'value': k << 1 + }, str(s)] + elif instrbytes[0] == 0xee: + instr['mnemonic'] = 'lfsr' + instr['length'] = 2 + f = (instrbytes[1] >> 4) & 3 + followingbytes = blob[offset + 2:offset + 4] + followingbytes.reverse() + if followingbytes[0] < 0xf0: + instr['mnemonic'] = 'lsfr (BAD)' + else: + k = ((instrbytes[1] & 0xf) << 8) | followingbytes[1] + instr['ops'] = [str(f), hex(k)] + elif instrbytes[0] == 0xef: + instr['mnemonic'] = 'goto' + instr['length'] = 2 + lowbits = instrbytes[1] + followingbytes = blob[offset + 2:offset + 4] + followingbytes.reverse() + if followingbytes[0] < 0xf0: + instr['mnemonic'] = 'GOTO (BAD)' + else: + k = ((followingbytes[0] & 0x0f) << 16) | (followingbytes[1] << 8) | lowbits + instr['ops'] = [{ + 'type': 'absolutedest', + 'value': k << 1 + }] + + else: + instr['mnemonic'] = 'TODO' + + return (offset + instr['length'] * 2, instr) diff --git a/source/notes/pic-mcu/pickit2/pk2cmd-stuff/pic18.pyc b/source/notes/pic-mcu/pickit2/pk2cmd-stuff/pic18.pyc Binary files differnew file mode 100644 index 0000000..0a12e73 --- /dev/null +++ b/source/notes/pic-mcu/pickit2/pk2cmd-stuff/pic18.pyc diff --git a/source/notes/pic-mcu/pickit2/pk2cmd-stuff/pic24.py b/source/notes/pic-mcu/pickit2/pk2cmd-stuff/pic24.py new file mode 100644 index 0000000..e0adef0 --- /dev/null +++ b/source/notes/pic-mcu/pickit2/pk2cmd-stuff/pic24.py @@ -0,0 +1,216 @@ +def render(instruction): + return "{} {}".format(instruction['mnemonic'], instruction['op']) + + +def Table_5_12(nibble): + return "Table 5.12 TODO" + +def Table_5_11(nibble): + return "Table 5.11 TODO" + +def Table_5_10(nibble): + return "Table 5.10 TODO" + +def YDataPrefetchDest_5_9(nibble): + return "Table 5.9 TODO" + +def YDataPrefetchOperation_5_8(nibble): + return "Table 5.8 TODO" + +def XDataPrefetchDest_5_7(nibble): + return "Table 5.7 TODO" + +def XDataPrefetchOperation_5_6(nibble): + return "Table 5.6 TODO" + +def readWd_5_5(octet): + return [ + "Wd", + "[Wd]", + "[Wd--]", + "[Wd++]", + "[--Wd]", + "[++Wd]", + "[Wd + Wb]", + "[Wd + Wb]" + ][octet] + +def readWs_5_4(octet): + return [ + "Ws", + "[Ws]", + "[Ws--]", + "[Ws++]", + "[--Ws]", + "[++Ws]", + "[Ws + Wb]", + "[Ws + Wb]" + ][octet] + +def readWd_5_3(octet): + return [ + "Wd", + "[Wd]", + "[Wd--]", + "[Wd++]", + "[--Wd]", + "[++Wd]", + "ERR", + "ERR" + ][octet] + +def readWs_5_2(octet): + return [ + "Ws", + "[Ws]", + "[Ws--]", + "[Ws++]", + "[--Ws]", + "[++Ws]", + "ERR", + "ERR" + ][octet] + +def disassemble(blob, offset): +# print ("Disassembling " + str(blob)) + instrbytes = blob[offset:offset + 3] +# instrbytes.reverse() + print("Disassembling {} {} {}".format(hex(instrbytes[0]), hex(instrbytes[1]), hex(instrbytes[2]))) + instr = {} + instr['op'] = '' + size = 1 + + if instrbytes[2] == 0x0: + instr['mnemonic'] = 'nop' + if instrbytes[2] == 0x1: + instr['mnemonic'] = 'br*' + if instrbytes[2] == 0x2: + instr['mnemonic'] = 'call' + if instrbytes[2] == 0x3: + instr['mnemonic'] = '-' + if instrbytes[2] == 0x4: + instr['mnemonic'] = 'goto' + size = 2 + w2 = blob[offset + 3:offset + 6] +# w2.reverse() + n_hi = ((instrbytes[1] << 8) + instrbytes[0]) + if w2[0] != 0 or w2[1] != 0: + instr['mnemonic'] = 'goto [BAD]' + n_lo = w2[0] + n = n_hi + (n_lo << 16) + instr["op"] = hex(n) + if instrbytes[2] == 0x5: + instr['mnemonic'] = 'retlw' + if instrbytes[2] == 0x6: + instr['mnemonic'] = 'retfie' + if instrbytes[2] == 0x7: + instr['mnemonic'] = 'rcall' + if instrbytes[2] == 0x8: + instr['mnemonic'] = 'do' + if instrbytes[2] == 0x9: + instr['mnemonic'] = 'repeat' + if instrbytes[2] == 0xa: + instr['mnemonic'] = '-' + if instrbytes[2] == 0xb: + instr['mnemonic'] = '-' + if instrbytes[2] == 0xc: + instr['mnemonic'] = 'bra(oa)' + instr['mnemonic'] += " (dsPIC3XF only)" + if instrbytes[2] == 0xd: + instr['mnemonic'] = 'bra(ob)' + instr['mnemonic'] += " (dsPIC3XF only)" + if instrbytes[2] == 0xe: + instr['mnemonic'] = 'bra(sa)' + instr['mnemonic'] += " (dsPIC3XF only)" + if instrbytes[2] == 0xf: + instr['mnemonic'] = 'bra(sb)' + instr['mnemonic'] += " (dsPIC3XF only)" + if instrbytes[2] >= 0x10 and instrbytes[2] < 0x18: + instr['mnemonic'] = 'subr' + if instrbytes[2] >= 0x18 and instrbytes[2] < 0x20: + instr['mnemonic'] = 'subbr' + if instrbytes[2] >= 0x20 and instrbytes[2] < 0x30: + instr['mnemonic'] = 'mov' + word = instrbytes[0] | (instrbytes[1] << 8) | (instrbytes[2] << 16) + imm = (word & 0x0ffff0) >> 4 + reg = word & 0xf + instr['op'] = "#" + hex(imm) + ", W" + str(reg) + + if instrbytes[2] >= 0x80 and instrbytes[2] < 0x90: + instr['mnemonic'] = 'mov' + word = instrbytes[0] | (instrbytes[1] << 8) | (instrbytes[2] << 16) + f = (word & 0x07fff0) >> 4 + reg = word & 0xf + + if instrbytes[2] < 0x88: + instr['op'] = "[" + hex(f) + "], W" + str(reg) + else: + instr['op'] = "W" + str(reg) + ", [" + hex(f) + "]" + + if instrbytes[2] >= 0xc0 and instrbytes[2] < 0xd0: + instr['mnemonic'] = "(dsPIC3XF only)" + + if instrbytes[2] == 0xB4 and (instrbytes[1] & 0x80) == 0x00: + instr['mnemonic'] = "ADD" + B = instrbytes[1] & 0x40 + D = instrbytes[1] & 0x20 + f = ((instrbytes[1] & 0x1f) << 8) + instrbytes[0] + + if B: + instr['mnemonic'] += '.B' + + instr['op'] = "RAM:" + hex(f) + + if D: + instr['op'] += ', W0' + if instrbytes[2] == 0xaa: + instr['mnemonic'] = "BTG" + # TODO: not clear what is .B mode + bit4 = ((instrbytes[1] >> 4) & 0x0e) + (instrbytes[0] & 0x01) + f = ((instrbytes[1] & 0x1f) << 7) + (instrbytes[0] >> 1) + instr['op'] = "{}, #{}".format(hex(f), hex(bit4)) + if instrbytes[2] == 0xba: + instr['mnemonic'] = "TBLRD" + if (instrbytes[1] & 0x80) != 0: + instr['mnemonic'] += 'H' + else: + instr['mnemonic'] += 'L' + + if (instrbytes[1] & 0x40) != 0: + instr['mnemonic'] += '.B' + + s = (instrbytes[0] & 0x0f) + p = (instrbytes[0] >> 4) & 0x07 + d = ((instrbytes[0] >> 7) & 0x01) + ((instrbytes[1] << 1) & 0xf) + q = (instrbytes[1] & 0x38) >> 3 + + srcOp = readWs_5_2(p).replace("Ws", "W" + str(s)) + dstOp = readWd_5_3(q).replace("Wd", "W" + str(d)) + + instr['op'] = "{}, {}".format(srcOp, dstOp) + if instrbytes[2] == 0xbb: + instr['mnemonic'] = "TBLWT" + if (instrbytes[1] & 0x80) != 0: + instr['mnemonic'] += 'H' + else: + instr['mnemonic'] += 'L' + + if (instrbytes[1] & 0x40) != 0: + instr['mnemonic'] += '.B' + + s = (instrbytes[0] & 0x0f) + p = (instrbytes[0] >> 4) & 0x07 + d = ((instrbytes[0] >> 7) & 0x01) + ((instrbytes[1] << 1) & 0xf) + q = (instrbytes[1] & 0x38) >> 3 + + srcOp = readWs_5_2(p).replace("Ws", "W" + str(s)) + dstOp = readWd_5_3(q).replace("Wd", "W" + str(d)) + + instr['op'] = "{}, {}".format(srcOp, dstOp) + + if 'mnemonic' not in instr: + instr = instrbytes[0] | (instrbytes[1] << 8) | (instrbytes[2] << 16) + return (offset + 3, "Unknown instruction: " + hex(instr)) + + return (offset + 3 * size, instr) + diff --git a/source/notes/pic-mcu/pickit2/pk2cmd-stuff/pic24.pyc b/source/notes/pic-mcu/pickit2/pk2cmd-stuff/pic24.pyc Binary files differnew file mode 100644 index 0000000..c9a39af --- /dev/null +++ b/source/notes/pic-mcu/pickit2/pk2cmd-stuff/pic24.pyc diff --git a/source/notes/pic-mcu/pickit2/pk2cmd-stuff/pk2_firmware_notes.md b/source/notes/pic-mcu/pickit2/pk2cmd-stuff/pk2_firmware_notes.md new file mode 100644 index 0000000..0d3535b --- /dev/null +++ b/source/notes/pic-mcu/pickit2/pk2cmd-stuff/pk2_firmware_notes.md @@ -0,0 +1,222 @@ +usb handler? + +walking through from the entry point for the script interpreter proves to be difficult. can't even find usb handler. alternative idea: look for instructions and registers that would be used by the usb handler, try to follow from there to the command handler, and from there maybe get to the script interpreter + +found a function that appears to handle usb status bits but no clear indication of reading packets.. next thought is to disassemble all of the firmware and look for what might be a dispatch table for script commands + +three jump tables found: +0x2334? +0x3b0a? +0x429e? + +there also seems to be some bit bang style logic around 0x525c, through lata 3 and somethig to do with trisa 4 + +the last two jump tables seem related, not sure how exactly. + +alternate approach again, maybe it's easier to find the implementation of some script commands? + +decent targets: SCMD_BUSY_LED_OFF, SCMD_BUSY_LED_ON aka 0xF4, 0xF5 +busy LED is pin 4 in portb, searching PORTB yields a lot of btfss and btfsc, but searching LATB is entirely bsf and bcf. further refining to `latb, 4` yields 12 possibly interesting instructions +because these would be the result of command dispatch, and are adjacent, they are probably close together + +0x26d0 (set) +0x26d4 (clear) + +0x3b60 (clear) +0x3b64 (set) + +further reading, noticed some interesting constants before the first jump table: +000022ae: xorlw #0x42 +000022b0: bz 0x2300 (ip+2+0x4e) +000022b2: xorlw #0x34 +000022b4: bz 0x22c0 (ip+2+0xa) +000022b6: xorlw #0x2c +000022b8: bz 0x22bc (ip+2+0x2) +000022ba: bra 0x2306 (ip+2+0x4a) + +immediately eyecatching on account of 0x42 being FWCMD_ENTER_BOOTLOADER +the following xorlw #0x34 functionally results in W == W_original ^ 0x42 ^ 0x34. because xor is associative that can be read as W == W_original ^ (0x42 ^ 0x34), or W == W_original ^ (0x76). 0x76 is, itself, also interesting, as that's the opcode for FWCMD_FIRMWARE_VERSION. +the third xor at 0x22b6 is equivalent to W == W_original ^ (0x42 ^ 0x34 ^ 0x2c) aka W == W_original ^ (0x5a). 0x53 maps to FWCMD_NO_OPERATION, so at this point this is definitely the start of the command interpreter dispatch table. + +added some labels on those branches so we don't forget. + +at this point there's something to closely inspect, so it's worth investigating a structure i've seen many times: +``` +; a call target +0x222c: movff FSR2L, POSTINC1 +0x2230: movff FSR1L, FSR2L +; ^ what's up with this and why? +; and at the return... (different function) +0x7532: movf POSTDEC1, POSTDEC1 +0x7534: movff INDF1, FSR2L +0x7536: return + +POSTDEC1 and INDF1 are ~special~ ~magic~ registers. they, along with PREDEC1, PREINC1, POSTINC1, and PLUSW1 are indirect registers that actually write to memory pointed at by the pair FSR1H:FSR1L. +* `INDF1` is an access to memory at `FSR1H:FSR1L`. +* `PLUSW1` is an access to memory at `FSR1H:FSR1L + W`. +* `POSTDEC`, `POSTINC`, and `PREINC` refer to additional functionality: before (or after) writing, the pair of FSR1 registers are incremented (or decremented) as described by the register name. + +pic18 2550 has three sets of FSR registers: 0, 1, and 2. each of these are distinct but have corresponding `PREDEC`, `POSTINC`, `INDF`, etc. + +so at function entry the code stores the previous FSR2L to `[FSR1++]`, then `FSR1 => FSR2`. because the pic18 2550 doesn't have a stack, this seems like a decent approximation of the same context-saving behavior. and of course, at return, context is restored appropriately. + +this provides some illumination on another interesting idiom: +``` +0x22d2: setf POSTINC1 +0x22d4: movlw #0x4 +0x22d6: movwf POSTINC1 +0x22d8: call 0x5466, 0 +0x22dc: movf POSTDEC1, POSTDEC1 +0x22de: movf POSTDEC1, POSTDEC1 +``` + +again, FSR1 is being used akin to a stack to pass parameters + +`setf POSTINC1` stores `0xFF` through `FSR1` and increments, the subsequent `movlw #0x4; movwf POSTINC1` provides a second argument, which aligns with the two `movf POSTDEC` after the call (undoing the increments to provide parameters) + +returning to this jump table stuff, register 0x54 is compared with 0xb9 (in the range of opcodes, though well into `SCMD_` space), and if the opcode is less than 0xb9, a branch is taken to `0x2306`: +``` +code from 0x2306 +``` + +at `0x2306` the opcode is turned into an offset into the subsequent jump table and added to PC, doing the switch by opcode. at this point it's reasonable to add labels for the cases to indicate what command they correspond to. + +confirmation: `FWCMD_RESET` matches up with the easily verifiably logic of the `reset` instruction. + +of note for later are: +* `FWCMD_EXECUTE_SCRIPT`: this is relevant for programmer operation. all operations seem to be scripts. +* `FWCMD_RUN_SCRIPT`: how is this different from "execute"? +* `FWCMD_DOWNLOAD_SCRIPT`: this is the command to download a script to the programmer. can we read script memory? how many scripts can there be? what's their size? +* `FWCMD_DOWNLOAD_DATA`: seems interesting. download to programmer or to target? +* `FWCMD_UPLOAD_DATA`: same as above +* `FWCMD_END_OF_BUFFER`: might be interesting to know later + +... it's not clear how SCMD commands are dispatched, which is probably a different table. time to keep looking. + +onward to `0x3b0a`... + +at `0x3aec` the opcode (again in register `0x54`) is compared against `0xd5`. if the opcode is that or above, `0x3af0` branches to a similar switch based on the value. + +since the entries are in order from `0xd5` up, script command names apply cleanly to each branch: +``` +TODO: before/after with script command names +``` + +and if the opcode was below `0xd5`, the branch at `0x3af2` kicks in and takes us to... + +``` +TODO: CODE AT prelude_to_jump_tbl_3 +``` + +very similar structure to other tables, but starts with `0xb3`. `0xb3` is not in the header file and is unknown, but the rest can be filled in. + +``` +TODO: CODE AT prelude_to_jump_tbl_3 with labels +``` + +(note: at this point as i was keymashing i accidentally hit ctrl+c, which my script doesn't handle, and lost three hours of notes give or take. largely looking through the interpreter cases, and easy enough to rebuild, but beware sigint) + +so to return to original questions: +* what script opcodes take how many parameters? +* how does programming actually take place? + +## Script Opcodes +easiest to start with obvious opcodes where i can assume that i know the intended functionality, but not the implementation. SCMD_NOP24 is an obvious candidate. functionally it *probably* does nothing, but does likely increment some pointers on the programmer side (current script opcode pointer, if such a thing exists), and possibly on the device side (to cause the target device to execute a no-op). + +``` +TODO: SCMD_NOP24 implementation +``` + +SCMD_NOP24 makes four calls to the same function, with parameters that vary: +* 0x5066(4, 0) +* 0x5066(8, 0) +* 0x5066(8, 0) +* 0x5066(8, 0) + +the sequence of three calls with (8, 0) probably correspond to the bytes 0x00, 0x00, 0x00, which decode under PIC24 to a NOP. so this seems sane! the remaining question if this is true, is why is there a call with arguments (4, 0)? + +to answer that, we have to look at 0x5066: +``` +TODO: fn at 0x5066 +``` + +so this function reads two parameters, stores the later parameter to 0x54, and the first to 0x55. as the first parameter for these calls is either 8 or 4, and the latter parameter is all 0's, this continues to make sense. + +the function then tests if 0x2e1 > 0x2 and branches below if so. + +``` +bitbang loop +``` + +this sequence of four instructions is responsible for putting pin 2 of latch A into a high or low state. bit 0 in 0x54 can only be 1 or 0, so exactly one of `btfss` or `btfcs` will result in a fallthrough. as a result, only one of `bcf LATA, 2; bsf LATA, 2` will be executed. afterward, the `nop; bsf LATA, 3; nop; bcf LATA, 3. This makes sense given that the programmer is responsible for directly driving clock signals on the remote chip in programming modes. + +??? ... programmer dialog, scmd, loop, arguments, ... ??? + +there is another region of ths function that's similar but just a little different, predicated on the value in 0x2e1. if that value is above 2, a different bit banging loop is reached, down at 0x509c: + +``` +loop 2 +``` + +this loop is the same as before as far as setting the data pin (LATA bit 2). the difference is that before alternating the clock three nops are used (rather than the earlier one nop), and those nops now have a loop around them. the timing loop counts down [0x2e1] times through W and advances when 0, and overall looks to be a bitbanging loop with longer timings between clock cycles. this may be relevant for other target devices, and a single "send this data" abstraction makes sense. + +back to the question of the two arguments, while one is sent one bit at a time, the other seems to count the number of bits to send: + +``` +TODO: 0x50c8 +``` + +so (4, 0) sends the bits `0000`, while (8, 0) sends `00000000`. + +moving on to SCMD_COREINST24, which functionally should send three user-specified bytes to the target... + +``` +TODO: SCMD_COREINST24 +``` + +as expected, this calls the same transmit function, and passes 4 and 8 in the same places. the major difference is how the second parameter is provided, where this version involves a bit of an incantation: + +``` +TODO: SCMD_COREINST24 0x41c6 to 0x41e2 +``` + +since the three bytes for a pic24 instruction are part of the script (in fact, the three bytes after the `SCMD_COREINST24`), it stands to reason that the value passed is read out of the script buffer. interestingly, the logic appears to be: +* read the current script buffer offset (through `INDF2` at `0x41c6`) +* increment the offset (`0x41c8`) +* load the pointer to the script array (`0x41cc`-`0x41d4`) into `FRS0` - this comes from an argument! +* add the offset into the pointer (`0x41d8`) +* read that address (`0x41e0`) +* "push" the parameter (`0x41e2`) + +this confirms that for the various commands we can count `INDF2` modification to determine the number of parameters for the various commands! + +first ones of interest: `SCMD_WRITE_BUFBYTE_W` and `SCMD_WRITE_BUFWORD_W` + +## `SCMD_WRITE_BUFWORD_W` + +``` +TODO: SCMD_WRITE_BUFWORD_W +``` + +this handler involves the same transmit function from earlier and also another function, `0x5006`. + +guessing from context it appears to read from a global address and return the byte in W. `SCMD_WRITE_BUFWORD_W` then uses that as bits to send down the wire. + +`SCMD_WRITE_BUFBYTE_W` does the same, but only reads one byte, the second value transmitted is a 0. + +`SCMD_WRITE_BITS_LITERAL` takes two parameters, the number of bits and the pattern to send. +`SCMD_WRITE_BYTE_LITERAL` takes one parameter, the pattern, and assumes the number of bits to send is 8. +TODO: `SCMD_RD2_BYTE_BUFFER` is an unknown. +TODO: `SCMD_READ_BYTE`. +TODO: `SCMD_VISI24`. (transmits (4, 1), (8, 0), then some unknown calls.) + +## `SCMD_DELAY_LONG` + +passes the single byte parameter along to the function at `0x4966`, which... +``` +TODO: 11 instructions at 0x4966 +``` + +at `0x496e` the flag indicating `timer0` has fired is cleared, followed by multiplying the argument by 0xff and loading the result into `tmr0h`? this really has no result other than to negate it before setting the timer. from there, the timer is enabled and the controller spins until the timer fires (`0x497e`). + +## `SCMD_LOOP` diff --git a/source/notes/pic-mcu/pickit2/pk2cmd-stuff/pk2cmd_firmware b/source/notes/pic-mcu/pickit2/pk2cmd-stuff/pk2cmd_firmware new file mode 160000 +Subproject 4e76e524ce8613f971b4167a9e2db1458e21e69 diff --git a/source/notes/pic-mcu/pickit2/pk2cmd-stuff/pk2cmd_script.py b/source/notes/pic-mcu/pickit2/pk2cmd-stuff/pk2cmd_script.py new file mode 100644 index 0000000..f1de6ce --- /dev/null +++ b/source/notes/pic-mcu/pickit2/pk2cmd-stuff/pk2cmd_script.py @@ -0,0 +1,146 @@ +import pic24 + +NoOperands = [ + 0xD5, 0xD6, 0xD7, 0xD8, + 0xEF, # comment on this one: Read & toss 2 response words + 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB +] + +ScriptCommandTable = { + 0xB4: 'SCMD_JT2_WAIT_PE_RESP', + 0xB5: 'SCMD_JT2_GET_PE_RESP', + 0xB6: 'SCMD_JT2_XFERINST_BUF', + 0xB7: 'SCMD_JT2_XFRFASTDAT_BUF', + 0xB8: 'SCMD_JT2_XFRFASTDAT_LIT', + 0xB9: 'SCMD_JT2_XFERDATA32_LIT', + 0xBA: 'SCMD_JT2_XFERDATA8_LIT', + 0xBB: 'SCMD_JT2_SENDCMD', + 0xBC: 'SCMD_JT2_SETMODE', + 0xBD: 'SCMD_UNIO_TX_RX', + 0xBE: 'SCMD_UNIO_TX', + 0xBF: 'SCMD_MEASURE_PULSE', + 0xC0: 'SCMD_ICDSLAVE_TX_BUF_BL', + 0xC1: 'SCMD_ICDSLAVE_TX_LIT_BL', + 0xC2: 'SCMD_ICDSLAVE_RX_BL', + 0xC3: 'SCMD_SPI_RDWR_BYTE_BUF', + 0xC4: 'SCMD_SPI_RDWR_BYTE_LIT', + 0xC5: 'SCMD_SPI_RD_BYTE_BUF', + 0xC6: 'SCMD_SPI_WR_BYTE_BUF', + 0xC7: 'SCMD_SPI_WR_BYTE_LIT', + 0xC8: 'SCMD_I2C_RD_BYTE_NACK', + 0xC9: 'SCMD_I2C_RD_BYTE_ACK', + 0xCA: 'SCMD_I2C_WR_BYTE_BUF', + 0xCB: 'SCMD_I2C_WR_BYTE_LIT', + 0xCC: 'SCMD_I2C_STOP', + 0xCD: 'SCMD_I2C_START', + 0xCE: 'SCMD_AUX_STATE_BUFFER', + 0xCF: 'SCMD_SET_AUX', + 0xD0: 'SCMD_WRITE_BITS_BUF_HLD', + 0xD1: 'SCMD_WRITE_BITS_LIT_HLD', + 0xD2: 'SCMD_CONST_WRITE_DL', + 0xD3: 'SCMD_WRITE_BUFBYTE_W', + 0xD4: 'SCMD_WRITE_BUFWORD_W', + 0xD5: 'SCMD_RD2_BITS_BUFFER', + 0xD6: 'SCMD_RD2_BYTE_BUFFER', + 0xD7: 'SCMD_VISI24', + 0xD8: 'SCMD_NOP24', + 0xD9: 'SCMD_COREINST24', + 0xDA: 'SCMD_COREINST18', + 0xDB: 'SCMD_POP_DOWNLOAD', + 0xDC: 'SCMD_ICSP_STATES_BUFFER', + 0xDD: 'SCMD_LOOP_BUFFER', + 0xDE: 'SCMD_ICDSLAVE_TX_BUF', + 0xDF: 'SCMD_ICDSLAVE_TX_LIT', + 0xE0: 'SCMD_ICDSLAVE_RX', + 0xE1: 'SCMD_POKE_SFR', + 0xE2: 'SCMD_PEEK_SFR', + 0xE3: 'SCMD_EXIT_SCRIPT', + 0xE4: 'SCMD_GOTO_INDEX', + 0xE5: 'SCMD_IF_GT_GOTO', + 0xE6: 'SCMD_IF_EQ_GOTO', + 0xE7: 'SCMD_DELAY_SHORT', + 0xE8: 'SCMD_DELAY_LONG', + 0xE9: 'SCMD_LOOP', + 0xEA: 'SCMD_SET_ICSP_SPEED', + 0xEB: 'SCMD_READ_BITS', + 0xEC: 'SCMD_READ_BITS_BUFFER', + 0xED: 'SCMD_WRITE_BITS_BUFFER', + 0xEE: 'SCMD_WRITE_BITS_LITERAL', + 0xEF: 'SCMD_READ_BYTE', + 0xF0: 'SCMD_READ_BYTE_BUFFER', + 0xF1: 'SCMD_WRITE_BYTE_BUFFER', + 0xF2: 'SCMD_WRITE_BYTE_LITERAL', + 0xF3: 'SCMD_SET_ICSP_PINS', + 0xF4: 'SCMD_BUSY_LED_OFF', + 0xF5: 'SCMD_BUSY_LED_ON', + 0xF6: 'SCMD_MCLR_GND_OFF', + 0xF7: 'SCMD_MCLR_GND_ON', + 0xF8: 'SCMD_VPP_PWM_OFF', + 0xF9: 'SCMD_VPP_PWM_ON', + 0xFA: 'SCMD_VPP_OFF', + 0xFB: 'SCMD_VPP_ON', + 0xFC: 'SCMD_VDD_GND_OFF', + 0xFD: 'SCMD_VDD_GND_ON', + 0xFE: 'SCMD_VDD_OFF', + 0xFF: 'SCMD_VDD_ON' +} + +def disassemble(blob, offset): + code = blob[offset] + length = 1 + command = ScriptCommandTable[code] + result = {} + result['mnemonic'] = command + if code == 0xCF: + length += 1 + result['op'] = hex(blob[offset + 1]) + elif code == 0xD3 or code == 0xD4: + length += 1 + immediate = blob[offset + 1] + elif code == 0xD9: + if blob[offset + 1 + 2] == 0x04: + # it's a goto, and there's a second instruction. this OUGHT to be + # followed by a SCMD_NOP24... + if blob[offset + 1 + 3] == 0xD8: + # it is! whew + instrbytes = blob[offset + 1:offset + 1 + 3] + instrbytes.append(0) + instrbytes.append(0) + instrbytes.append(0) + + (postinstr_offset, instr) = pic24.disassemble(instrbytes, 0) + length = 1 + 3 + 1 # the command, three real bytes + the nop + result['op'] = instr #pic24.render(instr) + else: + (postinstr_offset, instr) = pic24.disassemble(blob, offset + 1) +# length = postinstr_offset - offset + length = 4 + result['op'] = instr #pic24.render(instr) + print("Goto not followed by nop, uhh what's " + hex(blob[offset + 3 + 1])) + else: + (postinstr_offset, instr) = pic24.disassemble(blob, offset + 1) + length = postinstr_offset - offset + result['op'] = instr #pic24.render(instr) + elif code in NoOperands: + pass + elif code == 0xE7 or code == 0xE8: + length += 1 + result['op'] = hex(blob[offset + 1]) + elif code == 0xEE: + length += 2 +# not sure if this is really two operands + result['op'] = hex(blob[offset + 1]) + ", " + hex(blob[offset + 2]) + elif code == 0xE9: + length += 2 + result['op'] = hex((blob[offset + 2] << 8) + blob[offset + 1]) + elif code == 0xF2: + length += 1 + result['op'] = hex(blob[offset + 1]) + elif code == 0xF3: + length += 1 + result['op'] = hex(blob[offset + 1]) + else: + print("Unknown: " + command) + return None + + return (offset + length, result) diff --git a/source/notes/pic-mcu/pickit2/pk2cmd-stuff/pk2cmd_script.pyc b/source/notes/pic-mcu/pickit2/pk2cmd-stuff/pk2cmd_script.pyc Binary files differnew file mode 100644 index 0000000..2ad27ee --- /dev/null +++ b/source/notes/pic-mcu/pickit2/pk2cmd-stuff/pk2cmd_script.pyc diff --git a/source/notes/pic-mcu/pickit2/pk2cmd-stuff/pydare.py b/source/notes/pic-mcu/pickit2/pk2cmd-stuff/pydare.py new file mode 100644 index 0000000..f24f69f --- /dev/null +++ b/source/notes/pic-mcu/pickit2/pk2cmd-stuff/pydare.py @@ -0,0 +1,610 @@ +import json +import importlib +import traceback +import sys +import os + +import pic16 +import pic18 +import pic24 + +running = True +DEBUG = False + +ANSI_BLUE = "\x1b[34m" +ANSI_YELLOW = "\x1b[33m" +ANSI_DARK_GREEN = "\x1b[32m" +ANSI_GREEN = "\x1b[1m\x1b[32m" +ANSI_RED = "\x1b[31m" +ANSI_RESET = "\x1b[0m" + +COLOR_REGISTER = ANSI_YELLOW +COLOR_FUNCTION = ANSI_GREEN +COLOR_LABEL = ANSI_DARK_GREEN +COLOR_ADDRESS = ANSI_DARK_GREEN + +state = { + 'running': True, + 'dirty': False +} + +def parse_parts(msg): + parts = [] + i = 0 + wordstart = 0 + word = "" + stripped = msg.strip() + + in_quotes = False + escaping = False + + while i < len(stripped): + if escaping: + # escaping means even spaces aren't the end of the word, so + word = word + stripped[i] + escaping = False + else: + if stripped[i] == ' ': + if in_quotes: + # this isn't actually the end of a word + word = word + stripped[i] + else: + parts.append(word) + word = "" + elif stripped[i] == '\\': + escaping = True + elif stripped[i] == '"': + in_quotes = not in_quotes + else: + word = word + stripped[i] + + i = i + 1 + + parts.append(word) + word = "" + + # todo: signal unmatched quotes + + return parts + +def readnum(s): + if s.startswith("0x"): + return int(s[2:], 16) + else: + return int(s) + +def parse_cmd(cmd): + cmd_parts = parse_parts(cmd) + smol_to_big = { + "o": "open", + "c": "define-comment", + "c+": "define-comment", + "q": "quit", + "d": "disassemble", + "h": "help" + } + + result = {} + + if len(cmd_parts) > 0: + result['type'] = cmd_parts[0] + if result['type'] in smol_to_big: + result['type'] = smol_to_big[result['type']] + + result['params'] = cmd_parts[1:] + result['raw_text'] = cmd + + if len(cmd_parts) > 1 and cmd_parts[-1][0] == '@': + result['where'] = resolve_addr(cmd_parts[-1][1:], state) + elif len(cmd_parts) > 2 and cmd_parts[-2] == '@': + result['where'] = resolve_addr(cmd_parts[-1], state) + + if 'where' in result and result['where'] is None: + result['invalid'] = True + + return result + +def resolve_addr(where, state): + # where may be the name of a label or function + if where in state['notes']['functions-reverse']: + return state['notes']['functions-reverse'][where] + elif where in state['notes']['labels-reverse']: + return state['notes']['labels-reverse'][where] + else: + # if it's not there, it better be a number... + try: + return readnum(where) + except ValueError: + print("{} is not a known function or label.".format(where)) + +def do_help(cmd, state): + print("haha, help") + +def do_open(cmd, state): + f = open(cmd['params'][0]) + buf = f.read(6) + f.close() + if buf == ":02000": + return do_openhex(cmd, state) + else: + return do_openbin(cmd, state) + +def do_openbin(cmd, state): + return inneropen(cmd, state, lambda x: { 0: x.read() }) + +def do_openhex(cmd, state): + return inneropen(cmd, state, lambda x: read_hex(x)) + +def read_hex(f): + lines = f.readlines() + regions = { 0: [] } + curr_region = regions[0] + + for line in lines: + if not line.startswith(':'): + continue +# raise Exception("invalid hex line, needs to start with a ':', but was: " + line) + bytecount = int(line[1:3], 16) + addr = int(line[3:7], 16) + rec_type = int(line[7:9], 16) + data_end = bytecount * 2 + 9 + data = line[9:data_end] + # ignoring checksum because lazy + + if rec_type == 4: + ext_linear_addr = int(data, 16) + if ext_linear_addr not in regions: + regions[ext_linear_addr] = [] + + curr_region = regions[ext_linear_addr] + elif rec_type == 0: + for i in range(bytecount): + if len(curr_region) <= addr + i: + curr_region.extend([0] * (1 + addr + i - len(curr_region))) + curr_region[addr + i] = int(data[i*2:i*2 + 2], 16) + elif rec_type == 1: + if DEBUG: + print("Read HEX file ({} regions)".format(len(regions))) + return regions + else: + raise Exception("Unsupported record type: " + str(rec_type)) + +def do_goto(cmd, state): + try: + dest = int(cmd['params'][0]) + except ValueError: + # parse error, might be a function or label! + # labels first... + name = cmd['params'][0] + if name in state['notes']['labels-reverse']: + dest = state['notes']['labels-reverse'][name] + if name in state['notes']['functions-reverse']: + dest = state['notes']['functions-reverse'][name] + state['cursor'] = int(cmd['params'][0]) + +def do_goto_bank(cmd, state): + param = cmd['params'][0] + if not param in state['all-regions']: + state['all-regions'][param] = [] + + state['data'] = state['all-regions'][param] + +def inneropen(cmd, state, readfn): + newfile = cmd['params'][0] + if os.path.isfile(newfile): + newdata = None + try: + f = open(newfile) + newdata = readfn(f) + f.close() + except Exception as e: + print("Failed to open new file: {}".format(newfile)) + print("Got: {}".format(e)) + print(traceback.format_exc()) + return + state['notes'] = { + 'comments': {}, + 'functions': {}, + 'functions-reverse': {}, + 'labels': {}, + 'labels-reverse': {} + } + state['cursor'] = 0 + state['file'] = newfile + state['all-regions'] = newdata + state['selected-region'] = newdata.keys()[0] + state['data'] = newdata[state['selected-region']] + elif os.path.isdir(newfile): + print("Cannot open {}, it is a directory".format(newfile)) + else: + print("File {} does not exist".format(newfile)) + + if 'arch-name' not in state or state['arch-name'] is None: + # default arch to the best cpu, pic16 + do_setarch({ 'params': ['pic16'] }, state) + + if DEBUG: + print("Opened {} as {}".format(newfile, state['arch-name'])) + +def do_comment(cmd, state): + state['notes']['comments'][cmd['where']] = cmd['params'][0] + state['dirty'] = True + +def new_function(name): + return { + "name": name, + "params": None, + "returns": None + } + +def do_undefine_function(cmd, state): + name = cmd['params'][0] + if cmd['params'][0] in state['notes']['functions-reverse']: + fnaddr = state['notes']['functions-reverse'][cmd['params'][0]] + del state['notes']['functions'][fnaddr] + del state['notes']['functions-reverse'][name] + return + else: + print("Function {} is not defined".format(name)) + +def do_define_function(cmd, state): + if cmd['params'][0] in state['notes']['functions-reverse']: + fnaddr = state['notes']['functions-reverse'][cmd['params'][0]] + if fnaddr != cmd['where']: + print("Function {} is already defined at {}".format(cmd['params'][0], fnaddr)) + return + else: + newname = cmd['params'][0] + fn = state['notes']['functions'][cmd['where']] + del state['notes']['functions-reverse'][fn['name']] + state['notes']['functions-reverse'][newname] = fn + fn['name'] = newname + else: + state['notes']['functions'][cmd['where']] = new_function(cmd['params'][0]) + state['notes']['functions-reverse'][cmd['params'][0]] = cmd['where'] + state['dirty'] = True + +def do_define_label(cmd, state): + state['notes']['labels'][cmd['where']] = cmd['params'][0] + state['notes']['labels-reverse'][cmd['params'][0]] = cmd['where'] + state['dirty'] = True + +def colorize(string, color): + return "{}{}{}".format( + color, + string, + ANSI_RESET + ) + +def do_disassemble(cmd, state): + if 'data' not in state: + print("No file currently open") + return + if 'cursor' not in state: + print("No cursor into the file (this is a bug - a file must be open?") + return + + if 'where' in cmd: + where = cmd['where'] + else: + where = state['cursor'] + + if len(cmd['params']) > 0: + count = int(cmd['params'][0]) + else: + count = 1 + + arch = state['arch'] + + try: + disassembled = 0 + while disassembled < count: + prewhere = where + (where, instr) = arch.disassemble(state['data'], where) + if 'ops' in instr: + newops = instr['ops'] + for i, op in enumerate(instr['ops']): + if isinstance(op, dict) and 'type' in op: + note = None + if op['type'] == "absolutedest": + if op['value'] in state['notes']['functions']: + note = state['notes']['functions'][op['value']]['name'] + note = colorize(note, COLOR_FUNCTION) + elif op['value'] in state['notes']['labels']: + note = state['notes']['labels'][op['value']] + note = colorize(note, COLOR_LABEL) + else: + note = colorize(hex(op['value']), COLOR_ADDRESS) + elif op['type'] == "relpostdest": + # if there's a thing there replace with it + newops[i] = "relpostdest" + ea = prewhere + instr['length'] * 2 + op['value'] + if ea in state['notes']['functions']: + note = state['notes']['functions'][ea]['name'] + note = colorize(note, COLOR_FUNCTION) + elif ea in state['notes']['labels']: + note = state['notes']['labels'][ea] + note = colorize(note, COLOR_LABEL) + else: + note = "0x{:x} (ip+2{}{})".format( + ea, + "+" if op['value'] >= 0 else "", + hex(op['value']) + ) + note = colorize(note, COLOR_ADDRESS) + elif op['type'] == "relpredest": + pass + elif op['type'] == "register" or op['type'] == "banked-register": + nicename = arch.reg_name(op['value']) + if nicename is None: + if isinstance(op['value'], str): + note = op['value'] + else: + note = hex(op['value']) + else: + note = nicename + + note = colorize(note, COLOR_REGISTER) + + if not note is None: + newops[i] = str(note) + + instr['ops'] = newops + + prefix = None + if prewhere in state['notes']['functions']: + fn = state['notes']['functions'][prewhere] + prefix = colorize( + "{:08x}> start of {}\n".format(prewhere, fn['name']), + COLOR_FUNCTION + ) + elif prewhere in state['notes']['labels']: + label = state['notes']['labels'][prewhere] + prefix = colorize( + "{:08x}: {}\n".format(prewhere, label), + COLOR_LABEL + ) + instrstring = arch.render(instr) + to_show = "{:08x}: {}".format(prewhere, instrstring) + if prewhere in state['notes']['comments']: + to_show = "{: <35} {}; {}{}".format( + to_show, + ANSI_BLUE, + state['notes']['comments'][prewhere], + ANSI_RESET + ) + if not prefix is None: + to_show = prefix + to_show + print(to_show) + disassembled = disassembled + 1 + except Exception as e: + print("Exception while disassembling: {}".format(e)) + print(traceback.format_exc()) + +def do_setarch(cmd, state): + try: + loaded_arch = importlib.import_module(cmd['params'][0]) + except ImportError: + print("Cannot find module for arch '{}'".format(cmd['params'][0])) + except Exception as e: + print("General error loading '{}': {}".format(cmd['params'][0], e)) + + state['arch-name'] = cmd['params'][0] + state['arch'] = loaded_arch + +def dict_from_file(path): + f = open(path) + result = json.loads(f.read()) + f.close() + return result + +def dict_to_file(path, data): + f = open(path, 'w') + f.write(json.dumps(data, sort_keys=True, indent=2)) + f.close() + +# so json.dumps turns numeric keys into strings. +# this breaks some dictionaries. +def fix_keys(obj): + redo = [] + for k in obj: + try: + knum = int(k) + redo.append(k) + except ValueError: + pass + + for k in redo: + knum = int(k) + obj[knum] = obj[k] + del obj[k] + +def do_loaddb(cmd, state): + if len(cmd['params']) == 0: + if 'file' in state: + dbpath = state['file'] + '.nrt' + else: + print("No db path provided nor file loaded - I don't know what to load!") + return + else: + dbpath = cmd['params'][0] + if os.path.isdir(dbpath) and os.path.isdir(dbpath + '/.git'): + if DEBUG: + print("Loading {} ...".format(dbpath)) + try: + dbroot = dict_from_file(dbpath + '/root.json') + do_setarch({ "params": [dbroot['arch-name']] }, state) + state['notes']['comments'] = dict_from_file(dbpath + '/comments.json') + fix_keys(state['notes']['comments']) + state['notes']['functions'] = dict_from_file(dbpath + '/functions.json') + state['notes']['functions-reverse'] = dict_from_file(dbpath + '/functions-reverse.json') + fix_keys(state['notes']['functions']) + state['notes']['labels'] = dict_from_file(dbpath + '/labels.json') + state['notes']['labels-reverse'] = dict_from_file(dbpath + '/labels-reverse.json') + fix_keys(state['notes']['labels']) + state['default-dbpath'] = dbpath +# check db file path matches current file path? + if DEBUG: + print("wow you're really using this, huh?") + except Exception as e: + print("Error loading db: {}".format(e)) + elif os.path.isdir(dbpath): + print("Cannot load {}, there is no repository there".format(dbpath)) + elif os.path.isfile(dbpath): + print("Cannot load {}, it is a file".format(dbpath)) + else: + print("Cannot load {}, it does not exist".format(dbpath)) + +def do_savedb(cmd, state): + if len(cmd['params']) > 0: + dbpath = cmd['params'][0] + elif 'default-dbpath' in state: + dbpath = state['default-dbpath'] + else: + dbpath = state['file'] + '.nrt' + + if os.path.isfile(dbpath): + print("File is present, but should be a directory. Cannot save.") + return + elif os.path.isdir(dbpath): + if not os.path.isdir(dbpath + '/.git'): + print("dbpath is a directory, but there is no git repo there. Opting to not save.") + return + else: + # dbpath exists, and there's a git repo there, we can proceed + pass + else: + # none of the directories exist, so we can start fresh + os.mkdir(dbpath) + # TODO: pray the input filename doesn't have a ' in it i guess + os.system('cd \'{}\' && git init'.format(dbpath)) + + to_save = {} + to_save['arch-name'] = state['arch-name'] + dict_to_file(dbpath + '/root.json', to_save) + dict_to_file(dbpath + '/comments.json', state['notes']['comments']) + dict_to_file(dbpath + '/functions.json', state['notes']['functions']) + dict_to_file(dbpath + '/functions-reverse.json', state['notes']['functions-reverse']) + dict_to_file(dbpath + '/labels.json', state['notes']['labels']) + dict_to_file(dbpath + '/labels-reverse.json', state['notes']['labels-reverse']) + os.system('cd \'{}\' && git add . && git commit -m "automatic save"'.format(dbpath)) + state['dirty'] = False + +def do_quit(cmd, state): + # prompt before saving + if not 'dirty' in state or state['dirty']: + do_savedb({ "params": [] }, state) + state['running'] = False + +def do_sh(cmd, state): + if len(cmd['params']) == 1: + os.system(cmd['params'][0]) + else: + print("sh expects exactly one argument (may be a string)") + +def do_info(cmd, state): + if 'file' in state: + print("File: {}".format(state['file'])) + print("Regions:") + keys = state['all-regions'].keys() + keys.sort() + for key in keys: + print(" {}{}: {} bytes".format( + '*' if key == state['selected-region'] else ' ', + key, + hex(len(state['all-regions'][key])) + )) + +def readnum(string): + if string.startswith('0x'): + return int(string, 16) + else: + return int(string) + +def do_list_comments(cmd, state): + print("Comments:") + for l in state['notes']['comments']: + print("{}: 0x{:x}".format(state['notes']['comments'][l], l)) + +def do_list_functions(cmd, state): + print("Functions:") + for l in state['notes']['functions']: + print("{}: 0x{:x}".format(state['notes']['functions'][l]['name'], l)) + +def do_list_labels(cmd, state): + print("Labels:") + for l in state['notes']['labels']: + print("{}: 0x{:x}".format(state['notes']['labels'][l], l)) + +def do_hexprint(cmd, state): + count = readnum(cmd['params'][0]) + start = cmd['where'] + idx = start + + while count > idx - start: + sys.stdout.write("{:08x}: ".format(idx)) + for i in range(16): + if count <= idx - start: + break + sys.stdout.write("{:02x} ".format(state['data'][idx]),) + idx = idx + 1 + sys.stdout.write('\n') + +cmdmap = { + "px": do_hexprint, + "define-comment": do_comment, + "define-function": do_define_function, + "undefine-function": do_undefine_function, + "define-label": do_define_label, + "list-comments": do_list_comments, + "list-functions": do_list_functions, + "list-labels": do_list_labels, + "open": do_open, + "openhex": do_openhex, + "arch": do_setarch, + "disassemble": do_disassemble, + "loaddb": do_loaddb, + "savedb": do_savedb, + "quit": do_quit, + "help": do_help, + "info": do_info, + "goto": do_goto, + "goto-bank": do_goto_bank, + "sh": do_sh +} + +def do_cmd_thing(cmd, state): + if 'invalid' in cmd: + pass # can't do anything with it. + elif cmd['type'] in cmdmap: + cmdmap[cmd['type']](cmd, state) + else: + print("I don't recognize the command `{}`".format(cmd['raw_text'])) + +for i, arg in enumerate(sys.argv): + # just the path of this script + # i bet that only applies because i'm running as + # `python pydare.py ...` + if i == 0: + continue + do_cmd_thing(parse_cmd(arg), state) + +# if len(sys.argv) > 1: +# do_open({"params": [sys.argv[1]]}, state) +# if len(sys.argv) > 2: +# do_setarch({"params": [sys.argv[2]]}, state) + +import readline +readline.parse_and_bind("") +if os.path.isfile(".pydare_history"): + readline.read_history_file(".pydare_history") + +while state['running']: + try: + do_cmd_thing(parse_cmd(raw_input("> ")), state) + except Exception as e: + print("Unhandled exception: {}".format(e)) + print(traceback.format_exc()) + +if not os.path.isdir(".pydare_history"): + readline.write_history_file(".pydare_history") diff --git a/source/notes/pic-mcu/pickit2/pk2cmd-stuff/readdat.py b/source/notes/pic-mcu/pickit2/pk2cmd-stuff/readdat.py new file mode 100644 index 0000000..6fc8919 --- /dev/null +++ b/source/notes/pic-mcu/pickit2/pk2cmd-stuff/readdat.py @@ -0,0 +1,280 @@ +import struct +import sys + +import pic18 +import pic24 +import pk2cmd_script + +datfile = open("../pk2cmd/pk2cmd/PK2DeviceFile.dat").read() + +def readstr(datfile, offset): + length = ord(datfile[offset]) & 0xff + offset += 1 + if length > 0x7f: + length &= 0x7f + length += 0x80 * (ord(datfile[offset]) & 0xff) + offset += 1 + s = "" + for i in range(length): + s += datfile[offset] + offset += 1 +# if s[-1] == '\x0d': +# s += datfile[offset] +# offset += 1 + return (offset, s) + +def readDeviceFileParams(datfile, offset): + result = {} + (result['versionMajor'], result['versionMinor'], result['versionDot']) = struct.unpack_from('=iii', datfile, offset) + offset += 12 + (offset, result['versionNote']) = readstr(datfile, offset) + (result['numFamilies'], result['numParts'], result['numScripts']) = struct.unpack_from('=iii', datfile, offset) + offset += 12 + result['compatibility'] = ord(datfile[offset]) + offset += 1 + offset += 1 + 2 + 4 + return (offset, result) + +(offset, params) = readDeviceFileParams(datfile, offset=0) + +print(params) + +families = {} +parts = {} +scripts = {} + +def readDevicePart(datfile, offset): + result = {} + (offset, result['name']) = readstr(datfile, offset) + ( + result['family'], + result['id'], + result['programMem'], + result['EEMem'], + result['EEAddr'], + result['configWords'], + result['configAddr'], + result['userIDWords'], + result['userIDAddr'], + result['bandGapMask'] + ) = struct.unpack_from('=HIIHIBIBII', datfile, offset) + offset += 2 + 4 + 4 + 2 + 4 + 1 + 4 + 1 + 4 + 4 + result['configMasks'] = [0] * 9 + # entry 8 will come later. ~backwards compat~ + ( + result['configMasks'][0], + result['configMasks'][0], + result['configMasks'][0], + result['configMasks'][0], + result['configMasks'][0], + result['configMasks'][0], + result['configMasks'][0], + result['configMasks'][0] + ) = struct.unpack_from('=HHHHHHHH', datfile, offset) + offset += 2 * 8 + + result['configBlank'] = [0] * 9 + # entry 8 will come later. ~backwards compat~ + ( + result['configBlank'][0], + result['configBlank'][0], + result['configBlank'][0], + result['configBlank'][0], + result['configBlank'][0], + result['configBlank'][0], + result['configBlank'][0], + result['configBlank'][0] + ) = struct.unpack_from('=HHHHHHHH', datfile, offset) + offset += 2 * 8 + ( + result['CPMask'], + result['CPConfig'], + result['OSSCALSave'], + result['ignoreAddress'], + result['vddMin'], + result['vddMax'], + result['vddErase'], + result['calibrationWords'], + result['chipEraseScript'], + result['progMemAddrSetScript'], + result['progMemAddrBytes'], + result['progMemRdScript'], + result['progMemRdWords'], + result['EERdPrepScript'], + result['EERdScript'], + result['EERdLocations'], + result['userIDRdPrepScript'], + result['userIDRdScript'], + result['configRdPrepScript'], + result['configRdScript'], + result['progMemWrPrepScript'], + result['progMemWrScript'], + result['progMemWrWords'], + result['progMemPanelBufs'], + result['progMemPanelOffset'], + result['EEWrPrepScript'], + result['EEWrScript'], + result['EEWrLocations'], + result['userIDWrPrepScript'], + result['userIDWrScript'], + result['configWrPrepScript'], + result['configWrScript'], + result['OSCCALRdScript'], + result['OSCCALWrScript'], + result['DPMask'], + result['writeCfgOnErase'], + result['blankCheckSkipUsrIDs'], + result['ignoreBytes'], + result['chipErasePrepScript'], + result['bootFlash'] + ) = struct.unpack_from('=HB?IfffBHHBHHHHHHHHHHHHBIIIIIIIIIII??HHI', datfile, offset) + # f I B ? H + offset += 4 * 3 + 4 * 13 + 1 * 4 + 1 * 3 + 2 * 17 + ( + result['configMasks'][8], # and these are the last entries above + result['configBlank'][8], + result['progMemEraseScript'], + result['EEMemEraseScript'], + result['configMemEraseScript'], + result['Reserved1EraseScript'], + result['Reserved2EraseScript'], + result['testMemoryRdScript'], + result['testMemoryRdWords'], + result['EERowEraseScript'], + result['EERowEraseWords'], + result['exportToMPLAB'], + result['debugHaltScript'], + result['debugRunScript'], + result['debugStatusScript'], + result['debugReadExecVerScript'], + result['debugSingleStepScript'], + result['debugBulkWrDataScript'], + result['debugBulkRdDataScript'], + result['debugWriteVectorScript'], + result['debugReadVectorScript'], + result['debugRowEraseScript'], + result['debugRowEraseSize'], + result['debugReserved5Script'], + result['debugReserved6Script'], + result['debugReserved7Script'], + result['debugReserved8Script'], + result['LVPScript'] + ) = struct.unpack_from('=HHHHHHHHHHH?HHHHHHHHHHHHHHHH', datfile, offset) + offset += 2 * 27 + 1 * 1 +# uhhhhh + offset -= 20 + return (offset, result) + +def readDeviceFamily(datfile, offset): + result = {} + (result['id'], result['type'], result['searchPriority']) = struct.unpack_from('=HHH', datfile, offset) + offset += 6 + (offset, result['name']) = readstr(datfile, offset) + (result['progEntryScript'], result['progExitScript'], result['readDevIDScript'], result['deviceIDMask'], result['blankValue'], result['bytesPerLocation'], result['addressIncrement']) = struct.unpack_from('=HHHiiBB', datfile, offset) + offset += 2 * 3 + 4 * 2 + 1 * 2 + result['partDetect'] = ord(datfile[offset]) + offset += 1 + ( + result['progEntryVPPScript'], + result['unused1'], + result['EEMemBytesPerWord'], + result['EEMemAddressIncrement'], + result['userIDHexBytes'], + result['userIDBytes'], + result['progMemHexBytes'], + result['EEMemHexBytes'], + result['progMemShift'], + result['testMemoryStart'], + result['testMemoryLength'], + result['vpp'] + ) = struct.unpack_from('=HHBBBBBBBiHf', datfile, offset) + offset += 2 * 2 + 1 * 7 + 4 + 2 + 4 + return (offset, result) + +def readScript(datfile, offset): + result = {} + result['number'] = struct.unpack_from('=H', datfile, offset)[0] + offset += 2 + (offset, result['name']) = readstr(datfile, offset) + (result['version'], result['unused1'], result['length']) = struct.unpack_from('=HIH', datfile, offset) + offset += 8 + script = [] + print("Reading script " + result['name'] + " at " + hex(offset) + " len=" + str(result['length'])) + for i in range(result['length']): + script.append(struct.unpack_from('=B', datfile, offset)[0]) +# script.append(struct.unpack_from('=B', datfile, offset + 1)[0]) + offset += 2 + result['script'] = script + (offset, result['comment']) = readstr(datfile, offset) + return (offset, result) + +print("Reading families...") + +for i in range(params['numFamilies']): + (offset, family) = readDeviceFamily(datfile, offset) + families[family['id']] = family + +print("Reading parts...") + +for i in range(params['numParts']): + (offset, part) = readDevicePart(datfile, offset) + parts[part['id']] = part + +print("Reading scripts...") + +for i in range(params['numScripts']): + (offset, script) = readScript(datfile, offset) + scripts[script['number']] = script + +database = { "parts": parts, "families": families, "scripts": scripts } + +print("Ready!") + +def findPart(model, database): + for p in database['parts']: + if database['parts'][p]['name'] == model: + return database['parts'][p] + return None + +part = findPart("PIC24FJ256DA206", database) + +if part is None: + print("Could not find part.") + sys.exit(1) + +def disassemble_script(content): + offset = 0 + while offset < len(content): + (offset, instr) = pk2cmd_script.disassemble(content, offset) + print(instr) + +def printScript(script): + print(" Name: " + script['name']) + print(" Script length: " + str(script['length'])) + if True: + disassemble_script(script['script']) +# print("Comment: " + script['comment']) + +def printPart(part, database): + print("Name: " + part['name']) + family = database["families"][part["family"]] + print("Family: " + family['name']) + print("Program memory: " + str(part['programMem'])) + print("Vdd_min: " + str(part['vddMin'])) + print("Vdd_max: " + str(part['vddMax'])) + print("Vdd_erase: " + str(part['vddErase'])) + print("ProgMemAddrBytes: " + str(part['progMemAddrBytes'])) + print("ChipEraseScript: ") + printScript(database['scripts'][part['chipEraseScript']]) + print("ProgEntryScript: ") + printScript(database['scripts'][family['progEntryScript']]) + print("ProgExitScript: ") + printScript(database['scripts'][family['progExitScript']]) + print("ReadDevIDScript: ") + printScript(database['scripts'][family['readDevIDScript']]) + print("ProgMemRdScript (id " + str(part['progMemRdScript']) + "): ") + printScript(database['scripts'][part['progMemRdScript']]) + print("ProgMemAddrSetScript (id " + str(part['progMemAddrSetScript']) + "): ") + printScript(database['scripts'][part['progMemAddrSetScript']]) + +printPart(part, database) diff --git a/source/notes/pic-mcu/pickit2/pk2cmd-stuff/tablelines b/source/notes/pic-mcu/pickit2/pk2cmd-stuff/tablelines new file mode 100644 index 0000000..30008f4 --- /dev/null +++ b/source/notes/pic-mcu/pickit2/pk2cmd-stuff/tablelines @@ -0,0 +1,39 @@ +On branch master +nothing to commit, working directory clean +:02000 +Inferred input is intel HEX +Read HEX file (4 regions) +Opened ../pk2cmd/pk2cmd/PK2V023200.hex as pic16 +Loading pk2cmd_firmware ... +wow you're really using this, huh? +[32m00002334: jmp_tbl_1 +[0m00002334: bra [32m0x236a (ip+2+0x34)[0m +00002336: bra [32m0x23b6 (ip+2+0x7e)[0m +00002338: bra [32m0x2410 (ip+2+0xd6)[0m +0000233a: bra [32m0x2418 (ip+2+0xdc)[0m +0000233c: bra [32m0x2420 (ip+2+0xe2)[0m +0000233e: bra [32m0x2434 (ip+2+0xf4)[0m +00002340: bra [32m0x2464 (ip+2+0x122)[0m +00002342: bra [32m0x24a6 (ip+2+0x162)[0m +00002344: bra [32m0x24ae (ip+2+0x168)[0m +00002346: bra [32m0x24c2 (ip+2+0x17a)[0m +00002348: bra [32m0x24ca (ip+2+0x180)[0m +0000234a: bra [32m0x24d2 (ip+2+0x186)[0m +0000234c: bra [32m0x24da (ip+2+0x18c)[0m +0000234e: bra [32m0x24e2 (ip+2+0x192)[0m +00002350: bra [32m0x24e8 (ip+2+0x196)[0m +00002352: bra [32m0x24ee (ip+2+0x19a)[0m +00002354: bra [32m0x24f6 (ip+2+0x1a0)[0m +00002356: bra [32m0x2562 (ip+2+0x20a)[0m +00002358: bra [32m0x2574 (ip+2+0x21a)[0m +0000235a: bra [32m0x2586 (ip+2+0x22a)[0m +0000235c: bra [32m0x2598 (ip+2+0x23a)[0m +0000235e: bra [32m0x259e (ip+2+0x23e)[0m +00002360: bra [32m0x25b0 (ip+2+0x24e)[0m +00002362: bra [32m0x25b4 (ip+2+0x250)[0m +00002364: bra [32m0x25c4 (ip+2+0x25e)[0m +00002366: bra [32m0x265c (ip+2+0x2f4)[0m +00002368: bra [32m0x268a (ip+2+0x320)[0m +0000236a: incf [33mINDF2[0m, 0 +0000236c: clrf [33mFSR0H[0m +0000236e: addlw #0x0 |