diff --git a/firmware/DFU_release/INLretro6_PCBv2_0_FWv2_02.dfu b/firmware/DFU_release/INLretro6_PCBv2_0_FWv2_02.dfu new file mode 100644 index 0000000..e51900f Binary files /dev/null and b/firmware/DFU_release/INLretro6_PCBv2_0_FWv2_02.dfu differ diff --git a/firmware/release/avr_kazzo_FWv2_02.hex b/firmware/release/avr_kazzo_FWv2_02.hex new file mode 100644 index 0000000..f0c4b03 --- /dev/null +++ b/firmware/release/avr_kazzo_FWv2_02.hex @@ -0,0 +1,827 @@ +:100000000C9476000C947D180C9493000C9493003F +:100010000C9493000C9493000C9493000C94930014 +:100020000C9493000C9493000C9493000C94930004 +:100030000C9493000C9493000C9493000C949300F4 +:100040000C9493000C9493000C9493000C949300E4 +:100050000C9493000C9493000C9493000C949300D4 +:100060000C9493000C9493000C9493000C949300C4 +:100070000C9493000C9493000C94930009021200CA +:10008000010100806409040000000000000012016A +:100090001001FF000008C016DC050102010200018A +:1000A0001E0349004E004C00200052006500740001 +:1000B00072006F002D00500072006F0067002A036D +:1000C00049006E00660069006E00690074006500FA +:1000D0004E00650073004C006900760065007300F7 +:1000E0002E0063006F006D000403090411241FBE7D +:1000F000CFEFD4E0DEBFCDBF11E0A0E0B1E0E8E893 +:10010000F3E302C005900D92A630B107D9F723E0C2 +:10011000A6E0B1E001C01D92A43EB207E1F70E9443 +:1001200091190C94C2190C94000080E00895089570 +:100130000F931F93CF93DF93EC01FB01D901009143 +:100140004D0110914E01888187FF09C08E818C93EB +:10015000442399F00481158180E883831DC08FEFCB +:100160008C938E8180933801442309F44BC07093A3 +:100170006A036093690380E9F0CFE0912501F09173 +:1001800026018381883DA1F50481158180E8838360 +:10019000E0912501F09126011782E0912501F0916F +:1001A000260183818039F1F48A81813711F080340E +:1001B000C9F4E0916903F0916A030480F581E02DB0 +:1001C0008C818083E0916903F0916A030480F5815A +:1001D000E02D8D818183E0916903F0916A0387812D +:1001E0008E5F8783C801DF91CF911F910F91089592 +:1001F000803D11F41C92CCCF8FEF8C9380E10E9454 +:10020000E611C6CFE0912501F0912601838181118D +:1002100006C0F0936A03E093690380E9B8CF883998 +:1002200069F7E8CFE9E5F1E08FEF819391E0E936F6 +:10023000F907D9F780934C0180932B0180934B01F0 +:1002400080932A0180933C018093180180933B01A5 +:100250008093170181E00C94E611CF93DF93FC01AA +:1002600050E0CA01820F911D4197E4F52223E1F18C +:1002700083818F3FD9F582818F3FD1F5DA01A75A6B +:10028000BE4FED0180E099919F3FA1F58F5F28134C +:10029000FACF62831382982F9295990F907E915096 +:1002A0009683178210861182108211861286138619 +:1002B000148615861686178695E0440F551F9A9565 +:1002C000E1F72091000130910101420F531F558346 +:1002D000448390E06D939F5F8913FCCF80E0DF91B2 +:1002E000CF9108958EEBFBCF82ECF9CF8FEBF7CF58 +:1002F00080ECF5CF81ECF3CFCF93DF93DC01EB0102 +:100300009A0112969C91129780ED890F803318F50F +:1003100013968C911397813041F0E8F08230A9F068 +:100320008330B1F085EB888346C0E8E2F1E0913597 +:1003300009F476C048F5913309F449C078F499235B +:10034000B9F19033E1F184EBEECFE9E3F1E0EFCFE7 +:10035000E5E1F1E0ECCFE9E4F1E0E9CF933309F432 +:1003600046C0E8F1903579F7188286E08983868166 +:100370008A8383818B8387818C8380858D8382812F +:100380008E8387858F8317C0903808F05FC09037C1 +:1003900008F055C0903679F19136C9F1923599F649 +:1003A000188282E0898380818A8381818B8303C064 +:1003B0000E9412011882CE01DF91CF910895149608 +:1003C0008C91149715969C9191878287F3CF149600 +:1003D0008C91149715969C9193878487EBCF1496F4 +:1003E0008C91149715969C9195878687E3CF1496E8 +:1003F0008C918787DFCF188281E089831496ED91F5 +:10040000FC911597E75AFE4F80818A83D4CF1882DA +:1004100081E08983E0912501F09126018381F5CF68 +:10042000188286E0898381858A8382858B83838590 +:100430008C8384858D8385858E838685A3CF40E0DC +:10044000BF01CD01DF91CF910C949800892F877067 +:10045000813049F0F8F0823001F1833009F062CF49 +:10046000E5E1F1E002C0E8E2F1E0903808F4A3CF62 +:100470009838B0F09059983008F09DCF18821396B4 +:100480008C911397808714968D919C9115979183E9 +:10049000808391CFE9E4F1E0E8CFE9E3F1E0E5CF53 +:1004A00014964C91149715966C91159713962C9160 +:1004B000CF010E942D0137CF90914C0180912B01EB +:1004C0008F3F79F481E09F3F09F480E090913C01F7 +:1004D0009F3F09F083E0909118019F3F09F084E06D +:1004E000089582E0F3CF623059F421E08934920715 +:1004F00049F121E08832920789F489E491E00EC045 +:10050000633069F421E089349207E1F021E0883218 +:100510009207D9F021E08933920779F30895643086 +:10052000E9F721E08934920769F021E088329207E7 +:1005300061F021E08933920759F021E0853192077B +:1005400069F7DBCF88E291E0089589E391E00895AF +:1005500085E191E008951F93CF93DF930E94EC1102 +:10056000823D09F071C00E945C028093060189E41B +:1005700091E090932601809325010E94EC11823D29 +:10058000A1F4D09106018091250190912601C1E04E +:10059000CD1708F45FC0909326018093250120E8D1 +:1005A000FC01238380ED0E94E6110E94EC11823F42 +:1005B00041F480EF0E94E611E0912501F0912601BF +:1005C00013820E94EC11C82F803DE1F48091250137 +:1005D00090912601FC0123812038A1F4609106014D +:1005E0000E9473029093260180932501FC011782DB +:1005F000C3830E944403E0912501F09126018823E2 +:1006000071F183830E94EC11182F803FC9F4C091CF +:100610002501D09126018B81883991F460910601E2 +:10062000CE010E9473029093260180932501FC0164 +:1006300013821B83CE010E94D5088823C9F08B83C7 +:10064000DF91CF911F9108950E94EC11823F09F034 +:1006500094CF89CF6D2F0E947302CF5F99CF2085F1 +:1006600080819181820F911D9183808388EDC9CF14 +:1006700084EF8B83288588819981820F911D9983CE +:100680008883DECF88E80895CF92DF92EF920F93B0 +:100690001F93CF93DF931F92CDB7DEB76C01DC01C0 +:1006A0000D911C911197602F1996EC918E2F90E06F +:1006B000FC017097E631F10508F017C1EE59FC4FC7 +:1006C0000C94BC19DD032E044E045104750475040A +:1006D0007504750475047504750475047504750452 +:1006E00075047504780385039F03B203B903CE0331 +:1006F000F6016585603108F002C1F0E16F9FB0013D +:100700001124602B0FEFD60120C0D6011D966C91ED +:100710001D97862F837C8111F2C0602B0FEF1696F8 +:100720002C91169712964C91129714968D919C913C +:1007300015970E94340EF601878380E0D7C0D6015A +:100740001D966C911D97602B0FEF16962C911697A6 +:1007500012964C91129714968D919C9115970E9428 +:10076000FC0DE9CFD6011D966C911D97862F807CDC +:10077000D2CFD6011D966C911D97602BEE24EA9482 +:1007800016960C91169712962C91129740E014969B +:100790008D919C9115970E941E15CDCFD6011D9667 +:1007A0006C911D97602BEE24EA9416960C91169787 +:1007B00012962C91129741E0EACFD6011D968C91AA +:1007C0008E31E1F4202F2F7BB80146E076956795B6 +:1007D0004A95E1F780E090EC29830E949A0D2981E7 +:1007E000622F60680FEFF601268142818481958136 +:1007F0000E94FC0DD60117968C939FCF8C31A1F4EB +:1008000061E880E090E50E949A0DB801660F672FBD +:10081000661F770B719580E090E80E949A0D60E06A +:1008200080E090E50E949A0DF6018585102F8F31AA +:1008300039F010680FEFF60126814281612FD6CF83 +:100840001F7810686081718124E0769567952A95FC +:10085000E1F780E090E50E949A0DECCFF6018585E6 +:100860008E3F09F06ACFB80195E0769567959A9525 +:10087000E1F78FEF9FE30E94C40D602F6F710FEFC0 +:10088000D60116962C91169712964C9112971496A3 +:100890008D919C9115970E946C0E4DCF602F6066D4 +:1008A00031CFD6011D968C91811119C0602F6068DF +:1008B000000F012F001F110B1195202F8FEF84B90E +:1008C00025B95F9A5F9814B8EE24EA94F601068180 +:1008D000228140E0848195810E941E158BCF81305A +:1008E00069F7212F2F732064E9CF83EC0F90DF91FC +:1008F000CF911F910F91EF90DF90CF90089584ECEE +:10090000F5CFCF92DF92EF92FF920F931F93CF9389 +:10091000DF937B016A01DB011796CC91D0E0082FB1 +:1009200010E0102F0027D70116968C91169790E0B3 +:100930008C179D0760F41796CC9380E0DF91CF91E0 +:100940001F910F91FF90EF90DF90CF900895CE010F +:100950009927D7011496ED91FC911597E80FF91F8F +:100960006081802B912BF60109952196DCCF4F9267 +:100970005F926F927F928F929F92AF92BF92CF922F +:10098000DF92EF92FF920F931F93CF93DF934A0171 +:100990003901E8015F80A52CB12C8501162B8E81D1 +:1009A000851598F45F8280E0DF91CF911F910F91C0 +:1009B000FF90EF90DF90CF90BF90AF909F908F907F +:1009C0007F906F905F904F9008956AEAC401F7019D +:1009D000099565E5C301F701099560EAC401F701CE +:1009E0000995EC81FD81EA0DFB1D6081C801F701CD +:1009F00009950E945E17C801F6010995482EC801A5 +:100A0000F60109954812F5CFCACF2F923F924F9227 +:100A10005F926F927F928F929F92AF92BF92CF928E +:100A2000DF92EF92FF920F931F93CF93DF93CDB797 +:100A3000DEB727970FB6F894DEBF0FBECDBF582E96 +:100A40004A013C832B831F830E83D80117964C9059 +:100A5000042D10E070E0F62FEE27FA83E983252CB1 +:100A6000312CF7E92F1AF2E03F0AAE81BF811696CA +:100A70008C91169790E080179107E0F417964C92AE +:100A800080E027960FB6F894DEBF0FBECDBFDF9192 +:100A9000CF911F910F91FF90EF90DF90CF90BF907B +:100AA000AF909F908F907F906F905F904F903F900E +:100AB0002F90089560E089E69DEF0E949A0D6AEA02 +:100AC000C401F701099565E58B819C81F7010995C2 +:100AD00060EAC401F7010995652DC1010E949A0DD4 +:100AE000642C712CA980BA80A628B728AE81BF815A +:100AF0001496ED91FC911597E60DF71D6081C501E7 +:100B0000F70109950E945E17C501F6010995282F86 +:100B1000C5012D83F60109952D812813F3CFAE81F0 +:100B2000BF8114968D919C911597680E791EF301E3 +:100B30008081281307C043940F5F1F4F5198599A23 +:100B4000599893CF519A599A90CF2F923F924F92A2 +:100B50005F926F927F928F929F92AF92BF92CF924D +:100B6000DF92EF92FF920F931F93CF93DF9300D00A +:100B700000D01F92CDB7DEB7382E4A0129011D8360 +:100B80000C83D80117962C90022D10E070E0F62F00 +:100B9000EE27FA83E983AC81BD8116968C91169776 +:100BA00090E080179107D8F417962C9280E00F9070 +:100BB0000F900F900F900F90DF91CF911F910F9199 +:100BC000FF90EF90DF90CF90BF90AF909F908F906D +:100BD0007F906F905F904F903F902F90089561E0CD +:100BE00080E090EC0E949A0D6AEAC401F701099531 +:100BF00060E080E090EC0E949A0D65E5C201F7018B +:100C0000099561E080E090EC0E949A0D60EAC401D1 +:100C1000F7010995632D80E090EC0E949A0D622CFB +:100C2000712CA980BA80A628B728AC81BD81149602 +:100C3000ED91FC911597E60DF71D6081C501F70157 +:100C400009950E945E17C501F6010995282FC50177 +:100C50002B83F60109952B812813F3CFAC81BD813D +:100C600014968D919C911597680E791EF3018081E1 +:100C7000281307C023940F5F1F4F5198599A599812 +:100C80008ACF519A599A87CF3F924F925F926F9233 +:100C90007F928F929F92AF92BF92CF92DF92EF920C +:100CA000FF920F931F93CF93DF93482E662E7A0106 +:100CB000E901DA0117965C90A52CB12C6AEA8AEA60 +:100CC0009AE8F901099565E585E595E8FE0109953C +:100CD00060E28AEA9AE8FE010995712C762C662476 +:100CE000D70116968C91169790E08A159B0520F5F2 +:100CF00017965C9260E980E090E8FE01099560E05B +:100D000080E090E8FE01099560EF80E090E8FE0148 +:100D1000099580E0DF91CF911F910F91FF90EF90A7 +:100D2000DF90CF90BF90AF909F908F907F906F900B +:100D30005F904F903F90089564E580E090E50E94B9 +:100D40009A0D852C912C6401C628D72860EAC6012B +:100D5000FE010995D7011496ED91FC911597E80DC8 +:100D6000F91D6081C601FE0109950E945E17C6014A +:100D7000F8010995382EC601F80109953812F5CF0A +:100D8000D70114968D919C911597880E991EF401A8 +:100D90008081381208C05394FFEFAF1ABF0A5198F0 +:100DA000599A59989DCF61E880E090E50E949A0D8C +:100DB000642D80E090E80E949A0D64E580E090E563 +:100DC0000E949A0D519A599A8BCF4F925F926F92CF +:100DD0007F928F929F92AF92BF92CF92DF92EF92CB +:100DE000FF920F931F93CF93DF93662E7A01E90151 +:100DF000DA0117965C90A52CB12C6AEA8AEA9AE887 +:100E0000F901099565E585E595E8FE01099560E23A +:100E10008AEA9AE8FE010995712C762C6624D7019E +:100E200016968C91169790E08A159B0518F51796E3 +:100E30005C9260E980E090E8FE01099560E080E066 +:100E400090E8FE01099560EF80E090E8FE010995C9 +:100E500080E0DF91CF911F910F91FF90EF90DF9095 +:100E6000CF90BF90AF909F908F907F906F905F904A +:100E70004F900895852C912C6401C628D72860EAEC +:100E8000C601FE010995D7011496ED91FC911597C5 +:100E9000E80DF91D6081C601FE0109950E945E17EB +:100EA000C601F8010995482EC601F80109954812B6 +:100EB000F5CFD70114968D919C911597880E991EA8 +:100EC000F4018081481208C05394FFEFAF1ABF0AA3 +:100ED0005198599A5998A3CF519A599AA0CF4F92A5 +:100EE0005F926F927F928F929F92AF92BF92CF92BA +:100EF000DF92EF92FF920F931F93CF93DF93662EB3 +:100F00007A01E901DA0117965C90A52CB12C6AEA06 +:100F10008AEA9AE0F901099565E585E595E0FE0123 +:100F2000099560E28AEA9AE0FE010995712C762C17 +:100F30006624D70116968C91169790E08A159B052A +:100F400018F517965C9260E980E090E0FE01099543 +:100F500060E080E090E0FE01099560EF80E090E0C5 +:100F6000FE01099580E0DF91CF911F910F91FF90D5 +:100F7000EF90DF90CF90BF90AF909F908F907F9039 +:100F80006F905F904F900895852C912C6401C62836 +:100F9000D72860EAC601FE010995D7011496ED91A4 +:100FA000FC911597E80DF91D6081C601FE010995B8 +:100FB0000E945E17C601F8010995482EC601F80186 +:100FC00009954812F5CFD70114968D919C911597EC +:100FD000880E991EF4018081481208C05394FFEFD7 +:100FE000AF1ABF0A5198599A5998A3CF519A599A52 +:100FF000A0CF4F925F927F928F929F92AF92BF92BB +:10100000CF92DF92EF92FF920F931F93CF93DF93D4 +:10101000A62E6A01E901DA011796EC90F12CA89549 +:1010200000000000000000000000000000000000C0 +:10103000000040E06AEA8AEA9AE8F901099540E08E +:1010400065E585E595E8FE01099540E060E28AEAFC +:101050009AE8FE010995B12CBA2CAA24D60116965D +:101060008C91169790E08E159F0530F51796EC92AF +:1010700040E060E980E090E8FE01099540E060E032 +:1010800080E090E8FE01099540E060EF80E090E8A4 +:10109000FE010995000080E0DF91CF911F910F9133 +:1010A000FF90EF90DF90CF90BF90AF909F908F9088 +:1010B0007F905F904F90089560E080EA0E940F1546 +:1010C0002701552442018A289B28D6011496ED91C8 +:1010D000FC911597E40DF51D40E06081C401FE010F +:1010E0000995000000000000000000000000000062 +:1010F00000000000A8950E945E1760E0C401F8019E +:101100000995782E0000000000000000000000009B +:10111000000000000000D6011496ED91FC91159797 +:10112000E40DF51D80817816C1F00000000000007C +:1011300000000000000000000000000060E0C401AA +:10114000F801099578120DC00000000000000000B1 +:1011500000000000000000000000FFEFEF1AFF0A8F +:101160007DCF000000000000000000000000000033 +:10117000000000000000000000000000000000006F +:10118000000000000000000000000000000000005F +:10119000000000000000000000000000000060E00F +:1011A000C401F8010995782EC9CFBF92CF92DF9282 +:1011B000EF92FF920F931F93CF93DF93EC01B880D0 +:1011C0008985823109F43CC138F48031A9F081313C +:1011D00009F4E6C083EC06C0833109F439C18431D7 +:1011E000C9F780E0DF91CF911F910F91FF90EF90B1 +:1011F000DF90CF90BF9008958D85811107C046EC98 +:101200005EE0BE0180E88B0D0E9481048D858130F7 +:1012100039F444E15FE0BE0180E88B0D0E94810457 +:101220008D85833039F445E75FE0BE0180E88B0DA2 +:101230000E9481048D85843039F44CEF5FE0BE015B +:1012400080E88B0D0E9481048D858A3039F44FE44B +:1012500050E1BE0180E88B0D0E9481048D858D3F99 +:10126000D1F46B2D6F736068B62E8881998116E07A +:10127000969587951A95E1F708E8C02E0DE0D02ED7 +:101280009FE5E92E9DE0F92E8E012AEA3AE245E536 +:1012900055E50E9405058D858E31D1F46B2D6F7358 +:1012A0006068B62E88819981F6E096958795FA95C3 +:1012B000E1F7A8E8CA2EADE0DA2EBAE9EB2EBDE0E0 +:1012C000FB2E8E012AEA3AEA45E555E90E94A5057A +:1012D0008D858C3031F56B2D6F716068B62EE8808E +:1012E000F98065E0F694E7946A95E1F765EA80E0B5 +:1012F00090E60E949A0D6E2D8FEF9FEF0E949A0D3F +:1013000078E8C72E7DE0D72EEAE9EE2EEDE0FE2E3E +:101310008E012AEA3AEA45E555ED6B2D80E00E9400 +:10132000B7048D858C3101F5E880F980EE0CEF2C47 +:10133000EE1CFF08F19461E880E090E50E949A0DB0 +:101340006E2D80E090E80E949A0D64E580E090E5C3 +:101350000E949A0D08E81DE02AE93DE0AE016B2DE0 +:1013600060688E2D0E9444068D858F3109F039CF3B +:10137000E880F98044E0F694E7944A95E1F76E2D11 +:1013800080E090E50E949A0D6B2D6F78606808E808 +:101390001DE02AE93DE0AE018E2D0E94E50621CF39 +:1013A0008D85811106C04DEE5EE0BE018B2D0E9441 +:1013B00081048D85813031F441E45FE0BE018B2DE5 +:1013C0000E9481048D85823031F440EB5FE0BE01E4 +:1013D0008B2D0E9481048D85843031F448E250E1E8 +:1013E000BE018B2D0E9481048D858A3031F44CE73B +:1013F00050E1BE018B2D0E9481048D858B3031F42C +:1014000049EB50E1BE018B2D0E9481048D858E3FFA +:1014100009F0E7CE6881798135E0769567953A9550 +:10142000E1F78FEF9FE30E94C40D6B2D6F7108ED04 +:101430001DE02AEE3DE0AE0180E00E946F07D1CEB4 +:101440004AE95DE0BE0180E68B0D0E948104C9CEB1 +:101450008D85843039F44FE555E1BE0180E88B0D70 +:101460000E9481048D85853031F44FE555E1BE0140 +:101470008B2D0E9481048D85863039F44CE855E12E +:10148000BE0180E88B0D0E9481048D85873031F488 +:101490004CE855E1BE018B2D0E9481048D858111A0 +:1014A00019C08B2D8068B82E88819981880F892F6B +:1014B000881F990B91959FEF94B985B95F9A5F98B2 +:1014C00014B80AED14E126EF34E1AE016B2D80E093 +:1014D0000E94F9078D85813009F083CE89818F7351 +:1014E00080649FEF94B985B95F9A5F9814B80AED4C +:1014F00014E126EF34E1AE016B2D80E00E94F90784 +:1015000070CE882321F0813041F480E0089591E08D +:10151000F90190839AEA918308958FEA08958AEAFF +:1015200008950895882321F0813041F480E00895E2 +:1015300091E0F90190839AEA9183089580EB0895F0 +:101540008AEA089508953898409A3998419A3A98C5 +:10155000429A3C98449A3D98459A3E98469A5398A8 +:101560005B9A55985D9A3B98439A3F98479A57984B +:101570005F9A5098589814B88FEF85B93F9A47985A +:1015800081B911B882B914B885B914B885B9519820 +:10159000599A08950E94A30A399A419A389A409814 +:1015A0003A9A429A3C9A449A3D9A459A14B88FEFD7 +:1015B00085B914B885B914B885B93F9A479881B9E7 +:1015C00012B884B915B8479A479814B808950E947C +:1015D000A30A399A419A3C9A449A3D9A459A589A54 +:1015E000509A14B88FEF85B914B885B914B885B975 +:1015F0003F9A479881B912B884B915B8479A479865 +:1016000014B814B885B9579A5F9884B915B85F9A19 +:101610005F9814B80895823081F0833061F0813092 +:10162000A1F40898109A1092B90380E290E0909388 +:10163000B8038093B70380E008955098589A88E0E3 +:101640008093B90389E290E0F2CF87E90895813071 +:1016500049F414B88FEF85B9579A5F980E94A00B90 +:1016600080E0089588E908955898509A000089B15B +:101670005098589880FD22C05098589A59B149B155 +:10168000000039B10000000029B100000000000096 +:1016900099B1000000000000000089B150985898EE +:1016A00050FD0EC040FD0EC030FD0EC020FD0EC02E +:1016B00090FD0EC080FD0EC080EE089580EF08956D +:1016C00080E0089581E0089583E0089586E008951C +:1016D0008AE008958FE008950F931F93CF93C82F4A +:1016E000842F8901C230F9F030F4CC2389F0C13065 +:1016F000B1F0C6E90FC0C430F1F0C0F0C038C9F78E +:1017000081E0F90180830E94340BF801818309C0D4 +:101710000E94A30A8C2FCF911F910F9108950E94D0 +:10172000CA0AC0E0F7CF0E94E70AFBCFCF911F9112 +:101730000F910C940B0BCF911F910F910C94270BD1 +:10174000109214018FEF84B915B85F9A5F9814B89E +:101750005098589A80E880936C0310927A03EBE7D4 +:10176000F3E0119283E0EB39F807D9F7089560911F +:101770007A03813109F441C0109214019FEF94B9AA +:101780009091140195B95F9A5F9814B820E070E0C9 +:101790003FEF8032C9F4E72FF0E0E558FC4F40817D +:1017A00050E0022E02C0559547950A94E2F740FF9B +:1017B00028C092E034B995B95F9A5F9814B82F5F4A +:1017C000283011F47F5F20E0492F446034B945B9D7 +:1017D0005F9A5F9814B8615034B995B95F9A5F9871 +:1017E00014B86111D6CF909314014093270134B9F6 +:1017F00015B85F9A5F9814B8089592E09093140119 +:10180000BDCF90E0D7CF0F931F93CF93DF9350912D +:101810007A03B0917B03813109F46BC010921401FB +:101820009FEF94B99091140195B95F9A5F9814B89D +:1018300020E030E07FEFC1E0D0E0803281F4EB2F98 +:10184000F0E0022E02C0F595E7950A94E2F7E0FF7A +:1018500054C0916074B995B95F9A5F9814B86032BA +:10186000B1F4211105C0E32FF0E0E558FC4F1082E0 +:10187000489B0DC0E32FF0E0E558FC4FA0818E019E +:10188000022E01C0000F0A94EAF7A02BA08351504A +:10189000442341F0511106C0926074B995B95F9A22 +:1018A0005F9814B8A92FA46074B9A5B95F9A5F981E +:1018B00014B874B995B95F9A5F9814B82F5F28303F +:1018C00039F43F5FE32FF0E0E558FC4FB08120E0B2 +:1018D0005111B3CF90931401A09327018FEF84B9D6 +:1018E00015B85F9A5F9814B8DF91CF911F910F914F +:1018F000089591E09093140193CF9E7FABCF809198 +:101900006C038338D1F580916D03883009F463C08E +:10191000C0F4833009F445C030F4813079F182306D +:10192000A1F18EEE28C0863009F44AC008F04EC0FE +:101930008430B9F781E880936C0341E060E281E193 +:1019400036C08F30C1F148F48D3031F18E3049F717 +:1019500081E880936C0340E028C0803849F08F3FD5 +:1019600049F08031F1F681E880936C0340E02CC0AF +:101970000C94A00B80EF80936C03089581E8809312 +:101980006C0380E20E94B70B14C081E880936C0363 +:1019900041E060E080E20BC081E880936C0340E0AE +:1019A000F8CF81E880936C0341E060E280E10E941F +:1019B000030C82E8E0CF81E880936C0340E0BECF67 +:1019C00081E880936C0341E060E2E4CF81E880939A +:1019D0006C0380E1D7CF81E880936C0381E1D2CFA3 +:1019E000CF93DF93E901843061F138F48230E1F084 +:1019F00008F58130A1F087E80FC0873039F128F46D +:101A00008530C9F740937A0306C0883021F18038C9 +:101A100091F70E94A00B80E0DF91CF910895909103 +:101A20006D0399838883F7CF40936D0383E8809398 +:101A30006C03F1CF40936D0383E880936C030E94A5 +:101A40007F0C80916C03898381E0ECCF40937B0312 +:101A500050937C03E0CF80917B03898380917C034A +:101A60008A8380917D038B8380917E038C83809118 +:101A70007F038D83809180038E8386E0D3CF88237C +:101A800021F0813041F480E0089591E0F9019083E4 +:101A90009AEA9183089582EB08958AEA0895089559 +:101AA00082B98FEF84B995B9479A479814B884B929 +:101AB00065B9509A58985098589A14B8089582B9B0 +:101AC0008FEF84B995B9479A479814B884B965B926 +:101AD000509A5898589A14B8089550985898409821 +:101AE000419A429A82B92FEF24B995B9479A4798FB +:101AF00014B800000000409A97FD419800000000D3 +:101B0000000000000000000083B14098419A089551 +:101B100082B92FEF24B995B9479A479814B8409ADB +:101B200097FD4198000000000000000083B140983C +:101B3000419A08955098589882B92FEF24B995B9D1 +:101B4000479A479814B8429824B965B9409A97FDC6 +:101B50004198000000004098419A429A14B80895B4 +:101B6000811520E2920708F4906882B98FEF84B95A +:101B700095B9479A479814B84498000000000000AF +:101B8000000083B1449A0895811520E2920708F479 +:101B9000906882B98FEF84B995B9479A479814B87D +:101BA00084B965B9000045980000459A14B80895B5 +:101BB00082B98FEF84B995B9479A479814B8409A7B +:101BC0004198449800000000000083B1449A409876 +:101BD000419A089582B98FEF84B995B9479A479889 +:101BE00014B84098419884B965B900004598000040 +:101BF000459A14B8419A0895EF92FF920F93CF93AC +:101C0000DF9300D01F92CDB7DEB77C018FEF84B990 +:101C100065B9479A479814B8409A67FD419842B908 +:101C2000000080E0011117C00000000093B1F7012F +:101C3000E80FF11D90834F5F42B98F5F281790F72F +:101C40004098419A0F900F900F90DF91CF910F9194 +:101C5000FF90EF9008952B834A8389830E945E173B +:101C600089814A812B81E2CFEF92FF920F93CF932C +:101C7000DF9300D01F92CDB7DEB77C01603208F44D +:101C800060688FEF84B965B9479A479814B844984B +:101C900042B9000080E0011116C00000000093B1BD +:101CA000F701E80FF11D90834F5F42B98F5F28174E +:101CB00090F7449A0F900F900F90DF91CF910F9172 +:101CC000FF90EF9008952B834A8389830E945E17CB +:101CD00089814A812B81E3CFEF92FF920F93CF93BB +:101CE000DF9300D01F92CDB7DEB77C018FEF84B9B0 +:101CF00065B9479A479814B8409A4198449842B9B0 +:101D0000000080E0011118C00000000093B1F7014D +:101D1000E80FF11D90834F5F42B98F5F281790F74E +:101D2000449A4098419A0F900F900F90DF91CF9175 +:101D30000F91FF90EF9008952B834A8389830E942F +:101D40005E1789814A812B81E1CF0F931F93CF9337 +:101D5000DF938C01D62F442349F080E090E80E9465 +:101D6000880D60E880E090E80E949A0DC5E0C80107 +:101D70000E94880D6D2FC8010E949A0DD695C15002 +:101D8000B1F7DF91CF911F910F9108951F93CF93DA +:101D9000DF93EC01162F6AEA85E595E50E94500D68 +:101DA00065E58AEA9AE20E94500D60EA85E595E5CC +:101DB0000E94500D612FCE010E94500DCE010E9455 +:101DC000880D182F0E945E17CE010E94880D1813EF +:101DD000F5CFDF91CF911F9108951F93CF93DF939C +:101DE000EC01162F6AEA85E595E10E94C40D65E5D0 +:101DF0008AEA9AE00E94C40D60EA85E595E10E94B6 +:101E0000C40D612FCE010E94C40DCE010E94B00D01 +:101E1000182F0E945E17CE010E94B00D1813F5CF47 +:101E2000DF91CF911F9108951F93CF93DF93EC0122 +:101E3000162F40E065E080E090EC0E94A50E6AEA73 +:101E400085E595E50E949A0D65E58AEA9AEA0E9481 +:101E50009A0D60EA85E595E50E949A0D612FCE0105 +:101E60000E949A0DCE010E94880D182F0E945E17C5 +:101E7000CE010E94880D1813F5CFDF91CF911F91ED +:101E800008951F93CF93DF93EC01162F40E062E09B +:101E900080E090EA0E94A50E6AEA85E595E10E943D +:101EA000C40D65E58AEA9AE00E94C40D60EA85E502 +:101EB00095E10E94C40D40E060919D0380E090EAAE +:101EC0000E94A50E612FCE010E94C40DCE010E947A +:101ED000B00D182F0E945E17CE010E94B00D18138E +:101EE000F5CFDF91CF911F9108951F93CF93DF938B +:101EF000EC01162F60E080919B0390919C030E945F +:101F00009A0D6AEA85E595E50E94500D65E58AEA35 +:101F10009AE20E94500D60EA85E595E50E94500D19 +:101F200090919D0320919B0330919C03692FA901FF +:101F3000490F511DCA010E949A0D612FCE010E94C6 +:101F4000500DCE010E94880D182F0E945E17CE0101 +:101F50000E94880D1813F5CFDF91CF911F9108953E +:101F60001F93CF93DF93EC01162F80919B039091E9 +:101F70009C0362E002960E949A0D6AEA85E595E16B +:101F80000E94C40D80919B0390919C0361E0019697 +:101F90000E949A0D65E58AEA9AE00E94C40D80913C +:101FA0009B0390919C0362E002960E949A0D60EA66 +:101FB00085E595E10E94C40D90919D0320919B03BE +:101FC00030919C03692FA901490F511DCA010E943C +:101FD0009A0D612FCE010E94C40DCE010E94B00D5A +:101FE000182F0E945E17CE010E94B00D1813F5CF76 +:101FF000DF91CF911F9108951F93CF93DF93EC0151 +:10200000162F6AEA85E595ED0E949A0D65E58AEA44 +:102010009AEA0E949A0D60EA85E595ED0E949A0D74 +:10202000612FCE010E949A0D60E080E090E80E944E +:102030009A0DCE010E94880D182F0E945E17CE01C6 +:102040000E94880D1813F5CFDF91CF911F9108954D +:102050001F93CF93DF93EC01162F6AEA85E595E194 +:102060000E94C40D65E58AEA9AE10E94C40D60EA07 +:1020700085E595E10E94C40D612FCE010E94C40D3B +:10208000CE010E94B00D182F0E945E17CE010E9453 +:10209000B00D1813F5CFDF91CF911F9108951F93C5 +:1020A000CF93DF93EC01162F6AEA8AEA9AEF0E9437 +:1020B0009A0D65E585E595EF0E949A0D60EA8AEA3A +:1020C0009AEF0E949A0D612FCE010E949A0D6091A5 +:1020D0009D0380E090EA0E949A0DCE010E94880D37 +:1020E000182F0E945E17CE010E94880D1813F5CF9D +:1020F000DF91CF911F9108951F93CF93DF93EC0150 +:10210000162F6AE080E090EB0E949A0D6AE080E072 +:1021100090EC0E949A0D6AEA85E595E10E94C40D53 +:1021200065E58AEA9AE00E94C40D60EA85E595E1DA +:102130000E94C40D60919D0380E090EB0E949A0D77 +:1021400060919D0380E090EC0E949A0D612FCE017A +:102150000E94C40DCE010E94B00D182F0E945E1780 +:10216000CE010E94B00D1813F5CFDF91CF911F91D2 +:1021700008950F931F93CF93DF938C01D62FC091B7 +:102180009D03C295C07F80919B0390919C0360E268 +:1021900080960E949A0D6AEA85E595E10E94C40D39 +:1021A00080919B0390919C0360E140960E949A0D60 +:1021B00065E58AEA9AE00E94C40D80919B039091A4 +:1021C0009C0360E280960E949A0D60EA85E595E1A5 +:1021D0000E94C40D80919B0390919C036C2F8C0FE7 +:1021E000911D0E949A0D6D2FC8010E94C40DC80157 +:1021F0000E94B00DC82F0E945E17C8010E94B00D4A +:10220000C813F5CFDF91CF911F910F9108950F93D0 +:102210001F93CF93C82FCA018901CD3009F486C01E +:1022200060F5C63009F466C0A0F4C23009F469C094 +:1022300040F4CC2309F457C0C13009F45FC0C0EAB0 +:1022400054C0C43009F460C0C530C9F70E94EA0D1B +:1022500053C0C93009F461C040F4C73009F46CC000 +:10226000C83069F70E94281047C0CB3009F461C01C +:1022700008F456C00E94B9103FC0C13209F448C0EA +:10228000A0F4C03109F45BC040F4CE3009F44BC077 +:10229000CF30A9F60E94410F2FC0C13109F452C0BE +:1022A000C03269F640939D0327C0C23809F455C077 +:1022B00058F4C03809F449C0C13809F621E0F801E2 +:1022C00020830E94880D46C0C53809F44CC0C6382A +:1022D00009F44FC0C43809F0B2CF21E0F8012083DF +:1022E0000E94D80D37C00E94500D8C2FCF911F91A6 +:1022F0000F9108950E945F0DC0E0F7CF0E94C40DBA +:10230000FBCF0E949A0DF8CF40E00E94A50EF4CFBB +:1023100040939B0390939C03EFCF0E94C60EECCF9B +:102320000E94ED0EE9CF0E94140FE6CF0E94750FB8 +:10233000E3CF0E94B00FE0CF0E94FC0FDDCF0E94E0 +:102340004F10DACF0E947C10D7CF21E0F801208314 +:102350000E946D0DF8018183CFCF21E0F801208329 +:102360000E94B00DF7CF81E0F901808380919D0339 +:10237000F2CF82E0F901808380919B038183809179 +:102380009C038283B9CFCF93DF93FB01DC011296CC +:102390002C91222329F0203479F082ED808308C02B +:1023A0001082A0910201B0910301EC018C818C9309 +:1023B000CF01DF91CF910895108281E08183A091B8 +:1023C0000201B09103018C918283F2CFE09102016E +:1023D000F091030180830895E0910201F0910301DF +:1023E000808108950F931F93D901082F10E00831C1 +:1023F000110508F0C2C2F801E050FE4E0C94BC1961 +:102400003A1218127512D0121C136813B4135F1409 +:10241000641469146C14701473147B14831487147B +:102420008A148E1497149E14A214AA14B114B5140D +:102430004631510508F0A3C2FA01EF5DFD4E0C9440 +:10244000BC1937123D124112451249124D12511258 +:10245000551259125D126112651269126D12BF1484 +:10246000BF14BF14BF14BF14BF14BF147112389827 +:10247000409A80E01F910F9108953998419A80E029 +:10248000F9CF3A98429A80E0F5CF3B98439A80E0A2 +:10249000F1CF3C98449A80E0EDCF3D98459A80E09A +:1024A000E9CF3E98469A80E0E5CF3F98479A80E092 +:1024B000E1CF5098589A80E0DDCF5198599A80E04A +:1024C000D9CF53985B9A80E0D5CF55985D9A80E03C +:1024D000D1CF56985E9A80E0CDCF57985F9A80E032 +:1024E000C9CF5098589A80E0C5CF4631510508F0C1 +:1024F00048C2FA01E258FD4E0C94BC19941298128D +:102500009C12A012A412A812AC12B012B412B812EB +:10251000BC12C012C412C812C114C114C114C11417 +:10252000C114C114C114CC123898409880E0A2CFD5 +:102530003998419880E09ECF3A98429880E09ACFAF +:102540003B98439880E096CF3C98449880E092CFA7 +:102550003D98459880E08ECF3E98469880E08ACF9F +:102560003F98479880E086CF5098589880E082CF77 +:102570005198599880E07ECF53985B9880E07ACF4D +:1025800055985D9880E076CF56985E9880E072CF3F +:1025900057985F9880E06ECF5098589880E06ACF47 +:1025A0004631510508F0EFC1FA01E752FD4E0C9497 +:1025B000BC19EF12F212F512F812FB12FE120113FF +:1025C000041307130A130D13101313131613C31454 +:1025D000C314C314C314C314C314C3141913389AF3 +:1025E00080E048CF399A80E045CF3A9A80E042CFE8 +:1025F0003B9A80E03FCF3C9A80E03CCF3D9A80E020 +:1026000039CF3E9A80E036CF3F9A80E033CF509A60 +:1026100080E030CF519A80E02DCF539A80E02ACFCE +:10262000559A80E027CF569A80E024CF579A80E0D1 +:1026300021CF509A80E01ECF4631510508F0A5C148 +:10264000FA01EB5DFC4E0C94BC193B133E13411395 +:10265000441347134A134D1350135313561359136E +:102660005C135F136213C514C514C514C514C514D7 +:10267000C514C5146513409880E0FCCE419880E0F5 +:10268000F9CE429880E0F6CE439880E0F3CE4498AD +:1026900080E0F0CE459880E0EDCE469880E0EACE2E +:1026A000479880E0E7CE589880E0E4CE599880E0E3 +:1026B000E1CE5B9880E0DECE5D9880E0DBCE5E9878 +:1026C00080E0D8CE5F9880E0D5CE589880E0D2CE1A +:1026D0004631510508F05BC1FA01EF58FC4E0C94ED +:1026E000BC1987138A138D139013931396139913A0 +:1026F0009C139F13A213A513A813AB13AE13C714F7 +:10270000C714C714C714C714C714C714B113409A09 +:1027100080E0B0CE419A80E0ADCE429A80E0AACE71 +:10272000439A80E0A7CE449A80E0A4CE459A80E008 +:10273000A1CE469A80E09ECE479A80E09BCE589AE2 +:1027400080E098CE599A80E095CE5B9A80E092CE58 +:102750005D9A80E08FCE5E9A80E08CCE5F9A80E0BA +:1027600089CE589A80E086CE82E08C93463151051E +:1027700008F0A2C0FA01E154FC4E0C94BC19D51328 +:10278000DE13E713F013F91302140B1414141D14C1 +:1027900026142F14381441144A145C145C145C146D +:1027A0005C145C145C145C14531486B18170119633 +:1027B0008C93119712961C9280E05CCE86B1827049 +:1027C00090E012969C938E93119780E053CE86B141 +:1027D000847090E012969C938E93119780E04ACE7D +:1027E00086B1887090E012969C938E93119780E04A +:1027F00041CE86B1807190E012969C938E93119792 +:1028000080E038CE86B1807290E012969C938E93D1 +:10281000119780E02FCE86B1807490E012969C9341 +:102820008E93119780E026CE86B1807890E0129644 +:102830009C938E93119780E01DCE89B18170119683 +:102840008C93119712961C9280E014CE89B18270FD +:1028500090E012969C938E93119780E00BCE89B1F5 +:10286000887090E012969C938E93119780E002CE30 +:1028700089B1807290E012969C938E93119780E0BC +:10288000F9CD89B1807490E012969C938E93119744 +:1028900080E0F0CD89B1807890E012969C938E9381 +:1028A000119780E0E7CD89B1817011968C931197D3 +:1028B00012961C9280E0DECD1C928DE8DBCD14B820 +:1028C0008FEF85B980E0D6CD14B88FEF85B980E061 +:1028D000D1CD14B880E0CECD8FEF84B980E0CACDE1 +:1028E00045B980E0C7CD83B111968C93119781E0F3 +:1028F0008C9380E0BFCD14B88FEF85B93F9A47988D +:1029000081B980E0B7CD8FEF82B980E0B3CD11B847 +:1029100080E0B0CD8FEF81B980E0ACCD42B98FEFD0 +:1029200084B955B9479A479814B880E0A3CD14B834 +:102930008FEF85B9579A5F9880E09CCD57985F9A42 +:1029400080E098CD8FEF84B945B95F9A5F9814B84D +:1029500080E090CD14B88FEF85B9579A5F9880E0EA +:1029600089CD57985F9A80E085CD8FEF84B945B9BE +:102970005F9A5F9814B880E07DCD8CE87BCD8DE8C0 +:1029800079CD8DE877CD8DE875CD8DE873CD8DE867 +:1029900071CD882321F0813041F480E0089591E0E9 +:1029A000F90190839AEA9183089581EB08958AEA68 +:1029B0000895089582B98FEF84B995B9479A4798D9 +:1029C00014B8611101C04198449800000000000053 +:1029D00000000000000000000000000000000000F7 +:1029E0000000000083B1449A419A089582B98FEFA4 +:1029F00084B995B9479A479814B884B965B9459888 +:102A0000411101C0419800000000000000000000DA +:102A1000000000000000459A419A14B808959FEF05 +:102A200094B985B94598611101C041980000000032 +:102A300000000000459A419A14B80895CF92DF92A1 +:102A4000EF920F93CF93DF9300D0CDB7DEB76C0139 +:102A50008FEF84B965B9479A479814B844984111E3 +:102A600001C0419822B980E0E1101FC000000000C1 +:102A70000000000000000000000000000000000056 +:102A800093B1F601E80FF11D90832F5F22B98F5F9C +:102A9000081750F7449A419A0F900F90DF91CF9109 +:102AA0000F91EF90DF90CF9008952A8389830E9441 +:102AB0005E1700000000000089812A81DBCF1F9390 +:102AC000CF93DF93EC01162F40E06AEA85E595E5A8 +:102AD0000E94F61440E065E58AEA9AE20E94F61444 +:102AE00040E060EA85E595E50E94F61440E0612F3C +:102AF000CE010E94F61460E0CE010E94DA14182F75 +:102B00000E945E1760E0CE010E94DA141813F3CF22 +:102B1000DF91CF911F9108951F93CF93DF93EC0125 +:102B2000162F40E06AEA8AEA9AE80E94F61440E02A +:102B300065E585E595E80E94F61440E060EA8AEADA +:102B40009AE80E94F61440E0612FCE010E94F6142C +:102B500060E0CE010E94DA14182F0E945E1760E038 +:102B6000CE010E94DA141813F3CFDF91CF911F9199 +:102B700008950F931F93CF93DF93782FCA01E90134 +:102B8000072F10E00730110580F5F801E653FA4EE3 +:102B90000C94BC19D115EA15DD15E415E715F115EE +:102BA000E2159FEF94B985B95F9A5F9814B8872FA3 +:102BB000DF91CF911F910F91089540E00E94F6148C +:102BC00070E0F5CF41E0FACF0E945F15F9CF0E9487 +:102BD0008C15F6CF21E0288360E00E94DA14898307 +:102BE000EFCF21E0288361E0F8CF7AEAE0CF880FC9 +:102BF000991F880F991F20E030E02817390709F442 +:102C00000895000000002F5F3F4FF7CF20E030E035 +:102C10002817390709F40895000000002F5F3F4F7F +:102C2000F7CFCF93DF9380E190E00E94F715C4E0E7 +:102C3000D0E084EF91E00E94F71584EF91E00E94CC +:102C4000F7152197B1F7C4E0D0E08AEF90E00E9439 +:102C5000F7158AEF90E00E94F7152197B1F7DF9101 +:102C6000CF91089580E190E00C94F715CF93DF9316 +:102C70001F92CDB7DEB7F901813171F038F48130A0 +:102C8000C1F078F08230C9F082E80FC08132A9F03B +:102C9000823299F08231C1F782E080831282118200 +:102CA0000AC089830E94111689810F90DF91CF910C +:102CB00008950E94321680E0F8CF81E0808311826F +:102CC000FACF482F90E0982F882720E0411103C0C9 +:102CD00021118068089520953FEF340F4323F6CFEC +:102CE00080E090E0089580E0089560E070E0CB011E +:102CF0000895CF93DF931F92CDB7DEB7DC018FEF3E +:102D0000809307011092080187E091E09093C90336 +:102D10008093C80316968C91169789831196EC912F +:102D200011974E2F50E0FA013197EB30F10508F082 +:102D30009BC0E356F94E0C94BC19A816B816C616DB +:102D4000D4161A1734172B17E216F016FE160C17A6 +:102D500014964D915C91159728E031E013966C9193 +:102D6000139712968C910E94F211809307016EC006 +:102D700014964D915C91159728E031E013966C9173 +:102D8000139712968C910E946C0BEFCF14964D9175 +:102D90005C91159728E031E013966C911397129689 +:102DA0008C910E940711E1CF14964D915C9115977B +:102DB00028E031E013966C91139712968C910E9443 +:102DC000B915D3CF14964D915C91159728E031E059 +:102DD00013966C91139712968C910E943616C5CF5C +:102DE00014964D915C91159728E031E013966C9103 +:102DF000139712968C910E94F00CB7CF14964D91B8 +:102E00005C91159728E031E013966C911397129618 +:102E10008C910E949500A9CF14964D915C911597C5 +:102E200028E031E013966C91139712968C910E94D2 +:102E300042039BCFAE014F5F5F4F67E071E0CD0172 +:102E40000E947C019093C9038093C80389810F90ED +:102E5000DF91CF910895AE014F5F5F4F67E071E062 +:102E6000CD010E94C311EECF80E87FCFE0916903CE +:102E7000F0916A03278144815581322F360F231345 +:102E800012C0E0916903F0916A038781860F8783FE +:102E900080913801861B8093380181110DC088E92B +:102EA000838381E00895FC017191CF01FA01E20F63 +:102EB000F11D70832F5FE3CF80E00895CF93DF9300 +:102EC0006091CA03635067FD91C08091C703CCE055 +:102ED000D0E0C81BD109C253DC4F8091C6038D32AC +:102EE00009F0CFC0683009F07FC083EC8093BA034B +:102EF0008AE58093050110920F018881807679F030 +:102F0000CE010E9479168F3F09F466C09F8191110E +:102F100069C09E81981708F065C0892F63C02A8117 +:102F20001092C303998191110AC01092C40323EC3B +:102F300033E082E03093C9032093C803E7CF953094 +:102F400029F42093CB0323EC33E0F4CF963099F5AA +:102F50009B81913059F48EE890E09093C90380935F +:102F6000C80382E190E490930F01D0CF923019F41E +:102F70008CE790E0F2CF9330A9F7211108C088EEDA +:102F800090E09093C9038093C80384E0EBCF213095 +:102F900041F48EEB90E09093C9038093C8038AE2DA +:102FA000E1CF2230F9F680EA90E09093C903809354 +:102FB000C8038EE1D7CF983059F0993019F4209397 +:102FC000CD03C1CF81E09A3009F4BDCF80E0BBCF03 +:102FD0002DEC33E081E0AECF988197FD8E8190E8B3 +:102FE00090930F01809304011092CA038091050110 +:102FF00084FF3AC0809104018F3FB1F1C82F89301E +:1030000008F0C8E08C1B809304018091BA0398E813 +:1030100089278093BA03CC23D1F08091C803909183 +:10302000C90320910F0126FF3FC0ABEBB3E0FC01C9 +:103030002C2F34913D9331962150D9F701962FEFE3 +:103040002C0F820F911D9093C9038093C8036C2F9E +:103050008BEB93E00E947918CC5FCC3019F08FEFA6 +:1030600080930401C093050184E199B1947131F416 +:103070008150D9F71092CB031092C503DF91CF9105 +:10308000089580910F0187FFAFCFCE010E943617C0 +:103090008F3F21F48EE180930501A6CF882309F4A8 +:1030A000A3CF10920401A0CFEBEBF3E0DC012C2FB7 +:1030B0003D9131932150E1F7C1CFE9E6F0E0808105 +:1030C00082608083E89A0895A82FB92F80E090E06D +:1030D00041E050EA609530E009C02D918227979534 +:1030E000879510F084279527305EC8F36F5FA8F3AB +:1030F0000895EADF8D939D930895CF93CFB7CF9333 +:10310000DF93C3954C9BE9F74C9B0BC04C9B09C0CC +:103110004C9B07C04C9B05C04C9B03C04C9B01C003 +:1031200089C06F93C091C703DD27C253DC4F2F9333 +:1031300065E54C9B03C02F916F91E6CF0F931F93D2 +:103140004F9320E040E15F9309B1047104FB27F93C +:103150003F9350E03BE039C0147140642F77012F5A +:103160005F5F1EC0406819B114712F7752501FC0A5 +:10317000406409B12F770471D1F15F5F00C023C0B3 +:10318000406219B12F77147191F15F5F00C025C0C3 +:1031900004711027515012F45D5F00001150279503 +:1031A0002C3F19B1C8F614710127015027952C3F07 +:1031B000C8F64227499309B1047110274F73115083 +:1031C00027952C3FA8F64695469519B1147179F0CC +:1031D0000127015027952C3F98F66B5A60F3315028 +:1031E00009B1B0F600C011E01CBB002717C03B506E +:1031F0003195C31BD04011E01CBB0881033CF9F0A2 +:103200000B34E9F02091C5031981110F1213EDCF92 +:10321000093651F10D3211F0013E39F70093CC031C +:103220003F915F914F911F910F912F916F91CCB36F +:10323000C0FD67CFDF91CF91CFBFCF91189520917F +:10324000CC03222369F31091CA03112339F53430DA +:103250003AF13093CA032093C6031091C7033BE0B1 +:10326000311B3093C7031CC00091CA030130B4F472 +:103270000AE53091050134FD14C000930501CAEB45 +:10328000D3E013C0052710E000C000000BB91AC03E +:10329000052710E0221F1DC010E021C04AE502C032 +:1032A00032ED432FC4E1D0E032E01AB114615C9AF0 +:1032B0000BB11AB954E120E865E320FF05270BB9EB +:1032C000279517951C3FF0F66695B8F7B1F720FFE4 +:1032D00005270BB9279517951C3FD0F6279517950D +:1032E00017FF052700001C3F0BB9B0F629913A954E +:1032F00019F70B7E1091CB03110FC651D0400BB9BB +:1033000011F01093C50311E01CBB00611AB11B7EC4 +:10331000402F4B7E54E05A95F1F70BB91AB94BB9CF +:103320007FCF9EE088E10FB6F894A8958093600067 +:103330000FBE909360000E945D18549A80E0815007 +:1033400099F4549878940E94A30A80EF80936C03B8 +:10335000A8950E945E170E94AB0280916C03803F8B +:10336000B9F30E947F0CF4CFA895EFE9FFE0319705 +:10337000F1F700C00000E3CFEE0FFF1F0590F491BE +:08338000E02D0994F894FFCF41 +:0633880069019E03FF5ADB +:00000001FF diff --git a/firmware/release/inlretro_stm_INL6_PCBv2_0_FWv2_02.hex b/firmware/release/inlretro_stm_INL6_PCBv2_0_FWv2_02.hex new file mode 100644 index 0000000..20b89bd --- /dev/null +++ b/firmware/release/inlretro_stm_INL6_PCBv2_0_FWv2_02.hex @@ -0,0 +1,1312 @@ +:020000040800F2 +:1000000000180020C1000008FD0000089934000815 +:1000100000000000000000000000000000000000E0 +:10002000000000000000000000000000FD000008CB +:100030000000000000000000FD000008FD000008B6 +:10004000FD000008FD000008FD000008FD0000089C +:10005000FD000008FD000008FD000008FD0000088C +:10006000FD000008FD000008FD000008FD0000087C +:10007000FD000008FD000008FD000008FD0000086C +:10008000FD000008FD000008FD000008FD0000085C +:10009000FD000008FD000008FD000008FD0000084C +:1000A000FD000008FD000008FD000008FD0000083C +:1000B000FD000008FD000008FD0000080101000827 +:1000C00009490A4A0A4B9B1A03DD043BC858D05021 +:1000D000FBDC0849084A0020521A02DD043A885025 +:1000E000FCDC02F02DF900009C4D0008000000200F +:1000F000300400203004002038070020FEE7C0460E +:10010000F0B5B94A89B0138801921BB2002B01DB0C +:1001100001F009FD1388B54A1A4080231343019A60 +:100120001380019B1A8880231B011340B04A01D120 +:1001300001F0C7FCAF49B04C0B68B04801330B600D +:1001400023787F211D008D43AD49AE4E0D70E188AF +:10015000018000203080602633401370AA4A157059 +:10016000834201D100F0BDFEFF23A84ECAB2337016 +:10017000A74B70701E600292607801380E2801D97A +:1001800001F04DFC04F020FD0F00FC053A08340995 +:10019000F10A4B0C360C9909420AC90AEF0A720996 +:1001A0007B0983098B09A078A3888C22192824D87D +:1001B0008022D20004F008FD1A0024004601260225 +:1001C000EE028D031604D204EE04FA0402050A05B9 +:1001D00013051C052A0532053A05420547055B054E +:1001E00071059205A705BE05D602E202B023894A31 +:1001F0005B0351690B4353610022327000F06DFEC6 +:10020000152B01D900F0ADFD18008023DB0004F0B0 +:10021000DBFC160023002E00A805390044004F0027 +:10022000A8055C00690073008000A805A8058D0082 +:100230009A00A500B200BF00CC00D600E0009022DA +:10024000D205136874490B4013608023D1685B03A7 +:100250000B43D3600022D0E790210123C9050A682F +:100260009A430A60CA681343CB600022C5E7902115 +:100270000423C9050A689A430A60CA681343CB601D +:100280000022BAE790211023C9050A689A430A6040 +:10029000CA681343CB600022AFE790214023C90511 +:1002A0000A689A430A60CA681343CB600022A4E735 +:1002B0009022D205136859490B4013608023D168FE +:1002C000DB040B43D360002297E79022D20513682A +:1002D00053490B4013608023D1685B010B43D3600B +:1002E00000228AE704234F490A689A430A60CA68D1 +:1002F0001343CB60002280E79022D20513684A495D +:100300000B4013608023D168DB050B43D3600022D0 +:1003100073E79022D205136844490B401360802391 +:10032000D168DB020B43D360002266E79022D2053E +:1003300013683F490B4013608023D1685B000B4377 +:10034000D360002259E79022D20511683948014054 +:100350001160D1680B43D36000224EE79022D20592 +:10036000136835490B4013608023D168DB010B43D0 +:10037000D360002241E79022D205136827490B4041 +:1003800013608023D168DB040B43D360002234E781 +:100390009022D205136829490B4013608023D1684D +:1003A0005B050B43D360002227E701231D490A6840 +:1003B0009A430A60CA681343CB6000221DE71023EA +:1003C0001F490A689A430A60CA681343CB60002237 +:1003D00013E79021C9050A68164802400A60CA68F6 +:1003E0001343CB60002208E7005C00408F0F000041 +:1003F000FA06002098040020486000409E04002077 +:10040000F8060020A2040020F9060020FC060020C7 +:100410002C07002000100240FFFFEFFFFFFFFFFB53 +:10042000FFEFFFFF00040048FFFFFFBFFFFFFBFFE0 +:10043000FFFEFFFFFFFBFFFFFFBFFFFFFFFFFFEF21 +:10044000000C0048152B01D900F08EFC180004F0B8 +:10045000BBFB160021002C008B04370042004D002E +:100460008B04580063006D0078008B048B048300BC +:100470008E009900A400AF00BA00C400CE00902303 +:10048000DB051968D14801401960DA680240DA607A +:100490000022B2E690230121DB051A688A431A6024 +:1004A000DA688A43DA600022A7E690230421DB059C +:1004B0001A688A431A60DA688A43DA6000229CE686 +:1004C00090231021DB051A688A431A60DA688A4390 +:1004D000DA60002291E690234021DB051A688A4306 +:1004E0001A60DA688A43DA60002286E69023DB0528 +:1004F0001968B74801401960DA680240DA600022E2 +:100500007BE69023DB051968B24801401960DA6880 +:100510000240DA60002270E60421AF4B1A688A4379 +:100520001A60DA688A43DA60002266E69023DB0507 +:100530001968AA4801401960DA680240DA600022AE +:100540005BE69023DB051968A54801401960DA686D +:100550000240DA60002250E69023DB051968A148CA +:1005600001401960DA680240DA60002245E6902313 +:10057000DB0519689C4801401960DA680240DA60BE +:1005800000223AE69023DB0519689848014019607B +:10059000DA680240DA6000222FE69023DB05196852 +:1005A0008B4801401960DA680240DA60002224E6D4 +:1005B0009023DB0519688E4801401960DA68024013 +:1005C000DA60002219E60121834B1A688A431A6017 +:1005D000DA688A43DA6000220FE61021854B1A6838 +:1005E0008A431A60DA688A43DA60002205E69023BB +:1005F000DB0519687C4801401960DA680240DA605E +:100600000022FAE5152B00D9B1E3180004F0DCFA5A +:1006100016001F002700AF032F0037003F00AF0375 +:100620004800510058006100AF03AF036A00730037 +:100630007A0083008C0095009C00A3009022802308 +:10064000D20511685B030B4313600022D5E59022AD +:100650000123D20511680B4313600022CDE59022DF +:100660000423D20511680B4313600022C5E59022D4 +:100670001023D20511680B4313600022BDE59022C0 +:100680004023D20511680B4313600022B5E5902288 +:100690008023D2051168DB040B4313600022ACE514 +:1006A00090228023D20511685B010B431360002266 +:1006B000A3E50423484A11680B43136000229CE51C +:1006C00090228023D2051168DB050B4313600022C2 +:1006D00093E590228023D2051168DB020B4313605F +:1006E00000228AE590228023D20511685B000B432B +:1006F0001360002281E59021C9050B681A430A6046 +:1007000000227AE590228023D2051168DB010B4399 +:100710001360002271E590228023D2051168DB046A +:100720000B431360002268E590228023D2051168F4 +:100730005B050B43136000225FE50123264A116825 +:100740000B431360002258E510232A4A11680B431B +:100750001360002251E59021C9050B681A430A6015 +:1007600000224AE58D22082B00D046E59022D205D2 +:10077000516838330B43536000223EE58D22082B2D +:1007800000D03AE590224021D20553688B43536054 +:10079000002232E5152B00D9ECE2180004F014FA1F +:1007A0002C0031003700EA023D0043004900EA0214 +:1007B000500056005B006200EA02EA0269006F0026 +:1007C00075007B00820089008E009300FFFFEFFF21 +:1007D000FFFFFFFBFFEFFFFF00040048FFFFFFBF2D +:1007E000FFFFFBFFFFFEFFFFFFFBFFFFFFBFFFFF62 +:1007F000FFFFFFEF000C00489023DB059A62002208 +:10080000FBE490230122DB059A620022F5E49023A9 +:100810000222DB059A620022EFE490230422DB052A +:100820009A620022E9E490230822DB059A62002202 +:10083000E3E4802290239201DB059A620022DCE44B +:1008400090234022DB059A620022D6E40222CC4BA0 +:100850009A620022D1E4802290231202DB059A6280 +:100860000022CAE4802290239200DB059A620022D3 +:10087000C3E490231022DB059A620022BDE490239A +:100880002022DB059A620022B7E490238022DB0558 +:100890009A620022B1E4802290239201DB059A62E1 +:1008A0000022AAE480229023D201DB059A62002272 +:1008B000A3E40122B24B9A6200229EE40422B14BCF +:1008C0009A62002299E490232022DB059A6200229A +:1008D00093E4152B00D950E2180004F075F91600C6 +:1008E0001B0021004E0227002D0033004E023A006B +:1008F000400045004C004E024E02530059005F007C +:1009000065006C00730078007D009023DB059A6120 +:10091000002272E490230122DB059A6100226CE43C +:1009200090230222DB059A61002266E490230422D0 +:10093000DB059A61002260E490230822DB059A61BE +:1009400000225AE4802290239201DB059A61002262 +:1009500053E490234022DB059A6100224DE40222F9 +:10096000874B9A61002248E4802290231202DB0523 +:100970009A61002241E4802290239200DB059A6173 +:1009800000223AE490231022DB059A61002234E42D +:1009900090232022DB059A6100222EE490238022FE +:1009A000DB059A61002228E4802290239201DB0576 +:1009B0009A61002221E480229023D201DB059A6112 +:1009C00000221AE401226E4B9A61002215E40422EF +:1009D0006C4B9A61002210E490232022DB059A617F +:1009E00000220AE402227270152B00D9B1E018002F +:1009F00004F0D6F80B151EAF273039AF434C545DC9 +:100A0000AFAF677079828C969EA690238022DB051B +:100A10001B69D200134073800022FFF7EEFB902386 +:100A20000122DB051B69134073800022FFF7E5FB01 +:100A300090230222DB051B69134073800022FFF71D +:100A4000DCFB90230422DB051B691340738000222A +:100A5000FFF7D3FB90230822DB051B69134073804B +:100A60000022FFF7CAFB90238022DB051B6992015D +:100A7000134073800022FFF7C0FB90234022DB0568 +:100A80001B69134073800022FFF7B7FB02223C4B27 +:100A90001B69134073800022FFF7AFFB9023DB0537 +:100AA0001B690022DB0BDB037380FFF7A6FB90239F +:100AB0008022DB051B699200134073800022FFF740 +:100AC0009CFB90231022DB051B69134073800022DE +:100AD000FFF793FB90232022DB051B6913407380F3 +:100AE0000022FFF78AFB90238022DB051B6913405D +:100AF00073800022FFF781FB90238022DB051B69B6 +:100B00009201134073800022FFF777FB902380222D +:100B1000DB051B69D201134073800022FFF76DFBD8 +:100B20000122174B1B69134073800022FFF765FBFE +:100B30000422144B1B69134073800022FFF75DFBF6 +:100B400090232022DB051B69134073800022FFF7EE +:100B500054FB00238D227370FFF74FFB80230A4A5A +:100B6000DB0251690B435361054A084913680B4086 +:100B70001360D168064B0B43D3600022FFF73DFBA7 +:100B800000040048000C004800100240FFFFAAAA21 +:100B900000005555EB4AEC4913680B401360D168CF +:100BA000EA4B0B43D3600022FFF727FBE54AE649F7 +:100BB00013680B4013600022FFF71FFBE14AE34B71 +:100BC00011680B4313600022FFF717FBDD491B027E +:100BD0004A69D2B213434B610022FFF70EFBD94B97 +:100BE00000221B691B0AB37001237370FFF705FB1A +:100BF0008023D74A1B0351690B435361D54AD64B17 +:100C000011680B4313600022FFF7F7FAD14AD24B69 +:100C1000D1680B43D3600022FFF7EFFACD4ACF49EA +:100C200013680B4013600022FFF7E7FAC94ACA4B6A +:100C300011680B4313600022FFF7DFFAC54A5361C6 +:100C40000022FFF7DAFA8023C14A1B0351690B43E4 +:100C50005361BC4AC24B11680B4313609022D2050A +:100C60001168C04B0B4313600022FFF7C6FAB54A68 +:100C7000BB4BD1680B43D3609023DB05D868B949DF +:100C80000143D9601168B848014011601A68B7493A +:100C90000A401A600022FFF7B0FAF8228027A94D17 +:100CA00098026969D20110403F025A023A40890510 +:100CB0001043890D08439021686110205D08C90523 +:100CC00028404A69AA4DDB012A4002438020C00126 +:100CD000034013434B610022FFF78FFAC0239C4A65 +:100CE000DB0251690B435361964AA24B11680B43D7 +:100CF00013609022A023D20511685B030B4313609D +:100D00000022FFF77AFA8F4A9A4BD1680B43D360DF +:100D10009023A021DB05D86849030143D9601168FD +:100D20009548014011601A6894490A401A600022EF +:100D3000FFF763FAFF2183489D0042692940904DE7 +:100D4000DB002A400A4342619022C020D205C00045 +:100D5000516903408B4801400B4353610022FFF768 +:100D60004CFA8D22FFF749FA8D22FFF746FA8D22C1 +:100D7000FFF743FA8D22FFF740FA8D22FFF73DFA85 +:100D8000A578A288032D00D16CE156D87E4B012DA9 +:100D900060D000D8DBE1984790220121D20513688A +:100DA0000B4313601023916111680B4313600423FC +:100DB0004021936113680B43136008239361916191 +:100DC000802311685B010B43136080236048DB02C2 +:100DD00041695D4E0B435B4943610B6833400B60D7 +:100DE000CD685A4B1D43CD600D6835400D60CD6810 +:100DF0002B43CB60802345691B032B43554D436137 +:100E00002E68554B33432B6000236B61C025466928 +:100E1000ED02354345610D68564828430860A0201F +:100E200015684003284310604869554D28404861C3 +:100E300051695448014051614DE0052D00D1B1E0A8 +:100E400000D254E1072D00D1F0E0802D00D180E1E7 +:100E5000962340E098479023DB051A682A431A60DE +:100E600080229D61196852030A431A60802204217E +:100E7000D2009A621A68344D0A431A6002229A61BB +:100E800018680E3202431A604022996119680A43B9 +:100E90001A6008229A6180232D49DB024A691343B4 +:100EA0004B61284B1A682A401A60D868274A1043B9 +:100EB000D860186828401860D8680243DA60802338 +:100EC0004A691B031343234A4B611168224B0B43AE +:100ED0001360002353612D4A13706A462C4B12890C +:100EE0001A802378602259B2002901DB00F0BAFD94 +:100EF000134016D16278062A0FD16288110A02299E +:100F000001D100F08EFD032901D100F090FD214AAE +:100F1000012901D100F086FD03936A461C4B92899A +:100F20001A80019B1A881C4B13431C4A1A40C02389 +:100F30009B015340019A9BB21380194B984700F0D4 +:100F4000B2FDC04600040048FFFFAAAA00005555A4 +:100F5000001002400008004855555555AAAAAAAAF3 +:100F60000000505500010010FFFFAFAAFFFEFFEF89 +:100F7000EFBF000050550000AFAAFFFFFFFFEBFFDF +:100F800003FF0000FFF90000ED210008FC0600202F +:100F9000A0040020F64B00088081FFFF8FBFFFFFF9 +:100FA000DD330008C84B984790220121D205136811 +:100FB000C64E0B4313601023916111680B431360FD +:100FC00004234021936113680B431360082393614A +:100FD0008023916211685B010B4313608023BC493D +:100FE000DB02486903434B61BA4B18683040186014 +:100FF000DD68B9480543DD601D6835401D60DD686A +:101000002843D860802348691B0303434B61B349DD +:10101000B34B086803430B6000234B6180211068C9 +:10102000C901014311608021916254E7A64B9847A2 +:1010300090220121D205136840200B431360102336 +:10104000916111680B43136004239361116801439C +:1010500011600821916111680B43136002239361B1 +:101060009061ADE6D2B2022A21D00023032A00D13A +:1010700031E79723012A00D02DE7802394491B03F1 +:10108000486903434B6195490B6893430B60CB68F8 +:101090001343CB604B6813434B608A610B681A4360 +:1010A00000230A608F4A13708F4A116013E7B02340 +:1010B000874A5B03516940200B4353619023DB0552 +:1010C0001A688A490A401A608022D968520111437D +:1010D000D960596801435960986119680A43082129 +:1010E0001A60804A1170804A13600023F3E6D2B27E +:1010F0009823012A00D0EEE690210A207C4BC905F6 +:1011000019607C4B05321A70724B7B4A13607B4A24 +:1011100010707B4A013013607A4A10707A4A0130AD +:1011200013607A4A10708020694A00035569284389 +:1011300050611D687648284318600868754B034362 +:101140000B60B02351695B030B435361724B9847AB +:10115000CBE701279023402177708026DB05996239 +:101160001A68760132431A60C04660481D691A68E1 +:101170000D4002401A60DA680240DA60F022002D69 +:1011800039D11A6802401A60DA681643DE601A69BB +:1011900004921A690592C0461A690692C046C04672 +:1011A0001A699446C046C046C0461A690792C046AE +:1011B000C046C046C0461E691A6802401A60DA6816 +:1011C0001040D860049B2A000B4214D1059B3A00C2 +:1011D0000B4210D1069B02320B420CD10B00614630 +:1011E0000332194207D107990432194203D105325B +:1011F0001E4200D1D132494B9A7076E7A578E1784A +:10120000A0880D2D00D1AEE027D8062D59D012D8D8 +:10121000022D00D19CE006D8002D4ED0404B012D70 +:1012200007D0A0254BE0042D00D193E03D4B052DC8 +:10123000F7D1984725E0092D00D190E006D8072D79 +:1012400000D192E0384B082DF3D0EAE7374B0B2D55 +:10125000EFD0374BEDD9374BEBE7212D00D17BE0B9 +:1012600011D8102D00D182E005D80E2D79D0324B47 +:101270000F2DDED0D5E7112D7BD0202DD1D12F4BD6 +:10128000187000251BE0822D00D1A0E009D8802D28 +:1012900071D0812DC5D101237370294B9847B0704F +:1012A000EFE7852D00D196E0862D00D198E0842DC2 +:1012B000B7D101237370234BF0E7234B9847357068 +:1012C0000BE6224BB5E7C046ED210008FFFFAAAAB6 +:1012D0000010024000040048000055550008004876 +:1012E000555555550807002004070020FFEFFFFF64 +:1012F0001C070020200700201407002018070020EA +:1013000024070020280700200C07002010070020D9 +:10131000000050550001001029200008FC060020A4 +:10132000491F00082D360008DD2F00085D31000838 +:1013300021300008653000082933000888040020A7 +:10134000751C00087D360008D11F0008B51C000878 +:10135000C04B6EE7C04B6CE7C04B188091E7C04BA9 +:1013600067E7C04B65E7C04B63E7C04B61E7C04B25 +:101370005FE7C04B5DE7012290237270DB051968BF +:10138000BD4D29401960D9682940D96080210225C6 +:10139000C90099629A619D61B84D6861C046C046B6 +:1013A00000B29961002800DA9A62C046C046C04681 +:1013B000C046C046C04690228021B14BD205C9002C +:1013C0001B69916201211B0A9161B37059E70123E6 +:1013D0007370AC4B62E701237370AB4B1B78F4E77F +:1013E000022373709D4B1B88B3701B0AF37048E790 +:1013F000A078E178A388AA22062801D9FEF7FDFE8D +:1014000003F0CEFB04291B2226312000FF219C483B +:101410009D00426929409D4DDB002A400A434261FC +:101420009022C020D205C000516903409848014075 +:101430000B4353610022FEF7E0FE00221800954B9B +:101440009847F7E70122F9E71800934B9847F1E72F +:101450001800924BFAE70122002172701800904B9D +:101460009847B070E6E701217170F7E7A278002A8B +:101470001DD00023012A00D0AF2333702DE5A278C0 +:10148000002A14D00023012AF7D0B023F5E7A27870 +:10149000002A0CD00023012AEFD0B123EDE7A27877 +:1014A000002A04D00023012AE7D0B223E5E7012374 +:1014B0007370A933B3700023DFE7A578E278A188C1 +:1014C000112D00D19BE007D8012D6AD0002D0FD03F +:1014D000022D7CD0822561E0212D00D185E0222DD6 +:1014E00000D188E0122DF5D102231020737089E01D +:1014F000012631006B4D6C4F2A783B689140996210 +:101500005A6810208A435A60684B984731002B78FC +:10151000042599400B003A68916151680B43536070 +:10152000FA20624B4000984731005E4AFA20127858 +:101530005D4F91403B68400099625A68013D8A4383 +:101540005A605A4B98473100564B3A681B78ADB2F7 +:1015500099400B00916151680B435360002DDFD11E +:101560000435FA20514B984701214E4E4E4F3278A8 +:101570003B68914099625A68FA208A435A604B4B03 +:101580009847012133783A6899400B00916151687E +:10159000013D0B43ADB25360002DE2D1444B1D70B1 +:1015A0009BE429003F4E404F32783B68914099625E +:1015B0005A6810208A435A603C4B984732783B68FF +:1015C00095409D615A6815435D600025E6E701235B +:1015D000344A7370127837499340334A9BB2126889 +:1015E0000020354DA847B070EFE70123002073704D +:1015F000324B9847F7E7012310207370F8E7022376 +:10160000002073702E4B98477080DEE7A378A28885 +:10161000042B1AD006D8022B5CD061D8012B0FD036 +:1016200087232AE7072B64D003D8052BF8D1254B55 +:1016300054E0082B62D0802BF2D1234B98473AE735 +:10164000224A1278B270737035E7214B1B78B37061 +:101650000123F8E7091C0008993900083404002028 +:10166000E5320008893300087D3200083132000875 +:10167000DD310008ED300008FFEFFFFF00080048F3 +:1016800000040048991F00088804002003FF0000A0 +:10169000FFF90000952E00088D2F00083D2F00084F +:1016A000F52E000808070020040700201536000862 +:1016B000FC06002004000200D13900089D34000817 +:1016C00061350008E504002029200008C40400203A +:1016D000E6040020B64B1A708322B64B1A70EAE675 +:1016E000B34BB44D1A7083232B70B34B98472B78B0 +:1016F000ADE7B24B1A70120A5A70DCE6AF4B1A789B +:10170000B2705A78F2709A783271DA7872711A7906 +:10171000B2715B79F371062395E7A378A288022B57 +:1017200015D0032B16D0012B1BD102488546024849 +:10173000001C004778120020C5CAFF1F06000500E4 +:101740000800070019C9FF1FEFBEADDEB3E69C4BD2 +:101750001A60B0E69A4B18689A4B000410439847F9 +:10176000A9E68A2389E6882387E6A2781300303B1E +:101770002F2B19D8E078032800D9CEE003F010FA17 +:1017800014021012904B512A00D177E024D8312A4C +:1017900053D00BD8002A33D0302A49D0B42345E0A7 +:1017A0008A4BF0E78A4BEEE78A4BECE7332A4ED0C0 +:1017B00048D3502AF2D100223270063272701A7A5F +:1017C000B270DA78F2705A7A32719A7A72719A78C3 +:1017D000B2715B7CF37145E07F2A00D983E0702A07 +:1017E0005CD2602A36D0612A40D0522AD6D100225B +:1017F0001B883270B37002321B0A7270F37031E0D2 +:10180000FF23754953540132102AFBD16E4A7149A6 +:10181000D37093706E4ACB70D370937001228B702B +:101820006A49CB708B706D4B1A700023337019E0CE +:10183000A288110AD9721A73F7E7A288110A59739C +:101840009A73F2E7A288110AD9731A74EDE7A28895 +:101850005A74EAE70023337001337370A3885E4A39 +:10186000D35CB3705E4B1E60FFF737FB0023337011 +:10187000013373705B4B1B68DB78F2E70022327038 +:1018800006327270DA7AB2701A7BF2705A7B327159 +:101890009A7B7271DA7BB2711B7C9BE74D4B51498D +:1018A0005E6823787F2B00D95BE168464E4B007A57 +:1018B00018700868C378002B0ED000200290982B77 +:1018C00005D156E100200290D02B00D151E1434BCD +:1018D00010301870FF2304E0444B18609023C3704D +:1018E0006F33029345E107201040032815D803F019 +:1018F00057F916021812344B802AB3D3872A12D90B +:101900007032D2B2072AADD800223270E2789A72D1 +:10191000A2881A80A6E72E4BEEE7B52386E72D4B6B +:10192000EAE72A4BE8E7A1880A0A0492E078C9B2FC +:101930004518BE22102D30DC043200282DD0DD7871 +:10194000033AFF2D29D19D780132FF2D25D1224D5B +:101950000022AC46D5B2A84221D86A464501013DD5 +:10196000127C1D724D012F009A700022204DDA70FA +:10197000ED195A729A721A80DA721A735A739A733C +:10198000DA731A745A745D6061446B461B7C8B5425 +:101990000132D3B28342F8D30022327062E7674645 +:1019A00001328D18013D7D5DFF2DD3D0C122F4E7BA +:1019B000C4040020E604002009210008C50400201A +:1019C00030040020C53900084C04002060040020C9 +:1019D0007404002038040020E7040020A404002040 +:1019E0002C0700208C040020940400209004002088 +:1019F000F8040020A278002A04D0402A07D0D2227E +:101A0000327030E73270A188654A11702BE70022EE +:101A1000327001327270624A1278B27023E780230A +:101A20002BE5604A604B1A601223FFF775FAD2B2B9 +:101A3000012A11D0002A09D0022A01D0FFF76CFA3E +:101A4000594B5A4A1A605A4BFFF766FA564B594A95 +:101A50001A600423FFF760FA534B574A1A60574B3A +:101A6000FFF75AFA134208D16378052B05D1638832 +:101A7000534A1370534ADBB21380019B524A1B88AE +:101A800001991340514A13439BB20B800021504BE4 +:101A90001980019B1B881A434E4B1A404E4B5A40EB +:101AA000019B92B21A804D4BDA8F520507D58021E7 +:101AB0004B4A11800022DA874A4B019A138009B001 +:101AC000F0BD1278402AEED1474A1278002AEAD1B6 +:101AD000464A1088464AC0B211684D7A4E68DAB25A +:101AE0005419E4B2904218D84A7A82184A72414A8C +:101AF00013781B1ADBB21370002B01D19833CB7013 +:101B0000019B1A88314B13433B4A1A40C0239B0167 +:101B10005340019A9BB21380C5E7384A9A1812784D +:101B200001333255DBE7019B1B881B06BBD5019BAC +:101B3000334A1B881340802212021343019A1380F8 +:101B4000304B1B78802B01D1FFF7F7F91C4A137833 +:101B5000002BA8D080210B4321490B800023137058 +:101B6000A1E70868C378D82B00D0ABE6802346688D +:101B7000C3700B6800215972DB78902B00D071E69E +:101B8000712A00D06EE61A4BA2881B6859680A7049 +:101B9000A2885968120A4A705A7A02325A7261E669 +:101BA000A4040020E44B00082C070020604C00082F +:101BB0001E030000084C00080C4C00082A0300001B +:101BC0009C040020506000408F8EFFFF8080FFFF4C +:101BD00002600040BFBFFFFF30300000065C0040E5 +:101BE0004C5C004020320000F906002006600040F6 +:101BF00090040020940400208FBFFFFF4860004045 +:101C00000F8FFFFFF80600209023DB0530B51C681E +:101C1000134D09022C401C60DA68124C2A40DA602D +:101C2000114A506102229A62104A00B215682C4390 +:101C300014605469E4B2214351618021C900996163 +:101C4000002801DA01209862C046C046996201214D +:101C5000996149189961136805490B40136030BDBB +:101C6000FFEFFFFF00005555000800480004004842 +:101C7000FFFFAAAA0D4B802258619023D200DB05FA +:101C800000B29A61002801DA01229A62C046C04679 +:101C9000C046C046064B802218699023D200DB055F +:101CA0009A620122000AC0B29A6170470008004897 +:101CB000000400480D4B0E4A58610E4B090218688B +:101CC00002431A605A69D2B21143902259618021AD +:101CD000D205106849010143116040219162916170 +:101CE0001A6805490A401A607047C0460008004853 +:101CF0000000555500040048FFFFAAAAF0B5404B6C +:101D00008BB0089119783F4B09921B780190029390 +:101D10003D4B019D1C683D4B3D481A7801231E0038 +:101D200096403C4AA662102D5ED11278006893401E +:101D3000836201200200364B05901F68354B1B78EB +:101D40009A4003920200344B1B680693334B1B7876 +:101D50009A4093B202000793314B1B689C46314B6B +:101D60001B789A40002304921A000198202806D17B +:101D7000029D05981D4105423ED00398B861089820 +:101D800020280FD1002B01D11E48835406980569E5 +:101D90000798054206D01B48855C05989840054386 +:101DA0001848855409980139C9B2002802D0002981 +:101DB00000D1A6616046049D0133DBB28561856276 +:101DC000082B05D101320F4BD2B29B5C029300234A +:101DD0000029CAD10E4B1A680E4B197801238B408B +:101DE0009362A6620BB0F0BD019D112DA1D11278B6 +:101DF0000068934083619CE70398B862BFE7C046E0 +:101E0000E5040020C5040020240700202807002046 +:101E100014070020180700201C07002020070020BE +:101E20000C07002010070020F7B51F4B1F491A7838 +:101E30001F4B10282ED101241E780D68B440AC62CF +:101E4000012635000C6831001B7801969D40194B26 +:101E50001B680093184B1B78994000238C4619008F +:101E600020280DD1154E019F765C1E413E4219D0AF +:101E7000A5610133DBB2082B02D100230131C9B2C5 +:101E80006646009F013AD2B2BE61BE62002AE7D127 +:101E9000A562F7BD1128D3D101241E780D68B44086 +:101EA000AC61CDE7A562E4E7E5040020240700204B +:101EB000280700200C07002010070020C504002080 +:101EC000F7B50D001600FF27000203B24C7A01930C +:101ED0002A7AE3B2A24202D26B720020FEBD200039 +:101EE0006A683840D15C019B0134184380B2B04726 +:101EF000A4B2EDE7022907D10F4B104A984218D03F +:101F0000904209D1180007E0032906D10A4B0B497A +:101F10000B4A98420BD1080070470429FCD1064BAC +:101F2000064A984205D006499042F4D0054A8842B4 +:101F3000E6D11000F0E7C046380400204C04002031 +:101F400060040020740400200E4B984202D88023C5 +:101F50001B0218430C4B0D4A58610D4B09021868BF +:101F600002431A605A69D2B211435961C0469022A5 +:101F70000821D2059162C04691611A6805490A405C +:101F80001A607047FF1F0000000800480000555508 +:101F900000040048FFFFAAAA0A4B984202D88023F7 +:101FA0001B021843084B042258619023DB059A62F8 +:101FB000C046C046C046C046044908699A61000A46 +:101FC000C0B27047FF1F000000080048000400482E +:101FD000104B114A10B558611068104B09020343A9 +:101FE000136053690E4CDBB2194390235161802179 +:101FF000DB0518684901084318604020986218689A +:1020000020401860D8680143D960136805490B4027 +:10201000136010BD0008004800040048000055553A +:10202000FFEFFFFFFFFFAAAAF0B52C4B85B01968A0 +:102030002B4B2C481B7800780193012302901E0043 +:1020400018001F00019A029C9640A040264D274A86 +:102050002D781268AF408E628446906224489D407D +:1020600000688762046803941C00AC402500039C50 +:10207000254305604568019CBD4345609C401D00AB +:10208000A54008681C00284308604868B0434860C1 +:102090001068029999408C4021000143604611600C +:1020A00051688143134851600078134A9840834037 +:1020B00012681248116899431160D1680B43D360CC +:1020C00080220F4B1A70002319000E4A13701A1841 +:1020D00001331170202BFAD105B0F0BD2407002088 +:1020E00028070020180700201007002014070020F0 +:1020F0000C070020200700201C070020C50400203A +:10210000E6040020E504002010B5334B1B78082BB3 +:102110005DD016D8314C032B44D007D8012B2DD0DD +:10212000022B31D0EE222D4B1A7023E0062B44D027 +:1021300049D8042BF6D181230122237020211120BC +:1021400027E00F2B34D008D8244C0D2B25D00E2B94 +:10215000E8D181230022237027E0802B08D01F4C78 +:10216000FF2B08D0102BDDD181230022237027E024 +:102170001B4B984710BDF0232370FBE781232020E1 +:102180002370184B984706E0812301220021237019 +:102190002020154B98478223EEE7812300222370ED +:1021A0001100F5E781230122237020211020F0E7A0 +:1021B00081230A4C00222370C0E78123012223706F +:1021C00020210800E5E7812310202370D9E781232F +:1021D000024C11202370D4E7C4040020E604002040 +:1021E00029200008291E0008FD1C0008BC234749BF +:1021F000DB038A6AF0B513438B628B6A444A01247D +:1022000013408B6290238022DB051868D2010243C1 +:102210001A6080229A61B0224869520302434A61DF +:102220001A683C483C4F02401A608022D86852032A +:1022300002430420DA601A68A2431A60DA68224373 +:10224000DA601A6882431A60DA680243DA601022A0 +:102250001D6895431D60DD682A43DA6040221D68D1 +:1022600095431D60DD682A43DA601A682B4D2A40C9 +:102270001A608022DD68D2042A43DA601A68284D89 +:102280002A401A608022DD68D2052A43DA601A6883 +:10229000244D2A4080251A60DA68ED022A43DA606C +:1022A000214A1668A6431660D6683443D4601E6877 +:1022B0003E401E60DC683C40DC6080234C691B03B0 +:1022C00023434B61194B1A4C1E681A4F26431E605C +:1022D0001E683E401E60DE683443DC604B691D436F +:1022E0004D611368144D2B401360D468134B1C438D +:1022F000D460116829401160D1680B43D360136822 +:1023000083431360D3681843D060F0BD00100240CF +:10231000FFFFA1FFFFFFEFFFFFEFFFFFFFFFFFFB4F +:10232000FFFFFFBFFFFFFBFF00040048000800485D +:1023300055555555AAAAAAAAFFFFAAAA00005555A5 +:102340009022CC4B12031968F0B50A431A60802220 +:1023500089B0920219681142FCD0012259680A43DF +:102360005A608022596852020A435A608022596892 +:1023700052030A435A608022196852040A431A60C1 +:102380008022920419681142FCD011210220BA4A1D +:1023900011605A680E398A4302435A601A6B7D31C4 +:1023A0000A431A638022DC6912042243DA6162B6AE +:1023B000B24B4025DA8FB24C8243DA87DA8F01388C +:1023C0008243DA870022AF48C2872280AE4C258044 +:1023D000AE4C083525808025AD4C6D012580AD4C77 +:1023E0002180C287AC49AD4A11808021AC4A0906E0 +:1023F00011608022D98FD2000A43DA87A94AAA4BFA +:102400001A80AA4B9847F022A94B1A70A94E202394 +:10241000327811009943D2292ED1A749A748C9780B +:10242000C3780224FF2904D1FF3B1C00631E9C419A +:10243000E4B2A34BDB78FF2B00D00324A14BDB7865 +:10244000FF2B00D00424A04BA04F1C703860D22A70 +:1024500012D10023012505E09D4B2100984701235F +:102460000135EDB2A542F7D3002B00D038608022B1 +:102470003B68DA70D02333703378F22B05D1002219 +:10248000023B3370914B1B68DA703578D02D01D048 +:1024900000F08BFC8D4E3068C378802B01D000F0AB +:1024A00084FC894B19788A4B9847002330600400DC +:1024B000C57043720588C07AEEB21038152801D96C +:1024C00000F071FC02F080FB51008700D100160182 +:1024D0006F046F046F046F046F046F046F046F0464 +:1024E0006F046F046F046F041600240035003A0077 +:1024F00040004A00E17BC4230F2901D900F054FCBD +:1025000009012943237AA278C9B26068714D0DE0B0 +:10251000E17B3C230A009A438833002A01D000F073 +:1025200043FC237AA27860686B4D3143A847607200 +:1025300092E0237AA278E17B3143E6E7E17B3F2317 +:102540000A009A438533E8E7227AE17BA378009278 +:10255000002231436068614DA847E8E7E17B227AB9 +:10256000A378314300920122F4E7E37B1E2B0BD1C9 +:10257000C0202233AD09E9B29E430002584B984770 +:10258000237AA2788021D7E71C2B0DD1A0208121AE +:10259000C001534FB8478020ED09E9B20002B847A7 +:1025A000A0200021C001B8478021E27B49421F2AB8 +:1025B00005D00E43F6B2237AA2783100A5E7702247 +:1025C000A02096430E432188C0010909C9B2444B9B +:1025D000F6B29847EFE7E37BFE2B3DD16D09E9B2F8 +:1025E0004048414B98471F2163680E409C463F4B33 +:1025F00036025A698021D2B216439022C900D20510 +:10260000A078277A5E6191610121FF2591620331F3 +:1026100091625A692D022A4002435A61C046002243 +:10262000334E0295C046654631690130090AA95406 +:102630005969029DC0B2294001320143D2B25961A9 +:102640009742EFD290230421DB0599618021C900D4 +:1026500099620121996162721C4B1B6819889A7AF0 +:1026600052181A80D822DA709FE3237AA278602168 +:1026700062E7C0460010024000200240025C0040B9 +:10268000505C0040065C0040006000400460004078 +:10269000066000404C5C004020320000005C0040BE +:1026A00000E100E00080FFFF585C0040ED210008E1 +:1026B000E6040020A40400204C040020380400207C +:1026C0006004002074040020300700208C040020E7 +:1026D000F51E0008C53800083139000849380008DF +:1026E000091C0008FF3F0000491F000800080048BF +:1026F00000040048E37B002B20D18033ED091E430A +:10270000EBB20493FF20049BDD499B004A69034020 +:10271000DC48024013434B61C0209021049BC90553 +:10272000C000DB004A690340D748024013434B61B5 +:10273000227AA3783100009200220BE7012BE1D12D +:102740004021AD04AD0E29430491DBE7F37B002B60 +:1027500006D10298CD4A8038C0B23100CC4B9847A0 +:10276000F37B012B06D10298CA4A8038C0B23100EF +:10277000C74B9847F37B032B06D10298C64A803893 +:10278000C0B23100C24B9847F37B042B06D10298AC +:10279000C24A8038C0B23100BD4B9847F37B0A2B48 +:1027A00006D10298BE4A8038C0B23100B84B984773 +:1027B000F37BFD2B18D13F20029B034018008023A0 +:1027C0001843338802909B0905936B461B7D069343 +:1027D000777ABBB2039303021BB20793337A039A4F +:1027E000934200D3AAE07772F37B1E2B16D13F20D1 +:1027F000029B0340180080231843338802909B09F2 +:10280000DBB20593777ABBB2039303021BB2069344 +:10281000337A039A934200D3D2E07772F37B0C2B86 +:102820001AD11F20029B35880340180080231843CB +:102830000290C0206D09EDB2A521C001994CA047BE +:1028400029009948A047029B777A1D023D43337ABD +:10285000BB4200D3FBE07772F37B1C2B35D1A02069 +:102860003388904CDB09DBB28121C0010593A0477E +:10287000802005990002A047A0205421C001A04754 +:10288000777AAA21BBB289480393A047552188488B +:10289000A04720218548A0478023029A13431B02AA +:1028A0001BB20693337A039A7E4C934200D313E112 +:1028B0008020902100027772A04780200021000232 +:1028C000A0478020F0210002A047F37B1F2B2ED1D0 +:1028D000A0203188734D0909C9B2C001A847747A94 +:1028E000AA21A3B271480393A84755217048A8476D +:1028F0006E482021A84770238020029A40429A43C4 +:10290000104340B203020293337A039A934200D3F6 +:1029100023E18020747290210002624CA047802045 +:1029200000210002A0478020F0210002A047F423EC +:102930003288F370B37A9B18338057E2594D0021E7 +:102940005C48A8475C4CAA215C48A04755215C48DC +:10295000A047A0215948A0476B46187D594B0699BE +:10296000C01880B2A847079B3B439DB273682800FC +:10297000D95DA047C046544B28009847524B0400ED +:10298000280098478442F5D17368DA5D3C4BA24237 +:102990000FD1039A1968013292B203920422914333 +:1029A0001960D96801370A43DA600222FFB29A62DD +:1029B00014E7042219680A431A6002229A610DE79B +:1029C000C020384D01210002A847AA213F48A8474E +:1029D000C02000210002A84755213D48A847C0203B +:1029E00001210002A847A0213848A847C020059926 +:1029F0000002A847069C73683C43A4B2D95D20003E +:102A0000A847C046304B200098472F4B05002000B8 +:102A100098478542F5D17368DA5D194BAA420FD108 +:102A2000039A1968013292B2039204229143196009 +:102A3000D96801370A43DA600222FFB29A62E7E6F8 +:102A4000042219680A431A6002229A61E0E6AA2168 +:102A50002048A04755211E48A047A0211D48A04757 +:102A600073682800D95DA047C046174B28009847D7 +:102A7000154B039028009847039B8342F4D1E6E668 +:102A80000004004803FF0000FFF90000E5320008E1 +:102A9000C11E0008893300087D3200083132000869 +:102AA000DD310008091C0008FFFF0000AA8A0000B1 +:102AB0005585000069FD0000B51C00085555000053 +:102AC000AA2A000069FDFFFF751C0008559500004B +:102AD000AAAA000055D50000A0205421C001A0479B +:102AE000069BA0213B439DB22800A04773682800A5 +:102AF000D95DA047C046C44B28009847C24B04008C +:102B0000280098478442F5D17368C04DDB5DA3422D +:102B10000FD1039B2A6801339BB2039304239A438A +:102B20002A60EA6801371343EB600223FFB2AB620D +:102B3000B8E6A020B64C8121C001A04780200599AD +:102B40000002A047A0205421C001A04704232A6806 +:102B500013432B600223AB61A4E6029FA02127430D +:102B6000BFB23800AA4DA84773683800195DA8475E +:102B7000C046A54B38009847A34B0500380098473E +:102B80008542F5D173681A5DA04BAA420FD104218A +:102B9000039A0134013292B203921A68E4B28A4372 +:102BA0001A60DA680A43DA6002229A62ACE604210B +:102BB0001A680A431A6002229A61A5E6F37B002B89 +:102BC00004D1944A31000298934B9847F37B012B30 +:102BD00004D1924A310002988F4B9847F37B022B25 +:102BE00004D18F4A310002988B4B9847F37B042B1A +:102BF00004D18C4A31000298874B9847F37B0A2B0B +:102C000004D1894A31000298834B9847F37B0B2B00 +:102C100004D1864A310002987F4B9847F37BFE2B04 +:102C200000D084E6318882484909C9B2814B98476F +:102C3000747A814DA3B2AA2180480393A8475521F5 +:102C40007F48A8477D482021A8471F20029B0340BA +:102C50001B020293337A039A93420AD27472902130 +:102C60000020754CA04700210800A047F02100205B +:102C70005CE6029FA021274338006F4DA847736888 +:102C80003800195DA847C0466E4B380098476D4B19 +:102C90000500380098478542F5D173681A5D5B4B93 +:102CA000AA420FD10421039A0134013292B2039255 +:102CB0001A68E4B28A431A60DA680A43DA600222C8 +:102CC0009A62C7E704211A680A431A6002229A61CD +:102CD000C0E702984E4A603031004F4BC0B298476F +:102CE00025E6F37B042B06D10298574A8038C0B200 +:102CF0003100494B9847F37B052B04D1524A3100F0 +:102D00000298454B9847F37B062B06D102984F4A11 +:102D10008038C0B23100404B9847F37B072B04D179 +:102D20004A4A310002983C4B9847F37B002B1ED156 +:102D3000FF24029A80331A4333883448DB09DBB21C +:102D400002929A0041692240414CDB0021400A4333 +:102D500042619021C020C905C0004A6903403D4836 +:102D6000024013434B61029831003B4B9847F37B81 +:102D7000012B00D0DBE53388244A354851699B0498 +:102D80009B0E01409B000B4390215361C9054B6989 +:102D9000304A02981A4080239B0013434B61310054 +:102DA0002D4B9847C3E5C323E3702C4B1C78F02CC4 +:102DB0001CD12B4D2E68F378982B17D1294B30005E +:102DC0001978294B984700232860C3703378F47032 +:102DD0000293F07A1038042806D801F0EBFEB7FC15 +:102DE000EFFE7AFF82FFA8FDC323F3701F4B1B7811 +:102DF000F02B01D1FFF70AFB832B01D0FFF706FB75 +:102E00001B4B9847FFF702FB751C000800040048A5 +:102E1000091C000821300008C11E000829330008E1 +:102E20005D310008DD2F0008ED3000086530000836 +:102E3000FF3F0000491F00082D360008AA0A0000C5 +:102E4000550500007D3600088D2F00083D2F000835 +:102E500003FF0000FFF90000B5360008A4040020BD +:102E60008C04002030070020F51E0008E604002036 +:102E700009210008002302000002002A04D1002BCF +:102E800001D0802318437047DB43511EDBB20A4058 +:102E9000F3E70000134B10B55861134B13481C683F +:102EA0000902204318605869C0B20143596190215A +:102EB0000820C9058862002A01D101328A62C04611 +:102EC000C046C046C046C046C046C046C046902226 +:102ED0000821D2059161073991611A6804490A40B5 +:102EE0001A6010BD00080048000400480000555555 +:102EF000FFFFAAAA0F4B58619023DB05002901D1DF +:102F000001229A6204229A62C046C046C046C04668 +:102F1000C046C046C046C046C046C046C046C04681 +:102F2000C046054908699A61000A033AC0B29A612D +:102F30007047C046000800480004004870B505000E +:102F40000E000E4C0022AA210D48A0470022552158 +:102F50000C48A0470022A0210948A04700223100C8 +:102F60002800A04700212800074CA0470600C046C3 +:102F700000212800A0478642F4D170BD952E00089C +:102F8000AA8A000055850000F52E000870B50500DE +:102F90000E000E4C0022AA210D48A0470022552108 +:102FA0000C48A0470022A0210948A0470022310078 +:102FB0002800A04700212800074CA0470600C04673 +:102FC00000212800A0478642F4D170BD952E00084C +:102FD00055550000AA2A0000F52E000870B505001E +:102FE0000E000B4CAA210B48A04755210A48A047C8 +:102FF000A0210848A04731002800A0472800074C1E +:10300000A0470600C0462800A0478642F6D170BD02 +:10301000491F000855150000AA1A0000991F000852 +:1030200070B505000E000B4CAA210B48A047552196 +:103030000A48A047A0210848A04731002800A0471F +:103040002800074CA0470600C0462800A04786423B +:10305000F6D170BD491F000855150000AA0A0000EE +:10306000991F0008F7B50700194E1A4B30881B78D6 +:1030700020301B01DBB2184D019180B2202100935A +:10308000A847164CAA211648A047308810211030B6 +:1030900080B2A84755211348A0473088202120300E +:1030A00080B2A847A0210E48A047009B3088190095 +:1030B000C01880B2A84701993800A04738000A4CD0 +:1030C000A0470500C0463800A0478542F6D1F7BDAD +:1030D0003404002088040020091C0008491F00084F +:1030E00055150000AA0A0000991F0008F7B5060050 +:1030F000B020144D019100020A21A847C0200A21E6 +:103100000002A847104CAA211048A047552110489A +:10311000A047A0210D48A047B0200E4F00023978EB +:10312000A847C02039780002A84701993000A0477D +:103130003000094CA0470500C0463000A04785423A +:10314000F6D1F7BD091C0008491F000855150000FD +:10315000AA0A000088040020991F0008F7B507009C +:10316000174E184D30880191023080B20221A847D5 +:10317000154CAA211548A04730880121013080B2A2 +:10318000A84755211248A04730880221023080B25A +:10319000A847A0210D48A0470E4B30881978401849 +:1031A00080B2A84701993800A04738000A4CA047D0 +:1031B0000500C0463800A0478542F6D1F7BDC0469D +:1031C00034040020091C0008491F000855150000A0 +:1031D000AA0A000088040020991F000870B50500A5 +:1031E0000E000E4CAA210E48A04755210D48A047BD +:1031F000A0210B48A04731002800A047A0200A4B7F +:1032000000021978A0472800084CA0470600C046D5 +:103210002800A0478642F6D170BDC046091C0008B0 +:10322000AAFA000055F5000088040020751C00086B +:1032300070B505000E000D4CAA210D48A047552180 +:103240000C48A047A0210A48A04731002800A04709 +:10325000802000210002A0472800074CA04706005C +:10326000C0462800A0478642F6D170BD091C000860 +:1032700055D50000AAAA0000751C0008F7B5050086 +:10328000114E019130880021104FB847104CAA21EF +:103290001048A04755211048A047A0210D48A0473D +:1032A0000E4B30881978401880B2B8470199280031 +:1032B000A04728000A4CA0470600C0462800A047A7 +:1032C0008642F6D1F7BDC04634040020091C000830 +:1032D000D11F000855550000AA2A000088040020CC +:1032E000751C000870B505000E000B4CAA210B4898 +:1032F000A04755210A48A047A0210848A04731000F +:103300002800A0472800074CA0470600C046280018 +:10331000A0478642F6D170BDD11F00085555000068 +:10332000AA2A0000751C0008F8B50500A0200F00AF +:10333000000202210E4EB0470E4CAA210E48A047B3 +:1033400055210E48A047A0210B48A047A0200C4BB8 +:1033500000021978B04739002800A0472800094C1E +:10336000A0470600C0462800A0478642F6D1F8BD17 +:1033700099390008491F000855150000AA0A0000E5 +:1033800088040020991F000870B50500C0200E00B9 +:103390000D4B0521000298470C4CAA210C48A04770 +:1033A00055210C48A047A0210948A047310028001A +:1033B000A0472800084CA0470600C0462800A047A8 +:1033C0008642F6D170BDC04699390008091C000834 +:1033D00055550000AAAA0000751C0008224B10B524 +:1033E0001968224B224C1A8852085200505A214A1E +:1033F00010801A88023292B21A8052085200505A33 +:103400001D4A10801A88023292B21A805208520065 +:10341000505A1A4A10801A881948023292B21A80F9 +:1034200052085200515A174A11801A8821880232D4 +:1034300092B21A808A4210D908318A1A92B2028056 +:1034400022881A801049114B0A881343104A1A40E7 +:10345000302353409BB20B8010BD0E4C21888A4212 +:10346000EAD808230380EDE72C070020A2040020FF +:10347000A0040020406000404260004044600040E2 +:103480000260004046600040005C00408080FFFF1A +:10349000BF8FFFFF9E040020FEE70000F0B5012370 +:1034A00002252B4F85B003923A7802910543934051 +:1034B0000421A020274E2D04274C9BB229433268BB +:1034C000C001A047040001283ED13B7809209C4060 +:1034D00005437830A3B232681F4C2900FF300195B4 +:1034E000A047040001282FD13B7832689C40019905 +:1034F000A3B20020184CA0470400012824D1029B4D +:10350000180A164B98473B7832689C400199A3B241 +:10351000114CA0470400012816D16B46187A0F4BB6 +:10352000984722003B7801999A400B4D93B232683C +:10353000A8470A4B039898473B7832689C4001990A +:10354000A3B2054CA0470400E0B205B0F0BDC046F0 +:103550000807002004070020D1390008752E000854 +:10356000F7B501230225274F00903A7801910543D2 +:1035700093400421C020244E2D04244C9BB22943A7 +:1035800032688001A0470400012838D109231D4377 +:103590003B78C0209C403268A3B229001B4C4000FD +:1035A000A047040001282AD13B7832689C402900BA +:1035B000A3B20020154CA047040001281FD1019B95 +:1035C000180A134B98473B7832689C402900A3B2F5 +:1035D0000E4CA0470400012811D16B4618790C4B02 +:1035E000984722003B789A4093B2009A14430922EC +:1035F000E1B209041143054C3268A0470400A0B2AF +:10360000FEBDC0460807002004070020D13900088D +:10361000752E00080023800080B2834200D17047DD +:10362000C046C04601339BB2F7E700000F4B30B5F0 +:103630009022586180230124D205DB0093620C4B59 +:1036400094621D680B480902284318605869C0B28B +:1036500001435961C04608219162C04691611968D1 +:10366000054801401960946130BDC046000800481B +:103670000004004800005555FFFFAAAA0B4B10B5E7 +:1036800080215861902301220424DB05C90099613F +:103690009A629C62C046C046C046054800699C616B +:1036A000000A9962C0B29A6110BDC0460008004885 +:1036B00000040048F7B504000D004F7AC046C0462C +:1036C000C046C046C046C046C046C046C046574E2B +:1036D0000022AA215648B047002255215548B0473C +:1036E0002402002220215248B04723B20193FBB2AA +:1036F00000932B7ABB4215D26B4680201B784B4C33 +:103700006B72002290210002A0470022802011004D +:103710000002A04780200022F0210002A047C046FE +:103720000020FEBD444B454A196808200A43FF218A +:103730001A605A690A40A02109020A435A6190227C +:103740000121D20590629162C046C046C046C04683 +:10375000FF24906191611A6839493C400A401A601F +:10376000019B009A1C436B68A4B2995C2000002264 +:103770002E4B9847C046C046C046C046C046C046CD +:10378000C046C046C046C046002120002D4B984789 +:103790000600C046C046C046C046C046C046C046F9 +:1037A000C046C0466B68009A9B5C834217D0C046F7 +:1037B000C046C046C046C046C046C046C046C046D9 +:1037C000002120001F4B9847B0420BD1C046C04695 +:1037D000C046C046C046C046C046C046C046013787 +:1037E000BFB284E7C046C046C046C046C046C046D9 +:1037F000C046C046C046C046C046C046C046C04699 +:10380000C046C046C046C046C046C046C046C04688 +:10381000C046C046C046C046C046C046C046C04678 +:1038200000212000074B98470600C9E7952E0008A5 +:10383000AA8A000055850000000400480000555584 +:10384000FFFFAAAAF52E0008F0B51C4D040005A83C +:10385000067868690902C0B20843686190200421B3 +:10386000C00581622900002A01D101328262FF2550 +:1038700000204A692D022A401A43114F4A61C0466E +:10388000C046C046C046C046C046C046C046C04608 +:10389000C0463A690133120A22544A69DBB22A400F +:1038A00001301A43C0B24A61B042E8D990230422E1 +:1038B000DB059A61033A9A61F0BDC04600080048F2 +:1038C00000040048F0B5184C050060690E02C0B253 +:1038D0003043606180269020F600C00549B28661C1 +:1038E000002901DA01218162FF2661693602314037 +:1038F00011436161C04600200C4FC0463969013256 +:10390000090A29546169D2B2314001301143C0B271 +:1039100061619842F1D990238022DB05D2009A623E +:1039200001229A61F0BDC04600080048000400482A +:10393000F0B5174C05000E0060691F2925D88021BD +:1039400031430902C0B20143616190210420FF2686 +:10395000C905886261693602314011436161C04620 +:1039600000200C4FC04639690132090A29546169A7 +:10397000D2B2314001301143C0B261619842F1D9F5 +:1039800090230422DB059A61F0BDC0B20902DAE798 +:10399000000800480004004870B506000D0005242A +:1039A000064B3000013C9847E4B229003000044B3C +:1039B00098476D08002CF3D170BDC046751C0008F7 +:1039C000091C00088047C0460000000000000000FD +:1039D000F0B5474680B4061C081C000C102801D521 +:1039E000162700E004270007000F8046FF20014053 +:1039F0005468251C1D439C43F60313850AD5C04615 +:103A0000C046C046C046C046C046C04694801383E8 +:103A1000958002E0012000F081F801390AD4381CB9 +:103A200000F07CF8C046948013839580C046C04661 +:103A30007600E2E7381C013800F070F894801383B8 +:103A40009580042000F06AF8108A184001D0FF2009 +:103A500061E0C046C046C046C046C046C0469480ED +:103A60009580108A184055D001200226B04552D0CA +:103A70000921168A1E40FCD1012000F04FF89480E5 +:103A8000C0469580C04603E0C046C046C046C0461A +:103A9000948095807600108A1840EFF300804000F3 +:103AA000C00F0643381C023800F038F89480958027 +:103AB000022000F033F80139EAD513859480012003 +:103AC00000F02CF813839580301C8021022399404C +:103AD0000E401BD1002341085E4149085E41490860 +:103AE0005E4149085E4149085E4149085E41490816 +:103AF0005E4149085E4149085E41760808D34008A6 +:103B0000FF21084048400002013004E00E2002E09E +:103B1000092000E0002080BCB846F0BD0138FDD18E +:103B20007047C04603685A0003D45B005B08C018A6 +:103B30007047802212061343F9E7C046F0B5574696 +:103B40004E46DE464546E0B5814683B092460029A2 +:103B500025D04B1E9B46002701935B46FB18DC0FCC +:103B6000E4184B466410E5005E193000FFF7DAFFF9 +:103B7000019B8046A3420BD0280008304844FFF741 +:103B8000D1FFD04506D80138504509D2671CE4E77B +:103B9000504505D9A74202D0631E9B46DDE70026AB +:103BA000300003B03CBC90469946A246AB46F0BDFF +:103BB000012809D0022805D0002801D00020704734 +:103BC0000248FCE70248FAE70248F8E7D142000859 +:103BD000E9420008DD42000830B5234B83B0050000 +:103BE0008C1E002B2AD001A9200000E000BF002875 +:103BF00020D001992200FFF7A1FF041E1AD0FFF781 +:103C000091FF6368A864012B10D0201D002B1BDBE3 +:103C1000FFF788FF0023E8642B650368002B17DBA0 +:103C2000FFF780FF2861002003B030BD002305208E +:103C30002B61F9E7002309202B61F5E70B480C49BC +:103C4000091AC9100191D5E70123E8642B65E4E75F +:103C50001801000FFFF7ACFF2861002801D10930DF +:103C6000E2E70020E0E7C04600000000CC4C00087E +:103C70009C4D0008036810B50400DA0705D49B07C3 +:103C80000FD5483000F084FC23685A070FD51A0777 +:103C900014D5DB0604D42000D130FF3000F084FCC2 +:103CA00010BD483000F070FC23685A07EFD42000A4 +:103CB000D03000F071FC23681A07EAD4200051309C +:103CC000FF3000F06DFC2368E3E7C0460368002B7B +:103CD00000D01B1818007047092070477047C04675 +:103CE00070B504000D0008E02B6C2A006361210010 +:103CF000012023699847082807D1296C2000FFF785 +:103D00006BFF0028F0D000F09FFE0728FBD10020B9 +:103D1000296CFFF7E3FF281D00F020FCF0B5CE462C +:103D2000474680B5C368324C9846A544836906006F +:103D300014000431402205A8994600F08DFE0023AE +:103D400004AD296C30000493FFF746FF631E9C41CD +:103D500007000934002F15D0AB6B10216B644B4664 +:103D600021430193C9B20095330032000120C047BE +:103D7000002833D13800F5239B009D440CBC9046AD +:103D80009946F0BDF0222B6C5200736129007CA88B +:103D900000F062FE7CAA31003369200098478A9BBC +:103DA00007006B6403934B46009501933200330088 +:103DB00021000120C047002810D1F0227CA9520028 +:103DC000280000F049FE082F06D1296C3000FFF7CB +:103DD00003FF09240700BDE7072F01D00927C9E722 +:103DE0000020296CFFF77AFF05A800F0B7FBC0465A +:103DF0002CFCFFFF406C704770B5CB6BFAB00B64C6 +:103E000004000E004022043103A800F025FE012327 +:103E10005B42029306E002AA21002369984705004D +:103E200008280AD1129B200019000193FFF7D4FE45 +:103E30000028F0D009207AB070BD02A8FFF71AFF61 +:103E4000062DF7D131002000FFF74AFF10B582613F +:103E5000DA6BC1601A6419000022FFF75FFF10BD22 +:103E6000436970B50B64C36804000D00002B04D0D7 +:103E70000122FFF753FF00F0E7FD0A00236901006C +:103E800002209847072807D0082803D129002000DE +:103E9000FFF726FF00F0D8FD0020296CFFF71EFF7A +:103EA000281D00F05BFBC046C36810B5002B05D091 +:103EB000CB6B00220B64FFF731FF10BDFFF79CFFB7 +:103EC000FBE7C0467047C046836810B5002B02D0A0 +:103ED00001000120984710BD10B5012907D0002925 +:103EE00007D003390224012901D9200010BD012483 +:103EF000FBE70224002BF8D10F2AF6D89200821893 +:103F00005268029B00241A60EFE7C04600B585B0F6 +:103F100003AB0A00009300210023FFF7DDFF0398A5 +:103F200005B000BD10B5012907D0002907D003391D +:103F30000224012901D9200010BD0124FBE702243D +:103F4000002BF8D10F2AF6D8029B92001B6882182A +:103F500053600024EFE7C04600B585B003AB039281 +:103F600000930A0000230021FFF7DCFF05B000BD2D +:103F700070B51A4CD36BA544136406000D0019A844 +:103F8000111D402200F068FD01235B42189314E0EC +:103F90000C2118A802AAFFF7DFFF290018A8B047D4 +:103FA000002812D1069B18AA02A90830019398474D +:103FB000040005280AD0092807D0289B02A8190068 +:103FC0000193FFF709FE0028E2D0092418A8FFF7A3 +:103FD00051FE200090239B009D4470BDC0FDFFFF5B +:103FE000F0B5DE464E464546574693460322E0B5B9 +:103FF0001E0013008BB003400193CB6C0D001C1D01 +:104000001B6808940793002E66D11B02079306AB2A +:104010005E731A73019B022B00D16EE02B6DDB07E0 +:1040200047D40023A846B2460293083303400393C3 +:104030002568002D00D137E15346022B49D0258851 +:10404000668804340123370099469F4343469B6C9E +:104050000F219C4658466744FFF758FF00228742CD +:1040600006D82A004B469A43D719B84280414242AB +:1040700002230121760033400D402B43012B3ED01B +:10408000002B5AD0022B1CD1236801995F007F08B6 +:10409000002965D1002A06D0039A002A00D188E0C1 +:1040A000002F00D1AAE0002B65DB0137BF00E41927 +:1040B000BEE700230293022E47DDFFF70DFE002826 +:1040C00049D009200BB03CBC90469946A246AB466D +:1040D000F0BD66680834B5E7022E9BDC1A0C1B04A1 +:1040E0000793022306A90B73FD3313409B00E418CA +:1040F000019B4A73022B00D090E7AC6B8EE7019BCB +:10410000002B3AD1002A16D02368DD0F63689A1C71 +:10411000D7D0424658320692013300D1C6E0201D66 +:10412000FFF7D4FD06AB01002A00404600E000BFC7 +:10413000002800D0A7E008347AE7019B002B02D0CA +:10414000002A00D08BE0043472E707A9584600F03B +:10415000D1FA0028B5D1029B002B5DD10820B1E730 +:1041600043460D2158461D6AFFF7D0FE854263D0B5 +:104170002368002B99DA043497E743460D2158460B +:104180001D6AFFF7C3FE8542D5D143469B6A9C4218 +:10419000D1D145462000FFF7C5FC0F21020058464B +:1041A000FFF7DAFE58462A000021FFF7D5FE072068 +:1041B00088E7002F22D058235146434406AABA4626 +:1041C000251D0026049405911F00914603E0043547 +:1041D0002600A24514D028000697FFF777FD4B462E +:1041E000010000224046741C00E000BF0028EED011 +:1041F0005746059B049C9A46B742B9D1454601E013 +:104200004546049C0D215846FFF780FE069B286218 +:104210006B62AC62062055E70F215846FFF776FE29 +:104220000E2102005846FFF797FE5846274A0F21F5 +:10423000FFF792FE072045E743469B6A9C4297D1D1 +:10424000434642469F620023D36204331363231D17 +:1042500053632368002B32DB0123029325E7200000 +:10426000FFF760FC454604340600AC63404600E0BE +:1042700000BF002800D124E7584632000F21FFF785 +:104280006BFE07201EE707000D2158464546FFF745 +:104290003DFE2862022F0FD1069BEB6243462C3372 +:1042A0006B62AC6206200DE7564604E70D215846C6 +:1042B0004546FFF72BFE2862069B6B62F1E738004C +:1042C000013080004546201865E7C0460000000028 +:1042D00010B50023FFF784FE10BDC04610B50123C2 +:1042E000FFF77EFE10BDC04610B50223FFF778FE33 +:1042F00010BDC046F0B5CE46474680B50600C3B0F7 +:1043000014001D0001294ED0002933D003290AD002 +:10431000042902D1002B00D189E0022043B00CBC5B +:1043200090469946F0BD032BF7D11404150C240CCC +:104330002B19102BF1D8082203681A4200D0E7E0AD +:1043400020AB1800984600F02DF9B36BED001A0071 +:10435000002C09D0E400EA1A1C1942441968D15013 +:1043600004339C42FAD12200B263404600F018F9AF +:104370000020D3E70220002BD0D100230127100416 +:10438000B56B000C321D39009940084202D02968F3 +:104390000435116001330432102BF4D10020A30442 +:1043A000BCD4B563BAE71404170C240C012B5FD0FE +:1043B000052BB2D13B19202BAFD80F2F7DD9A146A9 +:1043C000002C65D1002223009146B16B002B00DC4C +:1043D00088E020A88046FA00DB00521ACB1842443D +:1043E0000868505004318B42FAD119004B46002B1B +:1043F00010D04B4658003A00102F00D21022002354 +:10440000103AD2006A448000CC58D450043383421E +:10441000FAD1C918012D5ED0B1630F2F74D94B4664 +:10442000002BA5D0684600F0B7F8002076E7102AE8 +:1044300000D972E7102203681A4245D120AB180058 +:10444000984600F0B3F800230120B16B02009A40B7 +:10445000144204D045460F689A00AF50043101332E +:10446000042BF3D14046B16300F09EF8002055E7DD +:104470003B19102B00D950E70F2F00D94DE700232F +:104480009946012233681A4230D14B46002B5AD04C +:10449000042233681A4242D1012D47D00F2F06D88B +:1044A00020AB180000F076F84B46002B8AD0684607 +:1044B00000F074F81023DB1B87E7102BDFD91022E4 +:1044C000524291469944DCE793430360D130FF3078 +:1044D00000F06CF8B2E7043120A8B16300F054F8A2 +:1044E00000201BE74B46002B84D193E71900914332 +:1044F0000A003160052D1ED0032230009343336043 +:10450000483000F043F8C0E720A800F041F886E703 +:10451000934303605130FF3000F044F810E730005F +:1045200093433360D03000F039F8B5E720AB180082 +:1045300000F02CF8BEE7022330001A433260483006 +:1045400000F028F8A1E7012D03D00F2F00D939E79B +:10455000A6E720AB180000F019F833E7011C34314E +:1045600038C9043B9C461D60A646011C20313CC94D +:1045700090469946A246AB46011C0831FCC94168E9 +:104580000068E54600BDC0467047C0467047C0465B +:104590007047C0467047C0467047C0467047C04627 +:1045A0007047C0467047C0467047C0467047C04617 +:1045B00001B401A801B585B0FFB408A841464A4638 +:1045C00053465C4665463EC001A83EC80F98009021 +:1045D00000230CB401A9FFF70FFC109B12B0184781 +:1045E00001B401A801B585B0FFB408A841464A4608 +:1045F00053465C4665463EC001A83EC80F980090F1 +:1046000000230CB401A9FFF72BFC109B12B0184734 +:1046100001B401A801B585B0FFB408A841464A46D7 +:1046200053465C4665463EC001A83EC80F980090C0 +:1046300000230CB401A9FFF737FC109B12B01847F8 +:1046400001B401A801B585B0FFB408A841464A46A7 +:1046500053465C4665463EC001A83EC80F98009090 +:1046600000230CB401ABFFF7F1FB109B12B018470D +:1046700001B401A801B585B0FFB408A841464A4677 +:1046800053465C4665463EC001A83EC80F98009060 +:1046900000230CB401AAFFF76BFC109B12B0184763 +:1046A000027A0300002A04D1427AB020002A07D1FE +:1046B0007047013A02720268100E12021A60F7E7A0 +:1046C000013A5A725A68111D596003211268197211 +:1046D000F2E7C04600B585B003AB00930C2200237F +:1046E0000021FFF7F9FB039805B000BD10B5FFF7F7 +:1046F000F1FF10BDF0B557464E464546DE46002355 +:10470000E0B587B003930F339846083B9946802362 +:104710001B0306000F009A463800FFF7C1FF040094 +:10472000B02821D0030632D4FF2583001D4005ABFD +:104730009B4600930D220023002130000435FFF733 +:10474000CBFB63064CD5059B5D1B05955B46009333 +:1047500000230D2200213000FFF7E4FB3800FFF7B3 +:104760009FFF0400B028DDD1039B0024002B2FD134 +:1047700005AD00950E2200213000FFF7ADFB00953E +:1047800000230F2200213000FFF7CCFB20E00300C4 +:1047900042469343DBB2802B63D0902B25D0A02BD5 +:1047A00032D0B02B45D0C02B00D173E003004A4675 +:1047B0009343DBB2D02B0AD15346024001321A4355 +:1047C000052301213000FFF795FD0028A4D009241E +:1047D000200007B03CBC90469946A246AB46F0BDCF +:1047E000059B9C4665440595B0E7833B03400D2B34 +:1047F000EDD0424605AD0240009500230021300077 +:10480000FFF76AFB0095A3E7FF234A461B01190047 +:10481000824311410A001A40030702D58023DB01BD +:104820001A43002300213000FFF764FD0028CED199 +:1048300072E7B1284AD0B2285ED0B32800D18BE00D +:10484000FC230340B42BC2D04A46534602400132F7 +:104850001A43012101233000FFF74CFD0028B6D197 +:104860005AE704023800FFF71BFF802520432D0282 +:10487000A842ACD004010005020C00230021300046 +:10488000FFF738FD0028A2D12C4200D144E70123D4 +:10489000039341E7C6286AD0C7287CD003004A4664 +:1048A0009343DBB2C02B00D18BE0C82800D18FE04E +:1048B000C92800D08BE73800FFF7F2FEF02302038F +:1048C0001B03134042460240013278E73800FFF7ED +:1048D000E7FE002800D17AE7030042469343DBB2AB +:1048E000002B00D073E7020000213000FFF702FD2B +:1048F000002800D06BE70FE705AB00939B460D2225 +:10490000002300213000FFF7E7FA3800FFF7C8FE68 +:1049100003066AD57F25B03C059B2840A0409C46F5 +:104920006044059038000734FFF7BAFE0306F3D45D +:10493000812292009446863AFF3A1040A040059B9F +:10494000723A634418185B460590009300210023D7 +:104950003000FFF7E7FADFE63800FFF7A1FEF023AB +:1049600002031B03134042460240013270E7380045 +:10497000FFF796FEF02302031B031340424602405A +:1049800001321A43032303213000FFF7B3FC002850 +:1049900000D01CE7C0E63800FFF782FE002800D1F7 +:1049A00015E7030042469343DBB2002B00D00EE72D +:1049B000020004213000FFF79DFC002800D006E72C +:1049C000AAE64346A0221C40013412032243D9E741 +:1049D0003800FFF765FE434602009A43D2B2103218 +:1049E0001840120301300243EAE60224A0E7C04661 +:1049F000030000B5DB6C85B05A6808001202019212 +:104A00001A0001A908324A6003220A72DB794B724C +:104A1000FFF770FE05B000BD10B5FFF767FE806CB4 +:104A200010BDC04610B5FFF761FEC26CD3799B0084 +:104A30000833D01810BDC04610B500F005F8C046C8 +:104A400010B5FFF7F9FFC04610B5062000F074F866 +:104A5000012000F0A3F8C046F0B505000F2A2FD9B9 +:104A60000B0003439B0734D116000C000300103EDB +:104A7000350901352D01451927681F6067685F609A +:104A8000A7689F60E7681034DF6010339D42F3D160 +:104A90000F239E431036851989191340032B1AD909 +:104AA0001E1F0023B4080134A400CF58EF50043374 +:104AB000A342FAD10324A643331D2240C918ED189E +:104AC000002A05D00023CC5CEC5401339342FAD188 +:104AD000F0BD0500F6E71A00F2E7C04670B5050024 +:104AE0000C001F2922D8B7239B00C358002B14D0D9 +:104AF0008A009B181A68002A0FD0012A0BD0511C7B +:104B000005D00021200019609047002070BD1623B9 +:104B100003600120FAE70020F8E7280000F02AF8F7 +:104B200022000100280000F011F8EFE716230360CF +:104B300001204042EAE7C04610B5034B0100186867 +:104B4000FFF7CCFF10BDC04600000020002370B569 +:104B5000074C050008001100236000F017F8431C03 +:104B600000D070BD2368002BFBD02B60F9E7C04656 +:104B70003407002010B500F001F810BD58220120C4 +:104B8000014B40421A607047340700205822012030 +:104B9000014B40421A60704734070020FEE7C046D0 +:104BA00002B4714649084900095C49008E4402BCC0 +:104BB0007047C04603B47146490840004900095E89 +:104BC00049008E4403BC704703B471464908400055 +:104BD0004900095A49008E4403BC7047F8B5C046E5 +:104BE000F8B5C04609021200010100803209040034 +:104BF00000000000000012010002FF000008C016C3 +:104C0000DC05010201020001040309042A03490032 +:104C10006E00660069006E006900740065004E0059 +:104C2000650073004C0069007600650073002E007B +:104C300063006F006D000000000000000000000035 +:104C40000000000000000000000000000000000064 +:104C50000000000000000000000000000000000054 +:104C60001E0349004E004C002000520065007400F5 +:104C700072006F002D00500072006F00670000008E +:104C80000000000000000000000000000000000024 +:0C4C900000000000000000000000000018 +:104C9C0074B20181B0AB308000000000800A018149 +:104CAC00B0B0ABF0000000003F020181B0AB30802F +:104CBC000000000080060181B0B0ABF000000000E5 +:104CCC00F8ECFF7FB0B0B08050EEFF7F0100000029 +:104CDC00FCEEFF7FB0A9028090EFFF7FB0B0A88000 +:104CEC00E0EFFF7F01000000ECEFFF7FB0B0AA8087 +:104CFC0020F0FF7F9CFFFF7FF0F0FF7F01000000A2 +:104D0C00ECF0FF7FAA3F398038F1FF7FB0B0A8806C +:104D1C0044F1FF7FB0B0AA8084F1FF7FB0B0A880CF +:104D2C0098F1FF7F0100000094F1FF7FB0B0A880E4 +:104D3C009CF1FF7F010000002CF2FF7FAA0FB280D4 +:104D4C0094F2FF7F58FFFF7F7CF5FF7FB0B0A88007 +:104D5C0098F5FF7F54FFFF7FF8F7FF7F01000000FD +:104D6C0068F9FF7F0084048078F9FF7FB0B0A880D9 +:104D7C0078F9FF7F40FFFF7F6CFCFF7F008404808D +:104D8C008CFCFF7FB0B0A880A4FCFF7F010000006A +:104D9C00080000200000000000000000F4020020C9 +:104DAC005C030020C4030020000000000000000091 +:104DBC0000000000000000000000000000000000E7 +:104DCC0000000000000000000000000000000000D7 +:104DDC0000000000000000000000000000000000C7 +:104DEC0000000000000000000000000000000000B7 +:104DFC0000000000000000000000000000000000A7 +:104E0C000000000000000000000000000000000096 +:104E1C000000000000000000000000000000000086 +:104E2C000000000000000000000000000000000076 +:104E3C000000000000000000000000000000000066 +:104E4C0001000000000000000E33CDAB34126DE603 +:104E5C00ECDE05000B00000000000000000000006C +:104E6C000000000000000000000000000000000036 +:104E7C000000000000000000000000000000000026 +:104E8C000000000000000000000000000000000016 +:104E9C000000000000000000000000000000000006 +:104EAC0000000000000000000000000000000000F6 +:104EBC0000000000000000000000000000000000E6 +:104ECC0000000000000000000000000000000000D6 +:104EDC0000000000000000000000000000000000C6 +:104EEC0000000000000000000000000000000000B6 +:104EFC0000000000000000000000000000000000A6 +:104F0C000000000000000000000000000000000095 +:104F1C000000000000000000000000000000000085 +:104F2C000000000000000000000000000000000075 +:104F3C000000000000000000000000000000000065 +:104F4C000000000000000000000000000000000055 +:104F5C000000000000000000000000000000000045 +:104F6C000000000000000000000000000000000035 +:104F7C000000000000000000000000000000000025 +:104F8C000000000000000000000000000000000015 +:104F9C000000000000000000000000000000000005 +:104FAC0000000000000000000000000000000000F5 +:104FBC0000000000000000000000000000000000E5 +:104FCC0000000000000000000000000000000000D5 +:104FDC0000000000000000000000000000000000C5 +:104FEC0000000000000000000000000000000000B5 +:104FFC0000000000000000000000000000000000A5 +:10500C000000000000000000000000000000000094 +:10501C000000000000000000000000000000000084 +:10502C000000000000000000000000000000000074 +:10503C000000000000000000000000000000000064 +:10504C000000000000000000000000000000000054 +:10505C000000000000000000000000000000000044 +:10506C000000000000000000000000000000000034 +:10507C000000000000000000000000000000000024 +:10508C000000000000000000000000000000000014 +:10509C000000000000000000000000000000000004 +:1050AC0000000000000000000000000000000000F4 +:1050BC0000000000000000000000000000000000E4 +:1050CC0000000000000000000000000000000000D4 +:1050DC0000000000000000000000000000000000C4 +:1050EC0000000000000000000000000000000000B4 +:1050FC0000000000000000000000000000000000A4 +:10510C000000000000000000000000000000000093 +:10511C000000000000000000000000000000000083 +:10512C000000000000000000000000000000000073 +:10513C000000000000000000000000000000000063 +:10514C000000000000000000000000000000000053 +:10515C000000000000000000000000000000000043 +:10516C000000000000000000000000000000000033 +:10517C000000000000000000000000000000000023 +:10518C000000000000000000000000000000000013 +:10519C000000000000000000000000000000000003 +:1051AC0000000000000000000000000000000000F3 +:1051BC0000000000000000000000000000000000E3 +:04000005080000C12E +:00000001FF diff --git a/firmware/source/dump.c b/firmware/source/dump.c index c8cd90e..1b4a60a 100644 --- a/firmware/source/dump.c +++ b/firmware/source/dump.c @@ -10,13 +10,9 @@ uint8_t dump_buff( buffer *buff ) { uint8_t addrH = buff->page_num; //A15:8 while accessing page uint8_t bank; -//warn uint8_t addrX; //A23:16 while accessing page - //TODO use mapper to set mapper controlled address bits - - //use mem_type to set addrH/X as needed for dump loop - //also use to get read function pointer switch ( buff->mem_type ) { + // #ifdef NES_CONN case NESCPU_4KB: //mapper lower nibble specifies NES CPU A12-15 if (buff->mapper > 0x0F) { @@ -58,55 +54,29 @@ uint8_t dump_buff( buffer *buff ) { buff->cur_byte = nes_ppu_page_rd_poll( buff->data, addrH, buff->id, buff->last_idx, ~FALSE ); break; + // #endif + // #ifdef SNES_CONN case SNESROM_PAGE: //ROMSEL is always taken low //mapper byte specifies SNES CPU A15-8 addrH |= (buff->mapper); //no shift needed - buff->cur_byte = snes_rom_page_rd_poll( buff->data, addrH, buff->id, + buff->cur_byte = snes_page_rd_poll( buff->data, addrH, 0, buff->id, //id contains MSb of page when <256B buffer buff->last_idx, ~FALSE ); break; + case SNESSYS_PAGE: //ROMSEL stays high + //mapper byte specifies SNES CPU A15-8 + addrH |= (buff->mapper); //no shift needed + buff->cur_byte = snes_page_rd_poll( buff->data, addrH, 1, buff->id, + //id contains MSb of page when <256B buffer + buff->last_idx, ~FALSE ); + break; + // #endif + // #ifdef NES_CONN case PRGROM: addrH |= 0x80; //$8000 - if (buff->mapper == MMC1) { - //write bank value to bank table - //page_num shift by 6 bits A15 >> A9(1) - bank = (buff->page_num)>>6; - bank &= 0x0F; //only 4 bits in PRG - //LSb doesn't matter in 32KB mode - mmc1_wr(0x8000, 0x10, 1); //write bank to PRG-ROM bank register - mmc1_wr(0xE000, bank, 0); //write bank to PRG-ROM bank register - //TODO SXROM/SUROM require writting PRG-ROM MSb of address to CHR registers - } - if (buff->mapper == UxROM) { - //addrH &= 0b1011 1111 A14 must always be low - addrH &= 0xBF; - //write bank value to bank table - //page_num shift by 6 bits A14 >> A8(0) - bank = (buff->page_num)>>6; - //Nomolos bank table @ CC84 - //nes_cpu_wr( (0xCC84+bank), bank ); - //Owlia bank table @ CC84 - //nes_cpu_wr( (0xE473+bank), bank ); - //Rushnattack - //nes_cpu_wr( (0x8000+bank), bank ); - //twindragons - //nes_cpu_wr( (0xC000+bank), bank ); - //h1 - //nes_cpu_wr( (0xFFC0+bank), bank ); - //AFB - nes_cpu_wr( (0xFD69+bank), bank ); - - buff->cur_byte = nes_cpu_page_rd_poll( buff->data, addrH, buff->id, - //id contains MSb of page when <256B buffer - buff->last_idx, ~FALSE ); - break; - } - //if (buff->mapper == MMC3) { - // THIS IS HANDLED from the host side using NESCPU_4KB - //} if (buff->mapper == MAP30) { //addrH &= 0b1011 1111 A14 must always be low addrH &= 0xBF; @@ -121,18 +91,6 @@ uint8_t dump_buff( buffer *buff ) { buff->last_idx, ~FALSE ); break; } - //if ((buff->mapper == BxROM) || (buff->mapper == CDREAM)) { - // //write bank value to bank table - // //page_num shift by 7 bits A15 >> A8(0) - // bank = (buff->page_num)>>7; - // //Lizard bank table @ FF94 - // nes_cpu_wr( (0xFF94+bank), bank ); - // //HH85 - // //nes_cpu_wr( (0xFFE0+bank), bank ); - // //Mojon bank table @ FF94 - // //nes_cpu_wr( 0x800C, 0x00); //select first bank (only one with table) - // //nes_cpu_wr( (0xCC43+bank), bank ); //then select desired bank - //} if (buff->mapper == A53) { //write bank value to bank table //page_num shift by 7 bits A15 >> A8(0) @@ -159,44 +117,6 @@ uint8_t dump_buff( buffer *buff ) { break; case CHRROM: //$0000 - //if (buff->mapper == NROM) { - // buff->cur_byte = nes_ppu_page_rd_poll( buff->data, addrH, buff->id, - // buff->last_idx, ~FALSE ); - //} - - //if (buff->mapper == MMC3) { - // THIS IS HANDLED from the host side using NESPPU_4KB - //} - - //if (buff->mapper == CNROM) { - // //select bank - // //8KB banks $0000-1FFF - // //page_num shift by 5 bits A13 >> A8(0) - // bank = (buff->page_num)>>5; - - // //write bank to register - // //TODO account for bus conflicts - // nes_cpu_wr(0x8000, bank); - // - // addrH &= 0x1F; //only A12-8 are directly addressable - // buff->cur_byte = nes_ppu_page_rd_poll( buff->data, addrH, buff->id, - // buff->last_idx, ~FALSE ); - //} - - //if (buff->mapper == CDREAM) { - // //select bank - // //8KB banks $0000-1FFF - // //page_num shift by 5 bits A13 >> A8(0) - // bank = (buff->page_num)>>5; - - // //write bank to register - // //TODO account for bus conflicts - // nes_cpu_wr(0xFFFF, bank<<4); - // - // addrH &= 0x1F; //only A12-8 are directly addressable - // buff->cur_byte = nes_ppu_page_rd_poll( buff->data, addrH, buff->id, - // buff->last_idx, ~FALSE ); - //} if (buff->mapper == DPROM) { //select bank @@ -211,28 +131,16 @@ uint8_t dump_buff( buffer *buff ) { buff->cur_byte = nes_dualport_page_rd_poll( buff->data, addrH, buff->id, buff->last_idx, ~FALSE ); } - - if (buff->mapper == MMC1) { - //write bank value to bank table - //page_num shift by 4 bits A12 >> A8(0) - bank = (buff->page_num)>>4; - bank &= 0x1F; //only 5 bits in CHR regs - //LSb doesn't matter in 32KB mode - mmc1_wr(0x8000, 0x10, 1); //set to 4KB bank mode - mmc1_wr(0xA000, bank, 0); //write bank to CHR-ROM bank register - //TODO SXROM/SUROM require writting PRG-ROM MSb of address to CHR registers - - addrH &= 0x0F; //only A11-8 are directly addressable - buff->cur_byte = nes_ppu_page_rd_poll( buff->data, addrH, buff->id, - buff->last_idx, ~FALSE ); - } - break; + case PRGRAM: addrH |= 0x60; //$6000 buff->cur_byte = nes_cpu_page_rd_poll( buff->data, addrH, buff->id, buff->last_idx, ~FALSE ); break; + // #endif + + // #ifdef SNES_CONN case SNESROM: if (buff->mapper == LOROM) { addrH |= 0x80; //$8000 LOROM space @@ -251,12 +159,12 @@ uint8_t dump_buff( buffer *buff ) { bank = ((((buff->page_num)>>8) | 0x40) & 0x7F); } HADDR_SET( bank ); - buff->cur_byte = snes_rom_page_rd_poll( buff->data, addrH, buff->id, + buff->cur_byte = snes_page_rd_poll( buff->data, addrH, 0, buff->id, //id contains MSb of page when <256B buffer buff->last_idx, ~FALSE ); - case SNESRAM: -//warn addrX = ((buff->page_num)>>8); break; + // #endif + default: return ERR_BUFF_UNSUP_MEM_TYPE; } diff --git a/firmware/source/flash.c b/firmware/source/flash.c index 7bf7425..7a0ba97 100644 --- a/firmware/source/flash.c +++ b/firmware/source/flash.c @@ -20,89 +20,44 @@ uint8_t write_page( uint8_t addrH, buffer *buff, write_funcptr wr_func ) return SUCCESS; } -uint8_t write_page_old( uint8_t bank, uint8_t addrH, uint16_t unlock1, uint16_t unlock2, buffer *buff, write_funcptr wr_func, read_funcptr rd_func ) +//only used by cninja currently.. +uint8_t write_page_cninja( uint8_t bank, uint8_t addrH, uint16_t unlock1, uint16_t unlock2, buffer *buff, write_funcptr wr_func, read_funcptr rd_func ) { uint16_t cur = buff->cur_byte; uint8_t n = buff->cur_byte; uint8_t read; - while ( cur <= buff->last_idx ) { //write unlock sequence wr_func( unlock1, 0xAA ); wr_func( unlock2, 0x55 ); wr_func( unlock1, 0xA0 ); wr_func( ((addrH<<8)| n), buff->data[n] ); - do { usbPoll(); read = rd_func((addrH<<8)|n); - } while( read != rd_func((addrH<<8)|n) ); - - //retry if write failed - //this helped but still seeing similar fails to dumps -// if (read == buff->data[n]) { - n++; - cur++; -// LED_IP_PU(); -// LED_LO(); -// } else { -// nes_cpu_wr(0x5000, 0x81); //outer reg select mode -// nes_cpu_wr(0x8000, bank); //outer bank -// nes_cpu_wr(0x5000, 0x00); //chr reg select act like cnrom -// LED_OP(); -// LED_HI(); -// } - } - buff->cur_byte = n; - return SUCCESS; - } -uint8_t write_page_bank( uint8_t bank, uint8_t addrH, uint16_t unlock1, uint16_t unlock2, buffer *buff, write_funcptr wr_func, read_funcptr rd_func ) +//only used by MM2 currently +uint8_t write_page_mm2( uint8_t bank, uint8_t addrH, uint16_t unlock1, uint16_t unlock2, buffer *buff, write_funcptr wr_func, read_funcptr rd_func ) { uint16_t cur = buff->cur_byte; uint8_t n = buff->cur_byte; uint8_t read; - while ( cur <= buff->last_idx ) { - - //select first bank for unlock sequence - //needs to be written to bank table! -// nes_cpu_wr( (0xCC84), 0x00 ); -// nes_cpu_wr( (0xE473), 0x00 ); - // nes_cpu_wr( (0xC000), 0x00 ); nes_cpu_wr( (0xFD69), 0x00 ); - - //wr_func( 0x5555, 0xAA ); wr_func( unlock1, 0xAA ); - //wr_func( 0x2AAA, 0x55 ); wr_func( unlock2, 0x55 ); - //wr_func( 0x5555, 0xA0 ); wr_func( unlock1, 0xA0 ); - - //now need to select bank for the actual write! - //but this write can't be applied to the PRG-ROM - // nes_cpu_wr( (0xCC84+bank), bank ); - // nes_cpu_wr( (0xE473+bank), bank ); - // nes_cpu_wr( (0x8000+bank), bank ); - //nes_cpu_wr( (0xC000+bank), bank ); - // nes_cpu_wr( (0xFFC0+bank), bank ); nes_cpu_wr( (0xFD69+bank), bank ); - wr_func( ((addrH<<8)| n), buff->data[n] ); - do { usbPoll(); read = rd_func((addrH<<8)|n); - } while( read != rd_func((addrH<<8)|n) ); - - //retry if write failed - //this helped but still seeing similar fails to dumps if (read == buff->data[n]) { n++; cur++; @@ -112,26 +67,19 @@ uint8_t write_page_bank( uint8_t bank, uint8_t addrH, uint16_t unlock1, uint16_t LED_OP(); LED_HI(); } - } - buff->cur_byte = n; - return SUCCESS; - } - uint8_t write_page_bank_map30( uint8_t bank, uint8_t addrH, uint16_t unlock1, uint16_t unlock2, buffer *buff, write_funcptr wr_func, read_funcptr rd_func ) { uint16_t cur = buff->cur_byte; uint8_t n = buff->cur_byte; uint8_t read; - while ( cur <= buff->last_idx ) { //select first bank for unlock sequence - //wr_func( 0x5555, 0xAA ); nes_cpu_wr( 0xC000, 0x01 ); wr_func( unlock1, 0xAA ); @@ -144,17 +92,12 @@ uint8_t write_page_bank_map30( uint8_t bank, uint8_t addrH, uint16_t unlock1, ui //now need to select bank for the actual write! nes_cpu_wr( 0xC000, bank ); - wr_func( ((addrH<<8)| n), buff->data[n] ); - do { usbPoll(); read = rd_func((addrH<<8)|n); } while( read != rd_func((addrH<<8)|n) ); - - //retry if write failed - //this helped but still seeing similar fails to dumps if (read == buff->data[n]) { n++; cur++; @@ -166,78 +109,21 @@ uint8_t write_page_bank_map30( uint8_t bank, uint8_t addrH, uint16_t unlock1, ui } } - buff->cur_byte = n; - return SUCCESS; - } -uint8_t write_page_mmc1( uint8_t bank, uint8_t addrH, uint16_t unlock1, uint16_t unlock2, buffer *buff, write_funcptr wr_func, read_funcptr rd_func ) -{ - uint16_t cur = buff->cur_byte; - uint8_t n = buff->cur_byte; - uint8_t read; - - while ( cur <= buff->last_idx ) { - - mmc1_wr(0x8000, 0x10, 0); //32KB mode - //IDK why, but somehow only the first byte gets programmed when ROM A14=1 - //so somehow it's getting out of 32KB mode for follow on bytes.. - //even though we reset to 32KB mode after the corrupting final write - - wr_func( unlock1, 0xAA ); - wr_func( unlock2, 0x55 ); - wr_func( unlock1, 0xA0 ); - wr_func( ((addrH<<8)| n), buff->data[n] ); - - //writes to flash are to $8000-FFFF so any register could have been corrupted and shift register may be off - //In reality MMC1 should have blocked all subsequent writes, so maybe only the CHR reg2 got corrupted..? - mmc1_wr(0x8000, 0x10, 1); //32KB mode - mmc1_wr(0xE000, bank, 0); //reset shift register, and bank register - - do { - usbPoll(); - read = rd_func((addrH<<8)|n); - - } while( read != rd_func((addrH<<8)|n) ); - - //retry if write failed - //this helped but still seeing similar fails to dumps - if (read == buff->data[n]) { - n++; - cur++; - LED_IP_PU(); - LED_LO(); - } else { - mmc1_wr(0x8000, 0x10, 1); //32KB mode - mmc1_wr(0xE000, bank, 0); //reset shift register, and bank register - LED_OP(); - LED_HI(); - } - - } - - buff->cur_byte = n; - - return SUCCESS; - -} uint8_t write_page_a53( uint8_t bank, uint8_t addrH, buffer *buff, write_funcptr wr_func, read_funcptr rd_func ) { uint16_t cur = buff->cur_byte; uint8_t n = buff->cur_byte; uint8_t read; - //enter unlock bypass mode wr_func( 0x8AAA, 0xAA ); wr_func( 0x8555, 0x55 ); wr_func( 0x8AAA, 0x20 ); - while ( cur <= buff->last_idx ) { - - //TODO FIX THIS! It shouldn't be needed! //but for some reason the mapper is loosing it's setting for $5000 register to //permit flash writes. Many writes go through, but at somepoint it gets lost.. @@ -247,18 +133,13 @@ uint8_t write_page_a53( uint8_t bank, uint8_t addrH, buffer *buff, write_funcptr //AVR didn't need this patch so maybe is a speed issue //stmadapter didn't have problems either.. //added time delay before m2 rising edge and it didn't change anything for stm6 - // curaddresswrite( 0xA0 ); //gained ~3KBps (59.13KBps) inl6 with v3.0 proto wr_func( ((addrH<<8)| n), 0xA0 ); - wr_func( ((addrH<<8)| n), buff->data[n] ); - do { usbPoll(); read = rd_func((addrH<<8)|n); - } while( read != rd_func((addrH<<8)|n) ); - //retry if write failed //this helped but still seeing similar fails to dumps if (read == buff->data[n]) { @@ -274,20 +155,14 @@ uint8_t write_page_a53( uint8_t bank, uint8_t addrH, buffer *buff, write_funcptr LED_OP(); LED_HI(); } - } - buff->cur_byte = n; - //exit unlock bypass mode wr_func( 0x8000, 0x90 ); wr_func( 0x8000, 0x00 ); //reset the flash chip, supposed to exit too wr_func( 0x8000, 0xF0 ); - - return SUCCESS; - } uint8_t write_page_tssop( uint8_t bank, uint8_t addrH, buffer *buff, write_funcptr wr_func, read_funcptr rd_func ) @@ -295,26 +170,18 @@ uint8_t write_page_tssop( uint8_t bank, uint8_t addrH, buffer *buff, write_funcp uint16_t cur = buff->cur_byte; uint8_t n = buff->cur_byte; uint8_t read; - //enter unlock bypass mode wr_func( 0x8AAA, 0xAA ); wr_func( 0x8555, 0x55 ); wr_func( 0x8AAA, 0x20 ); - while ( cur <= buff->last_idx ) { - - // curaddresswrite( 0xA0 ); //gained ~3KBps (59.13KBps) inl6 with v3.0 proto wr_func( ((addrH<<8)| n), 0xA0 ); - wr_func( ((addrH<<8)| n), buff->data[n] ); - do { usbPoll(); read = rd_func((addrH<<8)|n); - } while( read != rd_func((addrH<<8)|n) ); - //retry if write failed //this helped but still seeing similar fails to dumps if (read == buff->data[n]) { @@ -330,173 +197,32 @@ uint8_t write_page_tssop( uint8_t bank, uint8_t addrH, buffer *buff, write_funcp LED_OP(); LED_HI(); } - } - buff->cur_byte = n; - //exit unlock bypass mode wr_func( 0x8000, 0x90 ); wr_func( 0x8000, 0x00 ); //reset the flash chip, supposed to exit too wr_func( 0x8000, 0xF0 ); - - return SUCCESS; - } -uint8_t write_page_chr( uint8_t bank, uint8_t addrH, buffer *buff, write_funcptr wr_func, read_funcptr rd_func ) -{ - uint16_t cur = buff->cur_byte; - uint8_t n = buff->cur_byte; - uint8_t read; - - while ( cur <= buff->last_idx ) { - //write unlock sequence - wr_func( 0x1555, 0xAA ); - wr_func( 0x0AAA, 0x55 ); - wr_func( 0x1555, 0xA0 ); - wr_func( ((addrH<<8)| n), buff->data[n] ); - - do { - usbPoll(); - read = rd_func((addrH<<8)|n); - - } while( read != rd_func((addrH<<8)|n) ); - //TODO verify byte is value that was trying to be flashed - //move on to next byte - //n++; - //cur++; - if (read == buff->data[n]) { - n++; - cur++; - LED_IP_PU(); - LED_LO(); - } else { - LED_OP(); - LED_HI(); - } - - } - - buff->cur_byte = n; - - return SUCCESS; - -} - -uint8_t write_page_chr_cnrom( uint8_t bank, uint8_t addrH, buffer *buff, write_funcptr wr_func, read_funcptr rd_func ) -{ - uint16_t cur = buff->cur_byte; - uint8_t n = buff->cur_byte; - uint8_t read; - - while ( cur <= buff->last_idx ) { - //write unlock sequence - nes_cpu_wr( 0x8000, 0x02 ); - wr_func( 0x1555, 0xAA ); - nes_cpu_wr( 0x8000, 0x01 ); - wr_func( 0x0AAA, 0x55 ); - nes_cpu_wr( 0x8000, 0x02 ); - wr_func( 0x1555, 0xA0 ); - nes_cpu_wr( 0x8000, bank ); - wr_func( ((addrH<<8)| n), buff->data[n] ); - - do { - usbPoll(); - nes_cpu_wr( 0x8000, bank ); - read = rd_func((addrH<<8)|n); - - } while( read != rd_func((addrH<<8)|n) ); - //TODO verify byte is value that was trying to be flashed - //move on to next byte - //n++; - //cur++; - if (read == buff->data[n]) { - // n++; - // cur++; - LED_IP_PU(); - LED_LO(); - } else { - LED_OP(); - LED_HI(); - } - - } - - buff->cur_byte = n; - - return SUCCESS; - -} - -uint8_t write_page_chr_cdream( uint8_t bank, uint8_t addrH, buffer *buff, write_funcptr wr_func, read_funcptr rd_func ) -{ - uint16_t cur = buff->cur_byte; - uint8_t n = buff->cur_byte; - uint8_t read; - - while ( cur <= buff->last_idx ) { - //write unlock sequence - nes_cpu_wr(0x8000, 0x20); - wr_func( 0x1555, 0xAA ); - nes_cpu_wr(0x8000, 0x10); - wr_func( 0x0AAA, 0x55 ); - nes_cpu_wr(0x8000, 0x20); - wr_func( 0x1555, 0xA0 ); - nes_cpu_wr(0x8000, bank<<4); - wr_func( ((addrH<<8)| n), buff->data[n] ); - - do { - usbPoll(); - read = rd_func((addrH<<8)|n); - - } while( read != rd_func((addrH<<8)|n) ); - //TODO verify byte is value that was trying to be flashed - //move on to next byte - //n++; - //cur++; - if (read == buff->data[n]) { - n++; - cur++; - LED_IP_PU(); - LED_LO(); - } else { - LED_OP(); - LED_HI(); - } - - } - - buff->cur_byte = n; - - return SUCCESS; - -} - uint8_t write_page_dualport( uint8_t bank, uint8_t addrH, buffer *buff, write_funcptr wr_func, read_funcptr rd_func ) { uint16_t cur = buff->cur_byte; uint8_t n = buff->cur_byte; uint8_t read; - //enter unlock bypass mode wr_func( 0x0AAA, 0xAA ); wr_func( 0x0555, 0x55 ); wr_func( 0x0AAA, 0x20 ); - while ( cur <= buff->last_idx ) { - wr_func( ((addrH<<8)| n), 0xA0 ); - wr_func( ((addrH<<8)| n), buff->data[n] ); - do { usbPoll(); read = rd_func((addrH<<8)|n); - } while( read != rd_func((addrH<<8)|n) ); //TODO verify byte is value that was trying to be flashed //move on to next byte @@ -511,21 +237,14 @@ uint8_t write_page_dualport( uint8_t bank, uint8_t addrH, buffer *buff, write_fu LED_OP(); LED_HI(); } - } - buff->cur_byte = n; - - //exit unlock bypass mode wr_func( 0x0000, 0x90 ); wr_func( 0x0000, 0x00 ); //reset the flash chip, supposed to exit too wr_func( 0x0000, 0xF0 ); - - return SUCCESS; - } //#define PRGM_MODE() swim_wotf(SWIM_HS, 0x500F, 0x40) @@ -535,71 +254,45 @@ uint8_t write_page_dualport( uint8_t bank, uint8_t addrH, buffer *buff, write_fu #define PRGM_MODE() NOP() #define PLAY_MODE() NOP() -uint8_t write_page_snes( uint8_t bank, uint8_t addrH, buffer *buff, write_funcptr wr_func, read_funcptr rd_func ) +uint8_t write_page_snes( uint8_t bank, uint8_t addrH, buffer *buff, write_snes_funcptr wr_func, read_snes_funcptr rd_func ) { uint16_t cur = buff->cur_byte; uint8_t n = buff->cur_byte; uint8_t read; - #ifdef AVR_CORE wdt_reset(); #endif - - //set to program mode for first entry //EXP0_LO(); //swim_wotf(SWIM_HS, 0x500F, 0x40) PRGM_MODE(); //; TODO I don't think all these NOPs are actually needed, but they work and don't seem to significantly affect program time on stm32 - NOP(); - NOP(); - NOP(); - NOP(); - NOP(); - NOP(); - NOP(); - NOP(); - + NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); //enter unlock bypass mode - wr_func( 0x8AAA, 0xAA ); - wr_func( 0x8555, 0x55 ); - wr_func( 0x8AAA, 0x20 ); - - + wr_func( 0x8AAA, 0xAA, 0 ); + wr_func( 0x8555, 0x55, 0 ); + wr_func( 0x8AAA, 0x20, 0 ); while ( cur <= buff->last_idx ) { //write unlock sequence - //unlocked wr_func( 0x0AAA, 0xAA ); //unlocked wr_func( 0x0555, 0x55 ); - //wr_func( 0x0000, 0xA0 ); - snes_rom_wr_cur_addr( 0xA0 ); //gained ~3KBps (59.13KBps) inl6 with v3.0 proto - - wr_func( ((addrH<<8)| n), buff->data[n] ); + snes_wr_cur_addr( 0xA0, 0 ); //gained ~3KBps (59.13KBps) inl6 with v3.0 proto + wr_func( ((addrH<<8)| n), buff->data[n], 0 ); //wr_func( ((addrH<<8)| n), cur_data ); //didn't actually speed up - //Targetting 2MByte 16mbit flash which doesn't have buffered writes //currently have average flash speed of 21.05KBps going to start removing some of these NOPs //and optimizing flash routine to get time down. - //exit program mode // EXP0_HI(); PLAY_MODE(); - NOP(); - NOP(); - NOP(); - NOP(); - NOP(); - NOP(); - NOP(); - NOP(); + NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); //pre-fetch next byte of data //cur_data = buff->data[n+1]; #ifdef AVR_CORE wdt_reset(); #endif - //wait for byte to flash // do { // usbPoll(); @@ -610,73 +303,33 @@ uint8_t write_page_snes( uint8_t bank, uint8_t addrH, buffer *buff, write_funcpt //this can cause things to hang on failed programs.. //need a smarter flash polling algo, kind of a pain because we don't have //a good way to toggle /OE or /CE quickly on v3 SNES boards - - usbPoll(); - read = rd_func((addrH<<8)|n); + read = rd_func((addrH<<8)|n, 0); //prepare for upcoming write cycle, or allow for a polling read //EXP0_LO(); PRGM_MODE(); - NOP(); - NOP(); - NOP(); - NOP(); - NOP(); - NOP(); - NOP(); - NOP(); + NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); //First check if already outputting final data if (read != buff->data[n] ) { //if not, lets see if toggle is occuring //EXP0_HI(); PLAY_MODE(); - NOP(); - NOP(); - NOP(); - NOP(); - NOP(); - NOP(); - NOP(); - NOP(); - while( read != rd_func((addrH<<8)|n) ){ + NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); + while( read != rd_func((addrH<<8)|n, 0) ){ //EXP0_LO(); PRGM_MODE(); - NOP(); NOP(); NOP(); NOP(); - NOP(); NOP(); NOP(); NOP(); - NOP(); NOP(); NOP(); NOP(); - NOP(); - NOP(); - NOP(); - NOP(); - NOP(); - NOP(); - NOP(); - NOP(); + NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); + NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); //EXP0_HI(); PLAY_MODE(); - NOP(); - NOP(); - NOP(); - NOP(); - NOP(); - NOP(); - NOP(); - NOP(); - read = rd_func((addrH<<8)|n); + NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); + read = rd_func((addrH<<8)|n, 0); } //prepare for upcoming write cycle //EXP0_LO(); PRGM_MODE(); - NOP(); - NOP(); - NOP(); - NOP(); - NOP(); - NOP(); - NOP(); - NOP(); + NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); } - // //IDK why, but AVR will exit early sometimes // //without this second check, ~20 errors per 32KByte on SNES v3.0 // //All error bytes are 0xFF instead of true data @@ -689,7 +342,6 @@ uint8_t write_page_snes( uint8_t bank, uint8_t addrH, buffer *buff, write_funcpt // //Ahh this is the issue, adding the code below only adds delay which gives flash // //enough time to complete write. - //retry if write failed //this helped but still seeing similar fails to dumps n++; @@ -709,17 +361,15 @@ uint8_t write_page_snes( uint8_t bank, uint8_t addrH, buffer *buff, write_funcpt buff->cur_byte = n; //exit unlock bypass mode - wr_func( 0x8000, 0x90 ); - wr_func( 0x8000, 0x00 ); + wr_func( 0x8000, 0x90, 0 ); + wr_func( 0x8000, 0x00, 0 ); //reset the flash chip, supposed to exit too - wr_func( 0x8000, 0xF0 ); + wr_func( 0x8000, 0xF0, 0 ); //exit program mode //EXP0_HI(); PLAY_MODE(); - return SUCCESS; - } /* Desc:Flash buffer contents on to cartridge memory @@ -734,54 +384,32 @@ uint8_t flash_buff( buffer *buff ) { uint8_t addrH = buff->page_num; //A15:8 while accessing page uint8_t bank; - //First need to initialize mapper register bits - //Perhaps this only needs to be done on first buffer though..? - //Actually think this is best handled from buffer.c in operation == STARTFLASH - - //TODO use mapper to set mapper controlled address bits - - //need to calculate current bank and addrH - - //TODO set unlock addresses based on what works for that mapper and how it's banks are initialized - - //use mem_type to set addrH/X as needed for dump loop - //also use to get read function pointer switch ( buff->mem_type ) { +// #ifdef NES_CONN case PRGROM: //$8000 + + //Latest method used here! + //leave the host responsible for init & banking + //we just need to call a page write algo and give it mmc3_prgrom_flash_wr function + //think of this only as an 8KB ROM + //ie MMC3 flash writes are always $8000-9FFF, but the host arranges this + if (buff->mapper == NROM) { - //write_page_old( 0, (0x80 | addrH), 0x5555, 0x2AAA, buff, discrete_exp0_prgrom_wr, nes_cpu_rd ); + //used by other 32KB PRG bank discrete mappers like BNROM, CNROM, & color dreams write_page( (0x80+addrH), buff, nrom_prgrom_flash_wr); } if (buff->mapper == MMC1) { - //write bank value - //page_num shift by 6 bits A15 >> A9(1) - bank = (buff->page_num)>>6; //LSbit doesn't matter in 32KB mode - bank &= 0x0F; //only 4 bits in PRG register - mmc1_wr(0x8000, 0x10, 1); //ensure 32KB mode - mmc1_wr(0xE000, bank, 0); //write bank to PRG-ROM bank register - //TODO SXROM/SUROM require writting PRG-ROM MSb of address to CHR registers - write_page_mmc1( bank, (0x80 | addrH), 0xD555, 0xAAAA, buff, nes_cpu_wr, nes_cpu_rd ); + write_page( (0x80+addrH), buff, mmc1_prgrom_flash_wr); } if (buff->mapper == UxROM) { - //addrH &= 0b1011 1111 A14 must always be low - addrH &= 0x3F; - addrH |= 0x80; //A15 doesn't apply to exp0 write, but needed for read back - //write bank value - //page_num shift by 6 bits A14 >> A8(0) - bank = buff->page_num >> 6; - //bank gets written inside flash algo - write_page_bank( bank, addrH, 0x5555, 0x2AAA, buff, discrete_exp0_prgrom_wr, nes_cpu_rd ); + write_page( (0x80+addrH), buff, unrom_prgrom_flash_wr); } - if (buff->mapper == MMC3) { - //Latest method used here! - //leave the host responsible for init & banking - //we just need to call a page write algo and give it mmc3_prgrom_flash_wr function - //think of this only as an 8KB ROM - //MMC3 flash writes are always $8000-9FFF, but the host arranges this write_page( (0x80+addrH), buff, mmc3_prgrom_flash_wr); } - + if (buff->mapper == MMC4) { + write_page( (0x80+addrH), buff, mmc4_prgrom_sop_flash_wr); + } if (buff->mapper == MM2) { //addrH &= 0b1011 1111 A14 must always be low addrH &= 0x3F; @@ -790,7 +418,7 @@ uint8_t flash_buff( buffer *buff ) { //page_num shift by 6 bits A14 >> A8(0) bank = buff->page_num >> 6; //bank gets written inside flash algo - write_page_bank( bank, addrH, 0x5555, 0x2AAA, buff, disc_push_exp0_prgrom_wr, nes_cpu_rd ); + write_page_mm2( bank, addrH, 0x5555, 0x2AAA, buff, disc_push_exp0_prgrom_wr, nes_cpu_rd ); } if (buff->mapper == MAP30) { //addrH &= 0b1011 1111 A14 must always be low @@ -802,31 +430,16 @@ uint8_t flash_buff( buffer *buff ) { //bank gets written inside flash algo write_page_bank_map30( bank, addrH, 0x9555, 0xAAAA, buff, nes_cpu_wr, nes_cpu_rd ); } - //if ((buff->mapper == BxROM) || (buff->mapper == CDREAM)) { - //new method uses same algo as NROM, host handles all the banking! - // //write bank value - // //page_num shift by 7 bits A15 >> A8(0) - // bank = buff->page_num >> 7; - // //Lizard banktable location - // nes_cpu_wr( (0xFF94+bank), bank ); - // //hh85 - // //nes_cpu_wr( (0xFFE0+bank), bank ); - // //Mojontales - // //nes_cpu_wr( 0x800C, 0x00); //select first bank (only bank with table) - // //nes_cpu_wr( (0xCC43+bank), bank ); //then select desired bank - // write_page_old( 0, (0x80 | addrH), 0x5555, 0x2AAA, buff, discrete_exp0_prgrom_wr, nes_cpu_rd ); - //} if (buff->mapper == CNINJA) { //addrH &= 0b1001 1111 A14-13 must always be low addrH &= 0x1F; addrH |= 0x80; - //write bank value //page_num shift by 5 bits A13 >> A8(0) bank = buff->page_num >> 5; nes_cpu_wr( (0x6000), 0xA5 ); //select desired bank nes_cpu_wr( (0xFFFF), bank ); //select desired bank - write_page_old( 0, addrH, 0xD555, 0xAAAA, buff, nes_cpu_wr, nes_cpu_rd ); + write_page_cninja( 0, addrH, 0xD555, 0xAAAA, buff, nes_cpu_wr, nes_cpu_rd ); } if (buff->mapper == A53) { //write bank value to bank table @@ -860,36 +473,24 @@ uint8_t flash_buff( buffer *buff ) { write_page_tssop( bank, (0x80 | addrH), buff, nes_cpu_wr, nes_cpu_rd ); } break; + case CHRROM: //$0000 if (buff->mapper == NROM) { - //write_page_chr( 0, addrH, buff, nes_ppu_wr, nes_ppu_rd ); write_page( addrH, buff, nrom_chrrom_flash_wr); } - + if (buff->mapper == MMC1) { + write_page( addrH, buff, mmc1_chrrom_flash_wr); + } if (buff->mapper == CNROM) { - //cur_bank and bank_table must be set in nes.c prior to calling write_page( addrH, buff, cnrom_chrrom_flash_wr); } if (buff->mapper == MMC3) { - //Latest method used here! - //leave the host responsible for init & banking - //we just need to call a page write algo and give it mmc3_prgrom_flash_wr function - //think of this only as an 8KB ROM - //MMC3 flash writes are always $8000-9FFF write_page( addrH, buff, mmc3_chrrom_flash_wr); } + if (buff->mapper == MMC4) { + write_page( addrH, buff, mmc4_chrrom_flash_wr); + } if (buff->mapper == CDREAM) { -// //select bank -// //8KB banks $0000-1FFF -// //page_num shift by 5 bits A13 >> A8(0) -// bank = (buff->page_num)>>5; -// -// //write bank to register -// //done inside write routine -// //nes_cpu_wr(0x8000, bank<<4); -// -// addrH &= 0x1F; //only A12-8 are directly addressable -// write_page_chr_cdream( bank, addrH, buff, nes_ppu_wr, nes_ppu_rd ); write_page( addrH, buff, cdream_chrrom_flash_wr); } if (buff->mapper == DPROM) { @@ -897,10 +498,8 @@ uint8_t flash_buff( buffer *buff ) { //8KB banks $0000-1FFF //page_num shift by 5 bits A13 >> A8(0) bank = (buff->page_num)>>5; - //write bank to register nes_ppu_wr(0x3FFF, bank); - addrH &= 0x1F; //only A12-8 are directly addressable write_page_dualport( 0, addrH, buff, nes_dualport_wr, nes_dualport_rd ); } @@ -909,7 +508,9 @@ uint8_t flash_buff( buffer *buff ) { case PRGRAM: write_page( addrH+0x60, buff, nes_cpu_wr); break; + //#endif + //#ifdef SNES_CONN case SNESROM: if (buff->mapper == LOROM_5VOLT) { //LOROM banks start at $XX:8000 @@ -938,7 +539,7 @@ uint8_t flash_buff( buffer *buff ) { //clear any reset state //EXP0_HI(); HADDR_SET( bank ); - write_page_snes( 0, addrH, buff, snes_rom_wr, snes_rom_rd ); + write_page_snes( 0, addrH, buff, snes_wr, snes_rd ); } if (buff->mapper == HIROM) { //need to split page_num @@ -948,11 +549,13 @@ uint8_t flash_buff( buffer *buff ) { //A23 ~page_num[14] (bank CO starts first half, bank 40 starts second) bank = ((((buff->page_num)>>8) | 0x40) & 0x7F); HADDR_SET( bank ); - write_page_snes( 0, addrH, buff, snes_rom_wr, snes_rom_rd ); + write_page_snes( 0, addrH, buff, snes_wr, snes_rd ); } case SNESRAM: //warn addrX = ((buff->page_num)>>8); break; + // #endif + default: return ERR_BUFF_UNSUP_MEM_TYPE; } diff --git a/firmware/source/nes.c b/firmware/source/nes.c index 5de010a..0df46d5 100644 --- a/firmware/source/nes.c +++ b/firmware/source/nes.c @@ -68,6 +68,15 @@ uint8_t nes_call( uint8_t opcode, uint8_t miscdata, uint16_t operand, uint8_t *r case NROM_CHR_FLASH_WR: nrom_chrrom_flash_wr( operand, miscdata ); break; + case MMC1_PRG_FLASH_WR: + mmc1_prgrom_flash_wr( operand, miscdata ); + break; + case MMC1_CHR_FLASH_WR: + mmc1_chrrom_flash_wr( operand, miscdata ); + break; + case UNROM_PRG_FLASH_WR: + unrom_prgrom_flash_wr( operand, miscdata ); + break; case CNROM_CHR_FLASH_WR: cnrom_chrrom_flash_wr( operand, miscdata ); break; @@ -77,6 +86,12 @@ uint8_t nes_call( uint8_t opcode, uint8_t miscdata, uint16_t operand, uint8_t *r case MMC3_CHR_FLASH_WR: mmc3_chrrom_flash_wr( operand, miscdata ); break; + case MMC4_PRG_SOP_FLASH_WR: + mmc4_prgrom_sop_flash_wr( operand, miscdata ); + break; + case MMC4_CHR_FLASH_WR: + mmc4_chrrom_flash_wr( operand, miscdata ); + break; case CDREAM_CHR_FLASH_WR: cdream_chrrom_flash_wr( operand, miscdata ); break; @@ -809,7 +824,7 @@ uint8_t nes_dualport_page_rd_poll( uint8_t *data, uint8_t addrH, uint8_t first, -/* Desc:NES MMC1 Write +/* Desc:NES MMC1 Mapper Register Write * write to entirety of MMC1 register * address selects register that's written to * address must be >= $8000 where registers are located @@ -896,6 +911,109 @@ void nrom_chrrom_flash_wr( uint16_t addr, uint8_t data ) } +/* Desc:NES MMC1 PRG-ROM FLASH Write + * Pre: nes_init() setup of io pins + * MMC1 must be properly inialized for flashing + * 32KB mode with current bank selected + * addr must be between $8000-FFFF as prescribed by init + * Post:Byte written and ready for another write + * Rtn: None + */ +void mmc1_prgrom_flash_wr( uint16_t addr, uint8_t data ) +{ + + uint8_t rv; + + //make a generic write to mapper reg so the last write will block all subsequent writes + mmc1_wr(0xC000, 0x05, 0); //just write to random CHR ROM register + + //unlock and write data + //all these writes will be block by MMC1 mapper register due to valid write above that ends with a write + nes_cpu_wr(0x5555, 0xAA); + nes_cpu_wr(0xAAAA, 0x55); + nes_cpu_wr(0x5555, 0xA0); + nes_cpu_wr(addr, data); + + do { + rv = nes_cpu_rd(addr); + usbPoll(); //orignal kazzo needs this frequently to slurp up incoming data + } while (rv != nes_cpu_rd(addr)); + //TODO handle timeout + + return; +} + + +/* Desc:NES MMC1 CHR-ROM FLASH Write + * Pre: nes_init() setup of io pins + * cur_bank global var must be set to desired mapper register value + * Post:Byte written and ready for another write + * Rtn: None + */ +void mmc1_chrrom_flash_wr( uint16_t addr, uint8_t data ) +{ + + uint8_t rv; + + //set banks for unlock commands + mmc1_wr(0xA000, 0x02, 0); + //PT1 always set to 0x05 for $5555 command + + //send unlock command + nes_ppu_wr(0x1555, 0xAA); + nes_ppu_wr(0x0AAA, 0x55); + nes_ppu_wr(0x1555, 0xA0); + + //select desired bank for write + mmc1_wr(0xA000, cur_bank, 0); + //write the data + nes_ppu_wr(addr, data); + + do { + rv = nes_ppu_rd(addr); + usbPoll(); //orignal kazzo needs this frequently to slurp up incoming data + } while (rv != nes_ppu_rd(addr)); + + return; +} + + + + +/* Desc:NES UNROM PRG-ROM FLASH Write + * Pre: nes_init() setup of io pins + * cur_bank global var must be set to desired mapper register value + * bank_table global var must be set to base address of the bank table + * Post:Byte written and ready for another write + * Rtn: None + */ +void unrom_prgrom_flash_wr( uint16_t addr, uint8_t data ) +{ + + uint8_t rv; + + //set A14 low for lower bank so to satisfy unlock commands + nes_cpu_wr(bank_table, 0x00); + + //unlock the flash + discrete_exp0_prgrom_wr(0x5555, 0xAA); + discrete_exp0_prgrom_wr(0x2AAA, 0x55); + discrete_exp0_prgrom_wr(0x5555, 0xA0); + + //select desired bank and write data + nes_cpu_wr(bank_table+cur_bank, cur_bank); + discrete_exp0_prgrom_wr(addr, data); + + do { + rv = nes_cpu_rd(addr); + usbPoll(); //orignal kazzo needs this frequently to slurp up incoming data + } while (rv != nes_cpu_rd(addr)); + + return; +} + + + /* Desc:NES CNROM CHR-ROM FLASH Write * Pre: nes_init() setup of io pins * cur_bank global var must be set to desired mapper register value @@ -993,6 +1111,93 @@ void mmc3_chrrom_flash_wr( uint16_t addr, uint8_t data ) } +/* Desc:NES MMC4 PRG-ROM FLASH Write + * Pre: nes_init() setup of io pins + * MMC4 must be properly inialized for flashing + * addr must be between $8000-BFFF as prescribed by init + * desired bank must already be selected + * cur_bank must be set to desired bank for recovery + * Post:Byte written and ready for another write + * Rtn: None + */ +void mmc4_prgrom_sop_flash_wr( uint16_t addr, uint8_t data ) +{ + + uint8_t rv; + + //unlock and write data SOP-44 flash + nes_cpu_wr(0xFAAA, 0xAA); + nes_cpu_wr(0xF555, 0x55); + nes_cpu_wr(0xFAAA, 0xA0); + nes_cpu_wr(addr, data); //corrupts bank register if addr $A000-AFFF + + //recover bank register as data write would have corrupted + nes_cpu_wr(0xA000, cur_bank); + + do { + rv = nes_cpu_rd(addr); + usbPoll(); //orignal kazzo needs this frequently to slurp up incoming data + } while (rv != nes_cpu_rd(addr)); + //TODO handle timeout + + return; +} + + +/* Desc:NES MMC4 CHR-ROM FLASH Write + * Pre: nes_init() setup of io pins + * cur_bank global var must be set to desired mapper register value + * Post:Byte written and ready for another write + * Rtn: None + */ +void mmc4_chrrom_flash_wr( uint16_t addr, uint8_t data ) +{ + + uint8_t rv; +//--set bank for unlock command +//dict.nes("NES_CPU_WR", 0xB000, 0x0A) --4KB @ PPU $0000 -> $2AAA cmd & writes +//dict.nes("NES_CPU_WR", 0xC000, 0x0A) --4KB @ PPU $0000 +// +//--send unlock command +//dict.nes("NES_PPU_WR", 0x1555, 0xAA) +//dict.nes("NES_PPU_WR", 0x0AAA, 0x55) +//dict.nes("NES_PPU_WR", 0x1555, 0xA0) +// +//--select desired bank +//dict.nes("NES_CPU_WR", 0xB000, bank) --4KB @ PPU $0000 -> $2AAA cmd & writes +//dict.nes("NES_CPU_WR", 0xC000, bank) --4KB @ PPU $0000 +//--write data +//dict.nes("NES_PPU_WR", addr, value) + + //set banks for unlock commands + nes_cpu_wr(0xB000, 0x0A); + nes_cpu_wr(0xC000, 0x0A); + + //PT1 always set to 0x05 for $5555 command + + //send unlock command + nes_ppu_wr(0x1555, 0xAA); + nes_ppu_wr(0x0AAA, 0x55); + nes_ppu_wr(0x1555, 0xA0); + + //select desired bank for write + nes_cpu_wr(0xB000, cur_bank); + nes_cpu_wr(0xC000, cur_bank); + + //write the data + nes_ppu_wr(addr, data); + + do { + rv = nes_ppu_rd(addr); + usbPoll(); //orignal kazzo needs this frequently to slurp up incoming data + } while (rv != nes_ppu_rd(addr)); + + return; +} + + + + /* Desc:NES ColorDreams CHR-ROM FLASH Write * Pre: nes_init() setup of io pins * cur_bank global var must be set to desired mapper register value @@ -1032,8 +1237,3 @@ void cdream_chrrom_flash_wr( uint16_t addr, uint8_t data ) return; } - - - - - diff --git a/firmware/source/nes.h b/firmware/source/nes.h index d0ceaff..ebc2a89 100644 --- a/firmware/source/nes.h +++ b/firmware/source/nes.h @@ -27,9 +27,14 @@ void mmc1_wr( uint16_t addr, uint8_t data, uint8_t reset ); void nrom_prgrom_flash_wr( uint16_t addr, uint8_t data ); void nrom_chrrom_flash_wr( uint16_t addr, uint8_t data ); +void mmc1_prgrom_flash_wr( uint16_t addr, uint8_t data ); +void mmc1_chrrom_flash_wr( uint16_t addr, uint8_t data ); +void unrom_prgrom_flash_wr( uint16_t addr, uint8_t data ); void cnrom_chrrom_flash_wr( uint16_t addr, uint8_t data ); void mmc3_prgrom_flash_wr( uint16_t addr, uint8_t data ); void mmc3_chrrom_flash_wr( uint16_t addr, uint8_t data ); +void mmc4_prgrom_sop_flash_wr( uint16_t addr, uint8_t data ); +void mmc4_chrrom_flash_wr( uint16_t addr, uint8_t data ); void cdream_chrrom_flash_wr( uint16_t addr, uint8_t data ); diff --git a/firmware/source/snes.c b/firmware/source/snes.c index 1ba205d..8667dff 100644 --- a/firmware/source/snes.c +++ b/firmware/source/snes.c @@ -33,7 +33,10 @@ uint8_t snes_call( uint8_t opcode, uint8_t miscdata, uint16_t operand, uint8_t * HADDR_SET( operand ); break; case SNES_ROM_WR: - snes_rom_wr( operand, miscdata ); + snes_wr( operand, miscdata, 0 ); //last arg is romsel state + break; + case SNES_SYS_WR: + snes_wr( operand, miscdata, 1 ); //last arg is romsel state break; case FLASH_WR_5V: snes_5v_flash_wr( operand, miscdata ); @@ -45,7 +48,11 @@ uint8_t snes_call( uint8_t opcode, uint8_t miscdata, uint16_t operand, uint8_t * //8bit return values: case SNES_ROM_RD: rdata[RD_LEN] = BYTE_LEN; - rdata[RD0] = snes_rom_rd( operand ); + rdata[RD0] = snes_rd( operand, 0 ); //last arg is romsel state + break; + case SNES_SYS_RD: + rdata[RD_LEN] = BYTE_LEN; + rdata[RD0] = snes_rd( operand, 1 ); //last arg is romsel state break; default: //macro doesn't exist @@ -57,7 +64,7 @@ uint8_t snes_call( uint8_t opcode, uint8_t miscdata, uint16_t operand, uint8_t * } /* Desc:SNES ROM Read without changing high bank - * /ROMSEL always set low + * /ROMSEL set based on romsel arg * EXP0/RESET not affected * NOTE: this will access addresses when /ROMSEL isn't low on the console * Pre: snes_init() setup of io pins @@ -65,14 +72,16 @@ uint8_t snes_call( uint8_t opcode, uint8_t miscdata, uint16_t operand, uint8_t * * data bus left clear * Rtn: Byte read from ROM at addr */ -uint8_t snes_rom_rd( uint16_t addr ) +uint8_t snes_rd( uint16_t addr, uint8_t romsel ) { uint8_t read; //return value //set address bus ADDR_SET(addr); - ROMSEL_LO(); + if (romsel==0) + ROMSEL_LO(); + CSRD_LO(); //couple more NOP's waiting for data @@ -110,7 +119,7 @@ uint8_t snes_rom_rd( uint16_t addr ) } /* Desc:SNES ROM Write - * /ROMSEL always set low + * /ROMSEL set based on romsel arg * EXP0/RESET unaffected * write value to currently selected bank * NOTE: this will access addresses when /ROMSEL isn't low on the console @@ -119,7 +128,7 @@ uint8_t snes_rom_rd( uint16_t addr ) * address left on bus * Rtn: None */ -void snes_rom_wr( uint16_t addr, uint8_t data ) +void snes_wr( uint16_t addr, uint8_t data, uint8_t romsel ) { ADDR_SET(addr); @@ -132,7 +141,8 @@ void snes_rom_wr( uint16_t addr, uint8_t data ) //level shifter on v3.0 boards CSWR_LO(); //Then set romsel as this enables output of level shifter - ROMSEL_LO(); + if (romsel==0) + ROMSEL_LO(); //Doing the other order creates bus conflict between ROMSEL low -> WR low //give some time @@ -142,8 +152,10 @@ void snes_rom_wr( uint16_t addr, uint8_t data ) //swaping /WR /ROMSEL order above helped greatly //but still had 2 byte fails adding NOPS NOP(); //4x total NOPs passed all bytes v3.0 SNES and inl6 - //NOP(); - //NOP(); //6x total NOPs passed all bytes + NOP(); + NOP(); //6x total NOPs passed all bytes + NOP(); + NOP(); //latch data to cart memory/mapper @@ -155,7 +167,7 @@ void snes_rom_wr( uint16_t addr, uint8_t data ) } /* Desc:SNES ROM Write to current address - * /ROMSEL always set low + * /ROMSEL set based on romsel arg * EXP0/RESET unaffected * write value to currently selected bank, and current address * Mostly used when address is don't care @@ -164,7 +176,7 @@ void snes_rom_wr( uint16_t addr, uint8_t data ) * address left on bus * Rtn: None */ -void snes_rom_wr_cur_addr( uint8_t data ) +void snes_wr_cur_addr( uint8_t data, uint8_t romsel) { // ADDR_SET(addr); @@ -177,7 +189,8 @@ void snes_rom_wr_cur_addr( uint8_t data ) //level shifter on v3.0 boards CSWR_LO(); //Then set romsel as this enables output of level shifter - ROMSEL_LO(); + if (romsel==0) + ROMSEL_LO(); //Doing the other order creates bus conflict between ROMSEL low -> WR low //give some time @@ -197,8 +210,10 @@ void snes_rom_wr_cur_addr( uint8_t data ) //Free data bus DATA_IP(); } + + /* Desc:SNES ROM Page Read with optional USB polling - * /ROMSEL always low, EXP0/RESET unaffected + * /ROMSEL based on romsel arg, EXP0/RESET unaffected * if poll is true calls usbdrv.h usbPoll fuction * this is needed to keep from timing out when double buffering usb data * Pre: snes_init() setup of io pins @@ -208,7 +223,7 @@ void snes_rom_wr_cur_addr( uint8_t data ) * data buffer filled starting at first to last * Rtn: Index of last byte read */ -uint8_t snes_rom_page_rd_poll( uint8_t *data, uint8_t addrH, uint8_t first, uint8_t len, uint8_t poll ) +uint8_t snes_page_rd_poll( uint8_t *data, uint8_t addrH, uint8_t romsel, uint8_t first, uint8_t len, uint8_t poll ) { uint8_t i; @@ -217,7 +232,10 @@ uint8_t snes_rom_page_rd_poll( uint8_t *data, uint8_t addrH, uint8_t first, uint //set /ROMSEL and /RD CSRD_LO(); - ROMSEL_LO(); + + if (romsel==0) { + ROMSEL_LO(); + } //set lower address bits ADDRL(first); //doing this prior to entry and right after latching @@ -276,15 +294,15 @@ void snes_5v_flash_wr( uint16_t addr, uint8_t data ) uint8_t rv; //unlock and write data - snes_rom_wr(0x5555, 0xAA); - snes_rom_wr(0x2AAA, 0x55); - snes_rom_wr(0x5555, 0xA0); - snes_rom_wr(addr, data); + snes_wr(0x5555, 0xAA, 0); + snes_wr(0x2AAA, 0x55, 0); + snes_wr(0x5555, 0xA0, 0); + snes_wr(addr, data, 0); do { - rv = snes_rom_rd(addr); + rv = snes_rd(addr, 0); usbPoll(); //orignal kazzo needs this frequently to slurp up incoming data - } while (rv != snes_rom_rd(addr)); + } while (rv != snes_rd(addr, 0)); return; } @@ -304,15 +322,15 @@ void snes_3v_flash_wr( uint16_t addr, uint8_t data ) uint8_t rv; //unlock and write data - snes_rom_wr(0x8AAA, 0xAA); - snes_rom_wr(0x8555, 0x55); - snes_rom_wr(0x8AAA, 0xA0); - snes_rom_wr(addr, data); + snes_wr(0x8AAA, 0xAA, 0); + snes_wr(0x8555, 0x55, 0); + snes_wr(0x8AAA, 0xA0, 0); + snes_wr(addr, data, 0); do { - rv = snes_rom_rd(addr); + rv = snes_rd(addr, 0); usbPoll(); //orignal kazzo needs this frequently to slurp up incoming data - } while (rv != snes_rom_rd(addr)); + } while (rv != snes_rd(addr, 0)); return; } diff --git a/firmware/source/snes.h b/firmware/source/snes.h index f8f5472..92a95a2 100644 --- a/firmware/source/snes.h +++ b/firmware/source/snes.h @@ -7,10 +7,10 @@ #include "shared_errors.h" uint8_t snes_call( uint8_t opcode, uint8_t miscdata, uint16_t operand, uint8_t *rdata ); -uint8_t snes_rom_rd( uint16_t addr ); -void snes_rom_wr( uint16_t addr, uint8_t data ); -void snes_rom_wr_cur_addr( uint8_t data ); -uint8_t snes_rom_page_rd_poll( uint8_t *data, uint8_t addrH, uint8_t first, uint8_t len, uint8_t poll ); +uint8_t snes_rd( uint16_t addr, uint8_t romsel ); +void snes_wr( uint16_t addr, uint8_t data, uint8_t romsel ); +void snes_wr_cur_addr( uint8_t data, uint8_t romsel ); +uint8_t snes_page_rd_poll( uint8_t *data, uint8_t addrH, uint8_t romsel, uint8_t first, uint8_t len, uint8_t poll ); void snes_5v_flash_wr( uint16_t addr, uint8_t data ); void snes_3v_flash_wr( uint16_t addr, uint8_t data ); diff --git a/firmware/source/types.h b/firmware/source/types.h index a6aab91..9f705c4 100644 --- a/firmware/source/types.h +++ b/firmware/source/types.h @@ -16,6 +16,8 @@ typedef struct setup_packet{ //typedef uint8_t (*read_funcptr) ( uint8_t addrH, uint8_t addrL ); typedef void (*write_funcptr) ( uint16_t addr, uint8_t data ); typedef uint8_t (*read_funcptr) ( uint16_t addr ); +typedef void (*write_snes_funcptr) ( uint16_t addr, uint8_t data, uint8_t romsel ); +typedef uint8_t (*read_snes_funcptr) ( uint16_t addr, uint8_t romsel ); //~16 bytes per buffer... diff --git a/host/scripts/app/nes.lua b/host/scripts/app/nes.lua index 3e4f3ff..93ce0f6 100644 --- a/host/scripts/app/nes.lua +++ b/host/scripts/app/nes.lua @@ -156,12 +156,13 @@ local function detect_mapper_mirroring (debug) elseif readV ~= 0 and readH ~= 0 then if debug then print("1screen B mirroring sensed") end return "1SCNB" + elseif readV ~= 0 and readH == 0 then if debug then print("vertical mirroring sensed") end return "VERT" elseif readV == 0 and readH ~= 0 then if debug then print("horizontal mirroring sensed") end - return "HORIZ" + return "HORZ" end --]] diff --git a/host/scripts/inlretro.lua b/host/scripts/inlretro.lua index 663ffcf..8f66240 100644 --- a/host/scripts/inlretro.lua +++ b/host/scripts/inlretro.lua @@ -64,10 +64,12 @@ function main () -- ===================================================== --cart/mapper specific scripts --local curcart = require "scripts.nes.nrom" - --local curcart = require "scripts.nes.cnrom" --local curcart = require "scripts.nes.mmc1" - local curcart = require "scripts.nes.mmc3" --local curcart = require "scripts.nes.unrom" + --local curcart = require "scripts.nes.cnrom" + local curcart = require "scripts.nes.mmc3" + --local curcart = require "scripts.nes.mmc2" + --local curcart = require "scripts.nes.mmc4" --local curcart = require "scripts.nes.mm2" --local curcart = require "scripts.nes.mapper30" --local curcart = require "scripts.nes.bnrom" @@ -76,10 +78,12 @@ function main () --local curcart = require "scripts.nes.action53" --local curcart = require "scripts.nes.action53_tsop" --local curcart = require "scripts.nes.easyNSF" + --local curcart = require "scripts.nes.fme7" --local curcart = require "scripts.nes.dualport" --local curcart = require "scripts.snes.v3" --and GAMEBOY for now --local curcart = require "scripts.snes.lorom_5volt" --catskull design --local curcart = require "scripts.snes.v2proto" + --local curcart = require "scripts.snes.v2proto_hirom" --quickly becoming the master SNES script... -- ===================================================== -- USERS: set cart_console to the to point to the mapper script you would like to use here. @@ -123,7 +127,7 @@ function main () -- --BOOTLOADER TEST - --print("jumping...") +-- print("jumping...") --jump to 0xDEADBEEF --dict.bootload("LOAD_ADDRH", 0xDEAD) @@ -132,9 +136,13 @@ function main () -- dict.bootload("JUMP_ADDR", 0xCAC5) -- dict.bootload("LOAD_ADDRH", 0x0800) -- dict.bootload("JUMP_ADDR", 0x00C1) +-- +-- dict.bootload("LOAD_ADDRH", 0x2000) +-- dict.bootload("JUMP_ADDR", 0x0430) - --dict.bootload("JUMP_BL") - --print("jumped") +-- dict.bootload("JUMP_BL") +-- dict.bootload("JUMP_TEST") +-- print("jumped") -- debug = true -- rv = cart.detect(debug) @@ -272,20 +280,6 @@ function main () --DUALPORT --curcart.process( true, false, false, false, false, "ignore/dump.bin", "ignore/ddug2.bin", "ignore/verifyout.bin") - --MMC1 - --curcart.process( true, false, true, true, true, "ignore/dump.bin", "ignore/BB_sgrom.prg", "ignore/verifyout.bin") - --curcart.process( true, false, true, true, true, "ignore/dump.bin", "ignore/Zelda2.bin", "ignore/verifyout.bin") - --curcart.process( true, false, true, true, true, "ignore/dump.bin", "ignore/Zelda2_doubleprg.bin", "ignore/verifyout.bin") - --curcart.process( true, false, true, true, true, "ignore/dump.bin", "ignore/alfonzoMMC1.bin", "ignore/verifyout.bin") - - --UxROM - --curcart.process( true, false, true, true, true, "ignore/dump.bin", "ignore/AFB_128.prg", "ignore/verifyout.bin") - --curcart.process( true, false, true, true, false, "ignore/dump.bin", "ignore/nomolosFINAL.prg", "ignore/verifyout.bin") - --curcart.process( true, false, true, true, false, "ignore/dump.bin", "ignore/owlia_revb.prg", "ignore/verifyout.bin") - --curcart.process( true, false, false, false, false, "ignore/dump.bin", "ignore/rushnattack.prg", "ignore/verifyout.bin") - --curcart.process( true, false, false, false, false, "ignore/dump.bin", "ignore/TDfix.prg", "ignore/verifyout.bin") - - --MM2 --curcart.process( true, false, true, true, false, "ignore/dump.bin", "ignore/mm2_i0.prg", "ignore/verifyout.bin") --curcart.process( true, true, false, false, false, "ignore/dump.bin", "ignore/mm2_i0.prg", "ignore/verifyout.bin") @@ -324,6 +318,7 @@ function main () --have a better idea of what works best and minimizing firmware compilation and updates --NROM + --curcart.process( true, false, true, true, true, "ignore/dump.bin", "ignore/M0_P32K_C8K.bin", "ignore/verifyout.bin") --curcart.process( true, true, true, true, true, "ignore/dump.bin", "ignore/ddug2.bin", "ignore/verifyout.bin") --curcart.process( true, false, true, true, false, "ignore/dump.bin", "ignore/NTB_RE.bin", "ignore/verifyout.bin") --curcart.process( true, false, true, true, false, "ignore/dump.bin", "ignore/MM_demo.bin", "ignore/verifyout.bin") @@ -331,13 +326,37 @@ function main () --curcart.process( true, false, true, true, false, "ignore/dump.bin", "ignore/DEMO.bin", "ignore/verifyout.bin") --curcart.process( true, false, true, true, false, "ignore/dump.bin", "ignore/NES_hb_present.bin", "ignore/verifyout.bin") + --MMC1 + --curcart.process( true, false, true, true, true, "ignore/dump.bin", "ignore/P256K.bin", "ignore/verifyout.bin") + --curcart.process( true, false, true, true, true, "ignore/dump.bin", "ignore/BB_sgrom.prg", "ignore/verifyout.bin") + --curcart.process( true, false, true, true, true, "ignore/dump.bin", "ignore/Zelda2.bin", "ignore/verifyout.bin") + --curcart.process( true, false, true, true, true, "ignore/dump.bin", "ignore/Zelda2_doubleprg.bin", "ignore/verifyout.bin") + --curcart.process( true, false, true, true, true, "ignore/dump.bin", "ignore/alfonzoMMC1.bin", "ignore/verifyout.bin") + --curcart.process( true, false, false, false, false, nil, nil, nil, true, false, "ignore/ramdump.bin", "ignore/zelda2_pauliscool.bin") + + + --UxROM + --curcart.process( true, false, true, true, true, "ignore/dump.bin", "ignore/AFB_128.prg", "ignore/verifyout.bin") + --curcart.process( true, false, true, true, true, "ignore/dump.bin", "ignore/nomolosFINAL.prg", "ignore/verifyout.bin") + --curcart.process( true, false, true, true, false, "ignore/dump.bin", "ignore/owlia_revb.prg", "ignore/verifyout.bin") + --curcart.process( true, false, false, false, false, "ignore/dump.bin", "ignore/rushnattack.prg", "ignore/verifyout.bin") + --curcart.process( true, false, false, false, false, "ignore/dump.bin", "ignore/TDfix.prg", "ignore/verifyout.bin") + --CNROM --curcart.process( true, false, true, true, true, "ignore/dump.bin", "ignore/galf.bin", "ignore/verifyout.bin") --MMC3 + --curcart.process( true, false, true, true, false, "ignore/dump.bin", "ignore/P512K_C256K.bin", "ignore/verifyout.bin") + --curcart.process( true, false, true, true, false, "ignore/dump.bin", "ignore/P256K_C128K.bin", "ignore/verifyout.bin") --curcart.process( true, true, true, false, true, "ignore/dump.bin", "ignore/kirby.nes", "ignore/verifyout.bin") --curcart.process( true, false, true, true, true, "ignore/dump.bin", "ignore/kirby.bin", "ignore/verifyout.bin", false, false, "ignore/ramdump.bin", "ignore/ramwrite.bin") - curcart.process( true, false, false, false, false, "ignore/dump.bin", "ignore/kirby.bin", "ignore/verifyout.bin", true, true, "ignore/ramdump.bin", "ignore/kirby3xSave.bin") + --curcart.process( true, false, false, false, false, "ignore/dump.bin", "ignore/kirby.bin", "ignore/verifyout.bin", true, true, "ignore/ramdump.bin", "ignore/kirby3xSave.bin") + + --MMC2 + --curcart.process( true, false, true, true, true, "ignore/dump.bin", "ignore/punchout.bin", "ignore/verifyout.bin") + --curcart.process( true, false, false, false, false, "ignore/dump.bin", "ignore/P256K_C128K.bin", "ignore/verifyout.bin") + --MMC4 + --curcart.process( true, false, true, true, true, "ignore/dump.bin", "ignore/fe.bin", "ignore/verifyout.bin") --COLOR DREAMS --curcart.process( true, false, true, true, true, "ignore/dump.bin", "ignore/multicart_mojontalesFINAL.prg", "ignore/verifyout.bin") @@ -347,6 +366,12 @@ function main () --curcart.process( true, true, true, true, true, "ignore/dump.bin", "ignore/lizard_v2.prg", "ignore/verifyout.bin") --curcart.process( true, false, true, true, false, "ignore/dump.bin", "ignore/hh85.prg", "ignore/verifyout.bin") + --FME7 + --curcart.process( true, false, true, true, false, "ignore/dump.bin", "ignore/P256K_C256K.bin", "ignore/verifyout.bin") + --curcart.process( true, false, true, true, true, "ignore/dump.bin", "ignore/gimmick.bin", "ignore/verifyout.bin") + --curcart.process( true, false, true, true, true, "ignore/dump.bin", "ignore/barcode_prgx2.bin", "ignore/verifyout.bin") + + --curcart.process( true, false, false, false, false, nil, nil, nil, true, true, "ignore/ramdump.bin", "ignore/kirby3xSave.bin") --[[ --FLASHING: --erase cart @@ -383,11 +408,16 @@ function main () --SNES --curcart.process( true, false, true, true, true, "ignore/dump.bin", "ignore/MMXdump.bin", "ignore/verifyout.bin") - curcart.process( true, false, true, true, true, "ignore/dump.bin", "ignore/smw.sfc", "ignore/verifyout.bin") + --curcart.process( true, false, true, true, false, "ignore/dump.bin", "ignore/smw.sfc", "ignore/verifyout.bin") + --curcart.process( true, false, true, true, true, "ignore/dump.bin", "ignore/SF2.bin", "ignore/verifyout.bin") + --curcart.process( true, false, true, true, true, "ignore/dump.bin", "ignore/dkc.bin", "ignore/verifyout.bin") + --curcart.process( true, true, false, false, false, "ignore/dump.bin", "ignore/dkc_orig.bin", "ignore/verifyout.bin") + --curcart.process( false, false, false, false, false, "ignore/dump.bin", "ignore/smw.sfc", "ignore/verifyout.bin", true, true, "ignore/ramdump.bin", "ignore/smw_lauren.bin") --curcart.process( true, true, false, false, false, "ignore/dump.bin", "ignore/hsbm_4Mbit_Lo.sfc", "ignore/verifyout.bin") --curcart.process( true, false, true, true, true, "ignore/dump.bin", "ignore/hsbm_4Mbit_Lo.sfc", "ignore/verifyout.bin") --curcart.process( true, false, true, true, true, "ignore/dump.bin", "ignore/hsbm_4Mbit_Hi.sfc", "ignore/verifyout.bin") --curcart.process( true, false, true, true, true, "ignore/dump.bin", "ignore/hsbm_32Mbit_Hi.sfc", "ignore/verifyout.bin") + --curcart.process( false, false, false, false, false, nil, nil, nil, true, true, "ignore/ramdump.bin", "ignore/dkc_paul.bin") -- --old SNES code diff --git a/host/scripts/nes/bnrom.lua b/host/scripts/nes/bnrom.lua index ae6e842..bcd9d6f 100644 --- a/host/scripts/nes/bnrom.lua +++ b/host/scripts/nes/bnrom.lua @@ -226,11 +226,9 @@ local function process( test, read, erase, program, verify, dumpfile, flashfile, nes.detect_mapper_mirroring(true) nes.ppu_ram_sense(0x1000, true) - print("EXP0 pull-up test:", dict.io("EXP0_PULLUP_TEST")) - --nes.read_flashID_prgrom_exp0(true) - prgrom_manf_id(true) + prgrom_manf_id(true) end --dump the cart to dumpfile @@ -251,7 +249,7 @@ local function process( test, read, erase, program, verify, dumpfile, flashfile, --erase the cart if erase then - print("\nerasing BxROM"); + print("\nErasing", mapname); print("erasing PRG-ROM"); dict.nes("DISCRETE_EXP0_PRGROM_WR", 0x5555, 0xAA) @@ -283,7 +281,7 @@ local function process( test, read, erase, program, verify, dumpfile, flashfile, --needs done to make board compatible with rom --write bank table to all banks of cartridge - wr_bank_table(banktable_base, 16) + wr_bank_table(banktable_base, prg_size/32) --32KB per bank --TODO need to verify where bank table belongs and properly determine number of banks --flash cart diff --git a/host/scripts/nes/fme7.lua b/host/scripts/nes/fme7.lua new file mode 100644 index 0000000..d296899 --- /dev/null +++ b/host/scripts/nes/fme7.lua @@ -0,0 +1,727 @@ + +-- create the module's table +local fme7 = {} + +-- import required modules +local dict = require "scripts.app.dict" +local nes = require "scripts.app.nes" +local dump = require "scripts.app.dump" +local flash = require "scripts.app.flash" + +-- file constants +local mapname = "FME7" + +-- local functions + +--disables WRAM, selects Vertical mirroring +--sets up CHR-ROM flash PT0 for DATA, Commands: $5555->$1555 $2AAA->$1AAA +--sets up PRG-ROM flash DATA: $8000-9FFF, Commands: $5555->D555 $2AAA->$AAAA +--leaves $8000 control reg selected to IRQ value selected so $A000 writes don't affect banking +local function init_mapper( debug ) + + + --for save data safety start by disable WRAM, and map PRG-ROM to $6000 + dict.nes("NES_CPU_WR", 0x8000, 0x08) + dict.nes("NES_CPU_WR", 0xA000, 0x00) --RAM disabled, ROM first bank mapped to $6000 + + --set mirroring + dict.nes("NES_CPU_WR", 0x8000, 0x0C) + dict.nes("NES_CPU_WR", 0xA000, 0x00) --00-vert 01-horz 10-NT0 11-NT1 + + --Bank $0 - PPU $0000-$03FF + --Bank $1 - PPU $0400-$07FF + --Bank $2 - PPU $0800-$0BFF + --Bank $3 - PPU $0C00-$0FFF + --Bank $4 - PPU $1000-$13FF + --Bank $5 - PPU $1400-$17FF + --Bank $6 - PPU $1800-$1BFF + --Bank $7 - PPU $1C00-$1FFF + + --For CHR-ROM flash writes, use lower 4KB (PT0) for writting data & upper 4KB (PT1) for commands + dict.nes("NES_CPU_WR", 0x8000, 0x00) + dict.nes("NES_CPU_WR", 0xA000, 0x00) --1KB @ PPU $0000 + + dict.nes("NES_CPU_WR", 0x8000, 0x01) + dict.nes("NES_CPU_WR", 0xA000, 0x01) --1KB @ PPU $0400 + + dict.nes("NES_CPU_WR", 0x8000, 0x02) + dict.nes("NES_CPU_WR", 0xA000, 0x02) --1KB @ PPU $0800 + + dict.nes("NES_CPU_WR", 0x8000, 0x03) + dict.nes("NES_CPU_WR", 0xA000, 0x03) --1KB @ PPU $0C00 + + --use lower half of PT1 for $5555 commands + dict.nes("NES_CPU_WR", 0x8000, 0x04) + dict.nes("NES_CPU_WR", 0xA000, 0x15) --1KB @ PPU $1000 + + dict.nes("NES_CPU_WR", 0x8000, 0x05) + dict.nes("NES_CPU_WR", 0xA000, 0x15) --1KB @ PPU $1400 + + --use upper half of PT1 for $2AAA commands + dict.nes("NES_CPU_WR", 0x8000, 0x06) + dict.nes("NES_CPU_WR", 0xA000, 0x0A) --1KB @ PPU $1800 + + dict.nes("NES_CPU_WR", 0x8000, 0x07) + dict.nes("NES_CPU_WR", 0xA000, 0x0A) --1KB @ PPU $1C00 + + + --For PRG-ROM flash writes: + --mode 0: $C000-FFFF fixed to last 16KByte + -- reg6 controls $8000-9FFF ($C000-DFFF in mode 1) + -- reg7 controls $A000-BFFF (regardless of mode) + --Don't want to write data to $8000-9FFF because those are the bank regs + --Writting data to $A000-BFFF is okay as that will only affect mirroring and WRAM ctl + + --$5555 commands can be written to $D555 (A14 set, A13 clear) + --$2AAA commands must be written through reg6/7 ($8000-BFFF) to clear A14 & set A13 + -- reg7 ($A000-BFFF) is ideal because it won't affect banking, just mirror/WRAM + -- actually $2AAA is even, so it'll only affect mirroring which is ideal + --DATA writes can occur at $8000-9FFF, but care must be taken to maintain banking. + -- Setting $8000 to a CHR bank prevents DATA writes from changing PRG banks + -- The DATA write will change the bank select if it's written to an even address though + -- To cover this, simply select the CHR bank again with $8000 reg after the data write + -- Those DATA writes can also corrupt the PRG/CHR modes, so just always follow + -- DATA writes by writting 0x00 to $8000 + + --$5555 commands written to $D555 + --$2AAA commands written to $AAAA + dict.nes("NES_CPU_WR", 0x8000, 0x0A) + dict.nes("NES_CPU_WR", 0xA000, 0x01) --8KB @ CPU $A000 + dict.nes("NES_CPU_WR", 0x8000, 0x0B) + dict.nes("NES_CPU_WR", 0xA000, 0x02) --8KB @ CPU $C000 + + --DATA writes written to $8000-9FFF + dict.nes("NES_CPU_WR", 0x8000, 0x09) + dict.nes("NES_CPU_WR", 0xA000, 0x00) --8KB @ CPU $8000 + + --dict.nes("NES_CPU_WR", 0x8000, 0x08) + --dict.nes("NES_CPU_WR", 0xA000, 0x00) --8KB @ CPU $6000 + + --set $8000 bank select register to IRQ ctl reg so $A000 writes don't change banking + dict.nes("NES_CPU_WR", 0x8000, 0x0E) + +end + + +--test the mapper's mirroring modes to verify working properly +--can be used to help identify board: returns true if pass, false if failed +local function mirror_test( debug ) + + --put mapper in known state (mirror bits cleared) + init_mapper() + + --Vertical + dict.nes("NES_CPU_WR", 0x8000, 0x0C) + dict.nes("NES_CPU_WR", 0xA000, 0x00) --00-vert 01-horz 10-NT0 11-NT1 + if (nes.detect_mapper_mirroring(false) ~= "VERT") then + print(mapname, " vert mirror test fail") + return false + end + + --Horizontal + dict.nes("NES_CPU_WR", 0x8000, 0x0C) + dict.nes("NES_CPU_WR", 0xA000, 0x01) --00-vert 01-horz 10-NT0 11-NT1 + if (nes.detect_mapper_mirroring(false) ~= "HORZ") then + print(mapname, " horz mirror test fail") + return false + end + + --NT0 + dict.nes("NES_CPU_WR", 0x8000, 0x0C) + dict.nes("NES_CPU_WR", 0xA000, 0x02) --00-vert 01-horz 10-NT0 11-NT1 + if (nes.detect_mapper_mirroring(false) ~= "1SCNA") then + print(mapname, " NT0 mirror test fail") + return false + end + + --NT1 + dict.nes("NES_CPU_WR", 0x8000, 0x0C) + dict.nes("NES_CPU_WR", 0xA000, 0x03) --00-vert 01-horz 10-NT0 11-NT1 + if (nes.detect_mapper_mirroring(false) ~= "1SCNB") then + print(mapname, " NT1 mirror test fail") + return false + end + + --passed all tests + if(debug) then print(mapname, " mirror test passed") end + return true +end + +--read PRG-ROM flash ID +local function prgrom_manf_id( debug ) + + init_mapper() + + if debug then print("reading PRG-ROM manf ID") end + --A0-A14 are all directly addressable in CNROM mode + --and mapper writes don't affect PRG banking + dict.nes("NES_CPU_WR", 0xD555, 0xAA) + dict.nes("NES_CPU_WR", 0xAAAA, 0x55) + dict.nes("NES_CPU_WR", 0xD555, 0x90) + rv = dict.nes("NES_CPU_RD", 0x8000) + if debug then print("attempted read PRG-ROM manf ID:", string.format("%X", rv)) end + rv = dict.nes("NES_CPU_RD", 0x8001) + if debug then print("attempted read PRG-ROM prod ID:", string.format("%X", rv)) end + + --exit software + dict.nes("NES_CPU_WR", 0x8000, 0xF0) + +end + +--read CHR-ROM flash ID +local function chrrom_manf_id( debug ) + + init_mapper() + + if debug then print("reading CHR-ROM manf ID") end + --A0-A14 are all directly addressable in CNROM mode + --and mapper writes don't affect PRG banking + dict.nes("NES_PPU_WR", 0x1555, 0xAA) + dict.nes("NES_PPU_WR", 0x1AAA, 0x55) + dict.nes("NES_PPU_WR", 0x1555, 0x90) + rv = dict.nes("NES_PPU_RD", 0x0000) + if debug then print("attempted read CHR-ROM manf ID:", string.format("%X", rv)) end + rv = dict.nes("NES_PPU_RD", 0x0001) + if debug then print("attempted read CHR-ROM prod ID:", string.format("%X", rv)) end + + --exit software + dict.nes("NES_PPU_WR", 0x8000, 0xF0) + +end + + +--dump the PRG ROM +local function dump_prgrom( file, rom_size_KB, debug ) + + --PRG-ROM dump 16KB at a time through FME7 reg9&A + local KB_per_read = 16 + local num_reads = rom_size_KB / KB_per_read + local read_count = 0 + local addr_base = 0x08 -- $8000 + + while ( read_count < num_reads ) do + + if debug then print( "dump PRG part ", read_count, " of ", num_reads) end + + --select desired bank(s) to dump + dict.nes("NES_CPU_WR", 0x8000, 0x09) + --the bank is half the size of KB per read so must multiply by 2 + dict.nes("NES_CPU_WR", 0xA000, read_count*2) --8KB @ CPU $8000 + + dict.nes("NES_CPU_WR", 0x8000, 0x0A) + --the bank is half the size of KB per read so must multiply by 2 and add 1 for second 8KB + dict.nes("NES_CPU_WR", 0xA000, read_count*2+1) --8KB @ CPU $A000 + + --16 = number of KB to dump per loop + --0x08 = starting read address A12-15 -> $8000 + --NESCPU_4KB designate mapper independent read of NES CPU address space + --mapper must be 0-15 to designate A12-15 + --dump.dumptofile( file, 16, 0x08, "NESCPU_4KB", true ) + dump.dumptofile( file, KB_per_read, addr_base, "NESCPU_4KB", false ) + + read_count = read_count + 1 + end + +end + +--dump the CHR ROM +local function dump_chrrom( file, rom_size_KB, debug ) + + local KB_per_read = 2 --dump one half PT at a time so only need 2 reg writes + local num_reads = rom_size_KB / KB_per_read + local read_count = 0 + local addr_base = 0x00 -- $0000 + + while ( read_count < num_reads ) do + + if debug then print( "dump CHR part ", read_count, " of ", num_reads) end + dict.nes("NES_CPU_WR", 0x8000, 0x00) + --the bank is half the size of KB per read so must multiply by 2 + dict.nes("NES_CPU_WR", 0xA000, (read_count*2)) --1KB @ PPU $0000 + + dict.nes("NES_CPU_WR", 0x8000, 0x01) + --the bank is half the size of KB per read so must multiply by 2 and add 1 for second 1KB + dict.nes("NES_CPU_WR", 0xA000, (read_count*2+1))--1KB @ PPU $0800 + + --4 = number of KB to dump per loop + --0x00 = starting read address A10-13 -> $0000 + --mapper must be 0x00 or 0x04-0x3C to designate A10-13 + -- bits 7, 6, 1, & 0 CAN NOT BE SET! + -- 0x04 would designate that A10 is set -> $0400 (the second 1KB PT bank) + -- 0x20 would designate that A13 is set -> $2000 (first name table) + dump.dumptofile( file, KB_per_read, addr_base, "NESPPU_1KB", false ) + + read_count = read_count + 1 + end + +end + + +--dump the WRAM, assumes the WRAM was enabled/disabled as desired prior to calling +local function dump_wram( file, rom_size_KB, debug ) + + local KB_per_read = 8 + local num_reads = rom_size_KB / KB_per_read + local read_count = 0 + local addr_base = 0x06 -- $6000 + + while ( read_count < num_reads ) do + + if debug then print( "dump WRAM part ", read_count, " of ", num_reads) end + + dump.dumptofile( file, KB_per_read, addr_base, "NESCPU_4KB", false ) + + read_count = read_count + 1 + end + +end + + +--write a single byte to PRG-ROM flash +--PRE: assumes mapper is initialized and bank is selected as prescribed in mapper_init +--REQ: addr must be in the first bank $8000-9FFF +local function wr_prg_flash_byte(addr, value, debug) + + if (addr < 0x8000 or addr > 0x9FFF) then + print("\n ERROR! flash write to PRG-ROM", string.format("$%X", addr), "must be $8000-9FFF \n\n") + return + end + + --send unlock command and write byte + dict.nes("NES_CPU_WR", 0xD555, 0xAA) + dict.nes("NES_CPU_WR", 0xAAAA, 0x55) + dict.nes("NES_CPU_WR", 0xD555, 0xA0) + dict.nes("NES_CPU_WR", addr, value) + + --recover by setting $8000 reg select back to a IRQ reg + dict.nes("NES_CPU_WR", 0x8000, 0x0E) + + local rv = dict.nes("NES_CPU_RD", addr) + + local i = 0 + + while ( rv ~= value ) do + rv = dict.nes("NES_CPU_RD", addr) + i = i + 1 + end + if debug then print(i, "naks, done writing byte.") end + + --TODO handle timeout for problems + + --TODO return pass/fail/info +end + + +--write a single byte to CHR-ROM flash +--PRE: assumes mapper is initialized and bank is selected as prescribed in mapper_init +--REQ: addr must be in the first 2 banks $0000-0FFF +local function wr_chr_flash_byte(addr, value, debug) + + if (addr < 0x0000 or addr > 0x0FFF) then + print("\n ERROR! flash write to CHR-ROM", string.format("$%X", addr), "must be $0000-0FFF \n\n") + return + end + + --send unlock command and write byte + dict.nes("NES_PPU_WR", 0x1555, 0xAA) + dict.nes("NES_PPU_WR", 0x1AAA, 0x55) + dict.nes("NES_PPU_WR", 0x1555, 0xA0) + dict.nes("NES_PPU_WR", addr, value) + + local rv = dict.nes("NES_PPU_RD", addr) + + local i = 0 + + while ( rv ~= value ) do + rv = dict.nes("NES_PPU_RD", addr) + i = i + 1 + end + if debug then print(i, "naks, done writing byte.") end + + --TODO handle timeout for problems + + --TODO return pass/fail/info +end + + +--host flash one bank at a time... +--this is controlled from the host side one bank at a time +--but requires mapper specific firmware flashing functions +--there is super slow version commented out that doesn't require mapper specific firmware code +local function flash_prgrom(file, rom_size_KB, debug) + + init_mapper() + + --test some bytes + --wr_prg_flash_byte(0x0000, 0xA5, true) + --wr_prg_flash_byte(0x0FFF, 0x5A, true) + + print("\nProgramming PRG-ROM flash") + + + local base_addr = 0x8000 --writes occur $8000-9FFF + local bank_size = 8*1024 --FME7 8KByte per PRG bank + local buff_size = 1 --number of bytes to write at a time + local cur_bank = 0 + local total_banks = rom_size_KB*1024/bank_size + + local byte_num --byte number gets reset for each bank + local byte_str, data, readdata + + + while cur_bank < total_banks do + + if (cur_bank %8 == 0) then + print("writting PRG bank: ", cur_bank, " of ", total_banks-1) + end + + --write the current bank to the mapper register + --DATA writes written to $8000-9FFF + dict.nes("NES_CPU_WR", 0x8000, 0x09) + dict.nes("NES_CPU_WR", 0xA000, cur_bank) --8KB @ CPU $8000 + + --set $8000 bank select back to a IRQ register + --keeps from having the PRG bank changing when writting data + dict.nes("NES_CPU_WR", 0x8000, 0x0E) + + + --program the entire bank's worth of data + + --[[ This version of the code programs a single byte at a time but doesn't require + -- mapper specific functions in the firmware + print("This is slow as molasses, but gets the job done") + byte_num = 0 --current byte within the bank + while byte_num < bank_size do + + --read next byte from the file and convert to binary + byte_str = file:read(buff_size) + data = string.unpack("B", byte_str, 1) + + --write the data + --SLOWEST OPTION: no firmware mapper specific functions 100% host flash algo: + --wr_prg_flash_byte(base_addr+byte_num, data, false) --0.7KBps + + --EASIEST FIRMWARE SPEEDUP: 5x faster, create mapper write byte function: + --MMC3 function works on FME7 just fine + --dict.nes("MMC3_PRG_FLASH_WR", base_addr+byte_num, data) --3.8KBps (5.5x faster than above) + --NEXT STEP: firmware write page/bank function can use function pointer for the function above + -- this may cause issues with more complex algos + -- sometimes cur bank is needed + -- for this to work, need to have function post conditions meet the preconditions + -- that way host intervention is only needed for bank controls + -- Is there a way to allow for double buffering though..? + -- YES! just think of the bank as a complete memory + -- this greatly simplifies things and is exactly where we want to go + -- This is completed below outside the byte while loop @ 39KBps + + if (verify) then + readdata = dict.nes("NES_CPU_RD", base_addr+byte_num) + if readdata ~= data then + print("ERROR flashing byte number", byte_num, " in bank",cur_bank, " to flash ", data, readdata) + end + end + + byte_num = byte_num + 1 + end + --]] + + --Have the device write a banks worth of data + --FAST! 13sec for 512KB = 39KBps + --MMC3 functions work perfectly for FME7 + flash.write_file( file, 8, "MMC3", "PRGROM", false ) + + cur_bank = cur_bank + 1 + end + + print("Done Programming PRG-ROM flash") + +end + + +--slow host flash one byte at a time... +--this is controlled from the host side byte by byte making it slow +--but doesn't require specific firmware mapper flashing functions +local function flash_chrrom(file, rom_size_KB, debug) + + init_mapper() + + --test some bytes + --wr_chr_flash_byte(0x0000, 0xA5, true) + --wr_chr_flash_byte(0x0FFF, 0x5A, true) + + print("\nProgramming CHR-ROM flash") + + local base_addr = 0x0000 + local bank_size = 4*1024 --FME7 1KByte per lower CHR bank and we're using 4 of them.. + local buff_size = 1 --number of bytes to write at a time + local cur_bank = 0 + local total_banks = rom_size_KB*1024/bank_size + + local byte_num --byte number gets reset for each bank + local byte_str, data, readdata + + + while cur_bank < total_banks do + + if (cur_bank %8 == 0) then + print("writting CHR bank: ", cur_bank, " of ", total_banks-1) + end + + --write the current bank to the mapper register + --DATA writes written to $0000-0FFF + dict.nes("NES_CPU_WR", 0x8000, 0x00) + dict.nes("NES_CPU_WR", 0xA000, (cur_bank*4)) --1KB @ PPU $0000 + dict.nes("NES_CPU_WR", 0x8000, 0x01) + dict.nes("NES_CPU_WR", 0xA000, (cur_bank*4+1)) --1KB @ PPU $0400 + dict.nes("NES_CPU_WR", 0x8000, 0x02) + dict.nes("NES_CPU_WR", 0xA000, (cur_bank*4+2)) --1KB @ PPU $0800 + dict.nes("NES_CPU_WR", 0x8000, 0x03) + dict.nes("NES_CPU_WR", 0xA000, (cur_bank*4+3)) --1KB @ PPU $0C00 + + --program the entire bank's worth of data + --[[ This version of the code programs a single byte at a time but doesn't require + -- mapper specific functions in the firmware + print("This is slow as molasses, but gets the job done") + byte_num = 0 --current byte within the bank + while byte_num < bank_size do + + --read next byte from the file and convert to binary + byte_str = file:read(buff_size) + data = string.unpack("B", byte_str, 1) + + --write the data + --SLOWEST OPTION: no firmware mapper specific functions 100% host flash algo: + --wr_chr_flash_byte(base_addr+byte_num, data, false) --0.7KBps + --EASIEST FIRMWARE SPEEDUP: 5x faster, create mapper write byte function: + dict.nes("MMC3_CHR_FLASH_WR", base_addr+byte_num, data) --3.8KBps (5.5x faster than above) + --FASTEST have the firmware handle flashing a bank's worth of data + --control the init and banking from the host side + + if (verify) then + readdata = dict.nes("NES_PPU_RD", base_addr+byte_num) + if readdata ~= data then + print("ERROR flashing byte number", byte_num, " in bank",cur_bank, " to flash ", data, readdata) + end + end + + byte_num = byte_num + 1 + end + --]] + + --Have the device write a "banks" worth of data, actually 2x banks of 2KB each + --FAST! 13sec for 512KB = 39KBps + flash.write_file( file, 4, "MMC3", "CHRROM", false ) + + cur_bank = cur_bank + 1 + end + + print("Done Programming CHR-ROM flash") +end + + +--Cart should be in reset state upon calling this function +local function process( test, read, erase, program, verify, dumpfile, flashfile, verifyfile, dumpram, writeram, ramdumpfile, ramwritefile) + + local rv = nil + local file + local prg_size = 256 + local chr_size = 256 + local wram_size = 8 + +--initialize device i/o for NES + dict.io("IO_RESET") + dict.io("NES_INIT") + +--test cart by reading manf/prod ID + if test then + print("Testing ", mapname) + + init_mapper() + + --verify mirroring is behaving as expected + mirror_test(true) + + nes.ppu_ram_sense(0x1000, true) + print("EXP0 pull-up test:", dict.io("EXP0_PULLUP_TEST")) + + --attempt to read PRG-ROM flash ID + prgrom_manf_id(true) + --attempt to read CHR-ROM flash ID + chrrom_manf_id(true) + end + +--dump the ram to file + if dumpram then + + print("\nDumping WRAM...") + + init_mapper() + + --enable RAM at $6000 + dict.nes("NES_CPU_WR", 0x8000, 0x08) + dict.nes("NES_CPU_WR", 0xA000, 0xC0) --RAM enable, RAM mapped to $6000 + + file = assert(io.open(ramdumpfile, "wb")) + + --dump cart into file + dump_wram(file, wram_size, false) + + --for save data safety start by disable WRAM, and map PRG-ROM to $6000 + dict.nes("NES_CPU_WR", 0x8000, 0x08) + dict.nes("NES_CPU_WR", 0xA000, 0x00) --RAM disabled, ROM first bank mapped to $6000 + + --close file + assert(file:close()) + + print("DONE Dumping WRAM") + end + + + +--dump the cart to dumpfile + if read then + + print("\nDumping PRG & CHR ROMs...") + + init_mapper() + + file = assert(io.open(dumpfile, "wb")) + + --dump cart into file + dump_prgrom(file, prg_size, false) + dump_chrrom(file, chr_size, false) + + --close file + assert(file:close()) + + print("DONE Dumping PRG & CHR ROMs") + end + + +--erase the cart + if erase then + + print("\nerasing ", mapname) + + init_mapper() + + print("erasing PRG-ROM"); + dict.nes("NES_CPU_WR", 0xD555, 0xAA) + dict.nes("NES_CPU_WR", 0xAAAA, 0x55) + dict.nes("NES_CPU_WR", 0xD555, 0x80) + dict.nes("NES_CPU_WR", 0xD555, 0xAA) + dict.nes("NES_CPU_WR", 0xAAAA, 0x55) + dict.nes("NES_CPU_WR", 0xD555, 0x10) + rv = dict.nes("NES_CPU_RD", 0x8000) + + local i = 0 + + --TODO create some function to pass the read value + --that's smart enough to figure out if the board is actually erasing or not + while ( rv ~= 0xFF ) do + rv = dict.nes("NES_CPU_RD", 0x8000) + i = i + 1 + end + print(i, "naks, done erasing prg."); + + + --TODO erase CHR-ROM only if present + init_mapper() + + print("erasing CHR-ROM"); + dict.nes("NES_PPU_WR", 0x1555, 0xAA) + dict.nes("NES_PPU_WR", 0x1AAA, 0x55) + dict.nes("NES_PPU_WR", 0x1555, 0x80) + dict.nes("NES_PPU_WR", 0x1555, 0xAA) + dict.nes("NES_PPU_WR", 0x1AAA, 0x55) + dict.nes("NES_PPU_WR", 0x1555, 0x10) + rv = dict.nes("NES_PPU_RD", 0x0000) + + local i = 0 + + --TODO create some function to pass the read value + --that's smart enough to figure out if the board is actually erasing or not + while ( rv ~= 0xFF ) do + rv = dict.nes("NES_PPU_RD", 0x8000) + i = i + 1 + end + print(i, "naks, done erasing chr."); + + + end + +--write to wram on the cart + if writeram then + + print("\nWritting to WRAM...") + + init_mapper() + + --enable RAM at $6000 + dict.nes("NES_CPU_WR", 0x8000, 0x08) + dict.nes("NES_CPU_WR", 0xA000, 0xC0) --RAM enable, RAM mapped to $6000 + + file = assert(io.open(ramwritefile, "rb")) + + flash.write_file( file, wram_size, "NOVAR", "PRGRAM", false ) + + --for save data safety start by disable WRAM, and map PRG-ROM to $6000 + dict.nes("NES_CPU_WR", 0x8000, 0x08) + dict.nes("NES_CPU_WR", 0xA000, 0x00) --RAM disabled, ROM first bank mapped to $6000 + + --close file + assert(file:close()) + + print("DONE Writting WRAM") + end + +--program flashfile to the cart + if program then + + --open file + file = assert(io.open(flashfile, "rb")) + --determine if auto-doubling, deinterleaving, etc, + --needs done to make board compatible with rom + + flash_prgrom(file, prg_size, true) + flash_chrrom(file, chr_size, true) + + --close file + assert(file:close()) + + end + +--verify flashfile is on the cart + if verify then + --for now let's just dump the file and verify manually + print("\nPost dumping PRG & CHR ROMs...") + + init_mapper() + + file = assert(io.open(verifyfile, "wb")) + + --dump cart into file + dump_prgrom(file, prg_size, false) + dump_chrrom(file, chr_size, false) + + --close file + assert(file:close()) + + print("DONE post dumping PRG & CHR ROMs") + end + + dict.io("IO_RESET") +end + + +-- global variables so other modules can use them + + +-- call functions desired to run when script is called/imported + + +-- functions other modules are able to call +fme7.process = process + +-- return the module's table +return fme7 diff --git a/host/scripts/nes/mmc1.lua b/host/scripts/nes/mmc1.lua index 02578c7..5e939d4 100644 --- a/host/scripts/nes/mmc1.lua +++ b/host/scripts/nes/mmc1.lua @@ -9,6 +9,7 @@ local dump = require "scripts.app.dump" local flash = require "scripts.app.flash" -- file constants +local mapname = "MMC1" -- local functions @@ -18,20 +19,25 @@ local function init_mapper( debug ) dict.nes("NES_CPU_RD", 0x8000) --reset MMC1 shift register with D7 set dict.nes("NES_CPU_WR", 0x8000, 0x80) + --this reset also effectively sets the control reg to 0x0C: + -- prg mode 3: last 16KB fixed + -- chr mode 0: single 8KB bank + -- mirroring 0: 1 screen NT0 -- mmc1_write(0x8000, 0x10); //32KB mode, prg bank @ $8000-FFFF, 4KB CHR mode dict.nes("NES_MMC1_WR", 0x8000, 0x10) -- //note the mapper will constantly reset to this when writing to PRG-ROM -- //PRG-ROM A18-A14 --- mmc1_write(0xE000, 0x00); //16KB bank @ $8000 - dict.nes("NES_MMC1_WR", 0xE000, 0x00) --- //CHR-ROM A16-12 (A14-12 are required to be valid) + --select first PRG-ROM bank, disable save RAM + dict.nes("NES_MMC1_WR", 0xE000, 0x10) --LSBit ignored in 32KB mode + --bit4 RAM enable 0-enabled 1-disabled + +-- //CHR-ROM A16-12 (A14-12 are required to be valid) +-- bit4 (CHR A16) is /CE pin for WRAM on SNROM + dict.nes("NES_MMC1_WR", 0xA000, 0x12) --4KB bank @ PT0 $2AAA cmd and writes + dict.nes("NES_MMC1_WR", 0xC000, 0x15) --4KB bank @ PT1 $5555 cmd fixed --- mmc1_write(0xA000, 0x02); //4KB bank @ PT0 $2AAA cmd and writes - dict.nes("NES_MMC1_WR", 0xA000, 0x02) --- mmc1_write(0xC000, 0x05); //4KB bank @ PT1 $5555 cmd fixed - dict.nes("NES_MMC1_WR", 0xC000, 0x05) end @@ -139,13 +145,358 @@ end +--dump the PRG ROM +local function dump_prgrom( file, rom_size_KB, debug ) + + --PRG-ROM dump 32KB at a time in 32KB bank mode + local KB_per_read = 32 + local num_reads = rom_size_KB / KB_per_read + local read_count = 0 + local addr_base = 0x08 -- $8000 + + while ( read_count < num_reads ) do + + if debug then print( "dump PRG part ", read_count, " of ", num_reads) end + + --select desired bank(s) to dump + dict.nes("NES_MMC1_WR", 0xE000, read_count<<1) --LSBit ignored in 32KB mode + + --16 = number of KB to dump per loop + --0x08 = starting read address A12-15 -> $8000 + --NESCPU_4KB designate mapper independent read of NES CPU address space + --mapper must be 0-15 to designate A12-15 + --dump.dumptofile( file, 16, 0x08, "NESCPU_4KB", true ) + dump.dumptofile( file, KB_per_read, addr_base, "NESCPU_4KB", false ) + + read_count = read_count + 1 + end + +end + +--dump the CHR ROM +local function dump_chrrom( file, rom_size_KB, debug ) + + local KB_per_read = 8 --dump both PT + local num_reads = rom_size_KB / KB_per_read + local read_count = 0 + local addr_base = 0x00 -- $0000 + + while ( read_count < num_reads ) do + + if debug then print( "dump CHR part ", read_count, " of ", num_reads) end + + dict.nes("NES_MMC1_WR", 0xA000, read_count*2) --4KB bank at $0000 + dict.nes("NES_MMC1_WR", 0xC000, read_count*2+1) --4KB bank at $1000 + + --4 = number of KB to dump per loop + --0x00 = starting read address A10-13 -> $0000 + --mapper must be 0x00 or 0x04-0x3C to designate A10-13 + -- bits 7, 6, 1, & 0 CAN NOT BE SET! + -- 0x04 would designate that A10 is set -> $0400 (the second 1KB PT bank) + -- 0x20 would designate that A13 is set -> $2000 (first name table) + dump.dumptofile( file, KB_per_read, addr_base, "NESPPU_1KB", false ) + + read_count = read_count + 1 + end + +end + + +--dump the WRAM, assumes the WRAM was enabled/disabled as desired prior to calling +local function dump_wram( file, rom_size_KB, debug ) + + local KB_per_read = 8 + local num_reads = rom_size_KB / KB_per_read + local read_count = 0 + local addr_base = 0x06 -- $6000 + + while ( read_count < num_reads ) do + + if debug then print( "dump WRAM part ", read_count, " of ", num_reads) end + + dump.dumptofile( file, KB_per_read, addr_base, "NESCPU_4KB", false ) + + read_count = read_count + 1 + end + +end + + +--write a single byte to PRG-ROM flash +--PRE: assumes mapper is initialized and bank is selected as prescribed in mapper_init +--REQ: addr must be in the first bank $8000-FFFF +local function wr_prg_flash_byte(addr, value, bank, debug) + + if (addr < 0x8000 or addr > 0xFFFF) then + print("\n ERROR! flash write to PRG-ROM", string.format("$%X", addr), "must be $8000-FFFF \n\n") + return + end + +--mmc1_wr(0x8000, 0x10, 0); //32KB mode +--//IDK why, but somehow only the first byte gets programmed when ROM A14=1 +--//so somehow it's getting out of 32KB mode for follow on bytes.. +--//even though we reset to 32KB mode after the corrupting final write +-- +--wr_func( unlock1, 0xAA ); +--wr_func( unlock2, 0x55 ); +--wr_func( unlock1, 0xA0 ); +--wr_func( ((addrH<<8)| n), buff->data[n] ); +--//writes to flash are to $8000-FFFF so any register could have been corrupted and shift register may be off +--//In reality MMC1 should have blocked all subsequent writes, so maybe only the CHR reg2 got corrupted..? mmc1_wr(0x8000, 0x10, 1); //32KB mode +--mmc1_wr(0xE000, bank, 0); //reset shift register, and bank register + + --MMC1 ignores all but the first write + --dict.nes("NES_CPU_RD", 0x8000) +-- dict.nes("NES_CPU_WR", 0x8000, 0x80) --reset MMC1 shift register with D7 set + + --dict.nes("NES_MMC1_WR", 0x8000, 0x10) --32KB mode, prg bank @ $8000-FFFF, 4KB CHR mode + --doing this after the write doesn't work for some reason.... + --I think the reason this works is because the last instruction is a write (and it's valid) + --so the next 4 writes are blocked by the MMC1 including the reset + dict.nes("NES_MMC1_WR", 0xC000, 0x05) --this seems to work as well which makes sense based on above.. + --so now all follow on writes will be blocked until there is a read + + --send unlock command and write byte + dict.nes("NES_CPU_WR", 0xD555, 0xAA) --this will reset the MMC1..?, + --but not if it was blocked by a previous write + dict.nes("NES_CPU_WR", 0xAAAA, 0x55) --blocked + dict.nes("NES_CPU_WR", 0xD555, 0xA0) --blocked + dict.nes("NES_CPU_WR", addr, value) --blocked + +-- dict.nes("NES_CPU_RD", 0x8000) --must read before resetting +-- dict.nes("NES_CPU_WR", 0x8000, 0x80) --reset MMC1 shift register with D7 set +-- dict.nes("NES_MMC1_WR", 0x8000, 0x10) --32KB mode, prg bank @ $8000-FFFF, 4KB CHR mode +-- dict.nes("NES_MMC1_WR", 0xE000, bank<<1) --32KB mode, prg bank @ $8000-FFFF, 4KB CHR mode + + local rv = dict.nes("NES_CPU_RD", addr) + + local i = 0 + + while ( rv ~= value ) do + rv = dict.nes("NES_CPU_RD", addr) + i = i + 1 + end + if debug then print(i, "naks, done writing byte.") end + + --TODO handle timeout for problems + + --TODO return pass/fail/info +end + + +--write a single byte to CHR-ROM flash +--PRE: assumes mapper is initialized and bank is selected as prescribed in mapper_init +--REQ: addr must be in the first bank $0000-0FFF +local function wr_chr_flash_byte(addr, value, bank, debug) + + if (addr < 0x0000 or addr > 0x0FFF) then + print("\n ERROR! flash write to CHR-ROM", string.format("$%X", addr), "must be $0000-0FFF \n\n") + return + end + + --set banks for unlock commands + dict.nes("NES_MMC1_WR", 0xA000, 0x02) --4KB bank @ PT0 $2AAA cmd and writes (always write data to PT0) + --dict.nes("NES_MMC1_WR", 0xC000, 0x05) --4KB bank @ PT1 $5555 cmd fixed (never changed) + + --send unlock command and write byte + dict.nes("NES_PPU_WR", 0x1555, 0xAA) + dict.nes("NES_PPU_WR", 0x0AAA, 0x55) + dict.nes("NES_PPU_WR", 0x1555, 0xA0) + + --select desired bank for write + dict.nes("NES_MMC1_WR", 0xA000, bank) --4KB bank @ PT0 $2AAA cmd and writes (always write data to PT0) + dict.nes("NES_PPU_WR", addr, value) + + local rv = dict.nes("NES_PPU_RD", addr) + + local i = 0 + + while ( rv ~= value ) do + rv = dict.nes("NES_PPU_RD", addr) + i = i + 1 + end + if debug then print(i, "naks, done writing byte.") end + + --TODO handle timeout for problems + + --TODO return pass/fail/info +end + + +--host flash one bank at a time... +--this is controlled from the host side one bank at a time +--but requires mapper specific firmware flashing functions +--there is super slow version commented out that doesn't require mapper specific firmware code +local function flash_prgrom(file, rom_size_KB, debug) + + init_mapper() + + --test some bytes + --wr_prg_flash_byte(0x0000, 0xA5, true) + --wr_prg_flash_byte(0x0FFF, 0x5A, true) + + print("\nProgramming PRG-ROM flash") + --initial testing of MMC3 with no specific MMC3 flash firmware functions 6min per 256KByte = 0.7KBps + + + local base_addr = 0x8000 --writes occur $8000-9FFF + local bank_size = 32*1024 --MMC1 32KByte bank mode + local buff_size = 1 --number of bytes to write at a time + local cur_bank = 0 + local total_banks = rom_size_KB*1024/bank_size + + local byte_num --byte number gets reset for each bank + local byte_str, data, readdata + + + while cur_bank < total_banks do + + if (cur_bank % 2 == 0) then + print("writting PRG bank: ", cur_bank, " of ", total_banks-1) + end + + --write the current bank to the mapper register + dict.nes("NES_MMC1_WR", 0xE000, cur_bank<<1) --LSBit ignored in 32KB mode + + --program the entire bank's worth of data + + --[[ This version of the code programs a single byte at a time but doesn't require + -- mapper specific functions in the firmware + print("This is slow as molasses, but gets the job done") + byte_num = 0 --current byte within the bank + while byte_num < bank_size do + + --read next byte from the file and convert to binary + byte_str = file:read(buff_size) + data = string.unpack("B", byte_str, 1) + + --write the data + --SLOWEST OPTION: no firmware mapper specific functions 100% host flash algo: + --wr_prg_flash_byte(base_addr+byte_num, data, cur_bank, false) --0.7KBps + + --EASIEST FIRMWARE SPEEDUP: 5x faster, create mapper write byte function: + --dict.nes("MMC1_PRG_FLASH_WR", base_addr+byte_num, data) --3.8KBps (5.5x faster than above) + --NEXT STEP: firmware write page/bank function can use function pointer for the function above + -- this may cause issues with more complex algos + -- sometimes cur bank is needed + -- for this to work, need to have function post conditions meet the preconditions + -- that way host intervention is only needed for bank controls + -- Is there a way to allow for double buffering though..? + -- YES! just think of the bank as a complete memory + -- this greatly simplifies things and is exactly where we want to go + -- This is completed below outside the byte while loop @ 39KBps + + --local verify = true + if (verify) then + readdata = dict.nes("NES_CPU_RD", base_addr+byte_num) + if readdata ~= data then + print("ERROR flashing byte number", byte_num, " in bank",cur_bank, " to flash ", data, readdata) + end + end + + byte_num = byte_num + 1 + end + --]] + + --Have the device write a banks worth of data + flash.write_file( file, bank_size/1024, mapname, "PRGROM", false ) + + cur_bank = cur_bank + 1 + end + + print("Done Programming PRG-ROM flash") + +end + + +--slow host flash one byte at a time... +--this is controlled from the host side byte by byte making it slow +--but doesn't require specific firmware mapper flashing functions +local function flash_chrrom(file, rom_size_KB, debug) + + init_mapper() + + print("\nProgramming CHR-ROM flash") + + --test some bytes + --wr_chr_flash_byte(0x0000, 0xA5, 0, true) + --wr_chr_flash_byte(0x0FFF, 0x5A, 0, true) + + + local base_addr = 0x0000 + local bank_size = 4*1024 --MMC1 always write to PT0 + local buff_size = 1 --number of bytes to write at a time + local cur_bank = 0 + local total_banks = rom_size_KB*1024/bank_size + + local byte_num --byte number gets reset for each bank + local byte_str, data, readdata + + + while cur_bank < total_banks do + + if (cur_bank %8 == 0) then + print("writting CHR bank: ", cur_bank, " of ", total_banks-1) + end + + --select bank to flash + dict.nes("SET_CUR_BANK", cur_bank) + if debug then print("get bank:", dict.nes("GET_CUR_BANK")) end + --this only updates the firmware nes.c global + --which it will use when calling mmc1_chrrom_flash_wr + + --program the entire bank's worth of data + --[[ This version of the code programs a single byte at a time but doesn't require + -- mapper specific functions in the firmware + print("This is slow as molasses, but gets the job done") + byte_num = 0 --current byte within the bank + while byte_num < bank_size do + + --read next byte from the file and convert to binary + byte_str = file:read(buff_size) + data = string.unpack("B", byte_str, 1) + + --write the data + --SLOWEST OPTION: no firmware mapper specific functions 100% host flash algo: + --wr_chr_flash_byte(base_addr+byte_num, data, cur_bank, false) --0.7KBps + --EASIEST FIRMWARE SPEEDUP: 5x faster, create mapper write byte function: + dict.nes("MMC1_CHR_FLASH_WR", base_addr+byte_num, data) --3.8KBps (5.5x faster than above) + --FASTEST have the firmware handle flashing a bank's worth of data + --control the init and banking from the host side + + if (verify) then + readdata = dict.nes("NES_PPU_RD", base_addr+byte_num) + if readdata ~= data then + print("ERROR flashing byte number", byte_num, " in bank",cur_bank, " to flash ", data, readdata) + end + end + + byte_num = byte_num + 1 + end + --]] + + --Have the device write a "banks" worth of data, actually 2x banks of 2KB each + --FAST! 13sec for 512KB = 39KBps + flash.write_file( file, bank_size/1024, mapname, "CHRROM", false ) + + cur_bank = cur_bank + 1 + end + + print("Done Programming CHR-ROM flash") +end + + + --Cart should be in reset state upon calling this function --this function processes all user requests for this specific board/mapper -local function process( test, read, erase, program, verify, dumpfile, flashfile, verifyfile) +local function process( test, read, erase, program, verify, dumpfile, flashfile, verifyfile, dumpram, writeram, ramdumpfile, ramwritefile) local rv = nil local file + local prg_size = 256 + local chr_size = 128 + local wram_size = 8 --initialize device i/o for NES dict.io("IO_RESET") @@ -153,6 +504,7 @@ local function process( test, read, erase, program, verify, dumpfile, flashfile, --test cart by reading manf/prod ID if test then + print("Testing ", mapname) --verify mirroring is behaving as expected mirror_test(true) @@ -166,27 +518,63 @@ local function process( test, read, erase, program, verify, dumpfile, flashfile, chrrom_manf_id(true) end + +--dump the ram to file + if dumpram then + print("\nDumping WRAM...") + + init_mapper() + + --enable save ram + dict.nes("NES_MMC1_WR", 0xE000, 0x00) --bit4 RAM enable 0-enabled 1-disabled + + --bit4 (CHR A16) is /CE pin for WRAM on SNROM + dict.nes("NES_MMC1_WR", 0xA000, 0x02) --4KB bank @ PT0 $2AAA cmd and writes + dict.nes("NES_MMC1_WR", 0xC000, 0x05) --4KB bank @ PT1 $5555 cmd fixed + + file = assert(io.open(ramdumpfile, "wb")) + + --dump cart into file + dump_wram(file, wram_size, false) + + --for save data safety disable WRAM, and deny writes + dict.nes("NES_MMC1_WR", 0xE000, 0x10) --bit4 RAM enable 0-enabled 1-disabled + + --bit4 (CHR A16) is /CE pin for WRAM on SNROM + dict.nes("NES_MMC1_WR", 0xA000, 0x12) --4KB bank @ PT0 $2AAA cmd and writes + dict.nes("NES_MMC1_WR", 0xC000, 0x15) --4KB bank @ PT1 $5555 cmd fixed + + --close file + assert(file:close()) + + print("DONE Dumping WRAM") + end + + + --dump the cart to dumpfile if read then - init_mapper() --32KB PRG-ROM banks + print("\nDumping PRG & CHR ROMs...") + + init_mapper() file = assert(io.open(dumpfile, "wb")) --dump cart into file - dump.dumptofile( file, 256, "MMC1", "PRGROM", true ) - dump.dumptofile( file, 128, "MMC1", "CHRROM", true ) + dump_prgrom(file, prg_size, false) + dump_chrrom(file, chr_size, false) --close file assert(file:close()) + + print("DONE Dumping PRG & CHR ROMs") end --erase the cart if erase then - init_mapper() - - print("\nerasing MMC1"); + print("\nerasing ", mapname) print("erasing PRG-ROM"); dict.nes("NES_CPU_WR", 0xD555, 0xAA) @@ -209,30 +597,63 @@ local function process( test, read, erase, program, verify, dumpfile, flashfile, --TODO erase CHR-ROM only if present - init_mapper() + if (chr_size ~= 0) then + init_mapper() - print("erasing CHR-ROM"); - dict.nes("NES_PPU_WR", 0x1555, 0xAA) - dict.nes("NES_PPU_WR", 0x0AAA, 0x55) - dict.nes("NES_PPU_WR", 0x1555, 0x80) - dict.nes("NES_PPU_WR", 0x1555, 0xAA) - dict.nes("NES_PPU_WR", 0x0AAA, 0x55) - dict.nes("NES_PPU_WR", 0x1555, 0x10) - rv = dict.nes("NES_PPU_RD", 0x8000) - - local i = 0 - - --TODO create some function to pass the read value - --that's smart enough to figure out if the board is actually erasing or not - while ( rv ~= 0xFF ) do + print("erasing CHR-ROM"); + dict.nes("NES_PPU_WR", 0x1555, 0xAA) + dict.nes("NES_PPU_WR", 0x0AAA, 0x55) + dict.nes("NES_PPU_WR", 0x1555, 0x80) + dict.nes("NES_PPU_WR", 0x1555, 0xAA) + dict.nes("NES_PPU_WR", 0x0AAA, 0x55) + dict.nes("NES_PPU_WR", 0x1555, 0x10) rv = dict.nes("NES_PPU_RD", 0x8000) - i = i + 1 + + local i = 0 + + --TODO create some function to pass the read value + --that's smart enough to figure out if the board is actually erasing or not + while ( rv ~= 0xFF ) do + rv = dict.nes("NES_PPU_RD", 0x8000) + i = i + 1 + end + print(i, "naks, done erasing chr."); end - print(i, "naks, done erasing chr."); end +--write to wram on the cart + if writeram then + + print("\nWritting to WRAM...") + + init_mapper() + + --enable save ram + dict.nes("NES_MMC1_WR", 0xE000, 0x00) --bit4 RAM enable 0-enabled 1-disabled + + --bit4 (CHR A16) is /CE pin for WRAM on SNROM + dict.nes("NES_MMC1_WR", 0xA000, 0x02) --4KB bank @ PT0 $2AAA cmd and writes + dict.nes("NES_MMC1_WR", 0xC000, 0x05) --4KB bank @ PT1 $5555 cmd fixed + + file = assert(io.open(ramwritefile, "rb")) + + flash.write_file( file, wram_size, "NOVAR", "PRGRAM", false ) + + --for save data safety disable WRAM, and deny writes + dict.nes("NES_MMC1_WR", 0xE000, 0x10) --bit4 RAM enable 0-enabled 1-disabled + + --bit4 (CHR A16) is /CE pin for WRAM on SNROM + dict.nes("NES_MMC1_WR", 0xA000, 0x12) --4KB bank @ PT0 $2AAA cmd and writes + dict.nes("NES_MMC1_WR", 0xC000, 0x15) --4KB bank @ PT1 $5555 cmd fixed + + --close file + assert(file:close()) + + print("DONE Writting WRAM") + end + --program flashfile to the cart if program then @@ -243,8 +664,9 @@ local function process( test, read, erase, program, verify, dumpfile, flashfile, --needs done to make board compatible with rom --flash cart - flash.write_file( file, 256, "MMC1", "PRGROM", true ) - flash.write_file( file, 128, "MMC1", "CHRROM", true ) + flash_prgrom(file, prg_size, false) + flash_chrrom(file, chr_size, false) + --close file assert(file:close()) @@ -253,15 +675,20 @@ local function process( test, read, erase, program, verify, dumpfile, flashfile, --verify flashfile is on the cart if verify then --for now let's just dump the file and verify manually + print("\nPost dumping PRG & CHR ROMs...") + + init_mapper() file = assert(io.open(verifyfile, "wb")) --dump cart into file - dump.dumptofile( file, 256, "MMC1", "PRGROM", true ) - dump.dumptofile( file, 128, "MMC1", "CHRROM", true ) + dump_prgrom(file, prg_size, false) + dump_chrrom(file, chr_size, false) --close file assert(file:close()) + + print("DONE post dumping PRG & CHR ROMs") end dict.io("IO_RESET") diff --git a/host/scripts/nes/mmc3.lua b/host/scripts/nes/mmc3.lua index f0acb12..cea5351 100644 --- a/host/scripts/nes/mmc3.lua +++ b/host/scripts/nes/mmc3.lua @@ -192,7 +192,7 @@ local function dump_prgrom( file, rom_size_KB, debug ) --select desired bank(s) to dump dict.nes("NES_CPU_WR", 0x8000, 0x06) --the bank is half the size of KB per read so must multiply by 2 - dict.nes("NES_CPU_WR", 0x8001, read_count*2) --1KB @ CPU $8000 + dict.nes("NES_CPU_WR", 0x8001, read_count*2) --8KB @ CPU $8000 dict.nes("NES_CPU_WR", 0x8000, 0x07) --the bank is half the size of KB per read so must multiply by 2 and add 1 for second 8KB @@ -534,7 +534,6 @@ local function process( test, read, erase, program, verify, dumpfile, flashfile, --dump the ram to file if dumpram then - print("\nDumping WRAM...") init_mapper() @@ -560,7 +559,6 @@ local function process( test, read, erase, program, verify, dumpfile, flashfile, --dump the cart to dumpfile if read then - print("\nDumping PRG & CHR ROMs...") init_mapper() diff --git a/host/scripts/nes/mmc4.lua b/host/scripts/nes/mmc4.lua new file mode 100644 index 0000000..7d6d93a --- /dev/null +++ b/host/scripts/nes/mmc4.lua @@ -0,0 +1,651 @@ + +-- create the module's table +local mmc4 = {} + +-- import required modules +local dict = require "scripts.app.dict" +local nes = require "scripts.app.nes" +local dump = require "scripts.app.dump" +local flash = require "scripts.app.flash" + +-- file constants +local mapname = "MMC4" + +-- local functions + +--disables WRAM, selects Vertical mirroring +--sets up CHR-ROM flash PT0 for DATA, Commands: $5555->$1555 $2AAA->$1AAA +--sets up PRG-ROM flash DATA: $8000-9FFF, Commands: $5555->D555 $2AAA->$AAAA +--leaves $8000 control reg selected to IRQ value selected so $A000 writes don't affect banking +local function init_mapper( debug ) + + + --RAM is always enabled.. + + --set mirroring + dict.nes("NES_CPU_WR", 0xF000, 0x00) --bit0: 0-vert 1-horz + + + --For CHR-ROM flash writes, use lower 4KB (PT0) for writting data & upper 4KB (PT1) for commands + dict.nes("NES_CPU_WR", 0xB000, 0x02) --4KB @ PPU $0000 -> $2AAA cmd & writes + dict.nes("NES_CPU_WR", 0xC000, 0x02) --4KB @ PPU $0000 + dict.nes("NES_CPU_WR", 0xD000, 0x05) --4KB @ PPU $1000 -> $5555 cmd + dict.nes("NES_CPU_WR", 0xE000, 0x05) --4KB @ PPU $1000 + + + --can use upper 16KB $D555 for $5555 commands + --need lower bank for $AAAA commands and writes + dict.nes("NES_CPU_WR", 0xA000, 0x00) --16KB @ CPU $8000 + +end + + +--test the mapper's mirroring modes to verify working properly +--can be used to help identify board: returns true if pass, false if failed +local function mirror_test( debug ) + + --put mapper in known state (mirror bits cleared) + init_mapper() + + --Vertical + --dict.nes("NES_CPU_WR", 0xF000, 0x00) --bit0: 0-vert 1-horz + if (nes.detect_mapper_mirroring(false) ~= "VERT") then + print(mapname, " vert mirror test fail") + return false + end + + --Horizontal + dict.nes("NES_CPU_WR", 0xF000, 0x01) --bit0: 0-vert 1-horz + if (nes.detect_mapper_mirroring(false) ~= "HORZ") then + print(mapname, " horz mirror test fail") + return false + end + + --passed all tests + if(debug) then print(mapname, " mirror test passed") end + return true +end + +--read PRG-ROM flash ID +local function prgrom_manf_id( debug ) + + init_mapper() + + if debug then print("reading PRG-ROM manf ID") end + --SOP + dict.nes("NES_CPU_WR", 0xFAAA, 0xAA) + dict.nes("NES_CPU_WR", 0xF555, 0x55) + dict.nes("NES_CPU_WR", 0xFAAA, 0x90) + --PLCC + --dict.nes("NES_CPU_WR", 0xD555, 0xAA) + --dict.nes("NES_CPU_WR", 0xAAAA, 0x55) + --dict.nes("NES_CPU_WR", 0xD555, 0x90) + rv = dict.nes("NES_CPU_RD", 0x8000) --0xC2 = MXIC + if debug then print("attempted read PRG-ROM manf ID:", string.format("%X", rv)) end + rv = dict.nes("NES_CPU_RD", 0x8002) --SOP 0x23/0xAB 512KB top/bottom + --SOP 0x51/0x57 256KB top/bottom + --SOP 0xD6/0x58 1MB top/bottom + if debug then print("attempted read PRG-ROM prod ID:", string.format("%X", rv)) end + + --exit software + dict.nes("NES_CPU_WR", 0x8000, 0xF0) + +end + +--read CHR-ROM flash ID +local function chrrom_manf_id( debug ) + + init_mapper() + + if debug then print("reading CHR-ROM manf ID") end + --A0-A14 are all directly addressable in CNROM mode + --and mapper writes don't affect PRG banking + dict.nes("NES_PPU_WR", 0x1555, 0xAA) + dict.nes("NES_PPU_WR", 0x0AAA, 0x55) + dict.nes("NES_PPU_WR", 0x1555, 0x90) + rv = dict.nes("NES_PPU_RD", 0x0000) + if debug then print("attempted read CHR-ROM manf ID:", string.format("%X", rv)) end + rv = dict.nes("NES_PPU_RD", 0x0001) + if debug then print("attempted read CHR-ROM prod ID:", string.format("%X", rv)) end + + --exit software + dict.nes("NES_PPU_WR", 0x8000, 0xF0) + +end + + +--dump the PRG ROM +local function dump_prgrom( file, rom_size_KB, debug ) + + --PRG-ROM dump 16KB at a time + local KB_per_read = 16 + local num_reads = rom_size_KB / KB_per_read + local read_count = 0 + local addr_base = 0x80 -- $8000 + + while ( read_count < num_reads ) do + + if debug then print( "dump PRG part ", read_count, " of ", num_reads) end + + --select desired bank(s) to dump + dict.nes("NES_CPU_WR", 0xA000, read_count) --16KB @ CPU $8000 + + --16 = number of KB to dump per loop + --0x08 = starting read address A12-15 -> $8000 + --NESCPU_4KB designate mapper independent read of NES CPU address space + --mapper must be 0-15 to designate A12-15 + --dump.dumptofile( file, 16, 0x08, "NESCPU_4KB", true ) + dump.dumptofile( file, KB_per_read, addr_base, "NESCPU_PAGE", false ) + + read_count = read_count + 1 + end + +end + +--dump the CHR ROM +local function dump_chrrom( file, rom_size_KB, debug ) + + local KB_per_read = 8 --dump both PT at once + local num_reads = rom_size_KB / KB_per_read + local read_count = 0 + local addr_base = 0x00 -- $0000 + + while ( read_count < num_reads ) do + + if debug then print( "dump CHR part ", read_count, " of ", num_reads) end + --the bank is half the size of KB per read so must multiply by 2 + dict.nes("NES_CPU_WR", 0xB000, (read_count*2)) --4KB @ PPU $0000 + dict.nes("NES_CPU_WR", 0xC000, (read_count*2)) --4KB @ PPU $0000 + + --the bank is half the size of KB per read so must multiply by 2 and add 1 for second 1KB + dict.nes("NES_CPU_WR", 0xD000, (read_count*2+1))--4KB @ PPU $1000 + dict.nes("NES_CPU_WR", 0xE000, (read_count*2+1))--4KB @ PPU $1000 + + --4 = number of KB to dump per loop + --0x00 = starting read address A10-13 -> $0000 + --mapper must be 0x00 or 0x04-0x3C to designate A10-13 + -- bits 7, 6, 1, & 0 CAN NOT BE SET! + -- 0x04 would designate that A10 is set -> $0400 (the second 1KB PT bank) + -- 0x20 would designate that A13 is set -> $2000 (first name table) + dump.dumptofile( file, KB_per_read, addr_base, "NESPPU_PAGE", false ) + + read_count = read_count + 1 + end + +end + + +--dump the WRAM, assumes the WRAM was enabled/disabled as desired prior to calling +local function dump_wram( file, rom_size_KB, debug ) + + local KB_per_read = 8 + local num_reads = rom_size_KB / KB_per_read + local read_count = 0 + local addr_base = 0x06 -- $6000 + + while ( read_count < num_reads ) do + + if debug then print( "dump WRAM part ", read_count, " of ", num_reads) end + + dump.dumptofile( file, KB_per_read, addr_base, "NESCPU_4KB", false ) + + read_count = read_count + 1 + end + +end + + +--write a single byte to PRG-ROM flash +--PRE: assumes mapper is initialized and bank is selected as prescribed in mapper_init +--REQ: addr must be in the first bank $8000-BFFF +local function wr_prg_flash_byte(addr, value, bank, debug) + + if (addr < 0x8000 or addr > 0xBFFF) then + print("\n ERROR! flash write to PRG-ROM", string.format("$%X", addr), "must be $8000-BFFF \n\n") + return + end + + --select bank + dict.nes("NES_CPU_WR", 0xA000, bank) + + --send unlock command and write byte + --dict.nes("NES_CPU_WR", 0xD555, 0xAA) + --dict.nes("NES_CPU_WR", 0xAAAA, 0x55) + --dict.nes("NES_CPU_WR", 0xD555, 0xA0) + dict.nes("NES_CPU_WR", 0xFAAA, 0xAA) + dict.nes("NES_CPU_WR", 0xF555, 0x55) + dict.nes("NES_CPU_WR", 0xFAAA, 0xA0) + dict.nes("NES_CPU_WR", addr, value) --if this write was $A000-AFFF it will also corrupt the bank + + --recover bank + dict.nes("NES_CPU_WR", 0xA000, bank) + + local rv = dict.nes("NES_CPU_RD", addr) + + local i = 0 + + while ( rv ~= value ) do + rv = dict.nes("NES_CPU_RD", addr) + i = i + 1 + end + if debug then print(i, "naks, done writing byte.") end + + --TODO handle timeout for problems + + --TODO return pass/fail/info +end + + +--write a single byte to CHR-ROM flash +--PRE: assumes mapper is initialized and bank is selected as prescribed in mapper_init +--REQ: addr must be in the first 2 banks $0000-0FFF +local function wr_chr_flash_byte(addr, value, bank, debug) + + if (addr < 0x0000 or addr > 0x0FFF) then + print("\n ERROR! flash write to CHR-ROM", string.format("$%X", addr), "must be $0000-0FFF \n\n") + return + end + + --set bank for unlock command + dict.nes("NES_CPU_WR", 0xB000, 0x0A) --4KB @ PPU $0000 -> $2AAA cmd & writes + dict.nes("NES_CPU_WR", 0xC000, 0x0A) --4KB @ PPU $0000 + + --send unlock command + dict.nes("NES_PPU_WR", 0x1555, 0xAA) + dict.nes("NES_PPU_WR", 0x0AAA, 0x55) + dict.nes("NES_PPU_WR", 0x1555, 0xA0) + + --select desired bank + dict.nes("NES_CPU_WR", 0xB000, bank) --4KB @ PPU $0000 -> $2AAA cmd & writes + dict.nes("NES_CPU_WR", 0xC000, bank) --4KB @ PPU $0000 + + --write data + dict.nes("NES_PPU_WR", addr, value) + + local rv = dict.nes("NES_PPU_RD", addr) + + local i = 0 + + while ( rv ~= value ) do + rv = dict.nes("NES_PPU_RD", addr) + i = i + 1 + end + if debug then print(i, "naks, done writing byte.") end + + --TODO handle timeout for problems + + --TODO return pass/fail/info +end + + +--host flash one bank at a time... +--this is controlled from the host side one bank at a time +--but requires mapper specific firmware flashing functions +--there is super slow version commented out that doesn't require mapper specific firmware code +local function flash_prgrom(file, rom_size_KB, debug) + + init_mapper() + + --test some bytes +-- wr_prg_flash_byte(0x8000, 0xA5, 0, true) +-- wr_prg_flash_byte(0xBFFF, 0x5A, 0, true) +-- wr_prg_flash_byte(0x8000, 0x15, 1, true) +-- wr_prg_flash_byte(0xBFFF, 0x1A, 1, true) +-- wr_prg_flash_byte(0x8000, 0xF5, 0xF, true) +-- wr_prg_flash_byte(0xBFFF, 0xFA, 0xF, true) + + print("\nProgramming PRG-ROM flash") + + + local base_addr = 0x8000 --writes occur $8000-BFFF + local bank_size = 16*1024 --MMC4 16KByte per PRG bank + local buff_size = 1 --number of bytes to write at a time + local cur_bank = 0 + local total_banks = rom_size_KB*1024/bank_size + + local byte_num --byte number gets reset for each bank + local byte_str, data, readdata + + + while cur_bank < total_banks do + + if (cur_bank %8 == 0) then + print("writting PRG bank: ", cur_bank, " of ", total_banks-1) + end + + --select desired bank, needed for first write + dict.nes("NES_CPU_WR", 0xA000, cur_bank) --16KB @ CPU $8000 + --set cur_bank for recovery and subsequent bytes + dict.nes("SET_CUR_BANK", cur_bank) + if debug then print("get bank:", dict.nes("GET_CUR_BANK")) end + + --program the entire bank's worth of data + + --[[ This version of the code programs a single byte at a time but doesn't require + -- mapper specific functions in the firmware + print("This is slow as molasses, but gets the job done") + byte_num = 0 --current byte within the bank + while byte_num < bank_size do + + --read next byte from the file and convert to binary + byte_str = file:read(buff_size) + data = string.unpack("B", byte_str, 1) + + --write the data + --SLOWEST OPTION: no firmware mapper specific functions 100% host flash algo: + --wr_prg_flash_byte(base_addr+byte_num, data, cur_bank, false) --0.7KBps + + --EASIEST FIRMWARE SPEEDUP: 5x faster, create mapper write byte function: + --MMC3 function works on FME7 just fine + dict.nes("MMC4_PRG_SOP_FLASH_WR", base_addr+byte_num, data) --3.8KBps (5.5x faster than above) + --NEXT STEP: firmware write page/bank function can use function pointer for the function above + -- this may cause issues with more complex algos + -- sometimes cur bank is needed + -- for this to work, need to have function post conditions meet the preconditions + -- that way host intervention is only needed for bank controls + -- Is there a way to allow for double buffering though..? + -- YES! just think of the bank as a complete memory + -- this greatly simplifies things and is exactly where we want to go + -- This is completed below outside the byte while loop @ 39KBps + + if (verify) then + readdata = dict.nes("NES_CPU_RD", base_addr+byte_num) + if readdata ~= data then + print("ERROR flashing byte number", byte_num, " in bank",cur_bank, " to flash ", data, readdata) + end + end + + byte_num = byte_num + 1 + end + --]] + + --Have the device write a banks worth of data + --FAST! but needs firmware specific functions and flash control + flash.write_file( file, bank_size/1024, "MMC4", "PRGROM", false ) + + cur_bank = cur_bank + 1 + end + + print("Done Programming PRG-ROM flash") + +end + + +--slow host flash one byte at a time... +--this is controlled from the host side byte by byte making it slow +--but doesn't require specific firmware mapper flashing functions +local function flash_chrrom(file, rom_size_KB, debug) + + init_mapper() + + --test some bytes + --wr_chr_flash_byte(0x0000, 0xA5, 0, true) + --wr_chr_flash_byte(0x0FFF, 0x5A, 0, true) + + print("\nProgramming CHR-ROM flash") + + local base_addr = 0x0000 + local bank_size = 4*1024 --MMC4 4KByte CHR bank + local buff_size = 1 --number of bytes to write at a time + local cur_bank = 0 + local total_banks = rom_size_KB*1024/bank_size + + local byte_num --byte number gets reset for each bank + local byte_str, data, readdata + + + while cur_bank < total_banks do + + if (cur_bank %8 == 0) then + print("writting CHR bank: ", cur_bank, " of ", total_banks-1) + end + + --set cur_bank so firmware can select desired bank during the write + dict.nes("SET_CUR_BANK", cur_bank) + if debug then print("get bank:", dict.nes("GET_CUR_BANK")) end + + --program the entire bank's worth of data + --[[ This version of the code programs a single byte at a time but doesn't require + -- mapper specific functions in the firmware + print("This is slow as molasses, but gets the job done") + byte_num = 0 --current byte within the bank + while byte_num < bank_size do + + --read next byte from the file and convert to binary + byte_str = file:read(buff_size) + data = string.unpack("B", byte_str, 1) + + --write the data + --SLOWEST OPTION: no firmware mapper specific functions 100% host flash algo: + wr_chr_flash_byte(base_addr+byte_num, data, cur_bank, false) --0.7KBps + --EASIEST FIRMWARE SPEEDUP: 5x faster, create mapper write byte function: + --dict.nes("MMC4_CHR_FLASH_WR", base_addr+byte_num, data) --3.8KBps (5.5x faster than above) + --FASTEST have the firmware handle flashing a bank's worth of data + --control the init and banking from the host side + + if (verify) then + readdata = dict.nes("NES_PPU_RD", base_addr+byte_num) + if readdata ~= data then + print("ERROR flashing byte number", byte_num, " in bank",cur_bank, " to flash ", data, readdata) + end + end + + byte_num = byte_num + 1 + end + --]] + + --Have the device write a "banks" worth of data, actually 2x banks of 2KB each + --FAST! 13sec for 512KB = 39KBps + flash.write_file( file, bank_size/1024, "MMC4", "CHRROM", false ) + + cur_bank = cur_bank + 1 + end + + print("Done Programming CHR-ROM flash") +end + + +--Cart should be in reset state upon calling this function +local function process( test, read, erase, program, verify, dumpfile, flashfile, verifyfile, dumpram, writeram, ramdumpfile, ramwritefile) + + local rv = nil + local file + local prg_size = 256 + local chr_size = 128 + local wram_size = 8 + +--initialize device i/o for NES + dict.io("IO_RESET") + dict.io("NES_INIT") + +--test cart by reading manf/prod ID + if test then + print("Testing ", mapname) + + init_mapper() + + --verify mirroring is behaving as expected + mirror_test(true) + + nes.ppu_ram_sense(0x1000, true) + print("EXP0 pull-up test:", dict.io("EXP0_PULLUP_TEST")) + + --attempt to read PRG-ROM flash ID + prgrom_manf_id(true) + --attempt to read CHR-ROM flash ID + chrrom_manf_id(true) + end + +--dump the ram to file + if dumpram then + + print("\nDumping WRAM...") + + init_mapper() + + --SRAM always enabled + + file = assert(io.open(ramdumpfile, "wb")) + + --dump cart into file + dump_wram(file, wram_size, false) + + --close file + assert(file:close()) + + print("DONE Dumping WRAM") + end + + + +--dump the cart to dumpfile + if read then + + print("\nDumping PRG & CHR ROMs...") + + init_mapper() + + file = assert(io.open(dumpfile, "wb")) + + --dump cart into file + dump_prgrom(file, prg_size, false) + dump_chrrom(file, chr_size, false) + + --close file + assert(file:close()) + + print("DONE Dumping PRG & CHR ROMs") + end + + +--erase the cart + if erase then + + print("\nerasing ", mapname) + + init_mapper() + + --PLCC + --print("erasing PRG-ROM"); + --dict.nes("NES_CPU_WR", 0xD555, 0xAA) + --dict.nes("NES_CPU_WR", 0xAAAA, 0x55) + --dict.nes("NES_CPU_WR", 0xD555, 0x80) + --dict.nes("NES_CPU_WR", 0xD555, 0xAA) + --dict.nes("NES_CPU_WR", 0xAAAA, 0x55) + --dict.nes("NES_CPU_WR", 0xD555, 0x10) + + --SOP + print("erasing PRG-ROM SOP-44 flash takes a couple sec..."); + dict.nes("NES_CPU_WR", 0xFAAA, 0xAA) + dict.nes("NES_CPU_WR", 0xF555, 0x55) + dict.nes("NES_CPU_WR", 0xFAAA, 0x80) + dict.nes("NES_CPU_WR", 0xFAAA, 0xAA) + dict.nes("NES_CPU_WR", 0xF555, 0x55) + dict.nes("NES_CPU_WR", 0xFAAA, 0x10) + rv = dict.nes("NES_CPU_RD", 0x8000) + + local i = 0 + + --TODO create some function to pass the read value + --that's smart enough to figure out if the board is actually erasing or not + while ( rv ~= 0xFF ) do + rv = dict.nes("NES_CPU_RD", 0x8000) + i = i + 1 + end + print(i, "naks, done erasing prg."); + + + --TODO erase CHR-ROM only if present + init_mapper() + + print("erasing CHR-ROM"); + dict.nes("NES_PPU_WR", 0x1555, 0xAA) + dict.nes("NES_PPU_WR", 0x0AAA, 0x55) + dict.nes("NES_PPU_WR", 0x1555, 0x80) + dict.nes("NES_PPU_WR", 0x1555, 0xAA) + dict.nes("NES_PPU_WR", 0x0AAA, 0x55) + dict.nes("NES_PPU_WR", 0x1555, 0x10) + rv = dict.nes("NES_PPU_RD", 0x0000) + + local i = 0 + + --TODO create some function to pass the read value + --that's smart enough to figure out if the board is actually erasing or not + while ( rv ~= 0xFF ) do + rv = dict.nes("NES_PPU_RD", 0x8000) + i = i + 1 + end + print(i, "naks, done erasing chr."); + + + end + +--write to wram on the cart + if writeram then + + print("\nWritting to WRAM...") + + init_mapper() + + --SRAM always enabled + + file = assert(io.open(ramwritefile, "rb")) + + flash.write_file( file, wram_size, "NOVAR", "PRGRAM", false ) + + --close file + assert(file:close()) + + print("DONE Writting WRAM") + end + +--program flashfile to the cart + if program then + + --open file + file = assert(io.open(flashfile, "rb")) + --determine if auto-doubling, deinterleaving, etc, + --needs done to make board compatible with rom + + flash_prgrom(file, prg_size, false) + flash_chrrom(file, chr_size, false) + + --close file + assert(file:close()) + + end + +--verify flashfile is on the cart + if verify then + --for now let's just dump the file and verify manually + print("\nPost dumping PRG & CHR ROMs...") + + init_mapper() + + file = assert(io.open(verifyfile, "wb")) + + --dump cart into file + dump_prgrom(file, prg_size, false) + dump_chrrom(file, chr_size, false) + + --close file + assert(file:close()) + + print("DONE post dumping PRG & CHR ROMs") + end + + dict.io("IO_RESET") +end + + +-- global variables so other modules can use them + + +-- call functions desired to run when script is called/imported + + +-- functions other modules are able to call +mmc4.process = process + +-- return the module's table +return mmc4 diff --git a/host/scripts/nes/unrom.lua b/host/scripts/nes/unrom.lua index 2925002..2d4b8e9 100644 --- a/host/scripts/nes/unrom.lua +++ b/host/scripts/nes/unrom.lua @@ -8,7 +8,20 @@ local nes = require "scripts.app.nes" local dump = require "scripts.app.dump" local flash = require "scripts.app.flash" --- file constants +-- file constants & variables +local mapname = "UxROM" +local banktable_base = 0xCC84 --Nomolos + --Nomolos' bank table is at $CC84 so hard code that for now + --wr_bank_table(0xCC84, 32) + --Owlia bank table + --wr_bank_table(0xE473, 32) + --rushnattack + --wr_bank_table(0x8000, 8) + --twindragons + --wr_bank_table(0xC000, 32) + --Armed for Battle + --wr_bank_table(0xFD69, 8) +--local rom_FF_addr = 0x8000 -- local functions local function init_mapper( debug ) @@ -23,11 +36,68 @@ local function init_mapper( debug ) dict.nes("NES_CPU_WR", 0x8000, 0x00) end -local function wr_flash_byte(addr, value, debug) +--read PRG-ROM flash ID +local function prgrom_manf_id( debug ) + init_mapper() + + if debug then print("reading PRG-ROM manf ID") end + + --enter software mode + --ROMSEL controls PRG-ROM /OE which needs to be low for flash writes + --So unlock commands need to be addressed below $8000 + --DISCRETE_EXP0_PRGROM_WR doesn't toggle /ROMSEL by definition though, so A15 is unused + -- 15 14 13 12 + -- 0x5 = 0b 0 1 0 1 -> $5555 + -- 0x2 = 0b 0 0 1 0 -> $2AAA + dict.nes("DISCRETE_EXP0_PRGROM_WR", 0x5555, 0xAA) + dict.nes("DISCRETE_EXP0_PRGROM_WR", 0x2AAA, 0x55) + dict.nes("DISCRETE_EXP0_PRGROM_WR", 0x5555, 0x90) + + --read manf ID + local rv = dict.nes("NES_CPU_RD", 0x8000) + if debug then print("attempted read PRG-ROM manf ID:", string.format("%X", rv)) end + + --read prod ID + rv = dict.nes("NES_CPU_RD", 0x8001) + if debug then print("attempted read PRG-ROM prod ID:", string.format("%X", rv)) end + + --exit software + dict.nes("DISCRETE_EXP0_PRGROM_WR", 0x8000, 0xF0) + +end + + +--dump the PRG ROM +local function dump_prgrom( file, rom_size_KB, debug ) + + local KB_per_read = 16 + local num_reads = rom_size_KB / KB_per_read + local read_count = 0 + local addr_base = 0x08 -- $8000 + + while ( read_count < num_reads ) do + + if debug then print( "dump PRG part ", read_count, " of ", num_reads) end + + --select desired bank(s) to dump + dict.nes("NES_CPU_WR", banktable_base+read_count, read_count) --16KB @ CPU $8000 + + dump.dumptofile( file, KB_per_read, addr_base, "NESCPU_4KB", false ) + + read_count = read_count + 1 + end + +end + + +local function wr_prg_flash_byte(addr, value, bank, debug) + + dict.nes("NES_CPU_WR", banktable_base, 0x00) dict.nes("DISCRETE_EXP0_PRGROM_WR", 0x5555, 0xAA) dict.nes("DISCRETE_EXP0_PRGROM_WR", 0x2AAA, 0x55) dict.nes("DISCRETE_EXP0_PRGROM_WR", 0x5555, 0xA0) + dict.nes("NES_CPU_WR", banktable_base+bank, bank) dict.nes("DISCRETE_EXP0_PRGROM_WR", addr, value) local rv = dict.nes("NES_CPU_RD", addr) @@ -57,7 +127,7 @@ local function wr_bank_table(base, entries, numtables) local i = 0 while( i < entries) do - wr_flash_byte(base+i, i) + wr_prg_flash_byte(base+i, i, 0) i = i+1; end @@ -80,7 +150,7 @@ local function wr_bank_table(base, entries, numtables) local i = 0 while( i < entries) do print("write entry", i, "bank:", cur_bank) - wr_flash_byte(base+i, i) + wr_prg_flash_byte(base+i, i) i = i+1; end @@ -97,13 +167,97 @@ local function wr_bank_table(base, entries, numtables) end + +--host flash one byte/bank at a time... +--this is controlled from the host side one bank at a time +--but requires mapper specific firmware flashing functions +local function flash_prgrom(file, rom_size_KB, debug) + + init_mapper() + + --bank table should already be written + + --test some bytes + --wr_prg_flash_byte(0x0000, 0xA5, true) + --wr_prg_flash_byte(0xFFFF, 0x5A, true) + + print("\nProgramming PRG-ROM flash") + + local base_addr = 0x8000 --writes occur $8000-9FFF + local bank_size = 16*1024 --UNROM 16KByte per PRG bank + local buff_size = 1 --number of bytes to write at a time + local cur_bank = 0 + local total_banks = rom_size_KB*1024/bank_size + + local byte_num --byte number gets reset for each bank + local byte_str, data, readdata + + --set the bank table address + dict.nes("SET_BANK_TABLE", banktable_base) + if debug then print("get banktable:", string.format("%X", dict.nes("GET_BANK_TABLE"))) end + + while cur_bank < total_banks do + + if (cur_bank %4 == 0) then + print("writting PRG bank: ", cur_bank, " of ", total_banks-1) + end + + --select bank to flash + dict.nes("SET_CUR_BANK", cur_bank) + if debug then print("get bank:", dict.nes("GET_CUR_BANK")) end + + --program the entire bank's worth of data + + --[[ This version of the code programs a single byte at a time but doesn't require + -- MMC3 specific functions in the firmware + print("This is slow as molasses, but gets the job done") + byte_num = 0 --current byte within the bank + while byte_num < bank_size do + + --read next byte from the file and convert to binary + byte_str = file:read(buff_size) + data = string.unpack("B", byte_str, 1) + + --write the data + --SLOWEST OPTION: no firmware MMC3 specific functions 100% host flash algo: + --wr_prg_flash_byte(base_addr+byte_num, data, cur_bank, false) --0.7KBps + --EASIEST FIRMWARE SPEEDUP: 5x faster, create MMC3 write byte function: + --can use same write function as NROM + dict.nes("UNROM_PRG_FLASH_WR", base_addr+byte_num, data) --3.8KBps (5.5x faster than above) + + if (verify) then + readdata = dict.nes("NES_CPU_RD", base_addr+byte_num) + if readdata ~= data then + print("ERROR flashing byte number", byte_num, " in bank",cur_bank, " to flash ", data, readdata) + end + end + + byte_num = byte_num + 1 + end + --]] + + --Have the device write a banks worth of data + --Same as NROM + flash.write_file( file, bank_size/1024, mapname, "PRGROM", false ) + + cur_bank = cur_bank + 1 + end + + print("Done Programming PRG-ROM flash") + +end + + + --Cart should be in reset state upon calling this function --this function processes all user requests for this specific board/mapper local function process( test, read, erase, program, verify, dumpfile, flashfile, verifyfile) local rv = nil local file - local size = 128 + local prg_size = 512 + local chr_size = 0 + local wram_size = 0 --initialize device i/o for NES dict.io("IO_RESET") @@ -111,34 +265,37 @@ local function process( test, read, erase, program, verify, dumpfile, flashfile, --test cart by reading manf/prod ID if test then + print("Testing ", mapname) + nes.detect_mapper_mirroring(true) nes.ppu_ram_sense(0x1000, true) print("EXP0 pull-up test:", dict.io("EXP0_PULLUP_TEST")) - --need to set PRG-ROM A14 low when lower bank selected - init_mapper() --this may not succeed due to bus conflicts... - nes.read_flashID_prgrom_exp0(true) + prgrom_manf_id(true) end --dump the cart to dumpfile if read then + print("\nDumping PRG-ROM...") file = assert(io.open(dumpfile, "wb")) --TODO find bank table to avoid bus conflicts! --dump cart into file - dump.dumptofile( file, size, "UxROM", "PRGROM", true ) + --dump.dumptofile( file, prg_size, "UxROM", "PRGROM", true ) + dump_prgrom(file, prg_size, false) --close file assert(file:close()) + print("DONE Dumping PRG-ROM") end --erase the cart if erase then - init_mapper() + print("\nErasing", mapname); - print("\nerasing UxROM"); + init_mapper() print("erasing PRG-ROM"); dict.nes("DISCRETE_EXP0_PRGROM_WR", 0x5555, 0xAA) @@ -172,19 +329,11 @@ local function process( test, read, erase, program, verify, dumpfile, flashfile, --find bank table in the rom --write bank table to all banks of cartridge - --Nomolos' bank table is at $CC84 so hard code that for now - --wr_bank_table(0xCC84, 32) - --Owlia bank table - --wr_bank_table(0xE473, 32) - --rushnattack - --wr_bank_table(0x8000, 8) - --twindragons - --wr_bank_table(0xC000, 32) - --Armed for Battle - wr_bank_table(0xFD69, 8) + wr_bank_table(banktable_base, prg_size/16) --16KB per bank gives number of entries --flash cart - flash.write_file( file, size, "UxROM", "PRGROM", true ) + flash_prgrom(file, prg_size, false) + --close file assert(file:close()) @@ -193,14 +342,17 @@ local function process( test, read, erase, program, verify, dumpfile, flashfile, --verify flashfile is on the cart if verify then --for now let's just dump the file and verify manually + print("\nPost dumping PRG-ROM") file = assert(io.open(verifyfile, "wb")) --dump cart into file - dump.dumptofile( file, size, "UxROM", "PRGROM", true ) + dump_prgrom(file, prg_size, false) --close file assert(file:close()) + + print("DONE post dumping PRG-ROM") end dict.io("IO_RESET") diff --git a/host/scripts/snes/v2proto_hirom.lua b/host/scripts/snes/v2proto_hirom.lua new file mode 100644 index 0000000..815b6a9 --- /dev/null +++ b/host/scripts/snes/v2proto_hirom.lua @@ -0,0 +1,587 @@ + +-- create the module's table +local v2proto = {} + +-- import required modules +local dict = require "scripts.app.dict" +local dump = require "scripts.app.dump" +local flash = require "scripts.app.flash" +local snes = require "scripts.app.snes" +local apperase = require "scripts.app.erase" + +-- file constants + +-- local functions + + +-- Desc: attempt to read flash rom ID +-- Pre: snes_init() been called to setup i/o +-- Post:Address left on bus memories disabled +-- Rtn: true if proper flash ID found +local function rom_manf_id( debug ) + + local rv + --enter software mode A11 is highest address bit that needs to be valid + --datasheet not exactly explicit, A11 might not need to be valid + --part has A-1 (negative 1) since it's in byte mode, meaning the part's A11 is actually A12 + --WR $AAA:AA $555:55 $AAA:AA + dict.snes("SNES_SET_BANK", 0x00) + + dict.snes("SNES_ROM_WR", 0x8AAA, 0xAA) + dict.snes("SNES_ROM_WR", 0x8555, 0x55) + dict.snes("SNES_ROM_WR", 0x8AAA, 0x90) + + --read manf ID + local manf_id = dict.snes("SNES_ROM_RD", 0x8000) --0x01 Cypress Manf ID + if debug then print("attempted read SNES ROM manf ID:", string.format("%X", manf_id)) end + + --read prod ID + local prod_id = dict.snes("SNES_ROM_RD", 0x8002) --0x7E Prod ID S29GL + if debug then print("attempted read SNES ROM prod ID:", string.format("%X", prod_id)) end + + local density_id = dict.snes("SNES_ROM_RD", 0x801C) --density 0x10=8MB 0x1A=4MB + if debug then print("attempted read SNES density ID: ", string.format("%X", density_id)) end + + local boot_sect = dict.snes("SNES_ROM_RD", 0x801E) --boot sector 0x00=top 0x01=bottom + if debug then print("attempted read SNES boot sect ID:", string.format("%X", boot_sect)) end + + --exit software + dict.snes("SNES_ROM_WR", 0x8000, 0xF0) + + --return true if detected flash chip + if (manf_id == 0x01 and prod_id == 0x49) then + print("2MB flash detected") + return true + elseif (manf_id == 0x01 and prod_id == 0x7E) then + print("4-8MB flash detected") + return true + else + return false + end + +end + + + +local function erase_flash( debug ) + + local rv = nil + + print("\nErasing TSSOP flash takes about 30sec..."); + + --WR $AAA:AA $555:55 $AAA:AA + dict.snes("SNES_SET_BANK", 0x00) + + dict.snes("SNES_ROM_WR", 0x8AAA, 0xAA) + dict.snes("SNES_ROM_WR", 0x8555, 0x55) + dict.snes("SNES_ROM_WR", 0x8AAA, 0x80) + dict.snes("SNES_ROM_WR", 0x8AAA, 0xAA) + dict.snes("SNES_ROM_WR", 0x8555, 0x55) + dict.snes("SNES_ROM_WR", 0x8AAA, 0x10) + + rv = dict.snes("SNES_ROM_RD", 0x8000) + + local i = 0 + + while ( rv ~= 0xFF ) do + rv = dict.snes("SNES_ROM_RD", 0x8000) + i = i + 1 + -- if debug then print(" ", i,":", string.format("%x",rv)) end + end + print(i, "naks, done erasing snes."); + + --reset flash + dict.snes("SNES_ROM_WR", 0x8000, 0xF0) +end + + +--dump the SNES ROM starting at the provided bank +--/ROMSEL is always low for this dump +local function dump_rom( file, start_bank, rom_size_KB, mapping, debug ) + + local KB_per_bank + local addr_base + + if (mapping=="LOROM") then + KB_per_bank = 32 -- LOROM has 32KB per bank + addr_base = 0x80 -- $8000 LOROM + elseif (mapping=="HIROM") then + KB_per_bank = 64 -- LOROM has 32KB per bank + addr_base = 0x00 -- $8000 LOROM + else + print("ERROR!! mapping:", mapping, "not supported") + end + + local num_reads = rom_size_KB / KB_per_bank + local read_count = 0 + + while ( read_count < num_reads ) do + + if debug then print( "dump ROM part ", read_count, " of ", num_reads) end + + if (read_count %8 == 0) then + print("dumping ROM bank: ", read_count, " of ", num_reads-1) + end + + --select desired bank + dict.snes("SNES_SET_BANK", start_bank+read_count) + + dump.dumptofile( file, KB_per_bank, addr_base, "SNESROM_PAGE", false ) + + read_count = read_count + 1 + end + +end + +--dump the SNES RAM starting at the provided bank +--this is currently only for lorom boards where /ROMSEL maps to RAM space +local function dump_ram( file, start_bank, ram_size_KB, mapping, debug ) + + local KB_per_bank + local addr_base --A15-8 address of ram start + + --determine max ram per bank and base address + if (mapping == "LOROM") then + KB_per_bank = 32 -- LOROM has 32KB per bank + addr_base = 0x00 -- $0000 LOROM RAM start address + elseif (mapping == "HIROM") then + KB_per_bank = 8 -- HIROM has 8KB per bank + addr_base = 0x60 -- $6000 HIROM RAM start address + else + print("ERROR! mapping:", mapping, "not supported by dump_ram") + end + + local num_banks + + --determine how much ram to read per bank + if (ram_size_KB < KB_per_bank) then + num_banks = 1 + KB_per_bank = ram_size_KB + else + num_banks = ram_size_KB / KB_per_bank + end + + local read_count = 0 + + while ( read_count < num_banks ) do + + if debug then print( "dump ROM part ", read_count, " of ", num_banks) end + + --select desired bank + dict.snes("SNES_SET_BANK", start_bank+read_count) + + if (mapping == "LOROM") then --LOROM sram is inside /ROMSEL space + dump.dumptofile( file, KB_per_bank, addr_base, "SNESROM_PAGE", false ) + else -- HIROM is outside of /ROMSEL space + dump.dumptofile( file, KB_per_bank, addr_base, "SNESSYS_PAGE", false ) + end + + read_count = read_count + 1 + end + +end + + + +--write a single byte to SNES ROM flash +--writes to currently selected bank address +local function wr_flash_byte(addr, value, debug) + + if (addr < 0x0000 or addr > 0xFFFF) then + print("\n ERROR! flash write to SNES", string.format("$%X", addr), "must be $0000-FFFF \n\n") + return + end + + --send unlock command and write byte + dict.snes("SNES_ROM_WR", 0x8AAA, 0xAA) + dict.snes("SNES_ROM_WR", 0x8555, 0x55) + dict.snes("SNES_ROM_WR", 0x8AAA, 0xA0) + dict.snes("SNES_ROM_WR", addr, value) + + local rv = dict.snes("SNES_ROM_RD", addr) + + local i = 0 + + while ( rv ~= value ) do + rv = dict.snes("SNES_ROM_RD", addr) + i = i + 1 + end + if debug then print(i, "naks, done writing byte.") end + if debug then print("written value:", string.format("%X",value), "verified value:", string.format("%X",rv)) end + + --TODO handle timeout for problems + + --TODO return pass/fail/info +end + + +--fast host flash one bank at a time... +--this is controlled from the host side one bank at a time + + + +--- TODO TODO TODO!!! need to specific first bank!!!! Just like dumping! +local function flash_rom(file, rom_size_KB, mapping, debug) + + print("\nProgramming ROM flash") + + --test some bytes +-- dict.snes("SNES_SET_BANK", 0x00) wr_flash_byte(0x8000, 0xA5, true) wr_flash_byte(0xFFFF, 0x5A, true) +-- dict.snes("SNES_SET_BANK", 0x01) wr_flash_byte(0x8000, 0x15, true) wr_flash_byte(0xFFFF, 0x1A, true) + --last of 512KB +-- dict.snes("SNES_SET_BANK", 0x0F) wr_flash_byte(0x8000, 0xF5, true) wr_flash_byte(0xFFFF, 0xFA, true) + + --most of this is overkill for NROM, but it's how we want to handle things for bigger mappers + local base_addr + local bank_size + local buff_size = 1 --number of bytes to write at a time + local cur_bank = 0 + + if (mapping=="LOROM") then + base_addr = 0x8000 --writes occur $8000-FFFF + bank_size = 32*1024 --SNES LOROM 32KB per ROM bank + elseif (mapping=="HIROM") then + base_addr = 0x0000 --writes occur $0000-FFFF + bank_size = 64*1024 --SNES HIROM 64KB per ROM bank + else + print("ERROR!! mapping:", mapping, "not supported") + end + + local total_banks = rom_size_KB*1024/bank_size + + local byte_num --byte number gets reset for each bank + local byte_str, data, readdata + + while cur_bank < total_banks do + + if (cur_bank %4 == 0) then + print("writting ROM bank: ", cur_bank, " of ", total_banks-1) + end + + --select the current bank + if (cur_bank <= 0xFF) then + dict.snes("SNES_SET_BANK", cur_bank) + else + print("\n\nERROR!!!! SNES bank cannot exceed 0xFF, it was:", string.format("0x%X",cur_bank)) + return + end + + --program the entire bank's worth of data + + --[[ This version of the code programs a single byte at a time but doesn't require + -- board specific functions in the firmware + print("This is slow as molasses, but gets the job done") + byte_num = 0 --current byte within the bank + while byte_num < bank_size do + + --read next byte from the file and convert to binary + byte_str = file:read(buff_size) + data = string.unpack("B", byte_str, 1) + + --write the data + --SLOWEST OPTION: no firmware specific functions 100% host flash algo: + --wr_flash_byte(base_addr+byte_num, data, false) --0.7KBps + --EASIEST FIRMWARE SPEEDUP: 5x faster, create firmware write byte function: + dict.snes("FLASH_WR_3V", base_addr+byte_num, data) --3.8KBps (5.5x faster than above) + + --if (verify) then + -- readdata = dict.nes("NES_CPU_RD", base_addr+byte_num) + -- if readdata ~= data then + -- print("ERROR flashing byte number", byte_num, " in bank",cur_bank, " to flash ", data, readdata) + -- end + --end + + byte_num = byte_num + 1 + end + --]] + + --Have the device write a banks worth of data + if (mapping == "LOROM") then + flash.write_file( file, bank_size/1024, "LOROM_3VOLT", "SNESROM", false ) + else + flash.write_file( file, bank_size/1024, "HIROM_3VOLT", "SNESROM", false ) + end + + cur_bank = cur_bank + 1 + end + + print("Done Programming ROM flash") + +end + + + +local function wr_ram(file, first_bank, ram_size_KB, mapping, debug) + + print("\nProgramming RAM") + + --test some bytes +-- dict.snes("SNES_SET_BANK", 0x00) wr_flash_byte(0x8000, 0xA5, true) wr_flash_byte(0xFFFF, 0x5A, true) +-- dict.snes("SNES_SET_BANK", 0x01) wr_flash_byte(0x8000, 0x15, true) wr_flash_byte(0xFFFF, 0x1A, true) + --last of 512KB +-- dict.snes("SNES_SET_BANK", 0x0F) wr_flash_byte(0x8000, 0xF5, true) wr_flash_byte(0xFFFF, 0xFA, true) + + local base_addr + local bank_size + local buff_size = 1 --number of bytes to write at a time + local cur_bank = 0 + local total_banks + + local byte_num --byte number gets reset for each bank + local byte_str, data, readdata + + + local addr_base --A15-8 address of ram start + + --determine max ram per bank and base address + if (mapping == "LOROM") then + bank_size = 32*1024 -- LOROM has 32KB per bank + base_addr = 0x0000 -- $0000 LOROM RAM start address + elseif (mapping == "HIROM") then + bank_size = 8*1024 -- HIROM has 8KB per bank + base_addr = 0x6000 -- $6000 HIROM RAM start address + else + print("ERROR! mapping:", mapping, "not supported by dump_ram") + end + + local num_banks + + --determine how much ram to read per bank + if (ram_size_KB*1024 < bank_size) then + total_banks = 1 + bank_size = ram_size_KB*1024 + else + total_banks = ram_size_KB*1024 / bank_size + end + + while cur_bank < total_banks do + + print("writting RAM bank: ", cur_bank, " of ", total_banks-1) + + --select the current bank + if (cur_bank <= 0xFF) then + dict.snes("SNES_SET_BANK", cur_bank+first_bank) + else + print("\n\nERROR!!!! SNES bank cannot exceed 0xFF, it was:", string.format("0x%X",cur_bank)) + return + end + + --program the entire bank's worth of data + + ---[[ This version of the code programs a single byte at a time but doesn't require + -- board specific functions in the firmware + print("This is slow as molasses, but gets the job done") + byte_num = 0 --current byte within the bank + while byte_num < bank_size do + + --read next byte from the file and convert to binary + byte_str = file:read(buff_size) + data = string.unpack("B", byte_str, 1) + + --write the data + --SLOWEST OPTION: no firmware specific functions 100% host flash algo: + --wr_flash_byte(base_addr+byte_num, data, false) --0.7KBps + --EASIEST FIRMWARE SPEEDUP: 5x faster, create firmware write byte function: + --dict.snes("FLASH_WR_3V", base_addr+byte_num, data) --3.8KBps (5.5x faster than above) + if (mapping == "LOROM") then + dict.snes("SNES_ROM_WR", base_addr+byte_num, data) --3.8KBps (5.5x faster than above) + else + dict.snes("SNES_SYS_WR", base_addr+byte_num, data) --3.8KBps (5.5x faster than above) + end + + --if (verify) then + -- readdata = dict.nes("NES_CPU_RD", base_addr+byte_num) + -- if readdata ~= data then + -- print("ERROR flashing byte number", byte_num, " in bank",cur_bank, " to flash ", data, readdata) + -- end + --end + + byte_num = byte_num + 1 + end + --]] + + --Have the device write a banks worth of data + --flash.write_file( file, bank_size/1024, "LOROM_3VOLT", "SNESROM", false ) + + cur_bank = cur_bank + 1 + end + + print("Done Programming ROM flash") + +end + + + +--Cart should be in reset state upon calling this function +--this function processes all user requests for this specific board/mapper +local function process( test, read, erase, program, verify, dumpfile, flashfile, verifyfile, dumpram, writeram, ramdumpfile, ramwritefile) + + local rv = nil + local file + + local snes_mapping = "LOROM" + --local snes_mapping = "HIROM" + + --local ram_size = 448 --max LOROM RAM size 32KByte * 0x70-0x7D banks + --local ram_size = 32 --just a single bank of LOROM RAM + --local ram_size = 8 --just a single bank of HIROM RAM + local ram_size = 2 --smallest SRAM cartridge RAM size (16kbit) + + --local rom_size = 32 + local rom_size = 512 + --local rom_size = 1024 + --local rom_size = 2048 + --local rom_size = 4096 + --local rom_size = 8192 + --local rom_size = 12288 + --local rom_size = 16384 + + + -- SNES memory map banking + -- A15 always high for LOROM (A22 is typically low too) + -- A22 always high for HIROM + -- A23 splits the map in half + -- A22 splits it in quarters (between what's typically low half and high half) + -- b 7 6 5 4 : 3 2 1 0 + -- A23 22 21 20 : 19 18 17 16 + + local rombank --first bank of rom byte that contains A23-16 + local rambank --first bank of ram + + if (snes_mapping == "LOROM") then + -- LOROM typically sees the upper half (A15=1) of the first address 0b0000:1000_0000 + rombank = 0x00 + rambank = 0x70 --LOROM maps from 0x70 to 0x7D + --some for lower half of bank only, some for both halfs... + elseif (snes_mapping == "HIROM") then + -- HIROM typically sees the last 4MByte as the first addresses = 0b1100:0000_0000 + rombank = 0xC0 + --rombank = 0x40 --second HiROM bank (slow) + rambank = 0x30 + end + + +--initialize device i/o for SNES + dict.io("IO_RESET") + dict.io("SNES_INIT") + + +--test cart by reading manf/prod ID + if test then + + print("Testing SNES board"); + + --SNES detect HiROM or LoROM & RAM + + --SNES detect if able to read flash ID's + if not rom_manf_id(true) then + print("ERROR unable to read flash ID") + return + end + end + + +--dump the ram to file + if dumpram then + + print("\nDumping SAVE RAM...") + + --may have to verify /RESET is high to enable SRAM + + file = assert(io.open(ramdumpfile, "wb")) + + --dump cart into file + dump_ram(file, rambank, ram_size, snes_mapping, true) + + --may disable SRAM by placing /RESET low + + --close file + assert(file:close()) + + print("DONE Dumping SAVE RAM") + end + +--dump the cart to dumpfile + if read then + print("\nDumping SNES ROM...") + + file = assert(io.open(dumpfile, "wb")) + + --dump cart into file + dump_rom(file, rombank, rom_size, snes_mapping, false) + + --close file + assert(file:close()) + print("DONE Dumping SNES ROM") + end + +--erase the cart + if erase then + + erase_flash() + end + +--write to wram on the cart + if writeram then + + print("\nWritting to SAVE RAM...") + + file = assert(io.open(ramwritefile, "rb")) + + --flash.write_file( file, ram_size, "NOVAR", "PRGRAM", false ) + --flash.write_file( file, ram_size, "LOROM_3VOLT", "SNESROM", false ) + wr_ram(file, rambank, ram_size, snes_mapping, true) + + --close file + assert(file:close()) + + print("DONE Writting SAVE RAM") + end + + +--program flashfile to the cart + if program then + + --open file + file = assert(io.open(flashfile, "rb")) + --determine if auto-doubling, deinterleaving, etc, + --needs done to make board compatible with rom + + --flash cart + flash_rom(file, rom_size, snes_mapping, true) + + --close file + assert(file:close()) + + end + +--verify flashfile is on the cart + if verify then + print("\nPost dumping SNES ROM...") + --for now let's just dump the file and verify manually + + file = assert(io.open(verifyfile, "wb")) + + --dump cart into file + dump_rom(file, rombank, rom_size, snes_mapping, false) + + --close file + assert(file:close()) + print("DONE Post dumping SNES ROM") + end + + dict.io("IO_RESET") +end + + +-- global variables so other modules can use them + + +-- call functions desired to run when script is called/imported + + +-- functions other modules are able to call +v2proto.process = process + +-- return the module's table +return v2proto diff --git a/shared/shared_dict_buffer.h b/shared/shared_dict_buffer.h index 414fd0b..a280974 100644 --- a/shared/shared_dict_buffer.h +++ b/shared/shared_dict_buffer.h @@ -112,13 +112,14 @@ // designate the address base with mapper since this read is mapper independent #define NESCPU_4KB 0x20 //mapper (bits 3-0) specifies A12-15 (4bits) #define NESPPU_1KB 0x21 //mapper (bits 5-2) specifies A10-13 (4bits) + //DON'T WANT TO USE THESE ANY MORE, USE THE PAGE VERSIONS BELOW //since the types above only specify the granularity of the read, there is no reason //to limit it to 1-4KByte. May as well give page granularity and use the whole mapper byte! #define NESCPU_PAGE 0x22 //mapper byte specifies A15-8 #define NESPPU_PAGE 0x23 //mapper byte specifies A13-8 bits 6 & 7 can't be set - #define SNESROM_PAGE 0x24 //mapper byte specifies A15-8 - + #define SNESROM_PAGE 0x24 //mapper byte specifies A15-8 ROMSEL low + #define SNESSYS_PAGE 0x25 //mapper byte specifies A15-8 ROMSEL high //operand LSB //SST 39SF0x0 manf/prod IDs diff --git a/shared/shared_dict_nes.h b/shared/shared_dict_nes.h index bb0e6e1..488f13e 100644 --- a/shared/shared_dict_nes.h +++ b/shared/shared_dict_nes.h @@ -39,6 +39,7 @@ //#define DISCRETE_EXP0_MAPPER_WR 0x03 +//write to an MMC1 register, provide bank/address & data #define NES_MMC1_WR 0x04 #define NES_DUALPORT_WR 0x05 @@ -52,6 +53,11 @@ #define NROM_CHR_FLASH_WR 0x0A #define CNROM_CHR_FLASH_WR 0x0B //needs cur_bank & bank_table prior to calling #define CDREAM_CHR_FLASH_WR 0x0C //needs cur_bank & bank_table prior to calling +#define UNROM_PRG_FLASH_WR 0x0D //needs cur_bank & bank_table prior to calling +#define MMC1_PRG_FLASH_WR 0x0E +#define MMC1_CHR_FLASH_WR 0x0F //needs cur_bank set prior to calling +#define MMC4_PRG_SOP_FLASH_WR 0x10 //current bank must be selected, & needs cur_bank set prior to calling +#define MMC4_CHR_FLASH_WR 0x11 //needs cur_bank set prior to calling #define SET_CUR_BANK 0x20 diff --git a/shared/shared_dict_snes.h b/shared/shared_dict_snes.h index a789169..5548c7a 100644 --- a/shared/shared_dict_snes.h +++ b/shared/shared_dict_snes.h @@ -31,7 +31,9 @@ #define FLASH_WR_5V 0x03 //5v PLCC flash algo #define FLASH_WR_3V 0x04 //3v TSSOP flash algo - +//similar to ROM RD/WR above, but /ROMSEL doesn't go low +#define SNES_SYS_RD 0x05 //RL=3 +#define SNES_SYS_WR 0x06 #endif