From dfeaf960effd12de952b23c2ec9d667816b196c7 Mon Sep 17 00:00:00 2001 From: Paul Molloy Date: Sun, 20 Aug 2017 16:38:12 -0500 Subject: [PATCH] commiting files as they were left a couple weeks ago.. Not 100% sure what all happened with this update.. :/ Tested and have all 3 recent kazzos flashing and dumping PRG-ROM and CHR-ROM on NROM NES board. Pretty sure I tested purple and green kazzos too as I had left those on in pinport and seem to recall having them all working when I tweeted 2 weeks ago.. Created new status_wait for buffers so can wait for them to finish dumping/flashing before starting/ending operations. That cleaned up dump/flash code a fair amount. On first tests today I had issues where setting flash operation would hang and fail with both stm kazzos. As I started to debug the issue it disappeared, so IDK what that was all about.. I think there might be an issue with my stm32 usb drivers.. Those were updated in this commit to properly allow write "OUT" packets to be supported. Planning to start tinkering with SNES in prep for the no save boards arriving tomorrow! --- firmware/build_avr/avr_kazzo.elf | Bin 12256 -> 19624 bytes firmware/build_avr/avr_kazzo.hex | 459 ++++++++++++++++++----- firmware/build_stm/inlretro_stm.bin | Bin 1368 -> 7736 bytes firmware/build_stm/inlretro_stm.elf | Bin 78532 -> 110928 bytes firmware/build_stm/inlretro_stm.hex | 546 ++++++++++++++++++++++++---- firmware/build_stm/inlretro_stm.map | 312 +++++++++++----- firmware/source/buffer.c | 10 + firmware/source/flash.c | 55 ++- firmware/source_stm_only/usbstm.c | 10 + host/scripts/app/buffers.lua | 27 ++ host/scripts/app/dict.lua | 6 +- host/scripts/app/dump.lua | 96 +++-- host/scripts/app/flash.lua | 145 +++++++- host/source/usb_operations.c | 10 +- 14 files changed, 1380 insertions(+), 296 deletions(-) diff --git a/firmware/build_avr/avr_kazzo.elf b/firmware/build_avr/avr_kazzo.elf index 0d8da1626453eeab60e59a78ad8b8d310253abc5..87471ad809c322f1414f826e4b61503757711eb9 100644 GIT binary patch literal 19624 zcmd6P3wTu3x%S?fBs0S$7YG7^5QrL}kj#W|7swq0frMP-Vs*%65=KH2CKE2LNB7K- zgkXS~OadWR(ML~9J?+tGepsmFgvhf^ktH;(I1q}i+kw8Gf{O`B->}0XEeg5bC zkA1r1+H1Y<_pPc)oGhN_IrR$R3OE%dgUnmWabbv)xmZre&EO)rQL?;M z&49RUf)YqC1cCBj1IO`#EDJ|c4J4!RHRR!tQ=scvWF#GujcVPF&_7~Ss}J!%HyA_4 zaBzoEW(*~>aE;-k_(6^{_;33lj0@pIIDU#Qn_I)>aIsuIXXPB6ovY^NaCvfE!OeoS ziYw=AxZ5DLLf6XGLf^)1ms1H`DROM(LUqQ_=sTyrDqea=`rB)#UW=BVk~*a`pIqw+ z@rQXvxBS@Dsef-EPWmxe-hW5SbBkZp_Y6d|8b*z3H6d_Zq;INE^nK{Nz<H^+!U8r!yDa~ni z3hrB(eNN{P)9Bo9X>_09KlF;;soqGhp-osC-9NeIq)3(tJrS)x41bfc#2Fp#55PuA zw(*#_XOV57S3G;RPdaeP>GMiw=U<0^1mC^9;EP9Cfp9m%LWFS$3lL&>r!)%Xl9z7q zdD0(vSEToj)I(>kOpoj7b2|?#fA5M5_qVUS&;Q59S934&f^^t>Wckxq4p?T4{ZcG( zk9D;twzM6N^gQCtJLn$oifV{Dy#bf$rvbOAGf;nik2}kM=A%BzJI~m^-GA>D z?_6Vlwtr{;;kd3o&)lBA-RD0S&wkt|T@pX)>60#qXV3IW=R_a0vi!Y$o_V_lCb$}; zCU=8#uiNc>%-!g0b_@0U+%D&ScVqnl_jtc&p&?-Ldlnc1MSjoxU47p9Z}qjzJA8G5 z%Y}Rb@;Q-D=Z|QOq48rGH#UAK zPH;IuJOlA+BdT^37B8~Ue7^~o*z?7nHz?xYrdQ-A##uN2`gHQ9oa zo`52G4{`n67X7ZvhPE=(xdA1gEhsGxN;e>OnOpR>f&USAf8<3y^&ivS)kAk>jfiM< zhP##;1KZGR8$twMI8SwYd~uj1)6ou+KHY!XixnAbfd^~Bap}}}LqEnrP$#zc1|R1Z zF48=e^_Qpi3zrC~eKgiZ{E0+iX-~ge3i3E(7e3v;2_;9g)`X~~-QdT&-f%~>rs&k% zd*ZhBxxqNYCnO5X-|F|nj?=K?G3TB|UO9iari8JsNp9k%hwh1cJMfrWSy>Eiigm_7 ztJoxNO{7{y%VBZPMYlV)UT}Jyv<6V`z9sIy^q6}_{T}CGnLF&>qVFPJw3oMvypeL?51H%kM`T&5Ll)8@!a3C@+yX6F;mh}O@-^nMmk4?o~OCvGag zC_dV9pyf!*^DVEnh%FzsTxuC?QP=K=_znE~{P=?>y{Dy568dI;J^S-J|HR*hxpdnh zkJLQ=3H_daNPSA3v~CW1E_pumh@RIx&wGw|4tO5*7}_5Ctp04<*(;rGutGUHFYI?s9|uTS0N{4GzK5v}hUf6HG(YG*<)9&<&UcJNpK9J_ml z?3RY?mbw4E-Q?Y$@i+KQPG`N-{B$4|eVEGhpR)gK+8l8yMvD79SrVj()`xVL#Ze!R zlVZ=#lkuCn^WyT3746tT-6CIkvlN+_8w(_VAcvhPL(Xc^w?r)Jf$CH>dj%cWmg)?&P>d2pl(4zH{8+ zV65uq-Hh<3Aeazh5j+S2h0n3;UP8dS;6!jEG$8CnIDnvz%Bd}#{*k?TYELIjvoJ9cUfe6LU;0&(KCY;RW8+b>PzOu6Mf>?Uar`-%M?%*3#wfOo8vI zenT70BetH0dGeD|+m&N#ZE5XFeJLFSHlK9_=T+Y0)Eb=2LnKJ>K)B z=q0n1-*^9)cAsveCD zu84*<8lUePo1CBggZefl8TvPER%%toS4Ob5+x~8C8ULWJPvz6wSNsP!yUq4akDD2Y zP2Lr7T@>5~f0XMfZwUW_SI1xAn{gf&gD0gZoOqmWRo3ivxxc`PfR*Dq}^<6DpiiUxAbso9o?ech`+eI=LB-F?6@rJ}G zDa;%lW(Yj~`ZfMy;q}~6t+Pgb7Jec;PXDm}O?{MMqv3{uH-;OH#?i(o;{@Xr<8;}T=4G0VIbc^`fKOa4;6lK0c_i{X9YtBhB|uZQ0Z=k;NFqkgnLT0c%dQNPN_ z{!P`>YAHy{dP}ROAYB(}jXqz0 zpMInML4Aq7T>p^1N^b|t{_P~I+Xd-a5f&qUiY!L_BeEEAJ6Vjll`KZ=A&U_=Q|*ZN zkj031lf{SyvKaBhWHI8MWN|z82c+%6JXJx9#p7S{=hrC~KdygL|Fk~W_^kdX`segN z*T0~DN&m9GOaE*AYhc;GH}nhPi5zhe?%CpE+_S`ca8DPP;+`Td!+j}sGeKG`=Hb3T zT#I|MSb)1(EW$lOybt&9iR(I+AdZ){?hM-02%CBe6r0ZKd-dn_YmJ}l`}F<#0sWWy zn|jWmGlUzAhP6iaZ?u7Y7$TAf2fN9CH@eAt*SpDgSG&n`m%GVtfo}5J#cuN1XWitn zPrJ!qXS&H-J>3@BQ-77U-tSg=b~$YN^uYnSXA=!chIxhp<3hs{!!kpvA;Yl3u+p&F zkY^|W%l@r1&}cl?P2=$Ybkit&v75%=^W8K8f7VUo@2A}~`hMI^WAB-68hKB3)3|%0 zn?_wnH;uVN-Ik7Y#6DTe)9sR)eTrR&{pi09id{c6>^AH(TsIsv95Ea zSw#%?jp1Br#5h=H5ivVi#?;-UsXZRdt+h`9v*(uD$AP)Eu2IC?QkRaHTk87ql(w$E zQci_yd;&pOKGh8NoM6^jvj7C;0a38k~4ub-GQd*k7HdCOnJ2 z9T0lQ`RlB1AmzlT$)Q#9A2c!S@Dr`<34kFXEdxDzcO<9&v5THECH=t}b{ZhHNKcc1R0bXqzw>22f5`##7O zyv@3ONydQa-;Ag4NB!;#f=|%xJuCRa;HPN3rxLdB3efXgk?{bYnall0oZe`g|4C>2 zctgPIZ%Qon&vHh!H0ch5AK{N`*{hq`J6Cc^CU`d%-u+Z;GtKOe^?7B!Up#0!eC2Vc z7th!Gdp$#a;Og<5@%WDv}l8W&*#H>yQTBuG*fE-{`14! z-j903>89&fh0lh${XKsc+f5q+hf!Lr&!;<%lTL@p*#8^&4`cJXldFbYT zr>B={7JQ*-u}3F(!}#5Ui{YtIyesJJJCWFgcMm6|X81c4&)tHqy|*czymS)Jvx0ZO z&f`T(z0v&LgUkI-_r4_E;AbZ$dzbpm2dCw|H^3iEyfizKo@Uj)u1s|H`tU3h7;(~a z(ljwZqcW8D!{fVq4tKV0Gxs}@FRI0>i)wjHr<|e%l;1e`yhuIqbM(Zt{{21FM?V(# z;633pVpK~g|CHF%ds+GbwJ-IWebe%K29As8J_$&I)3r%(_u^E1G_flYJE4>+<$boP z%_JH9bG)wjLv4+1QGwm@ZSkfDPh76H9L0N#&pzDed%{PfM|_25&>L+zkDnXJd3>Zl z=W!!~9w7`thrs)r{M9}`M%G{BX-p;htY=A*=&kmCBA;P%eX&wXkHu%~4BZy`Rs8kk zzC3A(w8$T`Eu}1R2cKxMO!22|p4b_)EpbPF-c)}|nXxl*N9eY<`z#jDALmagnFt)S z%`4-({Gr>T;@9Sl>3_h&anX74ZL^n8>^yNbW*Z;R%jm?_wD@efwy5~rT1DgN)vUIx zHmYM+K-Fu%x@F_0%jP^|=L=Ukf3!6DS6uvf|B^g&+Z&Tkrw}$cb@yBkj7&Zki1j|E zo9K*=95eQ!Xq>;cZ*)?0fM2#~fb+HJmU}JUT={(|wfW>r{+ksd^_%#b=$+6O>uu3Z zkF#Bl!YquATXZGaw7AdY^I&!~>!RSbC6alP$+u58+0Q|PH~pf2#90$YVe-uwKZic{ z_x`su)*luhC2=_Yj_kT!PEVhDhd)Z1=3jX>#GiCAJ@L0ar==w6_Rg5%?{|#syuGWi zC$`u6aqM7N{K&5Ow()I~mj|wvw;dbk9ALTAS4lP=S{yfd`N*ypuFmu>ZksqT@{uU7 zR~H@m=GxOKBfFvlQNG7?vVV$i@0|2VO5&8uF!hwC&QlLCJimZ-Cl$LHs;& zaB7&R-z&{Awq9!;6s>%PZgAs@^z_BCGghoAni)Gk!JJ@@O){D1o8~7i;OOoD90dA3 zBK5v}+;OEK5TX7wfZr?(L5eGOY_(Pto98DNgCR8o_q)p2r6Ht0xz=7SCtgWd8Y?HN z8yzF$#NZE&wQ}OwI!mgY7&pn7ASdo{l{@4Fl{Xn7ggc3!NR-MqO;A%LRpqsMl`VvP zlpu)Uc z0+_qcvP>tK_zNuaBA6Lpu*@&O%%o90G!k9{GwW-Xc^S<2bn^HOjux_TwvlBvfteG< zGHbykjANN1Fo}~`rVxy28q2H$W1hh>HZVyEEVC5M++>!y2TbxJmZ=3ZFNI~cf|?~z$`3cnI&Kr-OngsY;xl)nRM+DqvhhJ=Jf_P>hK z(u9htx`b+bMIzF3=Fcgy7gv>TPOP+*04J7KSC!i;5{tLni7}VgRh8Bz6mW@~tG8Mc zE39(1s=CCII$LE~umI@J*=nn**fBRr&Idd%SR98_NNj3BY*Iqf{DgUCd^@3->5|RF zZvY%^>0~NvBhvpGW*(HyOvE_522<(u@GoiRbF!Hq!8|f?%DzHxs%gH zj2yXaB**E7lc7AHJr>8TXe7C1z-enOb6&miV5Qn5`w|Xo&d-YZ> zH6y(sKaESpoy*A1$TxFE8Tlrz2-uXWL}^Nt&K0HQLzI`BUzo~eWaOuEdD&}l15P8H zMi@8Xbi(O`aRbgEoIyB)%T3QWrOEeHt}uN~p$T`Hk|S{0s|!|v%+5k(D~MF6B$>h; zOcG^9lqQ#uM5Q53_f#&m08LTyt;;B+cIBpL9Wyg zG8YoMr*SCN%w=Y#!l+Cbo0*AP3i7D5f;{vD?r;%TxGr@yys<8gZseDBXhq>VWPl`} zdJf%(mZ4ZVQhE**QqP&Wg8a-CDCrhg2PKS_zqN`%%^ z&;PxP7i5W!7CGk9VX31_{k~m?ujkoI$Az*GQd)b5FP;1~Jd5#am$`KEo9AId#~FtK zQaTO~1I(r4M&4p!DAzYg8q0=s`UYv;Udmv4=e(T3cMYW}(Kl$ueYn+qgH#r^mpC34 z#prT6Uy1}pE@ zzq|U6plBoNQ+`9zaX(S2lJDO|d+8lNev2NOpT7piug*ctb8l+ur?>L&k5kDI?sFth zF!(0$Nd}L^#Qzh6#{>V3!EwL=2G0h*%HVmxQA0mUg>d%(Pai*Ae2OPo3=`HMD1}_2L&)}879tLj! zZfEdjU^|2Dz%MfRVcI^(8s~|7 zfkQA~shVia+I--10Ih9fbtjz6rn*f@BVX899}|68NE^ z`uYYpGIH{t6}TLYtqSI^0)9E@AIiT2m~BrJ@N?)KT34yQ4q(>ae+Ryk@%MiK?}Wc* z1odAAZpPxT+WQ)CGW4lSsej%DzJc~61of%yZ21>}hyB+#_%*QdE2-ko5%BYK=s&um zP+kl$n?Dvzx7lfMpFwTJxs zutvTISYrHpNF#qngP+&nUjkEqsPp4pV0vt%@f{Ts!kqzr4DDC_`33MiUXbPF-)q41 zX#!nQa6}l|(#+_~ui-IX(PX*3Qy|Yn9#haCbAZ*0#>WC+*1ze%>iItkR;&U36Z(68 zu)KA^uOdAQfyVnb;C)Q}ZeaBy|Fr^tfywU=*8eOpTi^4fk1;?O&A&eatKWf;Ki&sc z`-AN51-=Gd+G0pP0G!GA=O*y5{W|V6%8tVP$$&ofzfpf{{V~89a8_kdJ`=czDQ^+* zRmkz5oPPyy801R-@LV3Sdd0&2`++NT`0N2B^;ab@+uj`->;h)n{|xXf6y6V-?0pf~ ziu#b0%XS%kf$(M-(;*s^lpu=Sd5n^A#Y*o{~0j;HSv)DUIjji`5gg$ zviD8kDKJhQ|9=L43bH8(H2(X5@zPNKYKZhhP#+pZH+eiyV(O>yIt|#z)Sm>*wr80J zuLN#|K8<%8PX)k*u;)o&s;?Ay7W}&=h^sXDe*jGWrHkfsqekun#ug@DH2_6)M_9gH}tiO5CC;PaPy7F?XJ)snDunO`l_u~6SIgz6z z@Pb25IJVYU?A8i7{R6ALItZ%jwpyrw1oNT=NnBao)*2L4URhkb8L_Pzx2?stDnwP* zTHLE^toCAut(uq`TUAZ9-GNkTojrAZPH|b8T~6MsBYB_dhkaKNr|oiBiBqA?!JswO z>#OZSNxrqXY!|nq*yhNpwy#tZtGM#&x~j5OTy1rErri$h&BfcTg*&R#Y>wJhoPB4B z&0*&1s%jnZ%zUoQR#v2@gX98+T%c-ZZbw6EttLj6smgN8${0Eqbquwkc8jeh$68!N zT(BY4+pYHU%IY1Qt)i;hZp|w$-C}icwGN~UtG8IIQme}Ht&Tc-6%4N`tF&emJBowJ zY?Uj3LQSqcx6Z+pRR^_etyN`finl1)ZLqbfEVc9&m|o>jrEq-#Dadu%IQT^N#~Nx! z0eNQ45GVUc=H?G^vWsMHfn3r0xoSy{;kF|gY%+Nv6(cCMwib;hH)dEXi+6F=Wo6cq zx(W;&i*={XfgxeBz!5bTysNFS7jNY(rIprVyQQSI7P5r0>R}AMV!K1bRR)JmhPAfT zZmWSyGpyTfrB-=pTWnS3RKa#@DFl|JByNY@=CE37iYu&^(#>{8v{0URbB7r-XWdz2 zveeX7R@T*69M)RATdplB+?iHaPP0OuWi*Q{H8pjX9aL0CYGJAc^D{eljU^{@&5A;0 z?mEz_n(9g$=_)M<&NNGDab+dk;IQtL%N}k*fy0jPM@+-U;8)QKtHV+SO{LL8E3 z;rw%DUzvwmZ!aSo?ABTgYFkxlHGTYIDZ!ks1xf3TQXl*T%^}N^$l1ddDy{*8o~jMn zi$QR!<#Wj=Il1YpzQxaKC(k3x^Qz(6q1DX-M)A>b{|_5tHY07TvXRGvg_!3C7aa5a z)S8-GoM&FZs4W^!W7()J8ScV#`MaSyWp#xXJCGGk8l^NtWM?KpMftr#ZZL|<-zhH* za=#BXgsZE8$E@-gu-a>fY9CHn@L6-vtz zyW}w-S3#XiU9Jv=U}q!`4K#V)+RH4MPL-U!cn1c2)fQ5B)YW2%aab5f(OjjS$YR-y z#aQ+#N#!L0S?qPCOhcJ|q@E}$$jtu-?NWAVtRlN;ZYhSyn>OYVwjjrjV!PFndT)*e zzd2A}V}HzZu!{{1ICZ4W<7m&uN>E+;jc&ChEmAgbWzx%|LTQsSOH@ZGepQAkxY8|L zsST@+rPyq;Y_-vjh#5(itg-G;mPdKu$sUvq$0|fKaoDVd!^tG<2I#>d6VmJKc59Ub zqf=f7QL3`UkXNXVY??{KMF-af2!dWL|tIZ}-%$JvI*}22hW@t5%S8X*fErIfCq&igm;6;JRORzB&eZh(i^8ME(50OEIc^#lN~^L~q}6vGq)g8`bj2g! z@j)(+o_Xm1FGcSU)k`gJHV8_af&$W`=Rfr#8HITWdX+>x0S}=m3=Te)$M zy&OhQm8}P-rb&DhdIBYa7uil%1p=!#1IBHZpBrTHkgQgt=ZV9+1l385%*mvwgf)2C z;QkiB?9=GI4M(m27QJZbsn0l6-YeO7CrpXprP@w0lbxHLi1y;e3_S}rB9Q+8lVus5r; zeCUbQAJuVK z>q)(IZ=8A9>@j)Z8y#<#ol5P$XZQChBmFlajCsvrog{|%Osv*3c}?ZoAwA&LRo-Ww zH_sJZNc;VZSC)JAbpCo-+Mp3wr=<;g0=sT{g^lkS@Cwe=4u$XbdADvG{FvMQoougY z$tqYdl6U)b$MAsKF^W$zOU<38CNj8FIQU*nU6q9qdr>gu<gzo#*)+=^2@~jI_sB1V@!Q z2KlV%_n64$<+@8>u76Wc*Qe?YdS7o~XstonjNce~Zl_bv=7mLd|5UN`j-u&zr)e{S zn#jaLrE?XV;3>1TK*OdQ6JYS*+Ud~n0S(hMZ73_iP}y(I3ua~@S)}G}RI|7v{lgXK zXODQ-F{lbV7rS%IrgZVD176ctIVV)r)#P8%werC6PP@OGeQ6x;yz{rPS-L-Xj|CXJ zZQS>V4e@2}DseO~OSzaVewjB`+|SDqxATVg=H}l_Nx6tqb2(Y`jN3nKCk{XoKfpv~ z;hXBd2rR`}u|vjkc<8md3{S-~9y1u8DcQd!zUTi=@XY^C@QC=H zVE9oZSd0Yp1)@=LeBZuD2_G_N)x@zzBix4m8k?n2SPQz95_f^CEcW1|cMOUbEd}@# z_$7(o2RBLl5%@KU&x5-p{sjD15+0GJFcbftlI*v@vtxD-eRV@nd@MN(fpeq)X&Cya zl05_bEy+F>d`+^KfNLfD6!1)mXMjJC`XfIIm=8sz@lx;6{iOoxB?k&XXZ*^;fWdH^WGDY_@GJ;5@;{8eT+nGS9YrdD z2J}0yT)=s-M^;>hB0hp(_%`@vBz!c%1Mpc3)}Q`#s!*zm z!p^|KjuAo?S@W}C#(eaEPZGNTPM7SLBld_Hc7oARP5@htW`Mp4a=`gyk0qrkt_E8(Mg=s0@53brLIZjY952Ae_JF$}vtg$t@azT1 z2@Zfcw`PE|BVemJk?=%<|GNo%mi(mx2fz;QMXKnG-ubG(hkfx?1xv-9MlL85j0@_+ zB^d*jM_iJ?kAuUp0;u3w;4JC=<>2^?;QZZ(b9`4PvFG6+7f_wRKL^v*ikcHsydIn_ zCD;zuuu1K((-iLlA3}dDgx35GFy@#ZO!c6`Gf-FoY0cgP=STtn0G127l)wYv(eS4= zrw`Tb1p5OpU0A5mCQMC@$6G|3EE9^@se(f=Tmr@<(Idihq!-A4DVYAI(=5{n+4}0b zdeK|{MDmtRYo^rnJ~#WYGSTJQ>aN+`(C8{FWAXlz@qQ_TcU99fTV4`1b0>+P&V6je zL%-58F#uiuyeCBKyq87x{Fc!!m)pIev0=T-U0+LYKG#&$@UpvJT%2DhY|lO|DxaND zLHRbhHf^qM+>AW64X&Do4clC`)tjq_6w&#A2y&V|k_=;m%|Y;@OeMoAQHQGK28EgU0GEL=J@_}WPY;{tfJcH@DAJU$PH7mv|V5?82gV<2F zIV*~}#f`fX99wcl{*vP4Li{&Co0z|(X!ce7N-&2rHVTd}Kxm`TCpHaYZ8UV**>B_K L8`*3`@dWq;<%+{1kqWY`nef9jw6h5oR39!caow`KTs>Q&FKEnj61VM+mb!^B`rmq z+5K;u-+lMobI!f@+;iUfxUXOa+ZzD732f9H(81sNBRrF20{?$EiUM7xTkp|}omS2J z%<_M&kFFg%t8?o-U|Vmc-)C+Nt{p#1B|aPjSXQXYZbSLi_8bkiOYw*+(fvEm-j_^4 zsx3bZrPKhG_~N1|_-l`qS2&YEb(j>Y(;8H`e9FY1@=!4<@yf-M?o+F?q*K*YRhG9j zaKF6(4hX+=zqV$k{Be*{z*eq!i>i2&{E8<>e$Yw9AmN-ya@{p=g*o|U(JL2t={6}q zEz2mT`l!Ubi&Wy%i5XziW@gOQ4Pn#io(XgX4{$lf^LiC-0I0+V6S*)C5^$E+t;CIZ^*iyf+3cU^?JI|fg>ZJ}r?|n-$32%FW zdnX=Zd$cC$L3b8!@+w?R+6Y;~8KnF^P5H+u%0Qa(%QPi0McGKD<~*OK?3khqq$$Va z6!#tXm3u#y=JroM^f0l zE3g;RSmPDgb0ZNKYy$q^Y=92*l}+e3)n4G6uy4olJ=hE(EB5Oeq3kEcD^GDeE!itqaQF7IzPETQoHxbMi!xVRyXL7~Qho@FV{~`2`hZ%0u6#X31sc91Q4=dd5 zo&jcZe$Ui=;v;1K>B|`O4T6av#xQM-UrccjZy+2mB4+w7PY)A)wVfmSx(oGH04x-v z#+JYhumS{dLoM76A$l{m)UR2EwxSp4*a2-v6L1d=qt(*z{RrFA@b?ks)9?<2l{EbA zVTvsj$xI2Q>CqlWsCk%XEh_E~B6xC51l^U(WIZS%a z3YF56rd&U5wTj`t=OaW9*{U7}zx-Qzn2mavO{ad%Dm0}BjQkYtrRo9Uv7xjc5dJH| zsvZ#j3}ICd2!A|8u^)&X2n`LXdO+yIA)4(|as9}t>H)Fu3@Pk8L=Oo62f}GR;OO`2 zNYw+5A~;9Y1H!*lDXJcD^s{NJJwHTq%`!Rf!-K@`cYK*;%I8X}ZWKK08=LlQ+k<~Q z_UySYW#N3kiEmbbYr_@D=_befaBQ14-i>2&%1L@Fj>$R?h&P%IM$o1k#x+ChZba*=gpG>}i?8Zck&Aqty6T&$rTe;F637U3GFc4yc+(IV+F z)6i_l-qCcNJ+0MAJv5EgfkoQjArvy}H)A38IC_3e8lZ`c)t(wLhOz97O6^7}sUND< z?0Adk)@d?6ot~Mk&NO*%@T{07ar+pFde#1$#K%CxM{Ej|^BO_)m5a;V^?swC;*+)v zewJ{DuTWZyXR8n_-UdI#>xD)i+SAw3WR;5DdOjuP_A!O!#2&iA&s7tSLX3VCpY4rG zHa8{2yn}3m->4y!)Vr2CIl~hFPmZofS+36f$x+wXOwr&rOGcVfcRw9gS6~@?kM@x7 z5K1s(N`msSAK*&Yj$y9FTuJhznn#meT>y1;YwG}#$uE;Hc45{W2hbz|2!F0R%cwqQ ztIwHZF9fKv8=_FgM3pj#Jv#VU5j6;jwuwK8h4NO{A4KCLR;4uHWgEg!0s{-qn|M=f zYaqihGqyFDt*1*M_Wn5yK0iG7TMvc(AJ1tHZ*{#Pw&6Td0Y^lW5W%WA!gW#`c&ei_ zY*HXWPuR~x;?9YwT%u+t19#Y$EtOZ17_Z|FHz^!iQ>ECDqK?#@q~Pc|@p;V9#7>I+ zao;NcY1%H_;>`=TUWvJo@SZ}BsSA})(xi%-%Yz$f_? z`cr+xRe-BpUW0-;PGgMe%m$NlR!rMTSD1Kxtl6chFgY_~Ohukk6Vq1YI3X6RXcCXe z^9KJjz#M)d@Jx^{%a3Y%p=@@PD$9-@FUpPYF54J=uRin+6(*97H6dW=z;6}w~1MN#Qq4}z>_;djkwOe$v=}%+Gq0% zg*$x(lBf12p}@Pz|CEc-&!-o{U9Oob<#FHRO@)%P##u|OVJmtJM-aYVnCHF2U%@kv zUx)tI;M3U;`JkBUcbgA25nbT831Oe1;*f6@R`eKG5{WPWS%t0@7rU)eav_Nu3VK@) z%A^-)d!z4&?+99G;hKdtmFTS`UKssmsV!_nd)NDOUAVx*k++jsVIyu zY`8!$*csGjeVpbsd=8kwS9su-TMC1>422_MSfq(&qg5eV9fwj)%t*@Zs51@@P0Xa? zZ;B`FH{$(})VFtGt=l#ibjkzCIFwtwA|s2zRZ1N@R<1L_%ZP_Y!~8Hjy2KhGix26 z$AD$!jLIh2+Im9n51f-5TiNX$txelI0w=a_yzl(>Zw%g#Idk`*?AX}jbzB$qIaWs3 zJKn>2`9W5GQl=~O^-c15xneNM?Q?IqjjA*_#$pe89(JFR56cgF-j+#EvHRuw-EYhL z<=vtcBR(fv2D>mK^tD)bjK&Gnu%lzg=PJ~z4xrz z=E}eCXK0Nx;UmtAs#M;%*F{ynVy0I9esgkhH2Mbnmv~nI988pV%!u}&+-u{k{L`St zlP!y?PAPmZ@;t`C30a6Mm=R`PGu)*GweHg9Or1U6a+!WtRB<;2>n&d4Npm0<3w`bzHlZM?kNY=!_; zRbDp`Co<({y!I~DS&A~7c!f36CiUx2v6vrF@XZSj<$6r`R{k`q*s}zy8&AWT{(BWRBdq!C*Xn~*p}?&Gr$CX?ho zK36R7Zgc$-k~qirNR7D%(I8O)Cb5{t39(eL21F}6os6jnbGR|jTO8sl>LspLGY zQ84zAm`LgqQn!$}XuVP%tlC6>o@WnM*Acc2Sl)zHn@P-B-H7ryP@Y9Ri*;6kWI%aR zJLd8KMIC!W&1!At6VoJ^x^?Q?%#m=1 zPd@c^x**wWgJ15>uX#9ak0of24L-AInX*S2zXa`3DCO1wU4+%k9sW$Zj4z+EN1 z&cF;;C@oQ~wLq1evgb%Mg&gmprX1-2_U}k`tXr*Ey_mgUFAH5VBQ_hozujq$hMbu( zGt3y&lw`#8VwO7#u~{)4$hR^jByN#!QzU2e=pRmOtFRHj zLTBU2H!b34ucO~IAxz_r7_Tk-X znOYAk_Op^3QkbPvnA2%Y#bpd-7pVDt-fZa!A=?{M-wKOVf)%x5e_wKIO4K!rR!?G1 zYf~65jrl-2&7|sXawetdLunVa0&DL)>0vzSdsuZxy$04Sg|Hgym1z9tXq8T2oao1A zKjs>%l*`Y>5vi3Er&4#CC)B#>iaSlZep0^|lE>utLyT?sN1kKkP84E$MWe|9Y=OIkmbBo9?S$XN0TK? zEV;Y@nhTF&HTo~&Kp=_PLNouxG{nq*L42XMKwjqUaTsIxC1-(l&<@E_`z4B_mR<<| z#5sBfaKczWU{*f#|gmO$;7gQ;s?KRjNC#cR(!-Yb#^z(4v=5n-A=0wCr z`ZvaB0O?PS?{)q)MlF3l9E)R3F>Q~3KhtHu8P{OP>+CmSUpRi;egpQ_@vp9#J)T;# zF1_ZusWtoJZ*u45x#HYF0&V@f5&N1Y()mC;+Bz~aSF{1Kc7|&0H|4?BVcD>Z4KT$F zR>@CXeCX9sCn0mK|=x2(4D zCHOYg`!qiaEdbjEE&XW3br0Ur;b^Abj+M6`zX3c76?_q_;41{bPxCl_BPy@p>Bl4C zCHzc*I% F{{ZVAO)vle delta 694 zcmXw1O=uHA82vVXtQ)22Zf%lHT9V!Vn50dq{efboiz|}MG=i;%T0Ly_lHw&N$wA2U zlr1RRnqx0|)9XTumtqAEdfSLqo1mlz*@FnZiHKdl2p-<|-VDt5X5Ke1=RXS(h(YQ# z0RIQE=?A{i97t}DZE^eC`@@59viu8RB?vqKr2eB1^{IPst#P&g(U}M?1O(qW>Q`$a zRF&PEi>jHhAqVZvj%wZ@vc^mKdZ}bAm`3Lhts^(>Oj&*2ig0*2d|o_QY1$7;RZg z!O$T~=SVLDrB%;Tl~wjLG+~~&m_+Eup=yp|8>Wc9ZaQI_sIuI1CrYF$wRU&UH#9)B zk*1X_J=2@@rp3*78Pf5^<9de0OL+u8n`dk!R(inYS+sP49oM6UXpv_u6)i%DH(1)S z-T{Z_`igxR3{!5ci+(|0T@$HTl*@wFy}?nLf8RAVPTdBdoaXWW6+F-T-KY*6`~`(A B(is2% diff --git a/firmware/build_stm/inlretro_stm.elf b/firmware/build_stm/inlretro_stm.elf index 3eef63eb732624849d4d8738485d770c5070ccbd..7f3af3e5f8286b8c352a2d5fc98cce341b8aa64a 100644 GIT binary patch literal 110928 zcmeIb3t&{$xj(x0?3plm81e#>5MU+~UO^@g!aLxQAd*aY1yDdVnLJ=dAsHqC1ErE8 zYE)VyT8n4}t!*tn>PgjFUrnvGXsu1qS{^=VMW7zF)V68`&Hwk?YwwwzfW7CQ(|hm# z-n$3Ze9!f*wZ6Tc-`?4?^`fe|ilPYPV-sTqsb2`;ECFnP1e8rUN`wnwtVk27nq0_l zCsdqMM+m{>(2OX$+(yc!C-D%-IC6BUhFV{i2P_X*9lZ>e zzd%yX7tViGG3pp{;{Q)4MG?;UiiFAp|6SSYTlN|Im-j3>{id_RSt(rA*|xXr(>oTO zc~d#{&S@d0j?n7vLjAS$kWIM0JkdS()Z;H!-tcI8hq7~6ml&@cQBM8yv-FPVE3WS9V9cXPA=id$v;PRZji%vu7%vou3$dcAhdZv37jhR(ForQT|lL(+iTq zf9_D)g{!c=cJxGFdibZ68R2WolwNVF?2A6n<5e$rdBTtRYr{FUww=K?Woq15<&bh} zcrT#op-;m%`7PUiz{`#N@bGRBTP*zP$Zlv8hiF+_|Mr^K5|tL-yellrAP z*gnkev5&Wx*k{_8+t=7P*tgpsw7+bB!+z9rcjYj3aVW8TNkDi!VR5SO%#eKLkT~_y znH1Q1@{6IuExclem?xHr8nISv6yFfv6uZTX_8%h2e_a~(bJ6Mcd0uiP1b3Gw)V>@{ zFaJ%g@VtJaGxvZaJ$P+JqA$I+-P0SqOeB`S2Fb5=$u&{Q5nb|>E@_KOE>mQlhjmFy zRB}X@>^-4)nkxF2eTS|cifUh`N;@~6uzTtUXm35y=~m9Ff9r|MDle-@4;r;UVwVS67NCTbvq~t}_2)$OFViheK4*=_pO9B5MY}>L&hQFdAf||B zu~}>vw}?B%{o)bvGjX2%1tj_JcN%tBbb5U5BaZCgP376Ohw*(F*Fine={e%a3J#m6 z__DyY`N;k3xa1D)$Nf;}ruF0g>3H{Cu}b)E87#zZjFnXwH}h(RuMTh*=+%IC0^W^u zKaxnX`TD->>+3s>^cSR`_w@<8m`4I54^WeU+xHh)i|&5q?K`fxpYiu^#a_K;KkcXa z?c;WL*8t6%p{bnZh4$n7{QKr*1S zVtG2Q+_2-Fx$PRwkw#A1@lH3#WqNrcsKl5YV~28El*7?P&OhH%JPnnG#gE^MTEzIF z{Lk;%J*%SfKS8dTYH;|ycF!f1N9;!a1JV2(Bh3F&jDxX3PB%CyCL2#iH8>im@ndkz zrTp+c`fKN(=&uI&D@WvtvG7=lm?mb4a#0}`ic3VN?Q$gfuU^Bh#3*p)9&zlh6Q1kd z!&TGqt-xJ6z6rQb$6J86>-f6&l-v=1<_w}X2OPHntAEdyo2ButfTp5rE`P5*cZh$d zLfvZMot`wCEYq)1I~7UIK_0uFXO<>8pi8EhtQEcYuf_=dkgECN=;vSMhr#f}V4M6` zuVGO?VCGj)mgWcGr;q7=0R9i)nje7w1-Rx1;D0`*bt8}F2jEX>63q{weqyrr@G+aGKFs!Bf0Wn# ziq8|%hk3?NoL*j8y|QlmRon4t*}i>?yu!mm>Aw1Q;n@ibY@I>h1lnbyw}ECW4f$r! zY^gy<(AxX_26a_bdO%3~b!hqSsQfa>*?L2N30iYIJYdj%$SFONctmCG%A@vnV&6c{ zba3bkBS&#mB=sz#8v70^yKNw(dJ49UVq+cWRaW_XF_*ojNgs!l`-gej>NvadVpAP|sOL=8a;Dc#tDI%3@vhUH_2z|2 z{dWk}*X?Q-g+8_1A1L%stymsPOHh1$t~g(E`4xc?!2-0cs64B7MM&`_l&=indIoma zWe3MrB=}@4*Pm|B_4p6iR)jqBs4)VwpW;ic?FqUnl=9x%qq!?WX(}bMugR9%b2i%a$!#CPZJ~=Y2okhgI{85Ne+g)E}bdO4GgvYu`zyA8Av((|Uy0-qY?C zy|*8|W3+NqoZ9)t@BAaeSI+&NKkdfs_VI1CxhuNFIB{guyXn64-YeVU@{@Y6>_|

