From 7d001454313229ff65b24fa85b6246686b5ed937 Mon Sep 17 00:00:00 2001 From: Paul Molloy Date: Sun, 27 Nov 2016 00:18:46 -0600 Subject: [PATCH] Big step in confirmation of pin manipulations working on kazzo. Able to read PRG-ROM flash chip's manf and device ID from commandline. New dictionaries io and nes along with firmware files to support. now have io_reset, nes_init, and snes_init io.c functions nes.c functions including discrete_exp0_prgrom_wr and emulate_nes_cpu_rd. New dictionary.c/.h for host to make dictionary calls easier including setting proper return data lengths based on opcode. adding nop command to pinport.h AVR Memory Usage ---------------- Device: atmega164a Program: 2960 bytes (18.1% Full) (.text + .data + .bootloader) Data: 53 bytes (5.2% Full) (.data + .bss + .noinit) --- firmware/main.hex | 349 +++++++++++++++++++---------------- firmware/source/io.c | 162 +++++++++++++++- firmware/source/io.h | 7 +- firmware/source/main.c | 9 +- firmware/source/nes.c | 148 +++++++++++++++ firmware/source/nes.h | 15 ++ firmware/source/pinport.c | 32 ++-- firmware/source/pinport.h | 9 +- firmware/source/usb.c | 40 +++- firmware/source/usb.h | 4 + host/inlretro.exe | Bin 64255 -> 79049 bytes host/source/dictionary.c | 114 ++++++++++++ host/source/dictionary.h | 29 +++ host/source/erase.c | 54 +----- host/source/erase.h | 1 + host/source/usb_operations.c | 3 + shared/shared_dict_io.h | 56 ++++++ shared/shared_dict_nes.h | 69 +++++++ shared/shared_dict_pinport.h | 6 + shared/shared_dictionaries.h | 79 ++++++++ shared/shared_errors.h | 16 +- 21 files changed, 953 insertions(+), 249 deletions(-) create mode 100644 firmware/source/nes.c create mode 100644 firmware/source/nes.h create mode 100644 host/source/dictionary.c create mode 100644 host/source/dictionary.h create mode 100644 shared/shared_dict_io.h create mode 100644 shared/shared_dict_nes.h diff --git a/firmware/main.hex b/firmware/main.hex index 3250176..c2e6414 100644 --- a/firmware/main.hex +++ b/firmware/main.hex @@ -1,164 +1,187 @@ -:100000000C94E8000C94D1030C9405010C940501A8 -:100010000C9405010C9405010C9405010C94050148 -:100020000C9405010C9405010C9405010C94050138 -:100030000C9405010C9405010C9405010C94050128 -:100040000C9405010C9405010C9405010C94050118 -:100050000C9405010C9405010C9405010C94050108 -:100060000C9405010C9405010C9405010C940501F8 -:100070000C9405010C9405010C9405012101230148 -:10008000260128012B012D013001320135013701F4 -:1000900039013C013E014001420144014601480151 -:1000A0004A01BD01BD01BD01BD014C014E01500120 -:1000B0005201BD01BD01BD01BD01540156015801F0 -:1000C0005A015C015E016001620164016601680120 -:1000D0006A016C016E0170017201BD01BD01BD01BB -:1000E000BD0174017601BB0178017A017E018101B5 -:1000F000850188018E018B0187018A018D019001A4 -:1001000092019401960198019A019C019E01A0011F -:10011000A201A401A601A801AA01AC01AE01B0018F -:10012000B201BD01BD01BD01BD01B701B401B60100 -:10013000BA01CA01CE01CC01D001D601DD01DF0137 -:10014000E101E301ED01F0014402460248024A02E6 -:100150004C024E02500252025402560258025C02F5 -:10016000090212000101008096090400000000004D -:10017000000012011001FF000008C016DC0500029B -:10018000010200011E0349004E004C0020005200F5 -:100190006500740072006F002D00500072006F0047 -:1001A00067002A0349006E00660069006E0069005E -:1001B000740065004E00650073004C006900760015 -:1001C000650073002E0063006F006D0004030904D6 -:1001D00011241FBECFEFD4E0DEBFCDBF11E0A0E001 -:1001E000B1E0E0E2FAE002C005900D92A230B10762 -:1001F000D9F711E0A2E0B1E001C01D92A533B1072B -:10020000E1F70E94E5040C940E050C94000011B86F -:100210008FEF82B914B885B917B888B98AB18471DB -:100220008AB98BB18B6E8BB950985898089590E02D -:100230008B35910508F0A1C0FC01E25CFF4F0C94E6 -:10024000080511B895C08FEF81B992C012B890C05F -:100250008FEF82B98DC014B88BC08FEF84B988C07E -:1002600015B886C08FEF85B983C017B881C018B89C -:100270007FC08FEF88B97CC038987AC0389A78C030 -:10028000409876C0409A74C0399872C0399A70C04C -:1002900041986EC0419A6CC03A986AC03A9A68C058 -:1002A000429866C0429A64C03B9862C03B9A60C064 -:1002B00043985EC0439A5CC03C985AC03C9A58C070 -:1002C000449856C0449A54C03D9852C03D9A50C07C -:1002D00045984EC0459A4CC03E984AC03E9A48C088 -:1002E000469846C0469A44C03F9842C03F9A40C094 -:1002F000479A3EC08AB184718AB93AC08BB1847181 -:1003000002C08BB18B6E8BB933C0509831C05898F6 -:10031000509A2EC05098589A2BC05098589828C080 -:10032000519826C0519A24C0599822C0599A20C089 -:1003300053981EC0539A1CC05B981AC05B9A18C091 -:10034000559816C0559A14C05D9812C05D9A10C099 -:1003500056980EC0569A0CC05E980AC05E9A08C0A5 -:10036000579806C0579A04C05F9A02C05F9A5F9878 -:1003700080E00895479A4798FBCF81E8089590E080 -:10038000FC01E058F109EB30F105A0F5E756FF4F0D -:100390000C94080562B922C08FEF84B965B91EC0FC -:1003A0008FEF84B965B9479A479805C08FEF84B934 -:1003B00065B95F9A5F9814B811C061B90FC064B98C -:1003C0000DC067B90BC09AB1862F846189238AB9A1 -:1003D0008AB16B7E682B6AB901C068B980E0089564 -:1003E0009BB1862F846189238BB98BB16B7E682B7F -:1003F0006BB9F4CF82E80895813A61F0823AB9F09E -:10040000803A11F58FEF84B965B9479A479814B8C7 -:1004100042B916C08FEF84B965B9479A479814B8A6 -:1004200042B967FF02C041980BC0419A09C042B966 -:100430008FEF84B9603230F415B8479A479814B8F2 -:1004400080E0089565B9F9CF83E80895803B61F4B1 -:1004500022B98FEF84B945B9479A479865B95F9A31 -:100460005F9814B880E0089584E80895CF93DF93EF -:10047000EB0190E0805C91098C309105F8F48C558B -:100480009F4FFC010C94080580B113C083B111C0CB -:1004900086B10FC089B10DC082B10BC085B109C052 -:1004A00088B107C08BB105C081B103C084B101C060 -:1004B00087B1888380E003C08AB1FBCF85E8DF91F4 -:1004C000CF910895CF93FC01C081CC1FCC27CC1FC6 -:1004D0008181813079F582819FEF980F9E3718F4E2 -:1004E0000E94170128C09FE7980F9E3120F4648175 -:1004F0000E94BF0120C09FE5980F9E3028F44481E0 -:1005000065810E94FC0117C09FE4980F9E3030F473 -:100510002481458163810E9426020DC09FE3980FCC -:100520009E3358F463E071E00E943602809302012A -:10053000CF5F03C080E88093020122E031E0309376 -:100540001A01209319018C2FCF91089581E008950D -:10055000CF93DF9360911B01635067FDA4C080912E -:100560001801CCE0D0E0C81BD109C15EDE4F8091FC -:1005700017018D3209F085C0683009F092C083EC14 -:1005800080930B018AE58093010110920A01888112 -:10059000807621F0CE010E94620260C08A811092B2 -:1005A00014019981911106C01092150124E131E0E6 -:1005B00082E050C0953019F480931C013DC0963004 -:1005C000A9F59B81913019F482E791E004C0923043 -:1005D00041F480E691E090931A018093190182E141 -:1005E00021C09330F1F4811108C08CEC91E090931C -:1005F0001A018093190184E015C0813041F482EA28 -:1006000091E090931A01809319018AE20BC0823025 -:1006100041F484E891E090931A01809319018EE1EE -:1006200001C080E090E490930A0118C0983079F0FE -:10063000993031F480931E0124E131E080E00AC05A -:1006400081E09A3009F080E024E131E003C02EE13E -:1006500031E081E030931A01209319018F3F39F482 -:10066000988197FD8E8190E890930A0107C09F8141 -:10067000911104C09E81981708F4892F809300017E -:1006800010C080910A0187FF0CC0CE010E94A60213 -:100690008F3F21F48EE18093010103C081111092FC -:1006A000000110921B018091010184FF4DC08091D7 -:1006B00000018F3F09F448C0C82F893008F0C8E016 -:1006C0008C1B8093000180910B0198E8892780930F -:1006D0000B01CC2361F18091190190911A012091B5 -:1006E0000A0126FF12C0ACE0B1E02BE031E020951A -:1006F0003095280F391F4C2F4A0FF901EA0FFB1FC5 -:10070000E491ED934A13F9CF09C0ECE0F1E0DC018C -:100710002C2F2E0F3D9131932E13FCCF01962FEFEE -:100720002C0F820F911D90931A01809319016C2F49 -:100730008CE091E00E94CD03CC5FCC3019F08FEFBC -:1007400080930001C093010184E199B1947131F467 -:100750008150D9F710921C0110921601DF91CF91B0 -:100760000895E9E6F0E0808182608083E89A089548 -:10077000A82FB92F80E090E041E050EA609530E08A -:1007800009C02D9182279795879510F0842795278A -:10079000305EC8F36F5FA8F30895EADF8D939D93F1 -:1007A0000895CF93CFB7CF93DF93C3954C9BE9F7D1 -:1007B0004C9B0BC04C9B09C04C9B07C04C9B05C07D -:1007C0004C9B03C04C9B01C089C06F93C091180122 -:1007D000DD27C15EDE4F2F9365E54C9B03C02F9153 -:1007E0006F91E6CF0F931F934F9320E040E15F930B -:1007F00009B1047104FB27F93F9350E03BE039C095 -:10080000147140642F77012F5F5F1EC0406819B1DB -:1008100014712F7752501FC0406409B12F770471B3 -:10082000D1F15F5F00C023C0406219B12F7714710E -:1008300091F15F5F00C025C004711027515012F480 -:100840005D5F0000115027952C3F19B1C8F6147157 -:100850000127015027952C3FC8F64227499309B13B -:10086000047110274F73115027952C3FA8F6469519 -:10087000469519B1147179F00127015027952C3F45 -:1008800098F66B5A60F3315009B1B0F600C011E030 -:100890001CBB002717C03B503195C31BD04011E053 -:1008A0001CBB0881033CF9F00B34E9F020911601E0 -:1008B0001981110F1213EDCF093651F10D3211F0DC -:1008C000013E39F700931D013F915F914F911F91B8 -:1008D0000F912F916F91CCB3C0FD67CFDF91CF9176 -:1008E000CFBFCF91189520911D01222369F310915C -:1008F0001B01112339F534303AF130931B01209359 -:100900001701109118013BE0311B309318011CC0F6 -:1009100000911B010130B4F40AE53091010134FD6E -:1009200014C000930101CBE0D1E013C0052710E013 -:1009300000C000000BB91AC0052710E0221F1DC01F -:1009400010E021C04AE502C032ED432FC4E1D0E0FF -:1009500032E01AB114615C9A0BB11AB954E120E883 -:1009600065E320FF05270BB9279517951C3FF0F687 -:100970006695B8F7B1F720FF05270BB927951795AE -:100980001C3FD0F62795179517FF052700001C3F41 -:100990000BB9B0F629913A9519F70B7E10911C010D -:1009A000110FC651D0400BB911F01093160111E090 -:1009B0001CBB00611AB11B7E402F4B7E54E05A9540 -:1009C000F1F70BB91AB94BB97FCF2EE088E190E06F -:1009D0000FB6F894A895809360000FBE2093600036 -:1009E0000E94B103549A80E0815041F0A895EFE94C -:1009F000FFE03197F1F700C00000F6CF54980E9455 -:100A00000701519A599A7894A8950E94A802FCCFA0 -:100A1000EE0FFF1F0590F491E02D0994F894FFCF9D -:020A2000FF5A7B +:100000000C94D1000C94B1040C94EE000C94EE000E +:100010000C94EE000C94EE000C94EE000C94EE00A8 +:100020000C94EE000C94EE000C94EE000C94EE0098 +:100030000C94EE000C94EE000C94EE000C94EE0088 +:100040000C94EE000C94EE000C94EE000C94EE0078 +:100050000C94EE000C94EE000C94EE000C94EE0068 +:100060000C94EE000C94EE000C94EE000C94EE0058 +:100070000C94EE000C94EE000C94EE00C601C80146 +:10008000CB01CD01D001D201D501D701DA01DC01CC +:10009000DE01E101E301E501E701E901EB01ED0129 +:1000A000EF01C401C401C401C401F101F301F50170 +:1000B000F701C401C401C401C401F901FB01FD0140 +:1000C000FF01010203020502070209020B020D02F1 +:1000D0000F021102130215021702C401C401C40168 +:1000E000C40119021B021D021F022102250228025F +:1000F0002C022F02350232022E0231023402370264 +:1001000039023B023D023F024102430245024702DF +:1001100049024B024D024F0251025302550257024F +:100120005902C401C401C401C4015E025B025D0244 +:100130006102040309042A0349006E006600690095 +:100140006E006900740065004E00650073004C008D +:1001500069007600650073002E0063006F006D007B +:100160001E0349004E004C00200052006500740040 +:1001700072006F002D00500072006F0067001201C6 +:100180001001FF000008C016DC050002010200019A +:10019000090212000101008096090400000000001D +:1001A000000011241FBECFEFD4E0DEBFCDBF11E0B1 +:1001B000A0E0B1E0EEE8FBE002C005900D92A230B5 +:1001C000B107D9F711E0A2E0B1E001C01D92A5335B +:1001D000B107E1F70E9453010C94C5050C9400008F +:1001E00011B88FEF82B914B885B917B888B98AB138 +:1001F00084718AB98BB18B6E8BB95098589851988D +:10020000599A08950E94F000399A419A389A409874 +:100210003A9A429A3C9A449A3D9A459A3F9A479A0A +:1002200047988FEF84B915B8479A479814B812B811 +:1002300081B914B885B95998519A08950E94F0006F +:10024000399A419A3C9A449A3D9A459A509A589ABA +:100250003F9A479A4798579A5F9A5F988FEF84B969 +:1002600015B8479A479814B884B915B85F9A5F983B +:1002700014B812B881B914B885B95998519A08952B +:10028000813049F0813020F0823049F086E90895CC +:100290000E94F00002C00E94020180E008950E94C6 +:1002A0001E0180E008952EE088E190E00FB6F894FA +:1002B000A895809360000FBE209360000E948C037D +:1002C000549A20E040EA5FE004C0A895CA01019773 +:1002D000F1F72150D1F754980E94F0007894A89536 +:1002E0000E949303FCCF9FEF94B985B9479A479832 +:1002F00045B962B95898509A5098589A14B80895C8 +:10030000882311F080EA0895862F642F422F0E94DF +:10031000730180E00895509858984098419A429A05 +:1003200062B99FEF94B985B9479A479814B800000D +:10033000000087FF03C0409A419801C0409A000026 +:1003400000000000000083B14098419A0895CF93C7 +:10035000DF93E901803811F081EA06C0862F642F0F +:100360000E948B01888380E0DF91CF910895E82F70 +:10037000F0E0EB35F10540F4E25CFF4FEE0FFF1FBC +:100380000590F491E02D09948CE8089511B897C078 +:100390008FEF81B994C012B892C08FEF82B98FC02D +:1003A00014B88DC08FEF84B98AC015B888C08FEF9C +:1003B00085B985C017B883C018B881C08FEF88B9D8 +:1003C0007EC038987CC0389A7AC0409878C0409AED +:1003D00076C0399874C0399A72C0419870C0419AF9 +:1003E0006EC03A986CC03A9A6AC0429868C0429A05 +:1003F00066C03B9864C03B9A62C0439860C0439A11 +:100400005EC03C985CC03C9A5AC0449858C0449A1C +:1004100056C03D9854C03D9A52C0459850C0459A28 +:100420004EC03E984CC03E9A4AC0469848C0469A34 +:1004300046C03F9844C03F9A42C0479840C0479A40 +:100440003EC08AB184718AB93AC08BB1847102C04E +:100450008BB18B6E8BB933C0509831C05898509A7D +:100460002EC05098589A2BC05098589828C0519830 +:1004700026C0519A24C0599822C0599A20C0539836 +:100480001EC0539A1CC05B981AC05B9A18C055983E +:1004900016C0559A14C05D9812C05D9A10C0569847 +:1004A0000EC0569A0CC05E980AC05E9A08C0579853 +:1004B00006C0579A04C05F9A02C05F9A5F9880E0B6 +:1004C0000895479A479880E00895853891F18638D5 +:1004D00070F48238E9F0833828F48038B9F0813834 +:1004E00099F418C08338C1F0843871F41BC088387F +:1004F00031F1893828F48638F1F0873829F41DC0A5 +:10050000893839F18A3841F18DE8089562B922C0FD +:100510008FEF84B965B91EC08FEF84B965B9479A6A +:10052000479805C08FEF84B965B95F9A5F9814B892 +:1005300011C061B90FC064B90DC067B90BC08AB1F1 +:10054000962F946198239AB98AB16B7E862B8AB9CB +:1005500001C068B980E008958BB1962F946198230B +:100560009BB98BB16B7E862B8BB980E00895813A65 +:1005700071F0823AC9F0803A11F08EE808958FEF59 +:1005800084B965B9479A479814B842B917C08FEF34 +:1005900084B965B9479A479814B842B967FF02C051 +:1005A00041980CC0419A0AC042B9603248F48FEFBA +:1005B00084B9607865B9479A479814B880E008957F +:1005C0008FEF84B965B9479A479814B880E00895C9 +:1005D000803B11F08FE8089522B98FEF84B945B9B7 +:1005E000479A479865B95F9A5F9814B880E0089574 +:1005F000FB01853C59F1863C70F4823C09F1833C57 +:1006000028F4803CC9F0813CA9F418C0833CD1F0A7 +:10061000843C81F419C0883CF9F0893C28F4863C7C +:10062000B9F0873C39F416C08A3CD1F08A3CB0F06E +:100630008B3CD1F080E9089580B113C083B111C023 +:1006400086B10FC089B10DC082B10BC085B109C0A0 +:1006500088B107C08BB105C081B103C084B101C0AE +:1006600087B1808380E008958AB1808380E0089517 +:1006700081E008951F93FC0110E0808187FD11E067 +:100680008181823031F1833041F18130C9F582813D +:10069000803B28F4803A68F4803820F006C0803C23 +:1006A00068F012C00E94B7012CC064810E946502EC +:1006B00028C0658144810E94B70223C063814581BF +:1006C00024810E94E8021DC063E071E00E94F802EC +:1006D00013C082810E94400114C08281803830F4AE +:1006E0006581448123810E9480010BC06581448122 +:1006F00023E031E00E94A701809302011F5F03C045 +:1007000080E88093020182E091E090931A01809347 +:100710001901812F1F910895E9E6F0E08081826040 +:100720008083E89A08951F93CF93DF9360911B0114 +:10073000635067FDA5C080911801CCE0D0E0C81BD4 +:10074000D109C15EDE4F809117018D3209F085C05D +:10075000683009F093C083EC80930B018AE58093A5 +:10076000000110920A018881807641F0CE010E943A +:100770003A03282F8F3F09F45FC065C09A81109219 +:1007800014018981882321F41092150122E04DC0C3 +:10079000853019F490931C0147C08630B1F58B81E8 +:1007A000813019F48EE791E004C0823041F480E991 +:1007B00091E090931A018093190122E122C08330C5 +:1007C000F9F48A81882341F482E391E090931A013D +:1007D0008093190124E015C0813041F486E391E053 +:1007E00090931A01809319012AE20BC0823041F4E0 +:1007F00080E691E090931A01809319012EE101C0E7 +:1008000020E080E480930A011EC0883021F421E0BA +:100810008EE191E00CC0893019F490931E0104C060 +:100820008A3011F421E001C020E084E191E090934E +:100830001A018093190107C0888187FD2E8180E805 +:1008400080930A0106C08F81882319F48E81821754 +:1008500008F0822F8093010111C080910A0187FF67 +:100860000DC0CE010E9438038F3F21F48EE18093AA +:10087000000104C0882311F01092010110921B01A5 +:100880008091000184FF46C0809101018F3F09F4EF +:1008900041C0182F893008F018E0811B80930101B6 +:1008A00080910B0198E8892780930B01112321F196 +:1008B0002091190130911A0180910A0186FF0AC026 +:1008C000912FF901ACE0B1E084918D933196915074 +:1008D000D9F708C0912FD901ECE0F1E08D91819317 +:1008E0009150E1F7C90101961150810F911D1F5FD1 +:1008F00090931A01809319018CE091E0612F0E947E +:10090000AD04612F6C5F6C3019F08FEF80930101A3 +:100910006093000194E189B1847131F49150D9F769 +:1009200010921C0110921601DF91CF911F91089532 +:10093000A82FB92F80E090E041E050EA609530E0C8 +:1009400009C02D9182279795879510F084279527C8 +:10095000305EC8F36F5FA8F30895EADF8D939D932F +:100960000895CF93CFB7CF93DF93C3954C9BE9F70F +:100970004C9B0BC04C9B09C04C9B07C04C9B05C0BB +:100980004C9B03C04C9B01C089C06F93C091180160 +:10099000DD27C15EDE4F2F9365E54C9B03C02F9191 +:1009A0006F91E6CF0F931F934F9320E040E15F9349 +:1009B00009B1047104FB27F93F9350E03BE039C0D3 +:1009C000147140642F77012F5F5F1EC0406819B11A +:1009D00014712F7752501FC0406409B12F770471F2 +:1009E000D1F15F5F00C023C0406219B12F7714714D +:1009F00091F15F5F00C025C004711027515012F4BF +:100A00005D5F0000115027952C3F19B1C8F6147195 +:100A10000127015027952C3FC8F64227499309B179 +:100A2000047110274F73115027952C3FA8F6469557 +:100A3000469519B1147179F00127015027952C3F83 +:100A400098F66B5A60F3315009B1B0F600C011E06E +:100A50001CBB002717C03B503195C31BD04011E091 +:100A60001CBB0881033CF9F00B34E9F0209116011E +:100A70001981110F1213EDCF093651F10D3211F01A +:100A8000013E39F700931D013F915F914F911F91F6 +:100A90000F912F916F91CCB3C0FD67CFDF91CF91B4 +:100AA000CFBFCF91189520911D01222369F310919A +:100AB0001B01112339F534303AF130931B01209397 +:100AC0001701109118013BE0311B309318011CC035 +:100AD00000911B010130B4F40AE53091000134FDAE +:100AE00014C000930001CBE0D1E013C0052710E053 +:100AF00000C000000BB91AC0052710E0221F1DC05E +:100B000010E021C04AE502C032ED432FC4E1D0E03D +:100B100032E01AB114615C9A0BB11AB954E120E8C1 +:100B200065E320FF05270BB9279517951C3FF0F6C5 +:100B30006695B8F7B1F720FF05270BB927951795EC +:100B40001C3FD0F62795179517FF052700001C3F7F +:100B50000BB9B0F629913A9519F70B7E10911C014B +:100B6000110FC651D0400BB911F01093160111E0CE +:100B70001CBB00611AB11B7E402F4B7E54E05A957E +:0E0B8000F1F70BB91AB94BB97FCFF894FFCF3C +:020B8E005AFF0C :00000001FF diff --git a/firmware/source/io.c b/firmware/source/io.c index 27005c9..11bb70e 100644 --- a/firmware/source/io.c +++ b/firmware/source/io.c @@ -1,9 +1,42 @@ #include "io.h" +//================================================================================================= +// +// I/O operations +// This file includes all the io functions possible to be called from the io dictionary. +// +// See description of the commands contained here in shared/shared_dictionaries.h +// +//================================================================================================= + +/* Desc:Function takes an opcode which was transmitted via USB + * then decodes it to call designated function. + * shared_dict_io.h is used in both host and fw to ensure opcodes/names align + * Pre: Macros must be defined in firmware pinport.h + * opcode must be defined in shared_dict_io.h + * Post:function call complete. + * Rtn: SUCCESS if opcode found, ERR_UNKN_IO_OPCODE_ONLY if opcode not present. + */ +uint8_t io_opcode_only( uint8_t opcode ) +{ + switch (opcode) { + case IO_RESET: io_reset(); break; + case NES_INIT: nes_init(); break; + case SNES_INIT: snes_init(); break; + default: + //macro doesn't exist + return ERR_UNKN_IO_OPCODE_ONLY; + } + + return SUCCESS; + +} //pullup as many cart pins as possible //goal to be safe state for all hardware -void io_pullup() +//doesn't currently contain any checks to report error/success from +//this is intended to be the "reset" safest condition for the kazzo +void io_reset() { //pull up addr[7:0] bus _ADDR_IP(); @@ -18,10 +51,10 @@ void io_pullup() _CTL_HI(); //pull up aux port + //Aux port contains EXP /OE control + //pull up on EXP FF should disable FF ouput _AUX_IP(); _AUX_HI(); - //Aux port EXP /OE control - //pull up on EXP FF should disable FF ouput //EXP0 input no pullup //Lots of possibilities, ~safe bet it will have it's own pull-up/down if needed. @@ -32,4 +65,127 @@ void io_pullup() _EXP0_FLT(); //LED LAST displaying complete.. + //planning to have LED DIM at power on to signify kazzo is in default + //mostly all pins pulled up state. + //gives some insight to current state of kazzo since it doesn't reset itself + //or if kazzo does reset itself due to WDT dim LED can help detect that. + _LED_IP(); //DIM pulled up + //_LED_OP(); //BRIGHT full power + //boot with LED on/pulled up to differentiate bettwen BL/RUN + _LED_ON(); + } + +//NES cartridge interfacing setup +//set outputs as required +//latch address of $0000 +//disable NES cart memories +void nes_init() +{ + //start with a reset + //expecting user to do this but just to be sure + io_reset(); + + //enable control outputs and disable memories + //PRG-ROM + _ROMSEL_OP(); + _ROMSEL_HI(); + //WRAM (and state of m2 during first half of CPU cycle) + _M2_OP(); + _M2_LO(); + //CPU RD + _PRGRW_OP(); + _PRGRW_RD(); + + //other control pins are inputs, leave as IP pullup from reset + + //disable any CHR/VRAM memories with CHR /RD /WR + //prior to setting PPU A13 & /A13 which are /CE pins + //doing this helps ensure data bus is clear before + //using it for AHL clocking + _CSRD_OP(); + _CSRD_HI(); + _CSWR_OP(); + _CSWR_HI(); + + //memories are now disabled Data bus should be clear + + //setup AHL FF + _AHL_OP(); + _AHL_CLK(); + + //now meet conditions to call other macros + //setup address $0000 + _ADDRH_SET(0x00); + _ADDR_LO(); + + //default state of ADDR[7:0] + _ADDR_OP(); + + //default state data bus pulled up + _DATA_IP(); + _DATA_HI(); + + //turn LED off + _LED_OFF(); + //set as OP for future commands to utilize + _LED_OP(); + +} + + +//SNES cartridge interfacing setup +//set outputs as required +//latch address of $000000 +//disable cart memories +//reset high disables SRAM and puts INL carts in PRGM mode +void snes_init() +{ + //start with a reset + //expecting user to do this but just to be sure + io_reset(); + + //enable control outputs and disable memories + //ROM + _ROMSEL_OP(); + _ROMSEL_HI(); + _CSRD_OP(); + _CSRD_HI(); + _CSWR_OP(); + _CSWR_HI(); + + //disable SRAM and put cart in PRGM mode + _SRST_OP(); + _SRST_HI(); + + //other control pins are inputs or unused, leave as IP pullup from reset + + //memories are now disabled Data bus should be clear + + //setup AHL FF + _AHL_OP(); + _AHL_CLK(); + //setup AXL FF + _AXLOE_OP(); + _AXL_CLK(); + + //now meet conditions to call other macros + //setup address $000000 + _ADDRH_SET(0x00); + _ADDRX_SET(0x00); + _ADDR_LO(); + + //default state of ADDR[7:0] + _ADDR_OP(); + + //default state data bus pulled up + _DATA_IP(); + _DATA_HI(); + + //turn LED off + _LED_OFF(); + //set as OP for future commands to utilize + _LED_OP(); + +} + diff --git a/firmware/source/io.h b/firmware/source/io.h index 8bffa3c..fde8a1e 100644 --- a/firmware/source/io.h +++ b/firmware/source/io.h @@ -3,7 +3,12 @@ #include #include "pinport.h" +#include "shared_dictionaries.h" +#include "shared_errors.h" -void io_pullup(); +uint8_t io_opcode_only( uint8_t opcode ); +void io_reset(); +void nes_init(); +void snes_init(); #endif diff --git a/firmware/source/main.c b/firmware/source/main.c index 30ad199..b5ef775 100644 --- a/firmware/source/main.c +++ b/firmware/source/main.c @@ -37,13 +37,8 @@ int __attribute__((noreturn)) main(void) //reconnect to host usbDeviceConnect(); - //intialize i/o to pullup state - io_pullup(); - - //configure LED PORT/DDR - _LED_OP(); - //boot with LED on to differentiate bettwen BL/RUN - _LED_ON(); + //intialize i/o and LED to pullup state + io_reset(); //enable interrupts sei(); diff --git a/firmware/source/nes.c b/firmware/source/nes.c new file mode 100644 index 0000000..ff2caca --- /dev/null +++ b/firmware/source/nes.c @@ -0,0 +1,148 @@ +#include "nes.h" + +//================================================================================================= +// +// NES operations +// This file includes all the nes functions possible to be called from the nes dictionary. +// +// See description of the commands contained here in shared/shared_dictionaries.h +// +//================================================================================================= + +/* Desc:Function takes an opcode which was transmitted via USB + * then decodes it to call designated function. + * shared_dict_nes.h is used in both host and fw to ensure opcodes/names align + * Pre: Macros must be defined in firmware pinport.h + * opcode must be defined in shared_dict_nes.h + * Post:function call complete. + * Rtn: SUCCESS if opcode found, ERR_UNKN_NES_OPCODE_24BOP if opcode not present. + */ +uint8_t nes_opcode_24b_operand( uint8_t opcode, uint8_t addrH, uint8_t addrL, uint8_t data ) +{ + switch (opcode) { + case DISCRETE_EXP0_PRGROM_WR: + discrete_exp0_prgrom_wr( addrH, addrL, data ); + break; + default: + //macro doesn't exist + return ERR_UNKN_NES_OPCODE_24BOP; + } + + return SUCCESS; + +} + + +/* Desc:Function takes an opcode which was transmitted via USB + * then decodes it to call designated function. + * shared_dict_nes.h is used in both host and fw to ensure opcodes/names align + * Pre: Macros must be defined in firmware pinport.h + * opcode must be defined in shared_dict_nes.h + * Post:pointer to data updated with return value. + * Rtn: SUCCESS if opcode found, ERR_UNKN_NES_OPCODE_16BOP_8BRV if opcode not present. + */ +uint8_t nes_opcode_16b_operand_8b_return( uint8_t opcode, uint8_t addrH, uint8_t addrL, uint8_t *data ) +{ + switch (opcode) { + case EMULATE_NES_CPU_RD: + *data = emulate_nes_cpu_rd( addrH, addrL ); + break; + default: + //macro doesn't exist + return ERR_UNKN_NES_OPCODE_16BOP_8BRV; + } + + return SUCCESS; + +} + +/* Desc: Discrete board PRG-ROM only write, does not write to mapper + * PRG-ROM /WE <- EXP0 w/PU + * PRG-ROM /OE <- /ROMSEL + * PRG-ROM /CE <- GND + * PRG-ROM write: /WE & /CE low, /OE high + * mapper '161 CLK <- /ROMSEL + * mapper '161 /LOAD <- PRG R/W + * mapper '161 /LOAD must be low on rising edge of CLK to latch data + * This is a /WE controlled write with data latched on rising edge EXP0 + * Note:addrH bit7 has no effect (ends up on PPU /A13) + * /ROMSEL, M2, & PRG R/W signals untouched + * Pre: nes_init() setup of io pins + * Post:data latched by PRG-ROM, mapper register unaffected + * address left on bus + * data left on bus, but pullup only + * EXP0 left pulled up + * Rtn: None + */ +void discrete_exp0_prgrom_wr( uint8_t addrH, uint8_t addrL, uint8_t data ) +{ + _DATA_OP(); + DATA_OUT = addrH; + _AHL_CLK(); //addrH latched + DATA_OUT = data; + ADDR_OUT = addrL; + _EXP0_LO(); //Tas = 0ns, Tah = 30ns + _EXP0_PU(); //Twp = 40ns, Tds = 40ns, Tdh = 0ns + //16Mhz avr clk = 62.5ns period guarantees timing reqts + //Need to check with scope to make sure EXP0 P/U effective + _DATA_IP(); +} + + +/* Desc:Emulate NES CPU Read as best possible + * decode A15 from addrH to set /ROMSEL as expected + * float EXP0 + * toggle M2 as NES would + * insert some NOP's in to be slow like NES + * Note:not the fastest read operation + * Pre: nes_init() setup of io pins + * Post:address left on bus + * data bus left clear + * EXP0 left floating + * Rtn: None + */ +uint8_t emulate_nes_cpu_rd( uint8_t addrH, uint8_t addrL ) +{ + uint8_t read; //return value + + //m2 should be low as it aids in disabling WRAM + //this is also m2 state at beginging of CPU cycle + //all these pins should already be in this state, but + //go ahead and setup just to be sure since we're trying + //to be as accurate as possible + _EXP0_FLT(); //this could have been left pulled up + _M2_LO(); //start of CPU cycle + _ROMSEL_HI(); //trails M2 + _PRGRW_RD(); //happens just after M2 + + //set address bus + ADDR_OUT = addrL; + _ADDRH_SET(addrH); + + //couple NOP's to wait a bit + NOP(); + NOP(); + + //set M2 and /ROMSEL + if( addrH >= 0x80 ) { //addressing cart rom space + _M2_HI(); + _ROMSEL_LO(); //romsel trails M2 during CPU operations + } else { + _M2_HI(); + } + + //couple more NOP's waiting for data + NOP(); + NOP(); + NOP(); + NOP(); + + //latch data + read = DATA_IN; + + //return bus to default + _M2_LO(); + _ROMSEL_HI(); + + return read; +} diff --git a/firmware/source/nes.h b/firmware/source/nes.h new file mode 100644 index 0000000..963b170 --- /dev/null +++ b/firmware/source/nes.h @@ -0,0 +1,15 @@ +#ifndef _nes_h +#define _nes_h + +#include +#include "pinport.h" +#include "shared_dictionaries.h" +#include "shared_errors.h" + +uint8_t nes_opcode_only( uint8_t opcode ); +uint8_t nes_opcode_24b_operand( uint8_t opcode, uint8_t addrH, uint8_t addrL, uint8_t data ); +uint8_t nes_opcode_16b_operand_8b_return( uint8_t opcode, uint8_t addrH, uint8_t addrL, uint8_t *data ); +void discrete_exp0_prgrom_wr( uint8_t addrH, uint8_t addrL, uint8_t data ); +uint8_t emulate_nes_cpu_rd( uint8_t addrH, uint8_t addrL ); + +#endif diff --git a/firmware/source/pinport.c b/firmware/source/pinport.c index 67f5933..6ad4f0c 100644 --- a/firmware/source/pinport.c +++ b/firmware/source/pinport.c @@ -2,14 +2,14 @@ //This file was created based on pinport.h //the close relationship between these two files must be kept in mind when making changes. -//This file is also very dependent on shared_pinport.h -//the shared_pinport.h was generated from this file, so any changes here must be forwarded. +//This file is also very dependent on shared_dict_pinport.h +//the shared_dict_pinport.h was generated from this file, so any changes here must be forwarded. /* Desc:Function takes an opcode which was transmitted via USB * then decodes it to call designated macro. - * shared_pinport.h is used in both host and fw to ensure opcodes/names align + * shared_dict_pinport.h is used in both host and fw to ensure opcodes/names align * Pre: Macro must be defined in firmware pinport.h - * opcode must be defined in shared_pinport.h + * opcode must be defined in shared_dict_pinport.h * Post:Macro call complete. * Rtn: SUCCESS if opcode found, ERR_UNKN_PP_OPCODE_ONLY if opcode not present. */ @@ -284,14 +284,14 @@ void software_AHL_CLK() /* Desc:Function takes an opcode and 8bit operand which was transmitted via USB * then decodes it to call designated macro/function. - * shared_pinport.h is used in both host and fw to ensure opcodes/names align + * shared_dict_pinport.h is used in both host and fw to ensure opcodes/names align * Pre: Macro must be defined in firmware pinport.h - * opcode must be defined in shared_pinport.h + * opcode must be defined in shared_dict_pinport.h * data bus must be free and clear * control pins must be initialized * -FF latch /OE pins set as outputs * -FF CLK pins low ready for CLK - * See big CAUTION on shared_pinport.h for more details + * See big CAUTION on shared_dict_pinport.h for more details * ADDR_OP() expected to be set * Post:Macro/function called with operand * data bus left free and clear when possible @@ -370,16 +370,16 @@ uint8_t pinport_opcode_8b_operand( uint8_t opcode, uint8_t operand ) /* Desc:Function takes an opcode and 16bit operand which was transmitted via USB * then decodes it to call designated macro/function. * operandMSB is most significant byte, operandLSB is least significant - * shared_pinport.h is used in both host and fw to ensure opcodes/names align + * shared_dict_pinport.h is used in both host and fw to ensure opcodes/names align * Pre: Macros must be defined in firmware pinport.h - * opcode must be defined in shared_pinport.h + * opcode must be defined in shared_dict_pinport.h * data bus must be free and clear * control pins must be initialized * -FF latch /OE pins set as outputs * -FF CLK pins low ready for CLK * ADDR_OP() is expected to be set. * /ROMSEL and M2 expected to be OP. - * See big CAUTION on shared_pinport.h for more details + * See big CAUTION on shared_dict_pinport.h for more details * Post:Macro/function called with operand * data bus left free and clear when possible * -some opcodes diliberately drive the bus @@ -444,15 +444,15 @@ uint8_t pinport_opcode_16b_operand( uint8_t opcode, uint8_t operandMSB, uint8_t /* Desc:Function takes an opcode and 24bit operand which was transmitted via USB * then decodes it to call designated macro/function. * operandMSB is most signf byte, operandMID is center, operandLSB is least significant - * shared_pinport.h is used in both host and fw to ensure opcodes/names align + * shared_dict_pinport.h is used in both host and fw to ensure opcodes/names align * Pre: Macros must be defined in firmware pinport.h - * opcode must be defined in shared_pinport.h + * opcode must be defined in shared_dict_pinport.h * data bus must be free and clear * control pins must be initialized * -FF latch /OE pins set as outputs * -FF CLK pins low ready for CLK * ADDR_OP() is expected to be set. - * See big CAUTION on shared_pinport.h for more details + * See big CAUTION on shared_dict_pinport.h for more details * Post:Macro/function called with operand * data bus left free and clear when possible * -some opcodes may diliberately drive the bus @@ -488,10 +488,10 @@ uint8_t pinport_opcode_24b_operand( uint8_t opcode, uint8_t operandMSB, uint8_t /* Desc:Function takes an opcode and pointer to return value byte * then decodes it to retreive value. - * shared_pinport.h is used in both host and fw to ensure opcodes/names align + * shared_dict_pinport.h is used in both host and fw to ensure opcodes/names align * Pre: Macros must be defined in firmware pinport.h - * opcode must be defined in shared_pinport.h - * See big CAUTION on shared_pinport.h for more details + * opcode must be defined in shared_dict_pinport.h + * See big CAUTION on shared_dict_pinport.h for more details * Post:pointer updated to value designated by opcode. * Rtn: SUCCESS if opcode found, ERR_UNKN_PP_OPCODE_8BRV if opcode not present. */ diff --git a/firmware/source/pinport.h b/firmware/source/pinport.h index 6772d78..2c6f838 100644 --- a/firmware/source/pinport.h +++ b/firmware/source/pinport.h @@ -174,6 +174,8 @@ void software_AXL_CLK(); // Easier to add them than take them out maybe..? //Current rule is _ goes with () type macro +// used for a very short delay +#define NOP() do { __asm__ __volatile__ ("nop"); } while (0) //============================ //ADDR[7:0] PORTA @@ -323,7 +325,7 @@ void software_AXL_CLK(); #define EXP0 PD0 //NES EXP0 controls a number of varying flash cart features... #define FC_APU PD0 //FC Audio in cart from 2A03 APU #define TDO PD0 //CPLD JTAG on INL-ROM NES/FC boards released after ~Oct2016 -#define S_RST PD0 //SNES /RESET pin used for CPLD prgm/play mode and SRAM CE +#define SRST PD0 //SNES /RESET pin used for CPLD prgm/play mode and SRAM CE #define LED PD1 //LED on INL retro prog-dumper #define EXP9 PD1 //NES dual purposed pin @@ -354,6 +356,11 @@ void software_AXL_CLK(); #define _EXP0_LO() _EXP0_lo(); _EXP0_op(); //Sets low then DDR to o/p #define _EXP0_PU() _EXP0_ip(); _EXP0_hi(); //maybe add some NOP() to allow time for pull up #define _EXP0_FLT() _EXP0_ip(); _EXP0_lo(); //Set to i/p w/o pullup +//SNES /RESET versions, more permissible for driving EXP0 to 5v as NES cart shouldn't be inserted +#define _SRST_IP() _EXP0_ip() +#define _SRST_OP() _EXP0_op() +#define _SRST_LO() _EXP0_lo() +#define _SRST_HI() _EXP0_hi() #define _LED_IP() AUX_DDR &= ~(1<opcode, spacket->wIndexLSB ); + spacket->opcode, spacket->operandLSB ); break; case PP_OPCODE_16BOP_MIN ... PP_OPCODE_16BOP_MAX: rv[0] = pinport_opcode_16b_operand( - spacket->opcode, spacket->wIndexMSB, spacket->wIndexLSB ); + spacket->opcode, spacket->operandMSB, spacket->operandLSB ); break; case PP_OPCODE_24BOP_MIN ... PP_OPCODE_24BOP_MAX: rv[0] = pinport_opcode_24b_operand( spacket->opcode, - spacket->wValueMSB, spacket->wIndexMSB, spacket->wIndexLSB ); + spacket->miscdata, spacket->operandMSB, spacket->operandLSB ); break; case PP_OPCODE_8BRV_MIN ... PP_OPCODE_8BRV_MAX: rv[0] = pinport_opcode_8b_return( spacket->opcode, &rv[1]); @@ -108,6 +107,33 @@ USB_PUBLIC usbMsgLen_t usbFunctionSetup(uchar data[8]) { rv[0] = ERR_BAD_PP_OP_MINMAX; } break; //end of PINPORT + + case IO: + switch (spacket->opcode) { + case IO_OPCODE_ONLY_MIN ... IO_OPCODE_ONLY_MAX: + rv[0] = io_opcode_only( spacket->opcode ); + break; + default: //io opcode min/max definition error + rv[0] = ERR_BAD_IO_OP_MINMAX; + } + break; //end of IO + + case NES: + switch (spacket->opcode) { + case NES_OPCODE_24BOP_MIN ... NES_OPCODE_24BOP_MAX: + rv[0] = nes_opcode_24b_operand( spacket->opcode, + spacket->operandMSB, spacket->operandLSB, spacket->miscdata ); + break; + case NES_OPCODE_16BOP_8BRV_MIN ... NES_OPCODE_16BOP_8BRV_MAX: + rv[0] = nes_opcode_16b_operand_8b_return( spacket->opcode, + spacket->operandMSB, spacket->operandLSB, &rv[1]); + rlen++; + break; + default: //nes opcode min/max definition error + rv[0] = ERR_BAD_NES_OP_MINMAX; + } + break; //end of NES + default: //request (aka dictionary) is unknown rv[0] = ERR_UNKN_DICTIONARY; diff --git a/firmware/source/usb.h b/firmware/source/usb.h index 604dd81..d36b099 100644 --- a/firmware/source/usb.h +++ b/firmware/source/usb.h @@ -6,6 +6,10 @@ #include "usbdrv.h" #include "logic.h" #include "shared_dictionaries.h" +#include "shared_errors.h" +#include "pinport.h" +#include "io.h" +#include "nes.h" #endif diff --git a/host/inlretro.exe b/host/inlretro.exe index 39f75199ede1e74e59a0fd2abbbcaea9f83ac44b..a0357e802a113a856fb406fa04a1939505a7b413 100644 GIT binary patch delta 28262 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 cb?s+=ansQ7b%7 delta 15155 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 diff --git a/host/source/dictionary.c b/host/source/dictionary.c new file mode 100644 index 0000000..9f1be19 --- /dev/null +++ b/host/source/dictionary.c @@ -0,0 +1,114 @@ +#include "dictionary.h" + +/* Make dictionary calls simpler + * provide USBtransfer pointer with handle set to retro programmer + * provide dictionary as defined in shared_dictionaries.h (request) + * provide opcode from the dictionary (wValueLSB) + * provide 16bit addr used for usb transfer index (optional, can also send 8bits applied to wIndexLSB) + * provide miscdata optional to be used for wValueMSB + * + * makes call to usb_transfer after determining: + * endpoint direction + * data length + * + * debug print of call and return values + */ + +int dictionary_call( USBtransfer *transfer, uint8_t dictionary, uint8_t opcode, uint16_t addr, uint8_t miscdata) +{ + transfer->request = dictionary; + transfer->wValueMSB = miscdata; + transfer->wValueLSB = opcode; + transfer->wIndexMSB = (addr>>8); + transfer->wIndexLSB = addr; + + //default IN for now reading back error codes from short commands + transfer->endpoint = USB_IN; + //default length of zero + transfer->wLength = 0; + + //return data buffer big enough for one data packet + uint8_t rbuf[8]; + rbuf[0] = 0xA5; + rbuf[1] = 0xC3; + rbuf[2] = 0xA5; + rbuf[3] = 0xC3; + rbuf[4] = 0xA5; + rbuf[5] = 0xC3; + rbuf[6] = 0xA5; + rbuf[7] = 0xC3; + transfer->data = rbuf; + + + debug("dictionary call dict:%d opcode:%d/%x addr:%x data:%x", dictionary, opcode, opcode, addr, miscdata); + switch (dictionary) { + case PINPORT: debug("dict: PINPORT"); + transfer->wLength = 1; + switch (opcode) { + case PP_OPCODE_ONLY_MIN ... PP_OPCODE_ONLY_MAX: + debug("PP_OPCODE_ONLY"); + break; + case PP_OPCODE_8BOP_MIN ... PP_OPCODE_8BOP_MAX: + debug("PP_OPCODE_8BOP"); + break; + case PP_OPCODE_16BOP_MIN ... PP_OPCODE_16BOP_MAX: + debug("PP_OPCODE_16BOP"); + break; + case PP_OPCODE_24BOP_MIN ... PP_OPCODE_24BOP_MAX: + debug("PP_OPCODE_24BOP"); + break; + case PP_OPCODE_8BRV_MIN ... PP_OPCODE_8BRV_MAX: + debug("PP_OPCODE_8BRV"); + transfer->wLength = 2; + break; + default: //pinport opcode min/max definition error + sentinel("bad PP opcode min/max err:%d",ERR_BAD_PP_OP_MINMAX); + } + break; //end of PINPORT + + case IO: debug("dict: IO"); + transfer->wLength = 1; + switch (opcode) { + case IO_OPCODE_ONLY_MIN ... IO_OPCODE_ONLY_MAX: + debug("IO_OPCODE_ONLY"); + break; + default: //io opcode min/max definition error + sentinel("bad IO opcode min/max err:%d",ERR_BAD_IO_OP_MINMAX); + } + break; //end of IO + + case NES: debug("dict: NES"); + transfer->wLength = 1; + switch (opcode) { + case NES_OPCODE_24BOP_MIN ... NES_OPCODE_24BOP_MAX: + debug("NES_OPCODE_24BOP"); + break; + case NES_OPCODE_16BOP_8BRV_MIN ... NES_OPCODE_16BOP_8BRV_MAX: + debug("NES_OPCODE_16BOP_8BRV"); + transfer->wLength = 2; + break; + default: //nes opcode min/max definition error + sentinel("bad NES opcode min/max err:%d",ERR_BAD_NES_OP_MINMAX); + } + break; //end of NES + + default: + //request (aka dictionary) is unknown + sentinel("unknown DICT err:%d",ERR_UNKN_DICTIONARY); + } + + + int xfr_cnt; + + xfr_cnt = usb_transfer( transfer ); + debug("xf: %d er: %d rv: %x, %x, %x, %x, %x, %x, %x",xfr_cnt, rbuf[0], rbuf[1], rbuf[2], rbuf[3], rbuf[4], rbuf[5], rbuf[6], rbuf[7]); + check(rbuf[0] == SUCCESS, "retro programmer had error: %d, dict:%d, opcode:%d/%x, addr:%x, data:%x",rbuf[0], dictionary, opcode, opcode, addr, miscdata) + //send command + + return 0; + +error: + printf("dictionary call went to error\n"); + return -1; + +} diff --git a/host/source/dictionary.h b/host/source/dictionary.h new file mode 100644 index 0000000..d7c6f2d --- /dev/null +++ b/host/source/dictionary.h @@ -0,0 +1,29 @@ +#ifndef _dictionary_h +#define _dictionary_h + +#include +#include +#include +#include +#include +#include + +//include prior to other file includes +//that way DEBUG can be turned on/off for this file alone +//uncomment to DEBUG this file alone +#define DEBUG +//"make debug" to get DEBUG msgs on entire program +#include "dbg.h" + +#include "usb_operations.h" +#include "shared_errors.h" +#include "shared_dictionaries.h" + +//uncomment to DEBUG this file alone +#define DEBUG +//"make debug" to get DEBUG msgs on entire program +#include "dbg.h" + +int dictionary_call( USBtransfer *transfer, uint8_t dictionary, uint8_t opcode, uint16_t addr, uint8_t miscdata); + +#endif diff --git a/host/source/erase.c b/host/source/erase.c index cc3c3d4..f3cef7a 100644 --- a/host/source/erase.c +++ b/host/source/erase.c @@ -5,52 +5,14 @@ int erase_nes( USBtransfer *transfer ) debug("erasing"); - int xfr_cnt; - uint8_t rbuf[2]; - rbuf[0] = 0; - rbuf[1] = 0; - int i; - - transfer->endpoint = USB_IN; - transfer->request = PINPORT; - transfer->data = rbuf; - - uint8_t c[20]; - uint8_t o[20]; - - c[0] = LED_ON; - c[1] = ADDR_OP; - c[2] = DATA_IP; - c[3] = M2_OP; - c[4] = ROMSEL_OP; - c[5] = PRGRW_OP; - c[6] = CSRD_OP; - c[7] = CSWR_OP; - c[8] = AHL_OP; - c[9] = AXLOE_OP; - c[10] = AXL_CLK; - c[11] = ADDR_RD; - c[12] = ADDR_LO; - c[13] = ADDR_RD; - c[14] = LED_OFF; - c[15] = LED_OFF; - c[16] = LED_OFF; - c[17] = LED_OFF; - c[18] = LED_OFF; - c[19] = LED_OFF; - - for ( i = 0; i < 20; i++) { - transfer->wValueLSB = c[i]; - if (c[i] >= 0xc0) transfer->wLength = 2; - else transfer->wLength = 1; - xfr_cnt = usb_transfer( transfer ); - debug("xf: %d OP: %d/%x er: %d rv: %x",xfr_cnt, c[i], c[i], rbuf[0], rbuf[1]); - rbuf[0] = 0xAA; - rbuf[1] = 0; - - //send command - } - + //dict opcode addr data + dictionary_call( transfer, IO, IO_RESET, 0, 0); + dictionary_call( transfer, IO, NES_INIT, 0, 0); + dictionary_call( transfer, NES, DISCRETE_EXP0_PRGROM_WR, 0x5555, 0xAA); + dictionary_call( transfer, NES, DISCRETE_EXP0_PRGROM_WR, 0x2AAA, 0x55); + dictionary_call( transfer, NES, DISCRETE_EXP0_PRGROM_WR, 0x5555, 0x90); + dictionary_call( transfer, NES, EMULATE_NES_CPU_RD, 0x8000, 0); + dictionary_call( transfer, NES, EMULATE_NES_CPU_RD, 0x8001, 0); return 0; diff --git a/host/source/erase.h b/host/source/erase.h index 1d890b1..b140863 100644 --- a/host/source/erase.h +++ b/host/source/erase.h @@ -18,6 +18,7 @@ #include "usb_operations.h" #include "shared_errors.h" #include "shared_dictionaries.h" +#include "dictionary.h" //uncomment to DEBUG this file alone #define DEBUG diff --git a/host/source/usb_operations.c b/host/source/usb_operations.c index 186a765..b31376f 100644 --- a/host/source/usb_operations.c +++ b/host/source/usb_operations.c @@ -33,6 +33,7 @@ libusb_device_handle * open_usb_device( libusb_context *context ) //returns 0 on success LIBUSB_ERROR code on failure //int libusb_init ( libusb_context ** context) int usb_init = libusb_init(&context); + debug("Initalized libusb"); check( usb_init == LIBUSB_SUCCESS, "Failed to initialize libusb: %s", libusb_strerror(usb_init)); //void libusb_set_debug ( libusb_context * ctx, int level ) @@ -51,7 +52,9 @@ libusb_device_handle * open_usb_device( libusb_context *context ) // Returns a list of USB devices currently attached to the system. // return value is number of devices plus one as list is null terminated, or LIBUSB_ERROR if negative. // Must free device list after done with it + debug("getting device list"); ssize_t dev_count = libusb_get_device_list( context, &device_list); + debug("got device list"); check( dev_count >= 0, "libusb unable to find any devices: %s", libusb_strerror(dev_count)); ssize_t i = 0; diff --git a/shared/shared_dict_io.h b/shared/shared_dict_io.h new file mode 100644 index 0000000..fa336e2 --- /dev/null +++ b/shared/shared_dict_io.h @@ -0,0 +1,56 @@ +#ifndef _shared_dict_io_h +#define _shared_dict_io_h + +//define dictionary's reference number in the shared_dictionaries.h file +//then include this dictionary file in shared_dictionaries.h +//The dictionary number is literally used as usb transfer request field +//the opcodes and operands in this dictionary are fed directly into usb setup packet's wValue wIndex fields + + +//============================================================================================= +//============================================================================================= +// IO DICTIONARY +// +// opcodes contained in this dictionary must be implemented in firmware/source/io.c +// +//============================================================================================= +//============================================================================================= + + + + + +//============================================================================================= +// OPCODES with no operand and no return value besides SUCCESS/ERROR_CODE +//============================================================================================= +// 0x00-0xFF +// Detect this opcode/operand setup with opcode between the following defines: +#define IO_OPCODE_ONLY_MIN 0x00 +#define IO_OPCODE_ONLY_MAX 0xFF +// +//============================================================================================= +//============================================================================================= + +//pullup as many cart pins as possible +//goal to be safe state for all hardware +//doesn't currently contain any checks to report error/success from +//this is intended to be the "reset" safest condition for the kazzo +//LED is pulled up (DIM) to help indicate this io state +//EXP FF is disabled due to pull up on /OE +#define IO_RESET 0x00 + + +//NES cartridge interfacing setup +//set outputs as required +//latch address of $0000 +//disable NES cart memories +#define NES_INIT 0x01 + +//SNES cartridge interfacing setup +//set outputs as required +//latch address of $000000 +//disable cart memories +//reset high disables SRAM and puts INL carts in PRGM mode +#define SNES_INIT 0x02 + +#endif diff --git a/shared/shared_dict_nes.h b/shared/shared_dict_nes.h new file mode 100644 index 0000000..afacde1 --- /dev/null +++ b/shared/shared_dict_nes.h @@ -0,0 +1,69 @@ +#ifndef _shared_dict_nes_h +#define _shared_dict_nes_h + +//define dictionary's reference number in the shared_dictionaries.h file +//then include this dictionary file in shared_dictionaries.h +//The dictionary number is literally used as usb transfer request field +//the opcodes and operands in this dictionary are fed directly into usb setup packet's wValue wIndex fields + + +//============================================================================================= +//============================================================================================= +// NES DICTIONARY +// +// opcodes contained in this dictionary must be implemented in firmware/source/nes.c +// +//============================================================================================= +//============================================================================================= + + +// OPCODES with no operand and no return value besides SUCCESS/ERROR_CODE + + + + +//============================================================================================= +// OPCODES WITH OPERAND and no return value besides SUCCESS/ERROR_CODE +//============================================================================================= +// 0x00-0x7F +// Detect this opcode/operand setup with opcode between the following defines: +#define NES_OPCODE_24BOP_MIN 0x00 +#define NES_OPCODE_24BOP_MAX 0x7F +// +//============================================================================================= +//============================================================================================= + + + + +//Discrete board PRG-ROM only write, does not write to mapper +//This is a /WE controlled write with data latched on rising edge EXP0 +//PRG-ROM /WE <- EXP0 w/PU +//PRG-ROM /OE <- /ROMSEL +//PRG-ROM /CE <- GND +//PRG-ROM write: /WE & /CE low, /OE high +//mapper '161 CLK <- /ROMSEL +//mapper '161 /LOAD <- PRG R/W +//wValueMSB: data +//wIndex: address +#define DISCRETE_EXP0_PRGROM_WR 0x00 + + +//============================================================================================= +// OPCODES WITH OPERAND AND RETURN VALUE plus SUCCESS/ERROR_CODE +//============================================================================================= +// +// +#define NES_OPCODE_16BOP_8BRV_MIN 0x80 +#define NES_OPCODE_16BOP_8BRV_MAX 0xFF +// +//============================================================================================= +//============================================================================================= + +//read from NES CPU ADDRESS +//set /ROMSEL, M2, and PRG R/W +//read from cartridge just as NES's CPU would +//nice and slow trying to be more like the NES +#define EMULATE_NES_CPU_RD 0x80 + +#endif diff --git a/shared/shared_dict_pinport.h b/shared/shared_dict_pinport.h index 0439948..a402a91 100644 --- a/shared/shared_dict_pinport.h +++ b/shared/shared_dict_pinport.h @@ -144,10 +144,16 @@ #define EXP0_op 59 #define EXP0_lo 60 //Don't call this assuming EXP0 DDR is set to o/p #define EXP0_hi 61 //Don't call this unless you're certain pin is 5v tolerant +//SNES versions uppercase as assuming 5v tolerance without NES cart +#define SRST_IP 58 +#define SRST_OP 59 +#define SRST_LO 60 +#define SRST_HI 61 //User options pull up, force low, and float #define EXP0_LO 62 //Sets low then DDR to o/p #define EXP0_PU 63 //maybe add some NOP(); to allow time for pull up #define EXP0_FLT 64 //Set to i/p w/o pullup + #define LED_IP 65 #define LED_OP 66 diff --git a/shared/shared_dictionaries.h b/shared/shared_dictionaries.h index 148cf2f..cbf86ce 100644 --- a/shared/shared_dictionaries.h +++ b/shared/shared_dictionaries.h @@ -5,12 +5,91 @@ //these numbers literally sent in usb control transfer in request field //the included dictionaries define opcodes and operands contained in transfer wValue wIndex fields //they also define expected data buffer sizes and contents. +// +//TODO eventually the host code should have access to these libraries during run time. +//that way character strings can be interpreted by parsing the dictionary .h file +//this would also allow for dictionary expansion after compilation of host code. +//However the kazzo fw would still need rebuilt to support dictionary expansion. +//Possible to take this one step further and remove dictionaries from host compiliation. +//that way you simply point the host to a dictionary directory at runtime. +//Perhaps utilizing a database of some sort would be better than directory of text/.h files. +//but since firmware build relies on dictionary definition at build time, perhaps the simplest +//solution of using those avr build .h files slurped up by host at run time is safest and easiest. +//having host capability to convert command string to the usb dict/opcode is the first +//step in having scripting support on host side. The thought above just expands it one +//step further making the dictionaries themselves operate as run time 'scripts'. +//don't define dictionary #0 as it is common to forget to define +//============================================================================================= +//============================================================================================= #define PINPORT 1 #include "shared_dict_pinport.h" //pinport dictionary has various commands giving low and mid level access to retro prog's i/o pins. //It also contains internal avr registers associated with the avr's io. //Access to other internal avr registers should be placed in other associated dictionaries. +//The opcodes in this dictionary should not have any cyclic effect such as pulsing /ROMSEL +//low to read data and then disabling taking /ROMSEL high again. These commands are intended +//to appear as a single change/edge to cartridge hardware. Only potential exception to this +//is AHL/AXL clocking which is used to latch values to FF's, that effectively is only one +//state change for the cartridge hardware. +// +// Many of the opcodes in the second half of this dictionary have the following rules: +// +// The opcodes that follow operate under some rules that you must adhere to if calling +// 1) Data bus should be free and clear when possible +// -DATA_IP() is default state +// -Be cognizant if you're driving the data bus +// many of these opcodes use the data bus to function. +// -Many of these opcodes will end up driving the data bus +// know when that'll happen and free bus when data retreived +// +// -Flipflops must be initialized +// this primarily means CLK pin must be OP and LO ready for CLK command +// -output of FF must be enabled to actually feed latched value on cart +// final pcb version will enable EXP FF after clocking. +// early pcb versions have FF /OE on separate pin not so automatic. +// +// -control pins must be initialized +// -enable OP on pins necessary to perform desire of command +// ie M2 and /ROMSEL must be OP if you're trying to change them with a command. +// +// -be cognizant of what pins are inputs and which are outputs +// ie driving PPU /A13 will be fed back to CIRAM /CE so it needs to be IP +// -if in doubt, leave it as input with pull up, atleast that shouldn't break anything +// +// -ADDR_OP is default state, these opcodes assume it to be set as it shouldn't conflict +// -/ROMSEL & M2 expected to be set as outputs +// +// +//============================================================================================= +//============================================================================================= + + +//============================================================================================= +//============================================================================================= +#define IO 2 +#include "shared_dict_io.h" +//io dictionary contains commands +//Scope of functions contained is intended to be general and generic not specific +//to the cartridge inserted. The closest these operations get to being cart/system +//specific is in setup for a system. Calling the cart/system setup contained here +//prepares kazzo for system specific commands. Once complete with system specifc +//commands come back here to 'deinitialize' access to that cartridge. +//commands in this dictionary are meant to estabilish baseline rules of i/o to +//support calling higher level system/cart specific functions. +//============================================================================================= +//============================================================================================= + + +//============================================================================================= +//============================================================================================= +#define NES 3 +#include "shared_dict_nes.h" +//nes dictionary contains commands +//These commands rely on io initialization from io dictionary prior to calling +//This library is intended to contain all NES related opcodes/commands +//============================================================================================= +//============================================================================================= #endif diff --git a/shared/shared_errors.h b/shared/shared_errors.h index b38073b..5fa816f 100644 --- a/shared/shared_errors.h +++ b/shared/shared_errors.h @@ -6,13 +6,19 @@ //greater than 128 are possible avr return codes #define ERR_UNKN_DICTIONARY 128 #define ERR_BAD_PP_OP_MINMAX 129 +#define ERR_BAD_IO_OP_MINMAX 130 +#define ERR_BAD_NES_OP_MINMAX 131 -#define ERR_UNKN_PP_OPCODE_ONLY 139 -#define ERR_UNKN_PP_OPCODE_8BOP 130 -#define ERR_UNKN_PP_OPCODE_16BOP 131 -#define ERR_UNKN_PP_OPCODE_24BOP 132 -#define ERR_UNKN_PP_OPCODE_8BRV 133 +#define ERR_UNKN_PP_OPCODE_ONLY 140 +#define ERR_UNKN_PP_OPCODE_8BOP 141 +#define ERR_UNKN_PP_OPCODE_16BOP 142 +#define ERR_UNKN_PP_OPCODE_24BOP 143 +#define ERR_UNKN_PP_OPCODE_8BRV 144 +#define ERR_UNKN_IO_OPCODE_ONLY 150 + +#define ERR_UNKN_NES_OPCODE_24BOP 160 +#define ERR_UNKN_NES_OPCODE_16BOP_8BRV 161 #endif