aJN6byc@gXZqHrH5}&gBuCDZUamx0E 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 = EMPTY; + // cur_buff = get_next_buff( cur_buff, num_buff ); + //} + + //go back to buff0 + //cur_buff = &buff0; + } if (get_operation() == STARTDUMP) { //prepare both buffers to dump diff --git a/firmware/source/flash.c b/firmware/source/flash.c index 9b86c41..02cb88e 100644 --- a/firmware/source/flash.c +++ b/firmware/source/flash.c @@ -52,6 +52,59 @@ uint8_t write_page( uint8_t bank, uint8_t addrH, buffer *buff, write_funcptr wr_ } +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; +// extern operation_info *oper_info; + + while ( cur <= buff->last_idx ) { + //write unlock sequence + //need to make address and unlock data variable + //best for host to communcate these values + //actual value is part mapper dependent and part flash dependent + //mapper controlled address bits dictate where split is + //32KB banking A14-0 NES ctl, A15+ mapper ctl "bank" NROM, BNROM, ANROM + //addrH_dmask = 0b0111 1111 directly addressable addrH bits + //page2bankshft = A14->A8 = 7 shifts (equal to number of set bits in addrH_mask + //16KB banking A13-0 NES ctl, A14+ mapper ctl "bank" UxROM, MMC1 + //addrH_dmask = 0b0011 1111 + //page2bankshft = A13->A8 = 6 shifts + // 8KB banking A12-0 NES ctl, A13+ mapper ctl "bank" MMC3, FME7 + //addrH_dmask = 0b0001 1111 + //page2bankshft = A12->A8 = 5 shifts + // 4KB banking A11-0 NES ctl, A12+ mapper ctl "bank" ezNSF + //addrH_dmask = 0b0000 1111 + //page2bankshft = A11->A8 = 4 shifts + wr_func( 0x1555, 0xAA ); +// wr_func( oper_info->unlock1_AH, oper_info->unlock1_AL, oper_info->unlock1_data ); + wr_func( 0x0AAA, 0x55 ); +// wr_func( oper_info->unlock2_AH, oper_info->unlock2_AL, oper_info->unlock2_data ); + wr_func( 0x1555, 0xA0 ); +// wr_func( oper_info->command_AH, oper_info->command_AL, oper_info->command1_data ); + wr_func( ((addrH<<8)| n), buff->data[n] ); + //wr_func( ((addrH<<8)| n), buff->page_num ); + //wr_func( ((addrH<<8)| n), addrH); + + 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++; + + } + + buff->cur_byte = n; + + return SUCCESS; + +} + /* Desc:Flash buffer contents on to cartridge memory * Pre: buffer elements must be updated to designate how/where to flash * buffer's cur_byte must be cleared or set to where to start flashing @@ -80,7 +133,7 @@ uint8_t flash_buff( buffer *buff ) { write_page( 0, (0x80 | addrH), buff, discrete_exp0_prgrom_wr, nes_cpu_rd ); break; case CHRROM: //$0000 - //TODO write_page( 0, addrH, buff, nes_ppu_wr, nes_ppu_rd ); + write_page_chr( 0, addrH, buff, nes_ppu_wr, nes_ppu_rd ); break; case PRGRAM: //addrH |= 0x60; //$6000 diff --git a/firmware/source_stm_only/usbstm.c b/firmware/source_stm_only/usbstm.c index c89ad4c..d648408 100644 --- a/firmware/source_stm_only/usbstm.c +++ b/firmware/source_stm_only/usbstm.c @@ -586,6 +586,8 @@ static void control_xfr_in(){ //flag and value, since can't change address until after STATUS stage, must use this value //to denote that the USB device address needs updated after the status stage. static uint8_t new_address = 0; +static uint8_t reqtype = 0; +static uint8_t reqdir = 0; //return number of bytes expected @@ -724,6 +726,10 @@ static void control_xfr_init( usbRequest_t *spacket ) { * of this function for more information. If you just want to ignore the data * sent by the host, return 0 in 'usbFunctionSetup()'. */ + //set request type so it can be keyed from for subsequent IN/OUT data transfers + reqtype = (spacket->bmRequestType & REQ_TYPE); + reqdir = (spacket->bmRequestType & REQ_DIR); + //setup packets not handled by standard requests sent to usbFunctionSetup (just like Vusb) if ((spacket->bmRequestType & REQ_TYPE) != REQ_TYPE_STD) { //function must set usbMsgPtr to point to return data for IN transfers @@ -891,10 +897,14 @@ void USB_IRQHandler(void) control_xfr_init( setup_packet ); } else { //OUT packet + if ((reqtype == REQ_TYPE_VEND) & (reqdir == REQ_DIR_OUT)) { + //have to key off of reqdir so OUT status packets don't call usbFunctionWrite // if ( log >= LOG_COUNT) { DEBUG_HI(); DEBUG_LO(); } //number of bytes received is denoted in USB_COUNTn_RX buffer table //control_xfr_out(); usbFunctionWrite((uint8_t*) &usb_buff[EP0_RX_BASE], (usb_buff[USB_COUNT0_RX] & RX_COUNT_MSK)); + USB_EP0R_RX_VALID(); + } } diff --git a/host/scripts/app/buffers.lua b/host/scripts/app/buffers.lua index de6bcf4..2f6737e 100644 --- a/host/scripts/app/buffers.lua +++ b/host/scripts/app/buffers.lua @@ -91,6 +91,32 @@ local function allocate( num_buffers, buff_size ) end +-- pass in table buffer numbers would like to wait on +-- pass in table of status waiting on for all buffers +local function status_wait( buff_nums, end_status ) + + + local rv = nil + for key_buff, buff in pairs(buff_nums) do + rv = nil + print("buffer wait:", key_buff, buff) + while rv ~= "EXIT" do + for key_stat, stat in pairs(end_status) do + rv = (dict.buffer("GET_PRI_ELEMENTS", nil, buff, nil, true )) + --status is the second byte of return data + rv = string.unpack("B", rv, 2) + if rv == op_buffer[stat] then + print("buffer", buff, rv, "matched", stat) + rv = "EXIT" + break + else + print("buffer", buff, "is", rv, "not", stat) + end + end + end + + end +end -- global variables so other modules can use them @@ -100,6 +126,7 @@ end -- functions other modules are able to call buffers.allocate = allocate +buffers.status_wait = status_wait -- return the module's table return buffers diff --git a/host/scripts/app/dict.lua b/host/scripts/app/dict.lua index ee5d5f9..d420138 100644 --- a/host/scripts/app/dict.lua +++ b/host/scripts/app/dict.lua @@ -382,7 +382,7 @@ local function buffer_payload_out( num_bytes, data, buff_num ) end -- external call for buffer dictionary -local function buffer( opcode, operand, misc, data ) +local function buffer( opcode, operand, misc, data, stringout ) if not op_buffer[opcode] then print("ERROR undefined opcode:", opcode, "must be defined in shared_dict_buffer.h") @@ -426,7 +426,9 @@ local function buffer( opcode, operand, misc, data ) end --process the return data string and return it to calling function - if data_len then + if stringout then + return data:sub(RETURN_DATA, data_len+RETURN_DATA) + elseif data_len then return string_to_int( data:sub(RETURN_DATA, data_len+RETURN_DATA), data_len) else return nil diff --git a/host/scripts/app/dump.lua b/host/scripts/app/dump.lua index dc678a8..4428344 100644 --- a/host/scripts/app/dump.lua +++ b/host/scripts/app/dump.lua @@ -44,6 +44,7 @@ local function dump_nes( file, debug ) -- //Run some CRC's to determine size of memories -- -- //setup buffers and manager + dict.operation("SET_OPERATION", op_buffer["RESET"] ) -- //reset buffers first dict.buffer("RAW_BUFFER_RESET") @@ -76,17 +77,17 @@ local function dump_nes( file, debug ) -- -- //debugging print out buffer elements -- //get_operation( transfer ); - print("\nget operation:") - dict.operation("GET_OPERATION" ) - print("\n\ngetting cur_buff status") - dict.buffer("GET_CUR_BUFF_STATUS" ) - print("\n\ngetting elements") - dict.buffer("GET_PRI_ELEMENTS", nil, buff0 ) - dict.buffer("GET_PRI_ELEMENTS", nil, buff1 ) - dict.buffer("GET_SEC_ELEMENTS", nil, buff0 ) - dict.buffer("GET_SEC_ELEMENTS", nil, buff1 ) - dict.buffer("GET_PAGE_NUM", nil, buff0 ) - dict.buffer("GET_PAGE_NUM", nil, buff1 ) + --print("\nget operation:") + --dict.operation("GET_OPERATION" ) + --print("\n\ngetting cur_buff status") + --dict.buffer("GET_CUR_BUFF_STATUS" ) + --print("\n\ngetting elements") + --dict.buffer("GET_PRI_ELEMENTS", nil, buff0 ) + --dict.buffer("GET_PRI_ELEMENTS", nil, buff1 ) + --dict.buffer("GET_SEC_ELEMENTS", nil, buff0 ) + --dict.buffer("GET_SEC_ELEMENTS", nil, buff1 ) + --dict.buffer("GET_PAGE_NUM", nil, buff0 ) + --dict.buffer("GET_PAGE_NUM", nil, buff1 ) -- print("\n\nsetting operation STARTDUMP"); -- //inform buffer manager to start dumping operation now that buffers are initialized @@ -94,9 +95,9 @@ local function dump_nes( file, debug ) dict.operation("SET_OPERATION", op_buffer["STARTDUMP"] ) -- --need these calls to delay things a bit to let first buffer dump complete.. - dict.operation("GET_OPERATION" ) - dict.buffer("GET_PRI_ELEMENTS", nil, buff0 ) - dict.buffer("GET_PRI_ELEMENTS", nil, buff1 ) +-- dict.operation("GET_OPERATION" ) +-- dict.buffer("GET_PRI_ELEMENTS", nil, buff0 ) +-- dict.buffer("GET_PRI_ELEMENTS", nil, buff1 ) -- //manager updates buffer status' so they'll start dumping -- //once they're full manager prepares them to be read back on USB payloads -- //once the next payload request happens manager knows last buffer can start dumping again @@ -114,6 +115,8 @@ local function dump_nes( file, debug ) -- clock_t tstart, tstop; -- tstart = clock(); -- + --wait for first buffer to finish dumping before calling payload + buffers.status_wait({buff0}, {"DUMPED"}) -- //now just need to call series of payload IN transfers to retrieve data --for i=1, (1024*1024/buff_size) do for i=1, (32*1024/buff_size) do @@ -140,6 +143,52 @@ local function dump_nes( file, debug ) end -- } print("payload done"); + --buffer manager updates from USB_UNLOADING -> DUMPING -> DUMPED + --while one buffer is unloading, it sends next buffer off to dump + --payout opcode updates from DUMPED -> USB_LOADING + --so end result is buff0 will get sent off to dump extra data that's not needed + --but we never call payload on it, so buff1 never moves from USB_UNLOADING + --but it has to be done unloading if we sent a subsequent setup packet + --buffers.status_wait({buff0, buff1}, {"DUMPED","USB_UNLOADING"}) + --in reality I don't think this wait is needed. Because we've already gotten our data if + --we're at this point.. + --what we really need to do is set the buffer's status' to a reset state + --that way we can give them new instructions before restarting DUMP of CHR portion + --best way can think of doing this is a operation "RESET" which updates buffer status, + --without deallocating them. In reality should be able to do this by setting operation to reset. + --and having STARTDUMP/FLASH initialize buffer status' as well. + dict.operation("SET_OPERATION", op_buffer["RESET"] ) + dict.buffer("RAW_BUFFER_RESET") + +-- //need to allocate some buffers for dumping +-- //2x 128Byte buffers + num_buffers = 2 + buff_size = 128 + print("allocating buffers") + assert(buffers.allocate( num_buffers, buff_size ), "fail to allocate buffers") + +-- //set buffer elements as needed +-- //set reload which gets added to page_num after each buffer read +-- //set reload to 256 = 1 when translated to page_num (done in allocate buffers funct) +-- //set page_num to non-zero if offset arg sent +-- //set mem_type and part_num to designate how to get/write data +-- check(! set_mem_n_part( transfer, buff0, PRGROM, MASKROM ), "Unable to set mem_type and part"); + print("setting map n part") + dict.buffer("SET_MEM_N_PART", (op_buffer["CHRROM"]<<8 | op_buffer["MASKROM"]), buff0 ) + dict.buffer("SET_MEM_N_PART", (op_buffer["CHRROM"]<<8 | op_buffer["MASKROM"]), buff1 ) +-- //set multiple and add_mult only when flashing +-- //set mapper, map_var, and function to designate read/write algo +-- +-- //just dump visible NROM memory to start + print("setting map n mapvar") + dict.buffer("SET_MAP_N_MAPVAR", (op_buffer["NROM"]<<8 | op_buffer["NOVAR"]), buff0 ) + dict.buffer("SET_MAP_N_MAPVAR", (op_buffer["NROM"]<<8 | op_buffer["NOVAR"]), buff1 ) +-- +-- + print("\n\nsetting operation STARTDUMP"); +-- //inform buffer manager to start dumping operation now that buffers are initialized +-- check(! set_operation( transfer, STARTDUMP ), "Unable to set buffer operation"); + dict.operation("SET_OPERATION", op_buffer["STARTDUMP"] ) -- -- tstop = clock(); -- float timediff = ( (float)(tstop-tstart) / CLOCKS_PER_SEC); @@ -152,17 +201,12 @@ local function dump_nes( file, debug ) -- //reset buffers and setup to dump CHR-ROM --Can't get things to work without resetting all the buffers for some reason.. --Think the issue is need to get the buffer status needs reset - dict.buffer("RAW_BUFFER_RESET") - print("reallocate buffers") - assert(buffers.allocate( num_buffers, buff_size ), "fail to allocate buffers") - dict.buffer("SET_MEM_N_PART", (op_buffer["CHRROM"]<<8 | op_buffer["MASKROM"]), buff0 ) - dict.buffer("SET_MEM_N_PART", (op_buffer["CHRROM"]<<8 | op_buffer["MASKROM"]), buff1 ) - dict.buffer("SET_MAP_N_MAPVAR", (op_buffer["NROM"]<<8 | op_buffer["NOVAR"]), buff0 ) - dict.buffer("SET_MAP_N_MAPVAR", (op_buffer["NROM"]<<8 | op_buffer["NOVAR"]), buff1 ) - dict.operation("SET_OPERATION", op_buffer["STARTDUMP"] ) - --dict.operation("GET_OPERATION" ) - --dict.buffer("GET_PRI_ELEMENTS", nil, buff0 ) - --dict.buffer("GET_PRI_ELEMENTS", nil, buff1 ) +-- dict.buffer("RAW_BUFFER_RESET") +-- print("reallocate buffers") +-- assert(buffers.allocate( num_buffers, buff_size ), "fail to allocate buffers") + + --wait for first buffer to finish dumping prior to calling payload + buffers.status_wait({buff0}, {"DUMPED"}) for i=1, (8*1024/buff_size) do --cur_buff_status = dict.buffer("GET_CUR_BUFF_STATUS") @@ -180,7 +224,9 @@ local function dump_nes( file, debug ) -- //close file in main -- -- //reset io at end + dict.operation("SET_OPERATION", op_buffer["RESET"] ) dict.buffer("RAW_BUFFER_RESET") + dict.io("IO_RESET") return true end diff --git a/host/scripts/app/flash.lua b/host/scripts/app/flash.lua index b7b54e1..23463b0 100644 --- a/host/scripts/app/flash.lua +++ b/host/scripts/app/flash.lua @@ -53,6 +53,7 @@ local function flash_nes( file, debug ) -- -- //start operation at reset -- check(! set_operation( transfer, RESET ), "Unable to set buffer operation"); + dict.operation("SET_OPERATION", op_buffer["RESET"] ) -- -- //setup buffers and manager -- //reset buffers first @@ -90,21 +91,22 @@ local function flash_nes( file, debug ) dict.buffer("SET_MAP_N_MAPVAR", (op_buffer["NROM"]<<8 | op_buffer["NOVAR"]), buff1 ) -- -- //debugging print out buffer elements - print("\nget operation:") - dict.operation("GET_OPERATION" ) - print("\n\ngetting cur_buff status") - dict.buffer("GET_CUR_BUFF_STATUS" ) - print("\n\ngetting elements") - print(dict.buffer("GET_PRI_ELEMENTS", nil, buff0 )) - print(dict.buffer("GET_PRI_ELEMENTS", nil, buff1 )) - print(dict.buffer("GET_SEC_ELEMENTS", nil, buff0 )) - print(dict.buffer("GET_SEC_ELEMENTS", nil, buff1 )) - print(dict.buffer("GET_PAGE_NUM", nil, buff0 ) ) - print(dict.buffer("GET_PAGE_NUM", nil, buff1 ) ) + --print("\nget operation:") + --dict.operation("GET_OPERATION" ) + --print("\n\ngetting cur_buff status") + --dict.buffer("GET_CUR_BUFF_STATUS" ) + --print("\n\ngetting elements") + --print(dict.buffer("GET_PRI_ELEMENTS", nil, buff0 )) + --print(dict.buffer("GET_PRI_ELEMENTS", nil, buff1 )) + --print(dict.buffer("GET_SEC_ELEMENTS", nil, buff0 )) + --print(dict.buffer("GET_SEC_ELEMENTS", nil, buff1 )) + --print(dict.buffer("GET_PAGE_NUM", nil, buff0 ) ) + --print(dict.buffer("GET_PAGE_NUM", nil, buff1 ) ) print("\n\nsetting operation STARTFLASH"); -- //inform buffer manager to start dumping operation now that buffers are initialized dict.operation("SET_OPERATION", op_buffer["STARTFLASH"] ) + --print("set operation STARTFLASH"); -- clock_t tstart, tstop; -- tstart = clock(); @@ -144,13 +146,117 @@ local function flash_nes( file, debug ) -- //The device doesn't have a good way to respond if the last buffer is flashing -- //and the current one is full. We can only send a payload if the current buffer -- //is empty. --- waste some time for now.. - print(dict.buffer("GET_PRI_ELEMENTS", nil, buff0 )) - print(dict.buffer("GET_PRI_ELEMENTS", nil, buff1 )) - print(dict.buffer("GET_SEC_ELEMENTS", nil, buff0 )) - print(dict.buffer("GET_SEC_ELEMENTS", nil, buff1 )) - print(dict.buffer("GET_PAGE_NUM", nil, buff0 ) ) - print(dict.buffer("GET_PAGE_NUM", nil, buff1 ) ) + + -- wait till all buffers are done + --while flashing buffer manager updates from USB_FULL -> FLASHING -> FLASHED + --then next time a USB_FULL buffer comes it it updates the last buffer (above) to EMPTY + --the next payload opcode updates from EMPTY -> USB_LOADING + --so when complete, buff0 should be EMPTY, and buff1 should be FLASHED + --just pass the possible status to exit wait, and buffer numbers we're waiting on + buffers.status_wait({buff0, buff1}, {"EMPTY","FLASHED"}) + +-- //start operation at reset +-- check(! set_operation( transfer, RESET ), "Unable to set buffer operation"); + dict.operation("SET_OPERATION", op_buffer["RESET"] ) +-- +-- //setup buffers and manager +-- //reset buffers first + dict.buffer("RAW_BUFFER_RESET") +-- //need to allocate some buffers for flashing +-- //2x 256Byte buffers + num_buffers = 2 + buff_size = 256 + print("allocating buffers") + assert(buffers.allocate( num_buffers, buff_size ), "fail to allocate buffers") +-- +-- //tell buffers what function to use for flashing +-- //load operation elements into buff0 and then copy buff0 to oper_info +-- load_oper_info_elements( transfer, cart ); +-- get_oper_info_elements( transfer ); +-- +-- //setup buffers and manager +-- //reset buffers first +-- check(! reset_buffers( transfer ), "Unable to reset device buffers"); +-- //need to allocate some buffers for flashing +-- //2x 256Byte buffers +-- check(! allocate_buffers( transfer, num_buffers, buff_size ), "Unable to allocate buffers"); +-- +-- //set mem_type and part_num to designate how to get/write data + print("setting map n part") + dict.buffer("SET_MEM_N_PART", (op_buffer["CHRROM"]<<8 | op_buffer["MASKROM"]), buff0 ) + dict.buffer("SET_MEM_N_PART", (op_buffer["CHRROM"]<<8 | op_buffer["MASKROM"]), buff1 ) +-- //set multiple and add_mult only when flashing +-- //TODO +-- //set mapper, map_var, and function to designate read/write algo +-- +-- //just dump visible NROM memory to start + print("setting map n mapvar") + dict.buffer("SET_MAP_N_MAPVAR", (op_buffer["NROM"]<<8 | op_buffer["NOVAR"]), buff0 ) + dict.buffer("SET_MAP_N_MAPVAR", (op_buffer["NROM"]<<8 | op_buffer["NOVAR"]), buff1 ) +-- +-- //debugging print out buffer elements + --print("\nget operation:") + --dict.operation("GET_OPERATION" ) + --print("\n\ngetting cur_buff status") + --dict.buffer("GET_CUR_BUFF_STATUS" ) + --print("\n\ngetting elements") + --print(dict.buffer("GET_PRI_ELEMENTS", nil, buff0 )) + --print(dict.buffer("GET_PRI_ELEMENTS", nil, buff1 )) + --print(dict.buffer("GET_SEC_ELEMENTS", nil, buff0 )) + --print(dict.buffer("GET_SEC_ELEMENTS", nil, buff1 )) + --print(dict.buffer("GET_PAGE_NUM", nil, buff0 ) ) + --print(dict.buffer("GET_PAGE_NUM", nil, buff1 ) ) + + print("\n\nsetting operation STARTFLASH"); +-- //inform buffer manager to start dumping operation now that buffers are initialized + dict.operation("SET_OPERATION", op_buffer["STARTFLASH"] ) + +-- clock_t tstart, tstop; +-- tstart = clock(); +-- +-- //now just need to call series of payload IN transfers to retrieve data +-- +-- for( i=0; i<(32*KByte/buff_size); i++) { + local i = 1 + local nak = 0 + for bytes in file:lines(buff_size) do + dict.buffer_payload_out( buff_size, bytes ) + --for i = 1, #bytes do + -- local b = string.unpack("B", bytes, i) + -- io.write(string.format("%02X ", b)) + --end +-- io.write(string.rep(" ", blocksize - #bytes)) +-- bytes = string.gsub(bytes, "%c", ".") +-- io.write(" ", bytes, "\n") +-- break +-- while (cur_buff_status != EMPTY ) { +-- //debug("cur_buff->status: %x ", cur_buff_status); +-- check(! get_cur_buff_status( transfer, &cur_buff_status ), "Error retrieving cur_buff->status"); +-- } + cur_buff_status = dict.buffer("GET_CUR_BUFF_STATUS") + while (cur_buff_status ~= op_buffer["EMPTY"]) do + nak = nak +1 + --print(nak, "cur_buff->status: ", cur_buff_status) + cur_buff_status = dict.buffer("GET_CUR_BUFF_STATUS") +-- check(! get_cur_buff_status( transfer, &cur_buff_status ), "Error retrieving cur_buff->status"); +-- } + end + if ( i == 8*1024/buff_size) then break end + i = i + 1 + end + print("number of naks", nak) +-- +-- //The device doesn't have a good way to respond if the last buffer is flashing +-- //and the current one is full. We can only send a payload if the current buffer +-- //is empty. + + -- wait till all buffers are done + --while flashing buffer manager updates from USB_FULL -> FLASHING -> FLASHED + --then next time a USB_FULL buffer comes it it updates the last buffer (above) to EMPTY + --the next payload opcode updates from EMPTY -> USB_LOADING + --so when complete, buff0 should be EMPTY, and buff1 should be FLASHED + --just pass the possible status to exit wait, and buffer numbers we're waiting on + buffers.status_wait({buff0, buff1}, {"EMPTY","FLASHED"}) -- -- //Read next chunk from file -- check(! read_from_file( rom, data, buff_size ), "Error with file read"); @@ -251,6 +357,9 @@ local function flash_nes( file, debug ) -- io_reset( transfer ); -- -- return SUCCESS; + dict.operation("SET_OPERATION", op_buffer["RESET"] ) + dict.buffer("RAW_BUFFER_RESET") + dict.io("IO_RESET") end diff --git a/host/source/usb_operations.c b/host/source/usb_operations.c index b6b5b3b..c42ac52 100644 --- a/host/source/usb_operations.c +++ b/host/source/usb_operations.c @@ -358,17 +358,17 @@ typedef struct USBtransfer { usb_xfr.data = data_buff; -// printf("\nep %d, req %d", usb_xfr.endpoint, usb_xfr.request); -// printf("wValue %d, wIndex %d", usb_xfr.wValue, usb_xfr.wIndex); -// printf("wLength %d \n", usb_xfr.wLength); + //printf("\nep %d, req %d", usb_xfr.endpoint, usb_xfr.request); + //printf("wValue %d, wIndex %d", usb_xfr.wValue, usb_xfr.wIndex); + //printf("wLength %d \n", usb_xfr.wLength); //printf("predata: %d, %d, %d, %d, %d, %d, %d, %d \n", usb_xfr.data[0], usb_xfr.data[1],usb_xfr.data[2],usb_xfr.data[3],usb_xfr.data[4],usb_xfr.data[5], usb_xfr.data[6], usb_xfr.data[7]); check( lua_usb_handle != NULL, "usb device handle pointer not initialized.\n") xfr_count = usb_vendor_transfer( &usb_xfr); -// printf("postdata: %d, %d, %d, %d, %d, %d, %d, %d \n", usb_xfr.data[0], usb_xfr.data[1],usb_xfr.data[2],usb_xfr.data[3],usb_xfr.data[4],usb_xfr.data[5], usb_xfr.data[6], usb_xfr.data[7]); -// printf("bytes xfrd: %d\n", xfr_count); + //printf("postdata: %d, %d, %d, %d, %d, %d, %d, %d \n", usb_xfr.data[0], usb_xfr.data[1],usb_xfr.data[2],usb_xfr.data[3],usb_xfr.data[4],usb_xfr.data[5], usb_xfr.data[6], usb_xfr.data[7]); + //printf("bytes xfrd: %d\n", xfr_count); lua_pushnumber(L, xfr_count); /* push first result */ rv++;