From 3a340da8c7cdbb33293691a034593f082c80a0a7 Mon Sep 17 00:00:00 2001 From: spicyjpeg Date: Wed, 10 Jul 2024 18:13:03 +0200 Subject: [PATCH] Fix FPGA bitstream, rewrite I2C and 1-wire drivers --- data/fpga.bit | Bin 41407 -> 41407 bytes fpga/fpga.ucf | 366 +++++++++++------ fpga/fpga.ys | 35 +- fpga/runISE.bat | 4 +- fpga/src/main.v | 328 ++++++++------- fpga/src/spartanxl.v | 368 ----------------- fpga/src/spartanxl/map.v | 37 ++ fpga/src/spartanxl/primitives.lib | 551 +++++++++++++++++++++++++ fpga/src/spartanxl/primitives.v | 646 ++++++++++++++++++++++++++++++ fpga/src/techmap.v | 90 ----- src/common/io.cpp | 397 +++++++++--------- src/common/io.hpp | 182 ++++++--- src/common/rom.cpp | 6 +- src/main/app/cartworkers.cpp | 6 +- src/main/app/tests.cpp | 12 +- src/main/cart/cartio.cpp | 111 ++--- src/main/main.cpp | 2 +- src/ps1/registers573.h | 13 +- 18 files changed, 2098 insertions(+), 1056 deletions(-) delete mode 100644 fpga/src/spartanxl.v create mode 100644 fpga/src/spartanxl/map.v create mode 100644 fpga/src/spartanxl/primitives.lib create mode 100644 fpga/src/spartanxl/primitives.v delete mode 100644 fpga/src/techmap.v diff --git a/data/fpga.bit b/data/fpga.bit index e576432f0066a5ac250468f60a7b1454cbac34a7..5b27f292f3485cebc47f7e858cbd654836964960 100644 GIT binary patch literal 41407 zcmb`Qe~cbSdB)$c8YxmUKckTG-jyJvio$uPU>s{CH z-tjj(c06*Y{`Eh5s-eSVlv`#=~Ftmc( zpN!djV77FNx-F!=ZJUJ%Q_Ui`P%Scchc`Ve-DoR6;u)fCdUdEo=hor2=&T!Q{WX;e zR%$A8^U6@Q54~bOBovz5?3sRWo83=D zXt&*LzwLduPdd>HL22XX&5F$@8?%~*y3+aqy}G?PKePH|B4-Y7_vFm#wx$nh>Ed3J z^e58J?$eQ1D|95%#%zD)i?Edqa%#9f9nsMmm9}*f(RPZ&902plYgj2UOZq5Dd79F# zFvm0-DO0+i^wYye$22heZ$2q|!ft!}x3D?9OuEAGh)v_XMULbIr(QQ$z=cC9^T*`YCg(ogs7 zDr*&l&N#D3wOl=?$tJ z^gQKJ-jP-FWS=8;Yi!x7Wyep+JvmfUjCr%r4;bgEpMV@SaW3-(wNF7;J zTntSETVPvCEviRpLzL39;dp@Att(mShm0y{2o{cyD4UQrloqLZ%9N7}6;hz}HP))X zYP{RJ>jtpOpPO#&Yr4K$^O{B6b_I9Sj!OC`NCn5rjxsY;?cuUj+!^C)OSctUrZ$a2 zvddGLOPOGIkCcK@NlxvIL$Rrq<}g#XRD^4DusDV4RwESp9vjDj<;S)_4~%PEI_2bF zlVirE-a=@g63aF>GDxa7W9fRGuXc5|ce?x=$AlB`@@Z*#|IRipcQkCdTon%htFU$* zLkLh9V^iY=Q@f+2^>)yB41Q|Ex;#F#PPMEN(yzKMYutJo#IDPt31$@io78x~wceE0 zNSt~A<#zV`Qx6@iRnTrc3=4wolu*HdRxmEa) zP&3+=Ki(aiCDyjI_^H#fBVQ^TE0?9-Fi!O&cd7aLjk~O8)#P=HE_Qw+^<^5YX5177 z%fe`MgHo^y4JxJKbgHW5oPz^<*cEok+hvJdRw3D*=>?96LP1!Nov3ayLnqW~L0ZRW zXkikh|DT%f2l4Q0QdHa63^{U1-Q z(r7l@fJ&}96@b;V8J-O@3FP)3lX&@@ts0UqOGDYSIGVlI{X1N$c2b z6xgi!ywsQ8=IUJgoXhdDcQCXCH{;@zs%XYYQi~MetiNn{l+32r6l|rRm!=?@zqf7j zx)iod3H3M_G~+tzx>Rno(&wF3XFU?BJ<3!kqq&fQV*X7V%HF=3`BM|d@=*4y?XnrN zYD)dCDecnjZwD(JZ94Y zVRyE6joO`<{Ze0mDpRHfC5xjG9DNsP9cvywdNk!i*|VqC%#?wRV0kE;JYY9^0lB%t z?wk?k951=DLTM%r+DGqof&m?n2F)h0DqZAYWxW2R^o zw@kFUo&3uTc~=*=c5@*|%7(JrI%sa}gSKUArMLzzhYn3Q?tps2TJ>L3!kOdcz?BX~ z8<#t(rd=pIb-3VJ6`Pg4WUW_v&7(1v#?1IIYhJgw$rgyvp6zu;`m!xC9#mC?dozH~P~ec|DH3{>R}s}7l|RrTo3 zu{jt@E4DNoE;uV=0nV6_FvVM!mra%?nF-^(Lu*v}se8u+O;M$*+O&?@nW{pKRO|~9 zmc;>?>Lv>daw<-n{6J}w!KrZCShZF*VSk!3o1%cSyMG)CtJN*c+_{c~)>1d6E4Fy5 z$%M+ToH7QnxVF*Gg|gxN&5c$rlX@SA zBWbeQq@FWH(XtzCwPr5}Q?yw3XeO)IF@kx+q%qxMLfNI;7nU*?ODYd#yECSdu(2fy zFXks0xZ>ALwsN}J`;fmNt3=<^p{yaN~RCL4@Z!}wt zgeg}^vz2yT7RqL`lcsp+aGZaE z#I87|?kR+(VqBa`c9p{mrTDeWtn^+wjB$9NSf5BWQ8RQgx68ap=29jk9W(lGYwybd z&JWYzG3O)=-G)T-WlF9j^q{}NNbCElrNgq(gbIIkz8~LtWzxXdw@1Ztx_PsxKi{as zL+it~4jR`w8%3&f&#KUo(Df-<)d#kw_rF&sO&%tBklfv@UKC(xjoVIM5sCiar+U9R zMo=WHv7WPzQDo`+`!oo-`)j5_o--f&4Qbr#J>VxCkk<-!HsS8{PfXqh9hE2^WXhu;!Xua2#N^ftXM zzy8{2ZLtu%794IG)T+BRy>@mWedq?7u}EE|wNx}w5!P8)ejoWTGakt!WkshjTR@(bhqC9X%le7!x0-eg z-X;Szv19eqLU-rRPU^GaZi-M8ZCk?%sc0{KWO*ytjgsrQ$CtBD-sF1?Ic|+m(CI}m|mo9itM&ks+ZKQK+|gl!I9$p z01svRD}rh%vuH{qVf&%^DY%Yqrmm z<~JsK*^7F1Sh5i%%_@?XmBUg|joDH9#AQ3Mdh5kZjAE*!NoGQptGGjAly*}6UK|s2 zknGnL$hxwh}NAq-(@Sf)~wI+Z69x5mwOJLc3l3;SD07XSK zYm}$VzBZ+Jl}dZJwVP~cZC|Ex)!QSQ%{EQ>mE9CXG$pmul!{P=l+`DDTYhFxZ(vKJ z4n?acpZu&Wc-Aa{9V2DBZ0p3NQ1+8#r6Rh?Y)mGU)lcr3Yd2dRq+<2ZS-Ttcma!nK z)AYrLdJ|JJN5TJ@;a8_Je@f1K-F(Kc8yJZ~S?btHK}H;q6-~rQ${NxEDogZqSTF&O z9D9+Ic`(-5K2vadJKA@lwT}4KiejamCHbhLg^X_MK62Vb-n;|o+N z_(ZFY1ksi9T_HHMCKj1plVqExB$sl*J(L4yY;IwM;Une+gZwpF>t1;%o6snWwGgGM zT)7}^$9j$QCpEl`NBhb;*3uUYaN(GqnHkIVQv7&*S)s&yxp0z;r6bfy zCtk;KYt5`|q3JqtwyvPW)n4*GB?1*Xi$(&L6d^@q;B+lo7{`&$P&N_O zx=fFx{SGDL6)^DxvG)1XtV->&8i!@QM*BMX#Y)@?LfK2Arg{mRS=q@ax&AU}jH7Ky zja5>~Ww|oYWl5zLsV6wnlCfcnA+$R;aw{~R1UCyAQecvGx)80|Xhn z5HJKl{}g}>^^Sy$aiFx9FY7(Ts{-;xz&JV;aK?%H3(f%fAHXOSZp3Q=jB# z7mAYv1&3=3Bfaj`W!X37N-N-sb7YhJtc#;2`dK@NgwBi7dg->jJT+k4YsJN`5979} z>f~02G#KT7&#kmz?4o3-Jo)O1-61cTg3hs%KP4jyrz<+$MyxV~ z!2Jj^cFF6+M7zYA()vS_#?Tbvrd6i3uEwokR@U8?gSC{Wp`ac zi349#DtC&R$?!-I>&k2aoRyt82jkXc4mt3bmCbleRsgAjp^E`S=)^ZOF_i>-*(p)6 zAyqOI(IKxUusgq7wW0eSjz$4zAxFQ&5g5gGR+d{r1$ zJuk*J>LvG0x%%?7*SWm!aiY|XqkVvykH4@*}g(?Dgs}2CE#WuL-9=vp-}eU zxz+#Q{exLe;QmKom69CR>Kd4y>|_XlG z220h5-azPZ#!2#44^Kc}0TsL|C)-|a=|^}?K(+$_IXc7?Fzlzrc#5~8GoK$DB4Ou+lW#t+DFWYanl_wy| znwgI9yI~s9_KR@R)|u)0Y68COzp6H*OU{5V0B7`Dctzm;*8^@AG8E4la%-X7-h~$%Y@C zY(f@;X)iNy!vyMW2>=<2*XbR)il60A*7SE+MFd_B5M}HDBM1x-WGrqmguoH4*@P~i zju;A5moaeSFdO;;2Vek6z&JX@5g=#i0bkXr@+WIa2UO+gM;rmNE;tMsvhQbAXjIWj z{Ru}}Fh=ubEb&94-pY(LaR0~`NLDkMV+c*m&<#^H0rww^su9%rE+Mlaf{dkcG2>;B zyjPY1)RIqv3m><9>RQe?NxZDIdGCL6+V;EQ^YdkWIeCR-an#GoFO)_1n7sMKFD|>- z=2Zdl>RA0#P?MurdWEvr@tT16g|bNqs&eEP{d>;J?tdLa*+IuElzo7Qq`;T`Q1U(J z2z41aqp#*|0bh1j@TwuJ83XqjF{|{K*vnj$RigzQ0bl7C%3c(_F+e(iar7mQ0C{0Q zfDE0O5{z*WU6LGfa@@%|=VMD)QAYaE&)-OnURq!nf z8S)He(c}+rzZbCf!Q`d=4o$@nxPQNy4ArT$L@M{;^z9Osfcy6gWheezg- z%PS&sErM01{;o>sAt^`biYb{Hx~&Di>^@czy~B0bc+@*_c(NIG?dWzz}f% z`c`fQ$VI?78ibqyau_gy1RGWx-4pIO<*c>9376adK4a~uKkAAkYW0gNLWWgfG#o}uhAZyyl9P%sHVRgP}r z2oQQgQ*p8L8+=ywN()rw=*t`d@^isq$PjwHIAT`X&zD6VUK3oA!4xTQ|F814v}6oz zKXCsWtRiy%TY{SbG7T6<|Hcs@qw4@BK!3qg0I#$s`MQ*v~7s}2HUX_vPN0KoBR=lhf z`r06G?Gu7CPW%S8zMIzs#4nVkFXZ@yvX4lx28K=t3?cB#2r@Qe1Oe4Xlrg%ldW5n= z!72h^ev8o~(d)$?X(T<2;1nRJM~!)evPlT4a`YfafcS;7F>s&2m!T;-!B%=HUc+y-|vR+E36^{^n}AF`GvB6FBpvcy6lM0cIoZ5j~Tj01NHpkvY}rn zdlamIqw^dA5_bUP=r~7!3_+I zzy*BSy5Nn43?<<7jhL18dnl&^UbD;5RU85G69FJYNt+=A(6xlyt%9EARx4A2Lq;Mx zi#xg{Aw zq3m961>FA&+zPn=xXsP_93A8cxc|Q3W`L{%#?g=?K!$SwG8F%cWQ>F44zTCkY-yD< zPLd;>0pjPxl{7);@6m^t9P0 z`OWu5p-)@%`^G-$X|J<=P^J#WirzzR4z%@H7j-2igr*JVGaKWnxzT9d`8 zS^k1Suf^L31l=QZGx{l8mO@4}=rTGa)%0=|kS-WYIt(FSb|be+I6@DFBsT*mW}jPu z6BD@q*L9SAk#7Yc@f3gz#UGQ5ao{^E3*vgvnCGlA7(cwR{;iw=@=t(q6bGCELiflX z>9SWSJ2>pol=ghV;F9oZY_#lSrJwb(q9DURl%3S#l}QG+JPEzbp764|BD~CYdd(y4=@i9|ilmTCcCbA`KKk@TrU|IqAGIW-NY?Yqx%A(01!5WJsL&*L6T~`OZEkFh# zfE<07BS4vpnu`KYKfD8iw8KP$wJ}($N zBw0-W*1W8Iey@uf{}xyQM{&p*AmqzDLfLHrsxpM`F`1F}{56)L1XVc#aT7N(KP^&> zV(lwkJe2LXK~;{v$q^v01ssMP0rwekD>Owan3-xZgnZd&xD{~!+uTY^##G1;#M>zfgAYZvJx}JnB%py?*8I0=+a>`BiIK{Sg$U;|||gK+c*~E|pzS zS(Efv%K9SK!SZpl*vb~UkRx>m|Lv8^kF$_UGnK>H_Mulwi?T+AVi3@;B+*~8C@#vH zDfIl!pEH$)jCz!{hPn)#`1jLSeu`UV8sqJ63DDad&2t1!OccuU_Llgqx#9)-Ba?dJ0*y^J7}boPyYYpdoV)Ra z+Ouk2mk$ zo;x$|*ZqEH=BnZ*`{ta_J@?%Aq(&D-91-L==fbH}ys+Hu{^Z6Diq)wS<_&voy9&pUQ* z`}nqP-?`oW_Mbk|*yC)vu%4cGOY42Rx^OQ2oYCu_6QO@zFSPsCwcFO(dAE2zwQjL3 zi>2>9AchZ~w+j!fTdf7Pb-M1Xc2Bx-S?)Mz4!hJjog?S0b8VM7*Gp_NFMfPWcld*8 zcI3dR6P*L*j%$2XJGEh!7PZ~=xvVuxJ zm%TFdr&3=j7P~#l%dmkg%&;=2@_9^E6x&JMhVhQX%$K6yWT@tgwzHMGoI1Cw6mzM% zfocS$t#sgbLAj`C?GYa|#Cp8<^{7L=A-nbb_#llAjl0jS^{i^i;y`Qd7bt7~+6tKC@)sl#4!_qbDA2Nvc|ZJpC|rgK26Q!8$6 zbt}_?{Nl1-xP!%kkgn%l$FKKkX>B^_`Q`U01PlgQTuk zH@Z@@R*|h=BQ@NL3iaZJLRaHqY=}SmmxY;Yj|Y883Ta(e#=ESxKC3c!w(F0@xcH5d z{a74;RMyF6Mxd---SMxB)v!qPaq9<7GFIy!<5(txXy4E65x3KCqik&DVEQg?(fFLy z9~Og7wKwTld$)2dHgZe97u2$+VUg`=Yk~eRbDM5XTpE$`mR(CwLfXF^wfwMe~gqfcZlj&P>LBYM~f?l`*mF5QLj>2h`+MnTV+FiVa=uO z@d^|ML*awh=X#>tMd!YqtF_Pe@my{9WUs8Hxmy4He6Cv8baxmT`X(op&umYj>|1T8 zd*6S$&?`cAvQ&;7k#%p|5|q;GDwmB2bMjZ&FL~9dVx+D0wxmD40Z)s`XqQ>p5fYGO z7h>r)iZHq4zJAM|Z=_n*EsvbJWdA&GDSn2PxnBGHm}tXzE?2I$geg_4%@up2v;NvY zJb~7FbQ5JzY>55nlrW2#lig2u*+#7ollKvP+BtEMUpn^RJCZ6FlJOSot4q z^@0z+3$H!5bogIi^^*S^qGDmy=qSlCP{!%iRCH4AA0NwnTZxIFd#hO7`J#r)>LS&7 z^pq=O(t5csmE^cTQMA$R1*w<+YnPW%^~;5oKMF^fBjH(77FK-NO?OzGYJ0QsQIm?I z94#boy5EN~zkl+gN5TbFwoT25jXy@pXt_`*56D3uu76sfLhz$(RGO}NdViDbFR4x& zV24jIIKuUXl8$qKw5hqJ3 z!~9l)>Xv>`7KunM2(fay7P~BUdU>OCU3Xeu@tu>+X z`m8lxvwl%87n58!neB|+m>d^e26yFFa=%lGq4dFplC(-O zkeb&AfU50}=6LFg{h=D0`Bc{AO~TLKn+vk9kU%I?+2Polw0F-Wm6m4G?#SlT+-$A9 z!se*>e5DwGa_2Qy;6S+4$m8j$C3k2PUV{)Ts{Pfx*{NJ$pT&;#BTzF7&oWciq-9=G z!jV*Lr0o1jyTZAyD%)lIOF58a`-@cenz4kb?6XBHBd1BL(CR{Yk15>L>nd6i%Y?0r z`0(IYOhi0W*-w3AhLxk`P#iA?ja>VM2r5^?&&6TV8b2AXIpW*>`^t%NnZDA zl1o!RN!~&1C6-rH*-`QeschCDO%YX6S*$F`MOBDXgvpn`TBGM{+9ajBkf*ZcBmt(f z*;gjDuklw@O`V|h8dyPM*~4f>Vi~)97;L$KC`EJ{5%J$o(5wx}+z4o#99Ma|Rn^9F z3)ttIfEf4@gTT%yKn#3>L11stfC%_NLLi{_rwuRyKA{Li^b{f_+1HQ}vYrr#XgO5~ zfjn8}15j6jtko`~>sXqW%9bsO6n89blQacnj{>4VQ5rxiCuWh#=JNxX%03-5<7!WH z9?&NOovW{N9MVPzsD7U-qiZf<&Qe8B^RS%QQMeVs{}UdaHmCZveot3=@TN3i3A`noI9CC6L*)}p;{{N_d_V+PX?j;ptX34-N?c(k+(?&ikTR!h1sqB|Y z2Z(M%M93iOEMJPcN2txplD@{s@3M$gwtVzE*_BKLC(~++IuZ+tx>AUn{DBkGzuSc6 zH=|P7F#H>IB*gBeID}shf#?d@KnF+}mddVS(=2Exs!aYs(Le?U5T>$D-eQD;;oog4 zuyO{FT?WKvW#dxWUIU%sK1wXvj7fO^AqYdvk;W+L{N%z|)%1 zkeOCUm>xMR`yy)#jEyoda_-TnRQ7DtF6+eYvXhFe2cT2~V&G~9fjt+M$_6J+8{CY* z*$KRk*==pzVyJDeF;mk@rFAxl)-db>d># zNj=#`S#zpY%9EwYRF++&iPHvQh@Ov1WzR(IvaPsX_O!y)K(elp5wb=YqHa_w8yU;) zME`_DhW`c96wx_Eg!FgBq_UAO7_h*CefAs3NGv1IF-a`DpwO8?M8+bCWnuR3{U~t8 zVi_65##A)QL>{m%s1?;j0#PU8e5lmv)D*AHh zzi-ftg#UM-6$$?v%DE)4G=VNtAaY`cqc+r~k=)jjE<$g;R!FFRC8Z%elgJHg2tn`M zQ44PN7z!nb;`d1TQ~e!U7euWX3Q>gZ;47} z*XQIX2PSk>;;m)xY-V{}IseVc8Ks+a{PzH7m8h$ie_RsruB9GysNrkOu6 z!-89Ff6c*TEHcmu3Vn;7%B<|?f++)hSJqwaHU^}1fZ~#*^j_Co30jhYa)Z->5eqcz zw$_C0Ty_m02EIg~0w%xd0R@keJ8G80$qaHx&J2H4rS4DHRnf9mOvH0>6RAA~{t2+V zUHT!y1N4yvyQ~9->W6+G8ItxD$O!p>A`noIyr2R`F1v3pLL|?>7a5YucZ0FABr?UQ zOsP(gI{uKC?-mRt@`Ax$j0MEuXI;$ru`MURUNo~j61&W#q&p zvFtedhYsb6Gmnsj|2Lu)8JqniDwUNk!|e=p=}zu3Nf+UI40K4SzLU}rN|F&#Hh(L^ z$ZbAsBFt>B5n<&vpNO$?U(hjT=CD{bXIa|2#bSAumHY49f*irTNejyiE)`Yom_g!c*x#A*+yzs#WGed)(lFd@3Y=X^0EL_54J7|IOhp^3G5MfSI3u;i8H=OfKho-Adb znOs+?IX_oXCW@U0@mLb$AGnx%j!jLPB6=b!m3>ZO796C>qW1R0%w%K_%NaL&F!n)RbEr_Zmo78=HT1teAx;gyI{!k+H1oeTtMBtR!2#sGJHd6|`hen83)n z9j?FXUso6|#-hgY4!9>81o9*-uU-lGO=BACRoRd6qNP{0Pe@hl-{^i|N1 zftM4c22i#P$dRLTMt%%2EGh(Slh_W78)fXF9QHV9A|qsxFhtMYfegvYf`pu;{Md~YOrc{rsB*_Tp9_06)Lgas1M9p?~ zI$?tf+Fgm+57;>OiZhzv0A;NJaP?v5icp$AP{Su{63aAiU#0R@iHKuKzxIXRvjm+H z?<>_6m?+CT8R6W6{0eo5BJ;Ai%h&7sacvBsY}o=!fw*T7kzu#lB4&W>TLDSd0j0Rd ztkmd=JQ4@n0pVeDj-;}<-L9+98Is7~$%y=N;XHPLBzv1i2qgP38J}R~mQEox3~DU!}w3n7vpk&%a18yXoQ_Y;QbC$Xt4HU*L$0>r>ZlTlz%J2vL=qE5Gumv2{RRkozw(L<1|=2m#gaib`cS zB$bWmayL8mp<6#Cr~?}6@~z*UI1@vT+Ku8!1zYSuprt@LK~*Dm)J8jj0^wl=?pna_o08X3wsL9kVO9G&oOLC zNN-_nK=yZFIk<62wE~7}_SwU;=aHOyBq~YGo>k5n>?9zUlK@cFKVdpZYijVHB^Jy+ z%QN!0q2^|!?2`K%J*IMAUy9g9n4 z_q&)4I72!>WE)YBt`{XpnV_`_ba@Df2yA5C+dh>I<_9p9{WDpygftIOE6}NGuauv9 z3Tnt9xj-&nI%p>Aza0=8c0WKXLIw#!gJ?kmBjMlqPJEj+21YJlVB_3vgdt+Dv7nWEiZDc(ib-YV zED5Jz*{tk0Ni4uFPsF9N@~=2)jjaRnFOmt)KIGPrb0Y90>YcHvEH(w=e~U4quy6fp zXxEon*)S@RBF(aLFHgZT^+19Fre#*4HCU-SoT(8|q8k~F(~m2^N_B`)R#gDveIB8}@P zyOnHt-Nb84Pas2*y#*N|FYX`^(3U(qiYV-jY-}d`BBtyWBQ?|T$5E+lzlHDDpzG|Y zFpWGQshaq2q*N?@EQ=UHF(Xk@LH$ddmF-s6a*B1ECmIHyd56(vqMCVSp^j%g7=5Uueh%3Y#J&XY?NtXNX=%kQqQ(T=>5X4cWQXOVF&1 z=pICbM2vlD6?MIoX(>r%XP2WgD?7U!pI2lYhwV~1sd`3XPa6X&0TGbyAP`YpEKB23*}dqWkO5%?8Nv`fhKP{9A`sCHQK@X) ztY)`?{*gp}?duh6=`^rkYAoAS;NKZU7@pZo#xZP2QrUq}7>5k=WhH2w_udb!9ZNC-Ponmds22>PhEL@0$_@;!1|e}bOan!l0+M$!V&0Yg6f|U@-(WOk zmW(nI%OX?R-JyGY_f#xiMJtPlO)D5Q+kuFL|4p@SsT#`B0}PBn0kgZMf5F1 zggm*AKtRXa3K)X)XBr`rlMQ5qNcs>_KB*#%Tx2R674h7~B&JIjm&)F&W1O8xVyxV* zD61bvS!E{5Ok!C?Dr;4gv$*gdm&&>%s>`dRtmGeijF^?(YDPKxT9noE37Q!|>^UZh zWj}_7j>NKV3(ZI@BbP4{{x6{~r;!;%D%A>_@FBMwB z-9Lt&bQ_#&_qgjFY~J%yZBf^xQgsujjJ(EPUDP#S>Ao^yyXyFbz>!xEgE!ZzwK85K zqwFbp5?ij-9mADG|9v%V?|t~9hD%uZQ5JTQf|WZhkMcvRLf~`)h=Eam{#^9ZXdhR% zXtZtYx~fBWcF+hBZjV^3qZJ{W%J!D#TIYL9YVqZsb&Ka^Y{K}L-}|3`-!q$f{(Z;o z_1pJYo6M(aFoJcv{Lu%07L0ePf==azX{o)qE{g@5E)9pPmQDkAa*_5;waj{px3n(? P>uLDSvxRl}qV)d(zp)l* diff --git a/fpga/fpga.ucf b/fpga/fpga.ucf index 2592043..9ab0eef 100644 --- a/fpga/fpga.ucf +++ b/fpga/fpga.ucf @@ -8,151 +8,262 @@ CONFIG PROHIBIT = "P154"; # DOUT TIMESPEC "TS_clock29M" = PERIOD "clock29M" 29.4500 MHz HIGH 50 %; #TIMESPEC "TS_clock19M" = PERIOD "clock19M" 19.6608 MHz HIGH 50 %; -NET "clockIn29M" LOC = "P160"; -NET "clock29M" TNM = "clock29M"; -#NET "clockIn19M" LOC = "P207"; -#NET "clock19M" TNM = "clock19M"; +NET "clockIn29M" LOC = "P160"; +NET "clock29M" TNM_NET = "clock29M"; +NET "clockIn19M" LOC = "P207"; +#NET "clock19M" TNM_NET = "clock19M"; ## Host interface -NET "nHostRead" LOC = "P146"; -NET "nHostWrite" LOC = "P145"; -NET "nHostEnable" LOC = "P142"; +TIMESPEC "TS_hostAddress" = FROM "hostAddress" TO "FFS" "TS_clock29M" / 1; +TIMESPEC "TS_hostDataIn" = FROM "hostData" TO "FFS" "TS_clock29M" / 1; +TIMESPEC "TS_hostDataOut" = FROM "FFS" TO "hostData" "TS_clock29M" / 1; -NET "hostAddress[0]" LOC = "P117"; -NET "hostAddress[1]" LOC = "P116"; -NET "hostAddress[2]" LOC = "P115"; -NET "hostAddress[3]" LOC = "P114"; -NET "hostAddress[4]" LOC = "P113"; -NET "hostAddress[5]" LOC = "P112"; -NET "hostAddress[6]" LOC = "P110"; +NET "nHostRead" LOC = "P146"; +NET "nHostRead" TNM_NET = "hostControl"; +NET "nHostWrite" LOC = "P145"; +NET "nHostWrite" TNM_NET = "hostControl"; +NET "nHostEnable" LOC = "P142"; +NET "nHostEnable" TNM_NET = "hostControl"; -NET "hostData[0]" LOC = "P138"; -NET "hostData[1]" LOC = "P137"; -NET "hostData[2]" LOC = "P136"; -NET "hostData[3]" LOC = "P135"; -NET "hostData[4]" LOC = "P134"; -NET "hostData[5]" LOC = "P133"; -NET "hostData[6]" LOC = "P132"; -NET "hostData[7]" LOC = "P129"; -NET "hostData[8]" LOC = "P128"; -NET "hostData[9]" LOC = "P127"; -NET "hostData[10]" LOC = "P126"; -NET "hostData[11]" LOC = "P125"; -NET "hostData[12]" LOC = "P124"; -NET "hostData[13]" LOC = "P123"; -NET "hostData[14]" LOC = "P122"; -NET "hostData[15]" LOC = "P120"; +NET "hostAddress[0]" LOC = "P117"; +NET "hostAddress[0]" TNM_NET = "hostAddress"; +NET "hostAddress[1]" LOC = "P116"; +NET "hostAddress[1]" TNM_NET = "hostAddress"; +NET "hostAddress[2]" LOC = "P115"; +NET "hostAddress[2]" TNM_NET = "hostAddress"; +NET "hostAddress[3]" LOC = "P114"; +NET "hostAddress[3]" TNM_NET = "hostAddress"; +NET "hostAddress[4]" LOC = "P113"; +NET "hostAddress[4]" TNM_NET = "hostAddress"; +NET "hostAddress[5]" LOC = "P112"; +NET "hostAddress[5]" TNM_NET = "hostAddress"; +NET "hostAddress[6]" LOC = "P110"; +NET "hostAddress[6]" TNM_NET = "hostAddress"; + +NET "hostData[0]" LOC = "P138"; +NET "hostData[0]" TNM_NET = "hostData"; +NET "hostData[1]" LOC = "P137"; +NET "hostData[1]" TNM_NET = "hostData"; +NET "hostData[2]" LOC = "P136"; +NET "hostData[2]" TNM_NET = "hostData"; +NET "hostData[3]" LOC = "P135"; +NET "hostData[3]" TNM_NET = "hostData"; +NET "hostData[4]" LOC = "P134"; +NET "hostData[4]" TNM_NET = "hostData"; +NET "hostData[5]" LOC = "P133"; +NET "hostData[5]" TNM_NET = "hostData"; +NET "hostData[6]" LOC = "P132"; +NET "hostData[6]" TNM_NET = "hostData"; +NET "hostData[7]" LOC = "P129"; +NET "hostData[7]" TNM_NET = "hostData"; +NET "hostData[8]" LOC = "P128"; +NET "hostData[8]" TNM_NET = "hostData"; +NET "hostData[9]" LOC = "P127"; +NET "hostData[9]" TNM_NET = "hostData"; +NET "hostData[10]" LOC = "P126"; +NET "hostData[10]" TNM_NET = "hostData"; +NET "hostData[11]" LOC = "P125"; +NET "hostData[11]" TNM_NET = "hostData"; +NET "hostData[12]" LOC = "P124"; +NET "hostData[12]" TNM_NET = "hostData"; +NET "hostData[13]" LOC = "P123"; +NET "hostData[13]" TNM_NET = "hostData"; +NET "hostData[14]" LOC = "P122"; +NET "hostData[14]" TNM_NET = "hostData"; +NET "hostData[15]" LOC = "P120"; +NET "hostData[15]" TNM_NET = "hostData"; ## SRAM interface -NET "nSRAMRead" LOC = "P40"; +NET "nSRAMRead" LOC = "P40"; +NET "nSRAMRead" TNM_NET = "sramControl"; NET "nSRAMRead" FAST; -NET "nSRAMWrite" LOC = "P55"; +NET "nSRAMWrite" LOC = "P55"; +NET "nSRAMWrite" TNM_NET = "sramControl"; NET "nSRAMWrite" FAST; -NET "nSRAMEnable" LOC = "P34"; +NET "nSRAMEnable" LOC = "P34"; +NET "nSRAMEnable" TNM_NET = "sramControl"; NET "nSRAMEnable" FAST; -NET "sramAddress[0]" LOC = "P30"; -NET "sramAddress[1]" LOC = "P32"; -NET "sramAddress[2]" LOC = "P35"; -NET "sramAddress[3]" LOC = "P37"; -NET "sramAddress[4]" LOC = "P41"; -NET "sramAddress[5]" LOC = "P43"; -NET "sramAddress[6]" LOC = "P45"; -NET "sramAddress[7]" LOC = "P47"; -NET "sramAddress[8]" LOC = "P46"; -NET "sramAddress[9]" LOC = "P44"; -NET "sramAddress[10]" LOC = "P36"; -NET "sramAddress[11]" LOC = "P42"; -NET "sramAddress[12]" LOC = "P49"; -NET "sramAddress[13]" LOC = "P48"; -NET "sramAddress[14]" LOC = "P56"; -NET "sramAddress[15]" LOC = "P58"; -NET "sramAddress[16]" LOC = "P57"; +NET "sramAddress[0]" LOC = "P30"; +NET "sramAddress[0]" TNM_NET = "sramAddress"; +NET "sramAddress[1]" LOC = "P32"; +NET "sramAddress[0]" TNM_NET = "sramAddress"; +NET "sramAddress[2]" LOC = "P35"; +NET "sramAddress[0]" TNM_NET = "sramAddress"; +NET "sramAddress[3]" LOC = "P37"; +NET "sramAddress[0]" TNM_NET = "sramAddress"; +NET "sramAddress[4]" LOC = "P41"; +NET "sramAddress[0]" TNM_NET = "sramAddress"; +NET "sramAddress[5]" LOC = "P43"; +NET "sramAddress[0]" TNM_NET = "sramAddress"; +NET "sramAddress[6]" LOC = "P45"; +NET "sramAddress[0]" TNM_NET = "sramAddress"; +NET "sramAddress[7]" LOC = "P47"; +NET "sramAddress[0]" TNM_NET = "sramAddress"; +NET "sramAddress[8]" LOC = "P46"; +NET "sramAddress[0]" TNM_NET = "sramAddress"; +NET "sramAddress[9]" LOC = "P44"; +NET "sramAddress[0]" TNM_NET = "sramAddress"; +NET "sramAddress[10]" LOC = "P36"; +NET "sramAddress[10]" TNM_NET = "sramAddress"; +NET "sramAddress[11]" LOC = "P42"; +NET "sramAddress[11]" TNM_NET = "sramAddress"; +NET "sramAddress[12]" LOC = "P49"; +NET "sramAddress[12]" TNM_NET = "sramAddress"; +NET "sramAddress[13]" LOC = "P48"; +NET "sramAddress[13]" TNM_NET = "sramAddress"; +NET "sramAddress[14]" LOC = "P56"; +NET "sramAddress[14]" TNM_NET = "sramAddress"; +NET "sramAddress[15]" LOC = "P58"; +NET "sramAddress[15]" TNM_NET = "sramAddress"; +NET "sramAddress[16]" LOC = "P57"; +NET "sramAddress[16]" TNM_NET = "sramAddress"; -NET "sramData[0]" LOC = "P28"; -NET "sramData[1]" LOC = "P24"; -NET "sramData[2]" LOC = "P22"; -NET "sramData[3]" LOC = "P21"; -NET "sramData[4]" LOC = "P23"; -NET "sramData[5]" LOC = "P27"; -NET "sramData[6]" LOC = "P29"; -NET "sramData[7]" LOC = "P31"; +NET "sramData[0]" LOC = "P28"; +NET "sramData[0]" TNM_NET = "sramData"; +NET "sramData[1]" LOC = "P24"; +NET "sramData[1]" TNM_NET = "sramData"; +NET "sramData[2]" LOC = "P22"; +NET "sramData[2]" TNM_NET = "sramData"; +NET "sramData[3]" LOC = "P21"; +NET "sramData[3]" TNM_NET = "sramData"; +NET "sramData[4]" LOC = "P23"; +NET "sramData[4]" TNM_NET = "sramData"; +NET "sramData[5]" LOC = "P27"; +NET "sramData[5]" TNM_NET = "sramData"; +NET "sramData[6]" LOC = "P29"; +NET "sramData[6]" TNM_NET = "sramData"; +NET "sramData[7]" LOC = "P31"; +NET "sramData[7]" TNM_NET = "sramData"; ## DRAM interface # TODO: trace these pins out -NET "dramControl[0]" LOC = "P188"; -NET "dramControl[1]" LOC = "P189"; -NET "dramControl[2]" LOC = "P190"; -NET "dramControl[3]" LOC = "P191"; -NET "dramControl[4]" LOC = "P193"; -NET "dramControl[5]" LOC = "P194"; -NET "dramControl[6]" LOC = "P196"; -NET "dramControl[7]" LOC = "P197"; -NET "dramControl[8]" LOC = "P198"; -NET "dramControl[9]" LOC = "P199"; -NET "dramControl[10]" LOC = "P200"; -NET "dramControl[11]" LOC = "P201"; +NET "dramControl[0]" LOC = "P188"; +NET "dramControl[0]" TNM_NET = "dramControl"; +NET "dramControl[1]" LOC = "P189"; +NET "dramControl[1]" TNM_NET = "dramControl"; +NET "dramControl[2]" LOC = "P190"; +NET "dramControl[2]" TNM_NET = "dramControl"; +NET "dramControl[3]" LOC = "P191"; +NET "dramControl[3]" TNM_NET = "dramControl"; +NET "dramControl[4]" LOC = "P193"; +NET "dramControl[4]" TNM_NET = "dramControl"; +NET "dramControl[5]" LOC = "P194"; +NET "dramControl[5]" TNM_NET = "dramControl"; +NET "dramControl[6]" LOC = "P196"; +NET "dramControl[6]" TNM_NET = "dramControl"; +NET "dramControl[7]" LOC = "P197"; +NET "dramControl[7]" TNM_NET = "dramControl"; +NET "dramControl[8]" LOC = "P198"; +NET "dramControl[8]" TNM_NET = "dramControl"; +NET "dramControl[9]" LOC = "P199"; +NET "dramControl[9]" TNM_NET = "dramControl"; +NET "dramControl[10]" LOC = "P200"; +NET "dramControl[10]" TNM_NET = "dramControl"; +NET "dramControl[11]" LOC = "P201"; +NET "dramControl[11]" TNM_NET = "dramControl"; -NET "dramAddress[0]" LOC = "P186"; -NET "dramAddress[1]" LOC = "P184"; -NET "dramAddress[2]" LOC = "P180"; -NET "dramAddress[3]" LOC = "P178"; -NET "dramAddress[4]" LOC = "P176"; -NET "dramAddress[5]" LOC = "P174"; -NET "dramAddress[6]" LOC = "P175"; -NET "dramAddress[7]" LOC = "P177"; -NET "dramAddress[8]" LOC = "P179"; -NET "dramAddress[9]" LOC = "P181"; -NET "dramAddress[10]" LOC = "P185"; -NET "dramAddress[11]" LOC = "P187"; +NET "dramAddress[0]" LOC = "P186"; +NET "dramAddress[0]" TNM_NET = "dramAddress"; +NET "dramAddress[1]" LOC = "P184"; +NET "dramAddress[1]" TNM_NET = "dramAddress"; +NET "dramAddress[2]" LOC = "P180"; +NET "dramAddress[2]" TNM_NET = "dramAddress"; +NET "dramAddress[3]" LOC = "P178"; +NET "dramAddress[3]" TNM_NET = "dramAddress"; +NET "dramAddress[4]" LOC = "P176"; +NET "dramAddress[4]" TNM_NET = "dramAddress"; +NET "dramAddress[5]" LOC = "P174"; +NET "dramAddress[5]" TNM_NET = "dramAddress"; +NET "dramAddress[6]" LOC = "P175"; +NET "dramAddress[6]" TNM_NET = "dramAddress"; +NET "dramAddress[7]" LOC = "P177"; +NET "dramAddress[7]" TNM_NET = "dramAddress"; +NET "dramAddress[8]" LOC = "P179"; +NET "dramAddress[8]" TNM_NET = "dramAddress"; +NET "dramAddress[9]" LOC = "P181"; +NET "dramAddress[9]" TNM_NET = "dramAddress"; +NET "dramAddress[10]" LOC = "P185"; +NET "dramAddress[10]" TNM_NET = "dramAddress"; +NET "dramAddress[11]" LOC = "P187"; +NET "dramAddress[11]" TNM_NET = "dramAddress"; -NET "dramData[0]" LOC = "P15"; -NET "dramData[1]" LOC = "P14"; -NET "dramData[2]" LOC = "P10"; -NET "dramData[3]" LOC = "P8"; -NET "dramData[4]" LOC = "P2"; -NET "dramData[5]" LOC = "P206"; -NET "dramData[6]" LOC = "P205"; -NET "dramData[7]" LOC = "P204"; -NET "dramData[8]" LOC = "P3"; -NET "dramData[9]" LOC = "P4"; -NET "dramData[10]" LOC = "P5"; -NET "dramData[11]" LOC = "P9"; -NET "dramData[12]" LOC = "P11"; -NET "dramData[13]" LOC = "P17"; -NET "dramData[14]" LOC = "P19"; -NET "dramData[15]" LOC = "P20"; +NET "dramData[0]" LOC = "P15"; +NET "dramData[0]" TNM_NET = "dramData"; +NET "dramData[1]" LOC = "P14"; +NET "dramData[1]" TNM_NET = "dramData"; +NET "dramData[2]" LOC = "P10"; +NET "dramData[2]" TNM_NET = "dramData"; +NET "dramData[3]" LOC = "P8"; +NET "dramData[3]" TNM_NET = "dramData"; +NET "dramData[4]" LOC = "P2"; +NET "dramData[4]" TNM_NET = "dramData"; +NET "dramData[5]" LOC = "P206"; +NET "dramData[5]" TNM_NET = "dramData"; +NET "dramData[6]" LOC = "P205"; +NET "dramData[6]" TNM_NET = "dramData"; +NET "dramData[7]" LOC = "P204"; +NET "dramData[7]" TNM_NET = "dramData"; +NET "dramData[8]" LOC = "P3"; +NET "dramData[8]" TNM_NET = "dramData"; +NET "dramData[9]" LOC = "P4"; +NET "dramData[9]" TNM_NET = "dramData"; +NET "dramData[10]" LOC = "P5"; +NET "dramData[10]" TNM_NET = "dramData"; +NET "dramData[11]" LOC = "P9"; +NET "dramData[11]" TNM_NET = "dramData"; +NET "dramData[12]" LOC = "P11"; +NET "dramData[12]" TNM_NET = "dramData"; +NET "dramData[13]" LOC = "P17"; +NET "dramData[13]" TNM_NET = "dramData"; +NET "dramData[14]" LOC = "P19"; +NET "dramData[14]" TNM_NET = "dramData"; +NET "dramData[15]" LOC = "P20"; +NET "dramData[15]" TNM_NET = "dramData"; ## MP3 decoder interface -NET "mp3Reset" LOC = "P152"; -NET "mp3Ready" LOC = "P159"; -NET "mp3ClockIn" LOC = "P163"; -NET "mp3ClockOut" LOC = "P162"; -NET "mp3SDA" LOC = "P150"; -NET "mp3SCL" LOC = "P151"; +NET "mp3ClockIn" LOC = "P163"; +NET "mp3ClockIn" TNM_NET = "mp3Clock"; +NET "mp3ClockOut" LOC = "P162"; +NET "mp3ClockOut" TNM_NET = "mp3Clock"; + +NET "mp3Reset" LOC = "P152"; +NET "mp3Ready" LOC = "P159"; +NET "mp3SDA" LOC = "P150"; +NET "mp3SCL" LOC = "P151"; NET "mp3StatusCS" LOC = "P149"; NET "mp3StatusError" LOC = "P168"; NET "mp3StatusFrameSync" LOC = "P161"; NET "mp3StatusDataReq" LOC = "P148"; -NET "mp3InSDIN" LOC = "P167"; -NET "mp3InBCLK" LOC = "P164"; -NET "mp3InLRCK" LOC = "P166"; -NET "mp3OutSDOUT" LOC = "P172"; -NET "mp3OutBCLK" LOC = "P169"; -NET "mp3OutLRCK" LOC = "P171"; +NET "mp3InSDIN" LOC = "P167"; +NET "mp3InSDIN" TNM_NET = "mp3Data"; +NET "mp3InBCLK" LOC = "P164"; +NET "mp3InBCLK" TNM_NET = "mp3Data"; +NET "mp3InLRCK" LOC = "P166"; +NET "mp3InLRCK" TNM_NET = "mp3Data"; +NET "mp3OutSDOUT" LOC = "P172"; +NET "mp3OutSDOUT" TNM_NET = "mp3Data"; +NET "mp3OutBCLK" LOC = "P169"; +NET "mp3OutBCLK" TNM_NET = "mp3Data"; +NET "mp3OutLRCK" LOC = "P171"; +NET "mp3OutLRCK" TNM_NET = "mp3Data"; ## I2S audio output -NET "dacSDIN" LOC = "P96"; -NET "dacBCLK" LOC = "P94"; -NET "dacLRCK" LOC = "P95"; -NET "dacMCLK" LOC = "P97"; +NET "dacSDIN" LOC = "P96"; +NET "dacSDIN" TNM_NET = "dacData"; +NET "dacBCLK" LOC = "P94"; +NET "dacBCLK" TNM_NET = "dacData"; +NET "dacLRCK" LOC = "P95"; +NET "dacLRCK" TNM_NET = "dacData"; +NET "dacMCLK" LOC = "P97"; +NET "dacMCLK" TNM_NET = "dacData"; ## Light outputs @@ -186,16 +297,25 @@ NET "lightBankD[3]" LOC = "P59"; ## Serial interfaces # TODO: are pins 98 and 99 swapped? -NET "networkTXEnable" LOC = "P98"; -NET "networkTX" LOC = "P99"; -NET "networkRX" LOC = "P100"; +NET "networkTXEnable" LOC = "P98"; +NET "networkTXEnable" TNM_NET = "network"; +NET "networkTX" LOC = "P99"; +NET "networkTX" TNM_NET = "network"; +NET "networkRX" LOC = "P100"; +NET "networkRX" TNM_NET = "network"; -NET "serialTX" LOC = "P89"; -NET "serialRX" LOC = "P88"; -NET "serialRTS" LOC = "P93"; -NET "serialCTS" LOC = "P90"; -NET "serialDTR" LOC = "P87"; -NET "serialDSR" LOC = "P85"; +NET "serialTX" LOC = "P89"; +NET "serialTX" TNM_NET = "serial"; +NET "serialRX" LOC = "P88"; +NET "serialRX" TNM_NET = "serial"; +NET "serialRTS" LOC = "P93"; +NET "serialRTS" TNM_NET = "serial"; +NET "serialCTS" LOC = "P90"; +NET "serialCTS" TNM_NET = "serial"; +NET "serialDTR" LOC = "P87"; +NET "serialDTR" TNM_NET = "serial"; +NET "serialDSR" LOC = "P85"; +NET "serialDSR" TNM_NET = "serial"; ## 1-wire bus diff --git a/fpga/fpga.ys b/fpga/fpga.ys index 40f0991..bf8e291 100644 --- a/fpga/fpga.ys +++ b/fpga/fpga.ys @@ -1,16 +1,17 @@ # This script is roughly similar to the built-in synth_xilinx command, with the # appropriate modifications made in order to output gate netlists rather than -# precompiled LUTs. Note that more advanced features such as fast carry or -# distributed LUT RAM are not yet supported. +# precompiled LUTs (which are not supported by the ISE mapper for Spartan-XL +# devices). Note that more advanced features such as fast carry or distributed +# LUT RAMs are not yet supported. ## Input and preliminary optimization read_verilog src/main.v -read_verilog src/spartanxl.v +read_verilog src/spartanxl/primitives.v hierarchy -check -top FPGA proc -flatten -noscopeinfo +flatten tribuf -logic deminout opt_expr @@ -25,15 +26,16 @@ opt_clean ## Conversion to gate-level representation +techmap -D LUT_WIDTH=4 -map +/cmp2lut.v -map +/cmp2lcu.v alumacc share opt memory -nomap opt_clean - +memory_map opt -full -simplemap -techmap -D NOLUT -D LUT_SIZE=4 -map +/techmap.v -map +/xilinx/arith_map.v + +techmap -map +/techmap.v opt -fast clean @@ -41,25 +43,26 @@ clean dfflegalize -cell $_DFFE_PP?P_ r -cell $_DLATCH_PP?_ r opt_expr -mux_undef -noclkinv -abc -g gates -xilinx_dffopt -lut4 +abc -liberty src/spartanxl/primitives.lib +clean -#clkbufmap -buf BUFGLS O:I +#hilomap -hicell VCC P -locell GND G iopadmap -bits -inpad IBUF O:I -ignore IPAD IPAD -ignore OPAD OPAD -ignore IOPAD IOPAD -ignore IFDX D -ignore IFDXI D -ignore BUFGLS I -iopadmap -bits -outpad OBUF I:O -toutpad OBUFT ~T:I:O -tinoutpad IOBUFT ~T:O:I:IO -ignore IPAD IPAD -ignore OPAD OPAD -ignore IOPAD IOPAD -ignore OFDX Q -ignore OFDXI Q -ignore OFDTX O -ignore OFDTXI O -extractinv -inv INV O:I -techmap -map src/techmap.v +iopadmap -bits -outpad OBUF I:O -toutpad OBUFE E:I:O -tinoutpad IOBUFE E:O:I:IO -ignore IPAD IPAD -ignore OPAD OPAD -ignore IOPAD IOPAD -ignore OFDX Q -ignore OFDXI Q -ignore OFDTX O -ignore OFDTXI O +clkbufmap -buf BUFGLS O:I +#extractinv -inv INV O:I + +techmap -map src/spartanxl/map.v clean ## Output -# FIXME: for some reason invoking hierarchy here results in $or/$reduce_or -# primitives being added back when using wired-or -#hierarchy -check +hierarchy -check autoname stat -tech xilinx check -noinit blackbox =A:whitebox +show -notitle -colors 1 -format dot -viewer none -prefix build/synth write_verilog -noattr build/synth.v write_edif -top FPGA -pvector bra -lsbidx build/synth.edf diff --git a/fpga/runISE.bat b/fpga/runISE.bat index 62d5861..c8663c8 100755 --- a/fpga/runISE.bat +++ b/fpga/runISE.bat @@ -2,9 +2,9 @@ setlocal set TARGET=xcs40xl-pq208-4 -set COVER_MODE=area +set COVER_MODE=speed set OPTIMIZATION_MODE=speed -set OPTIMIZATION_LEVEL=high +set OPTIMIZATION_LEVEL=normal if not exist "%XILINX%\bin\nt\" ( echo The XILINX environment variable must be set to the root of a valid ^ diff --git a/fpga/src/main.v b/fpga/src/main.v index 66a0028..a2770f7 100644 --- a/fpga/src/main.v +++ b/fpga/src/main.v @@ -22,10 +22,11 @@ module FPGA ( output [11:0] dramAddress, inout [15:0] dramData, - output mp3Reset, - input mp3Ready, output mp3ClockIn, input mp3ClockOut, + + output mp3Reset, + input mp3Ready, inout mp3SDA, inout mp3SCL, @@ -69,113 +70,99 @@ module FPGA ( /* Register definitions */ - localparam SYS573D_FPGA_MAGIC = 8'h80; + function automatic [5:0] _hostReg (input [7:0] address); + _hostReg = address[6:1]; + endfunction - localparam SYS573D_FPGA_MP3_PTR_H = 8'ha0; - localparam SYS573D_FPGA_MP3_PTR_L = 8'ha2; - localparam SYS573D_FPGA_MP3_ENDPTR_H = 8'ha4; - localparam SYS573D_FPGA_MP3_ENDPTR_L = 8'ha6; - localparam SYS573D_FPGA_MP3_COUNTER = 8'ha8; - localparam SYS573D_FPGA_MP3_KEY1 = 8'ha8; - localparam SYS573D_FPGA_MP3_FEED_STAT = 8'haa; - localparam SYS573D_FPGA_MP3_I2C = 8'hac; - localparam SYS573D_FPGA_MP3_FEED_CTRL = 8'hae; + localparam SYS573D_FPGA_MAGIC = _hostReg(8'h80); + localparam SYS573D_FPGA_VERSION = _hostReg(8'h82); - localparam SYS573D_FPGA_DRAM_WRPTR_H = 8'hb0; - localparam SYS573D_FPGA_DRAM_WRPTR_L = 8'hb2; - localparam SYS573D_FPGA_DRAM_DATA = 8'hb4; - localparam SYS573D_FPGA_DRAM_RDPTR_H = 8'hb6; - localparam SYS573D_FPGA_DRAM_RDPTR_L = 8'hb8; + localparam SYS573D_FPGA_MP3_PTR_H = _hostReg(8'ha0); + localparam SYS573D_FPGA_MP3_PTR_L = _hostReg(8'ha2); + localparam SYS573D_FPGA_MP3_ENDPTR_H = _hostReg(8'ha4); + localparam SYS573D_FPGA_MP3_ENDPTR_L = _hostReg(8'ha6); + localparam SYS573D_FPGA_MP3_COUNTER = _hostReg(8'ha8); + localparam SYS573D_FPGA_MP3_KEY1 = _hostReg(8'ha8); + localparam SYS573D_FPGA_MP3_FEED_STAT = _hostReg(8'haa); + localparam SYS573D_FPGA_MP3_I2C = _hostReg(8'hac); + localparam SYS573D_FPGA_MP3_FEED_CTRL = _hostReg(8'hae); - localparam SYS573D_FPGA_NET_DATA = 8'hc0; - localparam SYS573D_FPGA_DAC_COUNTER_H = 8'hca; - localparam SYS573D_FPGA_DAC_COUNTER_L = 8'hcc; - localparam SYS573D_FPGA_DAC_COUNTER_D = 8'hce; + localparam SYS573D_FPGA_DRAM_WRPTR_H = _hostReg(8'hb0); + localparam SYS573D_FPGA_DRAM_WRPTR_L = _hostReg(8'hb2); + localparam SYS573D_FPGA_DRAM_DATA = _hostReg(8'hb4); + localparam SYS573D_FPGA_DRAM_RDPTR_H = _hostReg(8'hb6); + localparam SYS573D_FPGA_DRAM_RDPTR_L = _hostReg(8'hb8); - localparam SYS573D_FPGA_LIGHTS_AH = 8'he0; - localparam SYS573D_FPGA_LIGHTS_AL = 8'he2; - localparam SYS573D_FPGA_LIGHTS_BH = 8'he4; - localparam SYS573D_FPGA_LIGHTS_D = 8'he6; - localparam SYS573D_FPGA_INIT = 8'he8; - localparam SYS573D_FPGA_MP3_KEY2 = 8'hea; - localparam SYS573D_FPGA_MP3_KEY3 = 8'hec; - localparam SYS573D_FPGA_DS_BUS = 8'hee; + localparam SYS573D_FPGA_NET_DATA = _hostReg(8'hc0); + localparam SYS573D_FPGA_DAC_COUNTER_H = _hostReg(8'hca); + localparam SYS573D_FPGA_DAC_COUNTER_L = _hostReg(8'hcc); + localparam SYS573D_FPGA_DAC_COUNTER_D = _hostReg(8'hce); + + localparam SYS573D_FPGA_LIGHTS_AH = _hostReg(8'he0); + localparam SYS573D_FPGA_LIGHTS_AL = _hostReg(8'he2); + localparam SYS573D_FPGA_LIGHTS_BH = _hostReg(8'he4); + localparam SYS573D_FPGA_LIGHTS_D = _hostReg(8'he6); + localparam SYS573D_FPGA_INIT = _hostReg(8'he8); + localparam SYS573D_FPGA_MP3_KEY2 = _hostReg(8'hea); + localparam SYS573D_FPGA_MP3_KEY3 = _hostReg(8'hec); + localparam SYS573D_FPGA_DS_BUS = _hostReg(8'hee); /* System clocks */ - wire clock29M, clock19M; - // ISE rejects global buffer primitives unless they are wired either to an // IBUF (which results in suboptimal routing, as the dedicated IOB clock // output is left unused) or directly to a pad primitive. - IPAD clockPad29M (.IPAD(clockIn29M)); - IPAD clockPad19M (.IPAD(clockIn19M)); - BUFGLS clockBuf29M (.I(clockIn29M), .O(clock29M)); - BUFGLS clockBuf19M (.I(clockIn19M), .O(clock19M)); + wire clock29M; + IPAD _clockPad29M (.IPAD(clockIn29M)); + BUFGLS _clockBuf29M (.I(clockIn29M), .O(clock29M)); - /* Host address decoding */ + wire clock19M; + IPAD _clockPad19M (.IPAD(clockIn19M)); + BUFGLS _clockBuf19M (.I(clockIn19M), .O(clock19M)); + + /* Host interface */ + + wire _hostWriteLatchIn = ~nHostWrite & ~nHostEnable; + wire _hostWriteLatch; + BUFGLS _hostWriteLatchBuf (.I(_hostWriteLatchIn), .O(_hostWriteLatch)); + + reg [6:0] hostRegAddress; + reg [15:0] hostReadData; + reg [15:0] hostWriteData; + + always @(posedge clock29M) + hostRegAddress <= hostAddress; + always @(negedge _hostWriteLatch) + hostWriteData <= hostData; + + /* Read/write strobe edge detector */ + + reg [1:0] _hostReadState = 2'b00; + reg [1:0] _hostWriteState = 2'b00; + + always @(posedge clock29M) begin + _hostReadState <= { _hostReadState[0], ~nHostRead & ~nHostEnable }; + _hostWriteState <= { _hostWriteState[0], ~nHostWrite & ~nHostEnable }; + end + + wire hostReadAsserted = (_hostReadState == 2'b01); + wire hostReadReleased = (_hostReadState == 2'b10); + wire hostWriteAsserted = (_hostWriteState == 2'b01); + wire hostWriteReleased = (_hostWriteState == 2'b10); // The FPGA shall only respond to addresses in 0x80-0xef range, as 0xf0-0xff // is used by the CPLD and 0x00-0x7f seems to be reserved for debugging // hardware. Bit 0 of the 573's address bus is not wired to the FPGA as all // registers are 16 bits wide. - wire hostAddrValid = hostAddress[6] & (hostAddress[5:3] != 3'b111); - wire hostRegRead = ~nHostEnable & ~nHostRead & nHostWrite; - wire hostRegWrite = ~nHostEnable & nHostRead & ~nHostWrite; + reg _hostDataDir = 1'b0; + assign hostData = _hostDataDir ? hostReadData : 16'hzzzz; - wire [7:0] hostRegister = { 1'b1, hostAddress[5:0], 1'b0 }; - - /* Host interface */ - - reg [2:0] _delayedHostRegRead = 3'b000; - wire _hostDataInClock; - - wire [15:0] hostDataIn; - wor [15:0] hostDataOut; - - reg hostDataInValid = 1'b0; - reg hostDataOutValid = 1'b0; - - // Data is latched in the input flip flops once the 573 *deasserts* either - // the chip select or the write strobe. Konami's bitstream routes this - // signal through a global net (_hostDataInClock), possibly since it is - // asynchronous and not tied to the main clock. - BUFGLS hostDataInUpdateBuf(.I(hostRegWrite), .O(_hostDataInClock)); - - wire hostDataInPending = ~hostRegWrite & hostDataInValid; - - always @(posedge clock29M) begin - // Konami's bitstream pulls the output flip flops' clock enable low - // after 3 cycles if the register being read is in 0xa0-0xaf range (i.e. - // MP3 status and counters), in order to prevent any further updates - // while the counters are running. A 3-bit shift register is used to - // implement the delay. - _delayedHostRegRead <= { _delayedHostRegRead[1:0], hostRegRead }; - - // The direction of the bus is only changed on clock edges in order to - // prevent any data from being output before the output flip flops are - // updated. - hostDataInValid <= hostRegWrite; - hostDataOutValid <= hostAddrValid & hostRegRead; - end - - generate - for (i = 0; i < 16; i = i + 1) begin - IFDX hostDataInReg ( - .D(hostData[i]), - .C(~_hostDataInClock), - .CE(1'b1), - .Q(hostDataIn[i]) - ); - OFDTX hostDataOutReg ( - .D(hostDataOut[i]), - .C(clock29M), - .CE(~_delayedHostRegRead[2]), - .T(~hostDataOutValid), - .O(hostData[i]) - ); - end - endgenerate + always @(posedge clock29M) + _hostDataDir <= 1'b1 + & ~nHostRead + & ~nHostEnable + & hostAddress[6] + & (hostAddress[5:3] != 3'b111); /* SRAM interface (currently unused) */ @@ -191,29 +178,26 @@ module FPGA ( /* MP3 decoder interface (currently unused) */ - assign mp3Reset = 1'b1; + reg mp3SDAIn; + reg mp3SDAOut = 1'b1; + reg mp3SCLIn; + reg mp3SCLOut = 1'b1; + assign mp3ClockIn = 1'b1; + assign mp3Reset = 1'b1; assign mp3StatusCS = 1'b1; assign mp3InSDIN = 1'b1; assign mp3InBCLK = 1'b1; assign mp3InLRCK = 1'b1; - assign hostDataOut = (hostRegister == SYS573D_FPGA_MP3_I2C) - ? { 2'h0, mp3SCL, mp3SDA, 12'h000 } - : 16'h0000; + assign mp3SDA = mp3SDAOut ? 1'bz : 1'b0; + assign mp3SCL = mp3SCLOut ? 1'bz : 1'b0; - reg mp3SDAState = 1'b0; - reg mp3SCLState = 1'b0; - - always @(posedge clock29M) - if (hostDataInPending & (hostRegister == SYS573D_FPGA_MP3_I2C)) begin - mp3SDAState <= hostDataIn[12]; - mp3SCLState <= hostDataIn[13]; - end - - assign mp3SDA = mp3SDAState ? 1'bz : 1'b0; - assign mp3SCL = mp3SCLState ? 1'bz : 1'b0; + always @(posedge clock29M) begin + mp3SDAIn <= mp3SDA; + mp3SCLIn <= mp3SCL; + end /* I2S audio output */ @@ -222,39 +206,23 @@ module FPGA ( assign dacLRCK = mp3OutLRCK; assign dacMCLK = mp3ClockOut; - /* Magic number */ - - assign hostDataOut = (hostRegister == SYS573D_FPGA_MAGIC) - ? 16'h573f - : 16'h0000; - /* Light outputs */ + reg [3:0] lightBankAHState = 4'b1111; + reg [3:0] lightBankALState = 4'b1111; + reg [3:0] lightBankBHState = 4'b1111; + reg [3:0] lightBankDState = 4'b1111; + generate for (i = 0; i < 4; i = i + 1) begin - reg [3:0] lightBankState = 4'b1111; - - wire dataIn = hostDataIn[i + 12]; - - always @(posedge clock29M) - if (hostDataInPending) - case (hostRegister) - SYS573D_FPGA_LIGHTS_AH: - lightBankState[0] <= dataIn; - SYS573D_FPGA_LIGHTS_AL: - lightBankState[1] <= dataIn; - SYS573D_FPGA_LIGHTS_BH: - lightBankState[2] <= dataIn; - SYS573D_FPGA_LIGHTS_D: - lightBankState[3] <= dataIn; - endcase - - // Note that XCS40XL IOBs actually have a tristate flip flop, but - // there seems to be no primitive exposed by ISE to force its usage. - assign lightBankAH[i] = lightBankState[0] ? 1'bz : 1'b0; - assign lightBankAL[i] = lightBankState[1] ? 1'bz : 1'b0; - assign lightBankBH[i] = lightBankState[2] ? 1'bz : 1'b0; - assign lightBankD[i] = lightBankState[3] ? 1'bz : 1'b0; + // Note that XCS40XL IOBs actually have a built-in tristate flip + // flop, but ISE will not use it here as it does not have a clock + // enable input (used to gate writes to the state registers) and + // cannot be read back nor configured to be set on startup. + assign lightBankAH[i] = lightBankAHState[i] ? 1'bz : 1'b0; + assign lightBankAL[i] = lightBankALState[i] ? 1'bz : 1'b0; + assign lightBankBH[i] = lightBankBHState[i] ? 1'bz : 1'b0; + assign lightBankD[i] = lightBankDState[i] ? 1'bz : 1'b0; end endgenerate @@ -269,21 +237,81 @@ module FPGA ( /* 1-wire bus */ - assign hostDataOut = (hostRegister == SYS573D_FPGA_DS_BUS) - ? { 3'h0, ds2401, 3'h0, ds2433, 8'h00 } - : 16'h0000; - - reg ds2433State = 1'b0; - reg ds2401State = 1'b0; - - always @(posedge clock29M) - if (hostDataInPending & (hostRegister == SYS573D_FPGA_DS_BUS)) begin - ds2433State <= hostDataIn[8]; - ds2401State <= hostDataIn[12]; - end + reg ds2433In; + reg ds2433Out = 1'b0; + reg ds2401In; + reg ds2401Out = 1'b0; // The 1-wire pins are pulled low by writing 1 (rather than 0) to the // respective register bits, but not inverted when read. - assign ds2433 = ds2433State ? 1'b0 : 1'bz; - assign ds2401 = ds2401State ? 1'b0 : 1'bz; + assign ds2433 = ds2433Out ? 1'b0 : 1'bz; + assign ds2401 = ds2401Out ? 1'b0 : 1'bz; + + always @(posedge clock29M) begin + ds2433In <= ds2433; + ds2401In <= ds2401; + end + + /* Host registers */ + + always @(posedge clock29M) + case (hostRegAddress[5:0]) + SYS573D_FPGA_MAGIC: begin + hostReadData <= 16'h573f; + end + + SYS573D_FPGA_VERSION: begin + hostReadData <= 16'h0001; + end + + SYS573D_FPGA_MP3_I2C: begin + hostReadData <= { 2'h0, mp3SCLIn, mp3SDAIn, 12'h000 }; + + if (hostWriteReleased) begin + mp3SDAOut <= hostWriteData[12]; + mp3SCLOut <= hostWriteData[13]; + end + end + + SYS573D_FPGA_LIGHTS_AH: begin + hostReadData <= { lightBankAHState, 12'h000 }; + + if (hostWriteReleased) + lightBankAHState <= hostWriteData[15:12]; + end + + SYS573D_FPGA_LIGHTS_AL: begin + hostReadData <= { lightBankALState, 12'h000 }; + + if (hostWriteReleased) + lightBankALState <= hostWriteData[15:12]; + end + + SYS573D_FPGA_LIGHTS_BH: begin + hostReadData <= { lightBankBHState, 12'h000 }; + + if (hostWriteReleased) + lightBankBHState <= hostWriteData[15:12]; + end + + SYS573D_FPGA_LIGHTS_D: begin + hostReadData <= { lightBankDState, 12'h000 }; + + if (hostWriteReleased) + lightBankDState <= hostWriteData[15:12]; + end + + SYS573D_FPGA_DS_BUS: begin + hostReadData <= { 3'h0, ds2401In, 3'h0, ds2433In, 8'h00 }; + + if (hostWriteReleased) begin + ds2433Out <= hostWriteData[8]; + ds2401Out <= hostWriteData[12]; + end + end + + default: begin + hostReadData <= 16'hxxxx; + end + endcase endmodule diff --git a/fpga/src/spartanxl.v b/fpga/src/spartanxl.v deleted file mode 100644 index c90839c..0000000 --- a/fpga/src/spartanxl.v +++ /dev/null @@ -1,368 +0,0 @@ - -/* Logic primitives */ - -module BUF (input I, output O); -`ifndef SYNTHESIS - assign O = I; -`endif -endmodule - -module INV (input I, output O); -`ifndef SYNTHESIS - assign O = ~I; -`endif -endmodule - -module AND2 (input I0, input I1, output O); -`ifndef SYNTHESIS - assign O = I0 & I1; -`endif -endmodule - -module NAND2 (input I0, input I1, output O); -`ifndef SYNTHESIS - assign O = ~(I0 & I1); -`endif -endmodule - -module AND2B1 (input I0, input I1, output O); -`ifndef SYNTHESIS - assign O = I0 & ~I1; -`endif -endmodule - -module OR2 (input I0, input I1, output O); -`ifndef SYNTHESIS - assign O = I0 | I1; -`endif -endmodule - -module NOR2 (input I0, input I1, output O); -`ifndef SYNTHESIS - assign O = ~(I0 | I1); -`endif -endmodule - -module OR2B1 (input I0, input I1, output O); -`ifndef SYNTHESIS - assign O = I0 | ~I1; -`endif -endmodule - -module XOR2 (input I0, input I1, output O); -`ifndef SYNTHESIS - assign O = (I0 != I1); -`endif -endmodule - -module XNOR2 (input I0, input I1, output O); -`ifndef SYNTHESIS - assign O = (I0 == I1); -`endif -endmodule - -module BUFT (input I, input T, output O); -`ifndef SYNTHESIS - assign O = T ? 1'bz : I; -`endif -endmodule - -module FDCE (input D, input C, input CLR, input CE, output Q); -`ifndef SYNTHESIS - reg data; - assign Q = data; - - initial - data = 1'b0; - always @(CLR) - data <= 1'b0; - always @(posedge C) - data <= CE ? D : data; -`endif -endmodule - -module FDPE (input D, input C, input PRE, input CE, output Q); -`ifndef SYNTHESIS - reg data; - assign Q = data; - - initial - data = 1'b1; - always @(PRE) - data <= 1'b1; - always @(posedge C) - data <= CE ? D : data; -`endif -endmodule - -module LDCE_1 (input D, input G, input CLR, input GE, output Q); -`ifndef SYNTHESIS - reg data; - assign Q = data; - - initial - data = 1'b0; - always @(CLR) - data <= 1'b0; - always @(~G) - data <= GE ? D : data; -`endif -endmodule - -module LDPE_1 (input D, input G, input PRE, input GE, output Q); -`ifndef SYNTHESIS - reg data; - assign Q = data; - - initial - data = 1'b1; - always @(PRE) - data <= 1'b1; - always @(~G) - data <= GE ? D : data; -`endif -endmodule - -/* I/O primitives */ - -(* keep *) module BUFGLS (input I, output O); -`ifndef SYNTHESIS - BUF buffer (.I(I), .O(O)); -`endif -endmodule - -(* keep *) module IBUF (input I, output O); -`ifndef SYNTHESIS - BUF buffer (.I(I), .O(O)); -`endif -endmodule - -(* keep *) module OBUF (input I, output O); -`ifndef SYNTHESIS - BUF buffer (.I(I), .O(O)); -`endif -endmodule - -(* keep *) module OBUFT (input I, input T, output O); -`ifndef SYNTHESIS - BUFT buffer (.I(I), .T(T), .O(O)); -`endif -endmodule - -(* keep *) module IOBUFT (input I, input T, output O, inout IO); -`ifndef SYNTHESIS - assign O = IO; - - BUFT buffer (.I(I), .T(T), .O(IO)); -`endif -endmodule - -(* keep *) module IFDX (input D, input C, input CE, output Q); -`ifndef SYNTHESIS - reg data; - assign Q = data; - - initial - data = 1'b0; - always @(posedge C) - data <= CE ? D : data; -`endif -endmodule - -(* keep *) module IFDXI (input D, input C, input CE, output Q); -`ifndef SYNTHESIS - reg data; - assign Q = data; - - initial - data = 1'b1; - always @(posedge C) - data <= CE ? D : data; -`endif -endmodule - -(* keep *) module OFDX (input D, input C, input CE, output Q); -`ifndef SYNTHESIS - IFDX ff (.D(D), .C(C), .CE(CE), .Q(Q)); -`endif -endmodule - -(* keep *) module OFDXI (input D, input C, input CE, output Q); -`ifndef SYNTHESIS - IFDXI ff (.D(D), .C(C), .CE(CE), .Q(Q)); -`endif -endmodule - -(* keep *) module OFDTX (input D, input C, input CE, input T, output O); -`ifndef SYNTHESIS - wire Q; - - IFDX ff (.D(D), .C(C), .CE(CE), .Q(Q)); - BUFT buffer (.I(Q), .T(T), .O(O)); -`endif -endmodule - -(* keep *) module OFDTXI (input D, input C, input CE, input T, output O); -`ifndef SYNTHESIS - wire Q; - - IFDXI ff (.D(D), .C(C), .CE(CE), .Q(Q)); - BUFT buffer (.I(Q), .T(T), .O(O)); -`endif -endmodule - -/* I/O pads */ - -(* keep *) module IPAD (output IPAD); -endmodule - -(* keep *) module OPAD (input OPAD); -endmodule - -(* keep *) module IOPAD (inout IOPAD); -endmodule - -(* keep *) module UPAD (inout UPAD); -endmodule - -(* keep *) module TDI (inout I); -endmodule - -(* keep *) module TDO (input O); -endmodule - -(* keep *) module TCK (inout I); -endmodule - -(* keep *) module TMS (inout I); -endmodule - -/* Fixed-function blocks (not simulated) */ - -(* keep *) module STARTUP ( - input GSR, - input GTS, - input CLK, - - output DONEIN, - output Q1Q4, - output Q2, - output Q3 -); -endmodule - -(* keep *) module OSC4 ( - output F8M, - output F500K, - output F16K, - output F490, - output F15 -); -endmodule - -(* keep *) module BSCAN( - input TDI, - input TDO1, - input TDO2, - input TCK, - input TMS, - - output TDO, - output DRCK, - output IDLE, - output SEL1, - output SEL2 -); -endmodule - -(* keep *) module RDBK (input TRIG, output DATA, output RIP); -endmodule - -(* keep *) module RDCLK (input I); -endmodule - -/* ISE built-in macros */ - -module CC8CE ( - input C, input CLR, input CE, output [7:0] Q, output CEO, output TC -); -`ifndef SYNTHESIS - reg [7:0] data; - - assign Q = data; - assign TC = &data; - assign CEO = TC & CE; - - initial - data = 8'h00; - always @(CLR) - data <= 8'h00; - always @(posedge C) - data <= data + CE; -`endif -endmodule - -module CC8CLE ( - input [7:0] D, input L, input C, input CLR, input CE, output [7:0] Q, - output CEO, output TC -); -`ifndef SYNTHESIS - reg [7:0] data; - - assign Q = data; - assign TC = &data; - assign CEO = TC & CE; - - initial - data = 8'h00; - always @(CLR) - data <= 8'h00; - always @(posedge C) - if (L) - data <= D; - else - data <= data + CE; -`endif -endmodule - -module CC16CE ( - input C, input CLR, input CE, output [15:0] Q, output CEO, output TC -); -`ifndef SYNTHESIS - reg [15:0] data; - - assign Q = data; - assign TC = &data; - assign CEO = TC & CE; - - initial - data = 16'h0000; - always @(CLR) - data <= 16'h0000; - always @(posedge C) - data <= data + CE; -`endif -endmodule - -module CC16CLE ( - input [15:0] D, input L, input C, input CLR, input CE, output [15:0] Q, - output CEO, output TC -); -`ifndef SYNTHESIS - reg [15:0] data; - - assign Q = data; - assign TC = &data; - assign CEO = TC & CE; - - initial - data = 16'h0000; - always @(CLR) - data <= 16'h0000; - always @(posedge C) - if (L) - data <= D; - else - data <= data + CE; -`endif -endmodule diff --git a/fpga/src/spartanxl/map.v b/fpga/src/spartanxl/map.v new file mode 100644 index 0000000..79f7c64 --- /dev/null +++ b/fpga/src/spartanxl/map.v @@ -0,0 +1,37 @@ + +/* I/O cells */ + +module OBUFE (input I, input E, output O); + wire T; + + INV _TECHMAP_REPLACE_.inv (.I(E), .O(T)); + OBUFT _TECHMAP_REPLACE_.obuf (.I(I), .T(T), .O(O)); +endmodule + +module IOBUFE (input I, input E, output O, inout IO); + wire T; + + INV _TECHMAP_REPLACE_.inv (.I(E), .O(T)); + OBUFT _TECHMAP_REPLACE_.obuf (.I(I), .T(T), .O(IO)); + IBUF _TECHMAP_REPLACE_.ibuf (.I(IO), .O(O)); +endmodule + +/* Flip flops and latches */ + +// The dfflibmap command does not currently support mapping memory cells with an +// enable input, so these have to be declared here rather than in spartanxl.lib. +module \$_DFFE_PP0P_ (input D, input C, input R, input E, output Q); + FDCE _TECHMAP_REPLACE_ (.D(D), .C(C), .CLR(R), .CE(E), .Q(Q)); +endmodule + +module \$_DFFE_PP1P_ (input D, input C, input R, input E, output Q); + FDPE _TECHMAP_REPLACE_ (.D(D), .C(C), .PRE(R), .CE(E), .Q(Q)); +endmodule + +module \$_DLATCH_PP0_ (input E, input R, input D, output Q); + LDCE_1 _TECHMAP_REPLACE_ (.D(D), .G(E), .CLR(R), .GE(1'b1), .Q(Q)); +endmodule + +module \$_DLATCH_PP1_ (input E, input R, input D, output Q); + LDPE_1 _TECHMAP_REPLACE_ (.D(D), .G(E), .PRE(R), .GE(1'b1), .Q(Q)); +endmodule diff --git a/fpga/src/spartanxl/primitives.lib b/fpga/src/spartanxl/primitives.lib new file mode 100644 index 0000000..f8d4eaf --- /dev/null +++ b/fpga/src/spartanxl/primitives.lib @@ -0,0 +1,551 @@ + +library(spartanxl) { + /* Buffers */ + + cell(BUF) { + area: 1; + pin(I) { direction: input; } + pin(O) { direction: output; function: "I"; } + } + cell(INV) { + area: 1; + pin(I) { direction: input; } + pin(O) { direction: output; function: "!I"; } + } + + /* AND gates */ + + cell(AND2) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(O) { direction: output; function: "I0*I1"; } + } + cell(AND2B1) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(O) { direction: output; function: "!I0*I1"; } + } + + cell(AND3) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(O) { direction: output; function: "I0*I1*I2"; } + } + cell(AND3B1) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(O) { direction: output; function: "!I0*I1*I2"; } + } + cell(AND3B2) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(O) { direction: output; function: "!I0*!I1*I2"; } + } + + cell(AND4) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(O) { direction: output; function: "I0*I1*I2*I3"; } + } + cell(AND4B1) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(O) { direction: output; function: "!I0*I1*I2*I3"; } + } + cell(AND4B2) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(O) { direction: output; function: "!I0*!I1*I2*I3"; } + } + cell(AND4B3) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(O) { direction: output; function: "!I0*!I1*!I2*I3"; } + } + + cell(AND5) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(I4) { direction: input; } + pin(O) { direction: output; function: "I0*I1*I2*I3*I4"; } + } + cell(AND5B1) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(I4) { direction: input; } + pin(O) { direction: output; function: "!I0*I1*I2*I3*I4"; } + } + cell(AND5B2) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(I4) { direction: input; } + pin(O) { direction: output; function: "!I0*!I1*I2*I3*I4"; } + } + cell(AND5B3) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(I4) { direction: input; } + pin(O) { direction: output; function: "!I0*!I1*!I2*I3*I4"; } + } + cell(AND5B4) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(I4) { direction: input; } + pin(O) { direction: output; function: "!I0*!I1*!I2*!I3*I4"; } + } + + /* NAND gates */ + + cell(NAND2) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(O) { direction: output; function: "!(I0*I1)"; } + } + cell(NAND2B1) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(O) { direction: output; function: "!(!I0*I1)"; } + } + + cell(NAND3) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(O) { direction: output; function: "!(I0*I1*I2)"; } + } + cell(NAND3B1) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(O) { direction: output; function: "!(!I0*I1*I2)"; } + } + cell(NAND3B2) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(O) { direction: output; function: "!(!I0*!I1*I2)"; } + } + + cell(NAND4) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(O) { direction: output; function: "!(I0*I1*I2*I3)"; } + } + cell(NAND4B1) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(O) { direction: output; function: "!(!I0*I1*I2*I3)"; } + } + cell(NAND4B2) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(O) { direction: output; function: "!(!I0*!I1*I2*I3)"; } + } + cell(NAND4B3) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(O) { direction: output; function: "!(!I0*!I1*!I2*I3)"; } + } + + cell(NAND5) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(I4) { direction: input; } + pin(O) { direction: output; function: "!(I0*I1*I2*I3*I4)"; } + } + cell(NAND5B1) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(I4) { direction: input; } + pin(O) { direction: output; function: "!(!I0*I1*I2*I3*I4)"; } + } + cell(NAND5B2) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(I4) { direction: input; } + pin(O) { direction: output; function: "!(!I0*!I1*I2*I3*I4)"; } + } + cell(NAND5B3) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(I4) { direction: input; } + pin(O) { direction: output; function: "!(!I0*!I1*!I2*I3*I4)"; } + } + cell(NAND5B4) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(I4) { direction: input; } + pin(O) { direction: output; function: "!(!I0*!I1*!I2*!I3*I4)"; } + } + + /* OR gates */ + + cell(OR2) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(O) { direction: output; function: "I0+I1"; } + } + cell(OR2B1) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(O) { direction: output; function: "!I0+I1"; } + } + + cell(OR3) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(O) { direction: output; function: "I0+I1+I2"; } + } + cell(OR3B1) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(O) { direction: output; function: "!I0+I1+I2"; } + } + cell(OR3B2) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(O) { direction: output; function: "!I0+!I1+I2"; } + } + + cell(OR4) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(O) { direction: output; function: "I0+I1+I2+I3"; } + } + cell(OR4B1) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(O) { direction: output; function: "!I0+I1+I2+I3"; } + } + cell(OR4B2) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(O) { direction: output; function: "!I0+!I1+I2+I3"; } + } + cell(OR4B3) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(O) { direction: output; function: "!I0+!I1+!I2+I3"; } + } + + cell(OR5) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(I4) { direction: input; } + pin(O) { direction: output; function: "I0+I1+I2+I3+I4"; } + } + cell(OR5B1) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(I4) { direction: input; } + pin(O) { direction: output; function: "!I0+I1+I2+I3+I4"; } + } + cell(OR5B2) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(I4) { direction: input; } + pin(O) { direction: output; function: "!I0+!I1+I2+I3+I4"; } + } + cell(OR5B3) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(I4) { direction: input; } + pin(O) { direction: output; function: "!I0+!I1+!I2+I3+I4"; } + } + cell(OR5B4) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(I4) { direction: input; } + pin(O) { direction: output; function: "!I0+!I1+!I2+!I3+I4"; } + } + + /* NOR gates */ + + cell(NOR2) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(O) { direction: output; function: "!(I0+I1)"; } + } + cell(NOR2B1) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(O) { direction: output; function: "!(!I0+I1)"; } + } + + cell(NOR3) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(O) { direction: output; function: "!(I0+I1+I2)"; } + } + cell(NOR3B1) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(O) { direction: output; function: "!(!I0+I1+I2)"; } + } + cell(NOR3B2) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(O) { direction: output; function: "!(!I0+!I1+I2)"; } + } + + cell(NOR4) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(O) { direction: output; function: "!(I0+I1+I2+I3)"; } + } + cell(NOR4B1) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(O) { direction: output; function: "!(!I0+I1+I2+I3)"; } + } + cell(NOR4B2) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(O) { direction: output; function: "!(!I0+!I1+I2+I3)"; } + } + cell(NOR4B3) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(O) { direction: output; function: "!(!I0+!I1+!I2+I3)"; } + } + + cell(NOR5) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(I4) { direction: input; } + pin(O) { direction: output; function: "!(I0+I1+I2+I3+I4)"; } + } + cell(NOR5B1) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(I4) { direction: input; } + pin(O) { direction: output; function: "!(!I0+I1+I2+I3+I4)"; } + } + cell(NOR5B2) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(I4) { direction: input; } + pin(O) { direction: output; function: "!(!I0+!I1+I2+I3+I4)"; } + } + cell(NOR5B3) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(I4) { direction: input; } + pin(O) { direction: output; function: "!(!I0+!I1+!I2+I3+I4)"; } + } + cell(NOR5B4) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(I4) { direction: input; } + pin(O) { direction: output; function: "!(!I0+!I1+!I2+!I3+I4)"; } + } + + /* XOR gates */ + + cell(XOR2) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(O) { direction: output; function: "I0^I1"; } + } + + cell(XOR3) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(O) { direction: output; function: "I0^I1^I2"; } + } + + cell(XOR4) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(O) { direction: output; function: "I0^I1^I2^I3"; } + } + + cell(XOR5) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(I4) { direction: input; } + pin(O) { direction: output; function: "I0^I1^I2^I3^I4"; } + } + + /* XNOR gates */ + + cell(XNOR2) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(O) { direction: output; function: "!(I0^I1)"; } + } + + cell(XNOR3) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(O) { direction: output; function: "!(I0^I1^I2)"; } + } + + cell(XNOR4) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(O) { direction: output; function: "!(I0^I1^I2^I3)"; } + } + + cell(XNOR5) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(I4) { direction: input; } + pin(O) { direction: output; function: "!(I0^I1^I2^I3^I4)"; } + } +} diff --git a/fpga/src/spartanxl/primitives.v b/fpga/src/spartanxl/primitives.v new file mode 100644 index 0000000..99eaffc --- /dev/null +++ b/fpga/src/spartanxl/primitives.v @@ -0,0 +1,646 @@ + +/* Constants */ + +module VCC (output P); +`ifndef SYNTHESIS + assign P = 1'b1; +`endif +endmodule + +module GND (output G); +`ifndef SYNTHESIS + assign G = 1'b0; +`endif +endmodule + +/* Buffers */ + +module BUF (input I, output O); +`ifndef SYNTHESIS + assign O = I; +`endif +endmodule + +module BUFT (input I, input T, output O); +`ifndef SYNTHESIS + assign O = T ? 1'bz : I; +`endif +endmodule + +module INV (input I, output O); +`ifndef SYNTHESIS + assign O = ~I; +`endif +endmodule + +/* AND gates */ + +module AND2 (input I0, input I1, output O); +`ifndef SYNTHESIS + assign O = I0 & I1; +`endif +endmodule + +module AND2B1 (input I0, input I1, output O); +`ifndef SYNTHESIS + assign O = ~I0 & I1; +`endif +endmodule + +module AND3 (input I0, input I1, input I2, output O); +`ifndef SYNTHESIS + assign O = I0 & I1 & I2; +`endif +endmodule + +module AND3B1 (input I0, input I1, input I2, output O); +`ifndef SYNTHESIS + assign O = ~I0 & I1 & I2; +`endif +endmodule + +module AND3B2 (input I0, input I1, input I2, output O); +`ifndef SYNTHESIS + assign O = ~I0 & ~I1 & I2; +`endif +endmodule + +module AND4 (input I0, input I1, input I2, input I3, output O); +`ifndef SYNTHESIS + assign O = I0 & I1 & I2 & I3; +`endif +endmodule + +module AND4B1 (input I0, input I1, input I2, input I3, output O); +`ifndef SYNTHESIS + assign O = ~I0 & I1 & I2 & I3; +`endif +endmodule + +module AND4B2 (input I0, input I1, input I2, input I3, output O); +`ifndef SYNTHESIS + assign O = ~I0 & ~I1 & I2 & I3; +`endif +endmodule + +module AND4B3 (input I0, input I1, input I2, input I3, output O); +`ifndef SYNTHESIS + assign O = ~I0 & ~I1 & ~I2 & I3; +`endif +endmodule + +module AND5 (input I0, input I1, input I2, input I3, input I4, output O); +`ifndef SYNTHESIS + assign O = I0 & I1 & I2 & I3 & I4; +`endif +endmodule + +module AND5B1 (input I0, input I1, input I2, input I3, input I4, output O); +`ifndef SYNTHESIS + assign O = ~I0 & I1 & I2 & I3 & I4; +`endif +endmodule + +module AND5B2 (input I0, input I1, input I2, input I3, input I4, output O); +`ifndef SYNTHESIS + assign O = ~I0 & ~I1 & I2 & I3 & I4; +`endif +endmodule + +module AND5B3 (input I0, input I1, input I2, input I3, input I4, output O); +`ifndef SYNTHESIS + assign O = ~I0 & ~I1 & ~I2 & I3 & I4; +`endif +endmodule + +module AND5B4 (input I0, input I1, input I2, input I3, input I4, output O); +`ifndef SYNTHESIS + assign O = ~I0 & ~I1 & ~I2 & ~I3 & I4; +`endif +endmodule + +/* NAND gates */ + +module NAND2 (input I0, input I1, output O); +`ifndef SYNTHESIS + assign O = ~(I0 & I1); +`endif +endmodule + +module NAND2B1 (input I0, input I1, output O); +`ifndef SYNTHESIS + assign O = ~(~I0 & I1); +`endif +endmodule + +module NAND3 (input I0, input I1, input I2, output O); +`ifndef SYNTHESIS + assign O = ~(I0 & I1 & I2); +`endif +endmodule + +module NAND3B1 (input I0, input I1, input I2, output O); +`ifndef SYNTHESIS + assign O = ~(~I0 & I1 & I2); +`endif +endmodule + +module NAND3B2 (input I0, input I1, input I2, output O); +`ifndef SYNTHESIS + assign O = ~(~I0 & ~I1 & I2); +`endif +endmodule + +module NAND4 (input I0, input I1, input I2, input I3, output O); +`ifndef SYNTHESIS + assign O = ~(I0 & I1 & I2 & I3); +`endif +endmodule + +module NAND4B1 (input I0, input I1, input I2, input I3, output O); +`ifndef SYNTHESIS + assign O = ~(~I0 & I1 & I2 & I3); +`endif +endmodule + +module NAND4B2 (input I0, input I1, input I2, input I3, output O); +`ifndef SYNTHESIS + assign O = ~(~I0 & ~I1 & I2 & I3); +`endif +endmodule + +module NAND4B3 (input I0, input I1, input I2, input I3, output O); +`ifndef SYNTHESIS + assign O = ~(~I0 & ~I1 & ~I2 & I3); +`endif +endmodule + +module NAND5 (input I0, input I1, input I2, input I3, input I4, output O); +`ifndef SYNTHESIS + assign O = ~(I0 & I1 & I2 & I3 & I4); +`endif +endmodule + +module NAND5B1 (input I0, input I1, input I2, input I3, input I4, output O); +`ifndef SYNTHESIS + assign O = ~(~I0 & I1 & I2 & I3 & I4); +`endif +endmodule + +module NAND5B2 (input I0, input I1, input I2, input I3, input I4, output O); +`ifndef SYNTHESIS + assign O = ~(~I0 & ~I1 & I2 & I3 & I4); +`endif +endmodule + +module NAND5B3 (input I0, input I1, input I2, input I3, input I4, output O); +`ifndef SYNTHESIS + assign O = ~(~I0 & ~I1 & ~I2 & I3 & I4); +`endif +endmodule + +module NAND5B4 (input I0, input I1, input I2, input I3, input I4, output O); +`ifndef SYNTHESIS + assign O = ~(~I0 & ~I1 & ~I2 & ~I3 & I4); +`endif +endmodule + +/* OR gates */ + +module OR2 (input I0, input I1, output O); +`ifndef SYNTHESIS + assign O = I0 | I1; +`endif +endmodule + +module OR2B1 (input I0, input I1, output O); +`ifndef SYNTHESIS + assign O = ~I0 | I1; +`endif +endmodule + +module OR3 (input I0, input I1, input I2, output O); +`ifndef SYNTHESIS + assign O = I0 | I1 | I2; +`endif +endmodule + +module OR3B1 (input I0, input I1, input I2, output O); +`ifndef SYNTHESIS + assign O = ~I0 | I1 | I2; +`endif +endmodule + +module OR3B2 (input I0, input I1, input I2, output O); +`ifndef SYNTHESIS + assign O = ~I0 | ~I1 | I2; +`endif +endmodule + +module OR4 (input I0, input I1, input I2, input I3, output O); +`ifndef SYNTHESIS + assign O = I0 | I1 | I2 | I3; +`endif +endmodule + +module OR4B1 (input I0, input I1, input I2, input I3, output O); +`ifndef SYNTHESIS + assign O = ~I0 | I1 | I2 | I3; +`endif +endmodule + +module OR4B2 (input I0, input I1, input I2, input I3, output O); +`ifndef SYNTHESIS + assign O = ~I0 | ~I1 | I2 | I3; +`endif +endmodule + +module OR4B3 (input I0, input I1, input I2, input I3, output O); +`ifndef SYNTHESIS + assign O = ~I0 | ~I1 | ~I2 | I3; +`endif +endmodule + +module OR5 (input I0, input I1, input I2, input I3, input I4, output O); +`ifndef SYNTHESIS + assign O = I0 | I1 | I2 | I3 | I4; +`endif +endmodule + +module OR5B1 (input I0, input I1, input I2, input I3, input I4, output O); +`ifndef SYNTHESIS + assign O = ~I0 | I1 | I2 | I3 | I4; +`endif +endmodule + +module OR5B2 (input I0, input I1, input I2, input I3, input I4, output O); +`ifndef SYNTHESIS + assign O = ~I0 | ~I1 | I2 | I3 | I4; +`endif +endmodule + +module OR5B3 (input I0, input I1, input I2, input I3, input I4, output O); +`ifndef SYNTHESIS + assign O = ~I0 | ~I1 | ~I2 | I3 | I4; +`endif +endmodule + +module OR5B4 (input I0, input I1, input I2, input I3, input I4, output O); +`ifndef SYNTHESIS + assign O = ~I0 | ~I1 | ~I2 | ~I3 | I4; +`endif +endmodule + +/* NOR gates */ + +module NOR2 (input I0, input I1, output O); +`ifndef SYNTHESIS + assign O = ~(I0 | I1); +`endif +endmodule + +module NOR2B1 (input I0, input I1, output O); +`ifndef SYNTHESIS + assign O = ~(~I0 | I1); +`endif +endmodule + +module NOR3 (input I0, input I1, input I2, output O); +`ifndef SYNTHESIS + assign O = ~(I0 | I1 | I2); +`endif +endmodule + +module NOR3B1 (input I0, input I1, input I2, output O); +`ifndef SYNTHESIS + assign O = ~(~I0 | I1 | I2); +`endif +endmodule + +module NOR3B2 (input I0, input I1, input I2, output O); +`ifndef SYNTHESIS + assign O = ~(~I0 | ~I1 | I2); +`endif +endmodule + +module NOR4 (input I0, input I1, input I2, input I3, output O); +`ifndef SYNTHESIS + assign O = ~(I0 | I1 | I2 | I3); +`endif +endmodule + +module NOR4B1 (input I0, input I1, input I2, input I3, output O); +`ifndef SYNTHESIS + assign O = ~(~I0 | I1 | I2 | I3); +`endif +endmodule + +module NOR4B2 (input I0, input I1, input I2, input I3, output O); +`ifndef SYNTHESIS + assign O = ~(~I0 | ~I1 | I2 | I3); +`endif +endmodule + +module NOR4B3 (input I0, input I1, input I2, input I3, output O); +`ifndef SYNTHESIS + assign O = ~(~I0 | ~I1 | ~I2 | I3); +`endif +endmodule + +module NOR5 (input I0, input I1, input I2, input I3, input I4, output O); +`ifndef SYNTHESIS + assign O = ~(I0 | I1 | I2 | I3 | I4); +`endif +endmodule + +module NOR5B1 (input I0, input I1, input I2, input I3, input I4, output O); +`ifndef SYNTHESIS + assign O = ~(~I0 | I1 | I2 | I3 | I4); +`endif +endmodule + +module NOR5B2 (input I0, input I1, input I2, input I3, input I4, output O); +`ifndef SYNTHESIS + assign O = ~(~I0 | ~I1 | I2 | I3 | I4); +`endif +endmodule + +module NOR5B3 (input I0, input I1, input I2, input I3, input I4, output O); +`ifndef SYNTHESIS + assign O = ~(~I0 | ~I1 | ~I2 | I3 | I4); +`endif +endmodule + +module NOR5B4 (input I0, input I1, input I2, input I3, input I4, output O); +`ifndef SYNTHESIS + assign O = ~(~I0 | ~I1 | ~I2 | ~I3 | I4); +`endif +endmodule + +/* XOR gates */ + +module XOR2 (input I0, input I1, output O); +`ifndef SYNTHESIS + assign O = I0 ^ I1; +`endif +endmodule + +module XOR3 (input I0, input I1, input I2, output O); +`ifndef SYNTHESIS + assign O = I0 ^ I1 ^ I2; +`endif +endmodule + +module XOR4 (input I0, input I1, input I2, input I3, output O); +`ifndef SYNTHESIS + assign O = I0 ^ I1 ^ I2 ^ I3; +`endif +endmodule + +module XOR5 (input I0, input I1, input I2, input I3, input I4, output O); +`ifndef SYNTHESIS + assign O = I0 ^ I1 ^ I2 ^ I3 ^ I4; +`endif +endmodule + +/* XNOR gates */ + +module XNOR2 (input I0, input I1, output O); +`ifndef SYNTHESIS + assign O = ~(I0 ^ I1); +`endif +endmodule + +module XNOR3 (input I0, input I1, input I2, output O); +`ifndef SYNTHESIS + assign O = ~(I0 ^ I1 ^ I2); +`endif +endmodule + +module XNOR4 (input I0, input I1, input I2, input I3, output O); +`ifndef SYNTHESIS + assign O = ~(I0 ^ I1 ^ I2 ^ I3); +`endif +endmodule + +module XNOR5 (input I0, input I1, input I2, input I3, input I4, output O); +`ifndef SYNTHESIS + assign O = ~(I0 ^ I1 ^ I2 ^ I3 ^ I4); +`endif +endmodule + +/* Flip flops */ + +module FDCE (input D, input C, input CLR, input CE, output Q); +`ifndef SYNTHESIS + reg _Q = 1'b0; + assign Q = _Q; + + always @(posedge C, CLR) + if (CLR) + _Q <= 1'b0; + else if (CE) + _Q <= D; +`endif +endmodule + +module FDPE (input D, input C, input PRE, input CE, output Q); +`ifndef SYNTHESIS + reg _Q = 1'b1; + assign Q = _Q; + + always @(posedge C, PRE) + if (PRE) + _Q <= 1'b1; + else if (CE) + _Q <= D; +`endif +endmodule + +/* Latches */ + +module LDCE_1 (input D, input G, input CLR, input GE, output Q); +`ifndef SYNTHESIS + reg _Q = 1'b0; + assign Q = _Q; + + always @* + if (CLR) + _Q <= 1'b0; + else if (GE) + _Q <= D; +`endif +endmodule + +module LDPE_1 (input D, input G, input PRE, input GE, output Q); +`ifndef SYNTHESIS + reg _Q = 1'b1; + assign Q = _Q; + + always @* + if (PRE) + _Q <= 1'b1; + else if (GE) + _Q <= D; +`endif +endmodule + +/* CLB placement control primitives */ + +module FMAP (input I1, input I2, input I3, input I4, input O); +endmodule + +module HMAP (input I1, input I2, input I3, input O); +endmodule + +/* I/O buffers */ + +module BUFGLS (input I, output O); +`ifndef SYNTHESIS + assign O = I; +`endif +endmodule + +module IBUF (input I, output O); +`ifndef SYNTHESIS + assign O = I; +`endif +endmodule + +module OBUF (input I, output O); +`ifndef SYNTHESIS + assign O = I; +`endif +endmodule + +module OBUFT (input I, input T, output O); +`ifndef SYNTHESIS + assign O = T ? 1'bz : I; +`endif +endmodule + +/* I/O flip flops */ + +module IFDX (input D, input C, input CE, output Q); +`ifndef SYNTHESIS + reg data; + assign Q = data; + + initial + data = 1'b0; + always @(posedge C) + data <= CE ? D : data; +`endif +endmodule + +module IFDXI (input D, input C, input CE, output Q); +`ifndef SYNTHESIS + reg data; + assign Q = data; + + initial + data = 1'b1; + always @(posedge C) + data <= CE ? D : data; +`endif +endmodule + +module OFDX (input D, input C, input CE, output Q); +`ifndef SYNTHESIS + IFDX ff (.D(D), .C(C), .CE(CE), .Q(Q)); +`endif +endmodule + +module OFDXI (input D, input C, input CE, output Q); +`ifndef SYNTHESIS + IFDXI ff (.D(D), .C(C), .CE(CE), .Q(Q)); +`endif +endmodule + +module OFDTX (input D, input C, input CE, input T, output O); +`ifndef SYNTHESIS + wire Q; + assign O = T ? 1'bz : Q; + + IFDX ff (.D(D), .C(C), .CE(CE), .Q(Q)); +`endif +endmodule + +module OFDTXI (input D, input C, input CE, input T, output O); +`ifndef SYNTHESIS + wire Q; + assign O = T ? 1'bz : Q; + + IFDXI ff (.D(D), .C(C), .CE(CE), .Q(Q)); +`endif +endmodule + +/* I/O pads */ + +module IPAD (output IPAD); +endmodule + +module OPAD (input OPAD); +endmodule + +module IOPAD (inout IOPAD); +endmodule + +module UPAD (inout UPAD); +endmodule + +module TDI (inout I); +endmodule + +module TDO (input O); +endmodule + +module TCK (inout I); +endmodule + +module TMS (inout I); +endmodule + +/* Fixed-function blocks */ + +module STARTUP ( + input GSR, + input GTS, + input CLK, + + output DONEIN, + output Q1Q4, + output Q2, + output Q3 +); +endmodule + +module OSC4 ( + output F8M, + output F500K, + output F16K, + output F490, + output F15 +); +endmodule + +module BSCAN( + input TDI, + input TDO1, + input TDO2, + input TCK, + input TMS, + + output TDO, + output DRCK, + output IDLE, + output SEL1, + output SEL2 +); +endmodule + +module RDBK (input TRIG, output DATA, output RIP); +endmodule + +module RDCLK (input I); +endmodule diff --git a/fpga/src/techmap.v b/fpga/src/techmap.v deleted file mode 100644 index ad4b590..0000000 --- a/fpga/src/techmap.v +++ /dev/null @@ -1,90 +0,0 @@ -/* - * This file is used by Yosys to map its internal gate representations to the - * respective primitives supported by ISE's mapping tools. Note that ISE does - * not expose LUT primitives for Spartan-XL devices, so LUT-based synthesis and - * the synth_xilinx command built into Yosys cannot be used. - */ - -(* techmap_celltype = "IOBUFT" *) -module _ISE_IOBUFT (input I, input T, output O, inout IO); - IBUF _TECHMAP_REPLACE_.ibuf (.I(IO), .O(O)); - OBUFT _TECHMAP_REPLACE_.obuf (.O(IO), .I(I), .T(T)); -endmodule - -(* techmap_celltype = "$_BUF_" *) -module _ISE_BUF (input A, output Y); - BUF _TECHMAP_REPLACE_ (.I(A), .O(Y)); -endmodule - -(* techmap_celltype = "$_NOT_" *) -module _ISE_INV (input A, output Y); - INV _TECHMAP_REPLACE_ (.I(A), .O(Y)); -endmodule - -(* techmap_celltype = "$_AND_" *) -module _ISE_AND2 (input A, input B, output Y); - AND2 _TECHMAP_REPLACE_ (.I0(A), .I1(B), .O(Y)); -endmodule - -(* techmap_celltype = "$_NAND_" *) -module _ISE_NAND2 (input A, input B, output Y); - NAND2 _TECHMAP_REPLACE_ (.I0(A), .I1(B), .O(Y)); -endmodule - -(* techmap_celltype = "$_ANDNOT_" *) -module _ISE_AND2B1 (input A, input B, output Y); - AND2B1 _TECHMAP_REPLACE_ (.I0(A), .I1(B), .O(Y)); -endmodule - -(* techmap_celltype = "$_OR_" *) -module _ISE_OR2 (input A, input B, output Y); - OR2 _TECHMAP_REPLACE_ (.I0(A), .I1(B), .O(Y)); -endmodule - -(* techmap_celltype = "$_NOR_" *) -module _ISE_NOR2 (input A, input B, output Y); - NOR2 _TECHMAP_REPLACE_ (.I0(A), .I1(B), .O(Y)); -endmodule - -(* techmap_celltype = "$_ORNOT_" *) -module _ISE_OR2B1 (input A, input B, output Y); - OR2B1 _TECHMAP_REPLACE_ (.I0(A), .I1(B), .O(Y)); -endmodule - -(* techmap_celltype = "$_XOR_" *) -module _ISE_XOR2 (input A, input B, output Y); - XOR2 _TECHMAP_REPLACE_ (.I0(A), .I1(B), .O(Y)); -endmodule - -(* techmap_celltype = "$_XNOR_" *) -module _ISE_XNOR2 (input A, input B, output Y); - XNOR2 _TECHMAP_REPLACE_ (.I0(A), .I1(B), .O(Y)); -endmodule - -(* techmap_celltype = "$_TBUF_" *) -module _ISE_BUFT (input A, input E, output Y); - wire T; - - INV _TECHMAP_REPLACE_.inv (.I(E), .O(T)); - BUFT _TECHMAP_REPLACE_.buffer (.I(A), .T(T), .O(Y)); -endmodule - -(* techmap_celltype = "$_DFFE_PP0P_" *) -module _ISE_FDCE (input D, input C, input R, input E, output Q); - FDCE _TECHMAP_REPLACE_ (.D(D), .C(C), .CLR(R), .CE(E), .Q(Q)); -endmodule - -(* techmap_celltype = "$_DFFE_PP1P_" *) -module _ISE_FDPE (input D, input C, input R, input E, output Q); - FDPE _TECHMAP_REPLACE_ (.D(D), .C(C), .PRE(R), .CE(E), .Q(Q)); -endmodule - -(* techmap_celltype = "$_DLATCH_PP0_" *) -module _ISE_LDCE_1 (input E, input R, input D, output Q); - LDCE_1 _TECHMAP_REPLACE_ (.D(D), .G(E), .CLR(R), .GE(1'b1), .Q(Q)); -endmodule - -(* techmap_celltype = "$_DLATCH_PP1_" *) -module _ISE_LDPE_1 (input E, input R, input D, output Q); - LDPE_1 _TECHMAP_REPLACE_ (.D(D), .G(E), .PRE(R), .GE(1'b1), .Q(Q)); -endmodule diff --git a/src/common/io.cpp b/src/common/io.cpp index 9f5083b..6d4c6ab 100644 --- a/src/common/io.cpp +++ b/src/common/io.cpp @@ -9,7 +9,8 @@ namespace io { -uint16_t _bankSwitchReg, _cartOutputReg, _miscOutputReg; +uint16_t _bankSwitchReg, _cartOutputReg, _miscOutputReg; +static uint16_t _digitalIOI2CReg, _digitalIODSBusReg; /* System initialization */ @@ -50,9 +51,9 @@ void init(void) { _bankSwitchReg = 0; _cartOutputReg = 0; _miscOutputReg = 0 - | SYS573_MISC_OUT_ADC_MOSI + | SYS573_MISC_OUT_ADC_DI | SYS573_MISC_OUT_ADC_CS - | SYS573_MISC_OUT_ADC_SCK + | SYS573_MISC_OUT_ADC_CLK | SYS573_MISC_OUT_JVS_RESET; SYS573_BANK_CTRL = _bankSwitchReg; @@ -181,7 +182,13 @@ static void _writeBitstreamMSB(const uint8_t *data, size_t length) { } } -bool loadBitstream(const uint8_t *data, size_t length) { +bool isDigitalIOPresent(void) { + const uint16_t mask = SYS573D_CPLD_STAT_ID1 | SYS573D_CPLD_STAT_ID2; + + return ((SYS573D_CPLD_STAT & mask) == SYS573D_CPLD_STAT_ID2); +} + +bool loadDigitalIOBitstream(const uint8_t *data, size_t length) { // Konami's bitstreams are always stored LSB-first and with no headers, // however Xilinx tools export .bit files which contain MSB-first bitstreams // wrapped in a TLV container. In order to upload the bitstream properly, @@ -189,7 +196,7 @@ bool loadBitstream(const uint8_t *data, size_t length) { // https://www.fpga-faq.com/FAQ_Pages/0026_Tell_me_about_bit_files.htm and // the "Data Stream Format" section in the XCS40XL datasheet for details. if (data[0] == 0xff) - return loadRawBitstream(data, length); + return loadDigitalIORawBitstream(data, length); auto dataEnd = &data[length]; uint16_t headerLength = (data[0] << 8) | data[1]; @@ -208,7 +215,7 @@ bool loadBitstream(const uint8_t *data, size_t length) { | data[4]; data += 5; - return loadRawBitstream(data, tagLength); + return loadDigitalIORawBitstream(data, tagLength); default: tagLength = (data[1] << 8) | data[2]; @@ -221,7 +228,7 @@ bool loadBitstream(const uint8_t *data, size_t length) { return false; } -bool loadRawBitstream(const uint8_t *data, size_t length) { +bool loadDigitalIORawBitstream(const uint8_t *data, size_t length) { if (data[0] != 0xff) return false; @@ -266,7 +273,7 @@ bool loadRawBitstream(const uint8_t *data, size_t length) { return false; } -void initKonamiBitstream(void) { +void initDigitalIOFPGA(void) { SYS573D_FPGA_INIT = 0xf000; SYS573D_FPGA_INIT = 0x0000; delayMicroseconds(_FPGA_INIT_REG_DELAY); @@ -282,6 +289,16 @@ void initKonamiBitstream(void) { SYS573D_CPLD_LIGHTS_CL = 0xf000; SYS573D_CPLD_LIGHTS_CH = 0xf000; SYS573D_FPGA_LIGHTS_D = 0xf000; + + _digitalIOI2CReg = 0 + | SYS573D_FPGA_MP3_I2C_SDA + | SYS573D_FPGA_MP3_I2C_SCL; + _digitalIODSBusReg = 0 + | SYS573D_FPGA_DS_BUS_DS2401 + | SYS573D_FPGA_DS_BUS_DS2433; + + SYS573D_FPGA_MP3_I2C = _digitalIOI2CReg; + SYS573D_FPGA_DS_BUS = _digitalIODSBusReg; } /* I2C driver */ @@ -289,173 +306,204 @@ void initKonamiBitstream(void) { static constexpr int _I2C_BUS_DELAY = 50; static constexpr int _I2C_RESET_DELAY = 500; -// SDA is open-drain so it is toggled by changing pin direction. -#define _SDA(value) setCartSDADir(!(value)) -#define SDA(value) _SDA(value), delayMicroseconds(_I2C_BUS_DELAY) -#define _SCL(value) setCartOutput(OUT_SCL, value) -#define SCL(value) _SCL(value), delayMicroseconds(_I2C_BUS_DELAY) -#define _CS(value) setCartOutput(OUT_CS, value) -#define CS(value) _CS(value), delayMicroseconds(_I2C_BUS_DELAY) -#define _RESET(value) setCartOutput(OUT_RESET, value) -#define RESET(value) _RESET(value), delayMicroseconds(_I2C_BUS_DELAY) +void I2CDriver::start(void) const { + _setSDA(true); + _setSCL(true, _I2C_BUS_DELAY); -void i2cStart(void) { - _SDA(true); - SCL(true); - - SDA(false); // START: SDA falling, SCL high - SCL(false); + _setSDA(false, _I2C_BUS_DELAY); // START: SDA falling, SCL high + _setSCL(false, _I2C_BUS_DELAY); } -void i2cStartWithCS(int csDelay) { - _SDA(true); - _SCL(false); - CS(true); +void I2CDriver::startWithCS(int csDelay) const { + _setSDA(true); + _setSCL(false); + _setCS(true, _I2C_BUS_DELAY); - CS(false); - delayMicroseconds(csDelay); - SCL(true); + _setCS(false, _I2C_BUS_DELAY + csDelay); + _setSCL(true, _I2C_BUS_DELAY); - SDA(false); // START: SDA falling, SCL high - SCL(false); + _setSDA(false, _I2C_BUS_DELAY); // START: SDA falling, SCL high + _setSCL(false, _I2C_BUS_DELAY); } -void i2cStop(void) { - _SDA(false); - SCL(true); +void I2CDriver::stop(void) const { + _setSDA(false); - SDA(true); // STOP: SDA rising, SCL high + _setSCL(true, _I2C_BUS_DELAY); + _setSDA(true, _I2C_BUS_DELAY); // STOP: SDA rising, SCL high } -void i2cStopWithCS(int csDelay) { - _SDA(false); - SCL(true); +void I2CDriver::stopWithCS(int csDelay) const { + _setSDA(false); - SDA(true); // STOP: SDA rising, SCL high + _setSCL(true, _I2C_BUS_DELAY); + _setSDA(true, _I2C_BUS_DELAY); // STOP: SDA rising, SCL high - SCL(false); - delayMicroseconds(csDelay); - CS(true); + _setSCL(false, _I2C_BUS_DELAY + csDelay); + _setCS(true, _I2C_BUS_DELAY); } -uint8_t i2cReadByte(void) { +bool I2CDriver::getACK(void) const { + delayMicroseconds(_I2C_BUS_DELAY); // Required for ZS01 + + _setSCL(true, _I2C_BUS_DELAY); + bool ack = _getSDA(); + _setSCL(false, _I2C_BUS_DELAY * 2); + + return ack ^ 1; +} + +void I2CDriver::sendACK(bool ack) const { + _setSDA(ack ^ 1); + _setSCL(true, _I2C_BUS_DELAY); + _setSCL(false, _I2C_BUS_DELAY); + _setSDA(true, _I2C_BUS_DELAY); +} + +uint8_t I2CDriver::readByte(void) const { uint8_t value = 0; - for (int bit = 7; bit >= 0; bit--) { // MSB first - SCL(true); - if (getCartSDA()) - value |= (1 << bit); - SCL(false); + for (int i = 7; i >= 0; i--) { // MSB first + _setSCL(true, _I2C_BUS_DELAY); + value |= _getSDA() << i; + _setSCL(false, _I2C_BUS_DELAY); } delayMicroseconds(_I2C_BUS_DELAY); return value; } -void i2cWriteByte(uint8_t value) { - for (int bit = 7; bit >= 0; bit--) { // MSB first - _SDA(value & (1 << bit)); - SCL(true); - SCL(false); +void I2CDriver::writeByte(uint8_t value) const { + for (int i = 7; i >= 0; i--) { // MSB first + _setSDA((value >> i) & 1); + _setSCL(true, _I2C_BUS_DELAY); + _setSCL(false, _I2C_BUS_DELAY); } - SDA(true); + _setSDA(true, _I2C_BUS_DELAY); } -void i2cSendACK(bool ack) { - _SDA(!ack); - SCL(true); - SCL(false); - SDA(true); -} - -bool i2cGetACK(void) { - delayMicroseconds(_I2C_BUS_DELAY); // Required for ZS01 - SCL(true); - bool ack = !getCartSDA(); - SCL(false); - - delayMicroseconds(_I2C_BUS_DELAY); - return ack; -} - -void i2cReadBytes(uint8_t *data, size_t length) { +void I2CDriver::readBytes(uint8_t *data, size_t length) const { for (; length; length--) { - *(data++) = i2cReadByte(); + *(data++) = readByte(); if (length > 1) - i2cSendACK(true); + sendACK(true); } } -bool i2cWriteBytes(const uint8_t *data, size_t length, int lastACKDelay) { +bool I2CDriver::writeBytes( + const uint8_t *data, size_t length, int lastACKDelay +) const { for (; length; length--) { - i2cWriteByte(*(data++)); + writeByte(*(data++)); if (length == 1) delayMicroseconds(lastACKDelay); - if (!i2cGetACK()) + if (!getACK()) return false; } return true; } -uint32_t i2cResetX76(void) { +uint32_t I2CDriver::resetX76(void) const { uint32_t value = 0; - _SDA(true); - _SCL(false); - _CS(false); - _RESET(false); + _setSDA(true); + _setSCL(false); + _setCS(false); + _setReset(false); - RESET(true); - SCL(true); - SCL(false); - RESET(false); - delayMicroseconds(_I2C_RESET_DELAY); + _setReset(true, _I2C_RESET_DELAY); + _setSCL(true, _I2C_BUS_DELAY); + _setSCL(false, _I2C_BUS_DELAY); + _setReset(false, _I2C_RESET_DELAY); - for (int bit = 0; bit < 32; bit++) { // LSB first - SCL(true); - if (getCartSDA()) - value |= (1 << bit); - SCL(false); + for (int i = 0; i < 32; i++) { // LSB first + _setSCL(true, _I2C_BUS_DELAY); + value |= _getSDA() << i; + _setSCL(false, _I2C_BUS_DELAY); } - CS(true); - SCL(true); + _setCS(true, _I2C_BUS_DELAY); + _setSCL(true, _I2C_BUS_DELAY); return value; } // For whatever reason the ZS01 does not implement the exact same response to // reset protocol as the X76 chips. The reset pin is also active-low rather // than active-high, and CS is ignored. -uint32_t i2cResetZS01(void) { +uint32_t I2CDriver::resetZS01(void) const { uint32_t value = 0; - _SDA(true); - _SCL(false); - _CS(false); - _RESET(true); + _setSDA(true); + _setSCL(false); + _setCS(false); + _setReset(true); - RESET(false); - RESET(true); - delayMicroseconds(_I2C_RESET_DELAY); + _setReset(false, _I2C_RESET_DELAY); + _setReset(true, _I2C_RESET_DELAY); + _setSCL(true, _I2C_BUS_DELAY); + _setSCL(false, _I2C_BUS_DELAY); - SCL(true); - SCL(false); - - for (int bit = 31; bit >= 0; bit--) { // MSB first - if (getCartSDA()) - value |= (1 << bit); - SCL(true); - SCL(false); + for (int i = 31; i >= 0; i--) { // MSB first + value |= _getSDA() << i; + _setSCL(true, _I2C_BUS_DELAY); + _setSCL(false, _I2C_BUS_DELAY); } - SCL(true); + _setSCL(true, _I2C_BUS_DELAY); return value; } +bool CartI2CDriver::_getSDA(void) const { + return (SYS573_MISC_IN / SYS573_MISC_IN_CART_SDA) & 1; +} + +void CartI2CDriver::_setSDA(bool value) const { + // SDA is open-drain so it is toggled by tristating the pin. + setCartOutput(CART_OUTPUT_SDA, false); + setCartSDADirection(value ^ 1); +} + +void CartI2CDriver::_setSCL(bool value) const { + setCartOutput(CART_OUTPUT_SCL, value); +} + +void CartI2CDriver::_setCS(bool value) const { + setCartOutput(CART_OUTPUT_CS, value); +} + +void CartI2CDriver::_setReset(bool value) const { + setCartOutput(CART_OUTPUT_RESET, value); +} + +bool DigitalIOI2CDriver::_getSDA(void) const { + return (SYS573D_FPGA_MP3_I2C / SYS573D_FPGA_MP3_I2C_SDA) & 1; +} + +void DigitalIOI2CDriver::_setSDA(bool value) const { + if (value) + _digitalIOI2CReg |= SYS573D_FPGA_MP3_I2C_SDA; + else + _digitalIOI2CReg &= ~SYS573D_FPGA_MP3_I2C_SCL; + + SYS573D_FPGA_MP3_I2C = _digitalIOI2CReg; +} + +void DigitalIOI2CDriver::_setSCL(bool value) const { + if (value) + _digitalIOI2CReg |= SYS573D_FPGA_MP3_I2C_SDA; + else + _digitalIOI2CReg &= ~SYS573D_FPGA_MP3_I2C_SCL; + + SYS573D_FPGA_MP3_I2C = _digitalIOI2CReg; +} + +const CartI2CDriver cartI2C; +const DigitalIOI2CDriver digitalIOI2C; + /* 1-wire driver */ static constexpr int _DS_RESET_LOW_TIME = 480; @@ -471,95 +519,76 @@ static constexpr int _DS_ZERO_HIGH_TIME = 5; static constexpr int _DS_ONE_LOW_TIME = 10; static constexpr int _DS_ONE_HIGH_TIME = 55; -#define _CART1WIRE(value) setCartOutput(OUT_1WIRE, !(value)) -#define _DIO1WIRE(value) setDIO1Wire(value) +bool OneWireDriver::reset(void) const { + _set(false, _DS_RESET_LOW_TIME); + _set(true, _DS_RESET_SAMPLE_DELAY); + bool present = _get(); -bool dsCartReset(void) { - _CART1WIRE(false); - delayMicroseconds(_DS_RESET_LOW_TIME); - _CART1WIRE(true); - - delayMicroseconds(_DS_RESET_SAMPLE_DELAY); - bool present = !getCartInput(IN_1WIRE); delayMicroseconds(_DS_RESET_DELAY); - - return present; + return present ^ 1; } -bool dsDIOReset(void) { - _DIO1WIRE(false); - delayMicroseconds(_DS_RESET_LOW_TIME); - _DIO1WIRE(true); - - delayMicroseconds(_DS_RESET_SAMPLE_DELAY); - bool present = !getDIO1Wire(); - delayMicroseconds(_DS_RESET_DELAY); - - return present; -} - -uint8_t dsCartReadByte(void) { +uint8_t OneWireDriver::readByte(void) const { uint8_t value = 0; - for (int bit = 0; bit < 8; bit++) { // LSB first - _CART1WIRE(false); - delayMicroseconds(_DS_READ_LOW_TIME); - _CART1WIRE(true); - delayMicroseconds(_DS_READ_SAMPLE_DELAY); - if (getCartInput(IN_1WIRE)) - value |= (1 << bit); + for (int i = 0; i < 8; i++) { // LSB first + _set(false, _DS_READ_LOW_TIME); + _set(true, _DS_READ_SAMPLE_DELAY); + value |= _get() << i; delayMicroseconds(_DS_READ_DELAY); } return value; } -uint8_t dsDIOReadByte(void) { - uint8_t value = 0; - - for (int bit = 0; bit < 8; bit++) { // LSB first - _DIO1WIRE(false); - delayMicroseconds(_DS_READ_LOW_TIME); - _DIO1WIRE(true); - delayMicroseconds(_DS_READ_SAMPLE_DELAY); - if (getDIO1Wire()) - value |= (1 << bit); - delayMicroseconds(_DS_READ_DELAY); - } - - return value; -} - -void dsCartWriteByte(uint8_t value) { - for (int bit = 0; bit < 8; bit++) { // LSB first - if (value & (1 << bit)) { - _CART1WIRE(false); - delayMicroseconds(_DS_ONE_LOW_TIME); - _CART1WIRE(true); - delayMicroseconds(_DS_ONE_HIGH_TIME); +void OneWireDriver::writeByte(uint8_t value) const { + for (int i = 8; i; i--, value >>= 1) { // LSB first + if (value & 1) { + _set(false, _DS_ONE_LOW_TIME); + _set(true, _DS_ONE_HIGH_TIME); } else { - _CART1WIRE(false); - delayMicroseconds(_DS_ZERO_LOW_TIME); - _CART1WIRE(true); - delayMicroseconds(_DS_ZERO_HIGH_TIME); + _set(false, _DS_ZERO_LOW_TIME); + _set(true, _DS_ZERO_HIGH_TIME); } } } -void dsDIOWriteByte(uint8_t value) { - for (int bit = 0; bit < 8; bit++) { // LSB first - if (value & (1 << bit)) { - _DIO1WIRE(false); - delayMicroseconds(_DS_ONE_LOW_TIME); - _DIO1WIRE(true); - delayMicroseconds(_DS_ONE_HIGH_TIME); - } else { - _DIO1WIRE(false); - delayMicroseconds(_DS_ZERO_LOW_TIME); - _DIO1WIRE(true); - delayMicroseconds(_DS_ZERO_HIGH_TIME); - } - } +bool CartDS2401Driver::_get(void) const { + return getCartInput(CART_INPUT_DS2401); } +void CartDS2401Driver::_set(bool value) const { + setCartOutput(CART_OUTPUT_DS2401, value ^ 1); +} + +bool DigitalIODS2401Driver::_get(void) const { + return (SYS573D_FPGA_DS_BUS / SYS573D_FPGA_DS_BUS_DS2401) & 1; +} + +void DigitalIODS2401Driver::_set(bool value) const { + if (value) + _digitalIODSBusReg &= ~SYS573D_FPGA_DS_BUS_DS2401; + else + _digitalIODSBusReg |= SYS573D_FPGA_DS_BUS_DS2401; + + SYS573D_FPGA_DS_BUS = _digitalIODSBusReg; +} + +bool DigitalIODS2433Driver::_get(void) const { + return (SYS573D_FPGA_DS_BUS / SYS573D_FPGA_DS_BUS_DS2433) & 1; +} + +void DigitalIODS2433Driver::_set(bool value) const { + if (value) + _digitalIODSBusReg &= ~SYS573D_FPGA_DS_BUS_DS2433; + else + _digitalIODSBusReg |= SYS573D_FPGA_DS_BUS_DS2433; + + SYS573D_FPGA_DS_BUS = _digitalIODSBusReg; +} + +const CartDS2401Driver cartDS2401; +const DigitalIODS2401Driver digitalIODS2401; +const DigitalIODS2433Driver digitalIODS2433; + } diff --git a/src/common/io.hpp b/src/common/io.hpp index 1f474b6..db6967d 100644 --- a/src/common/io.hpp +++ b/src/common/io.hpp @@ -7,6 +7,7 @@ #include "common/util.hpp" #include "ps1/registers.h" #include "ps1/registers573.h" +#include "ps1/system.h" namespace io { @@ -52,27 +53,27 @@ enum JAMMAInput : uint32_t { }; enum CartInputPin { - IN_1WIRE = 6 + CART_INPUT_DS2401 = 6 }; enum CartOutputPin { - OUT_SDA = 0, - OUT_SCL = 1, - OUT_CS = 2, - OUT_RESET = 3, - OUT_1WIRE = 4 + CART_OUTPUT_SDA = 0, + CART_OUTPUT_SCL = 1, + CART_OUTPUT_CS = 2, + CART_OUTPUT_RESET = 3, + CART_OUTPUT_DS2401 = 4 }; enum MiscOutputPin { - MISC_ADC_MOSI = 0, - MISC_ADC_CS = 1, - MISC_ADC_SCK = 2, - MISC_COIN_COUNT1 = 3, - MISC_COIN_COUNT2 = 4, - MISC_AMP_ENABLE = 5, - MISC_CDDA_ENABLE = 6, - MISC_SPU_ENABLE = 7, - MISC_JVS_RESET = 8 + MISC_OUT_ADC_DI = 0, + MISC_OUT_ADC_CS = 1, + MISC_OUT_ADC_CLK = 2, + MISC_OUT_COIN_COUNT1 = 3, + MISC_OUT_COIN_COUNT2 = 4, + MISC_OUT_AMP_ENABLE = 5, + MISC_OUT_CDDA_ENABLE = 6, + MISC_OUT_SPU_ENABLE = 7, + MISC_OUT_JVS_RESET = 8 }; /* Inputs */ @@ -106,10 +107,6 @@ static inline bool getCartInput(CartInputPin pin) { return (SYS573_DIP_CART >> (8 + pin)) & 1; } -static inline bool getCartSDA(void) { - return (SYS573_MISC_IN / SYS573_MISC_IN_CART_SDA) & 1; -} - static inline void setCartOutput(CartOutputPin pin, bool value) { if (value) _cartOutputReg |= 1 << pin; @@ -125,7 +122,7 @@ static inline void setFlashBank(int bank) { SYS573_BANK_CTRL = _bankSwitchReg; } -static inline void setCartSDADir(bool dir) { +static inline void setCartSDADirection(bool dir) { if (dir) _bankSwitchReg |= 1 << 6; else @@ -143,22 +140,112 @@ static inline void setMiscOutput(MiscOutputPin pin, bool value) { SYS573_MISC_OUT = _miscOutputReg; } -/* Digital I/O board driver */ +/* I2C driver */ -static inline bool isDigitalIOPresent(void) { - return ( - (SYS573D_CPLD_STAT & (SYS573D_CPLD_STAT_ID1 | SYS573D_CPLD_STAT_ID2)) == - SYS573D_CPLD_STAT_ID2 - ); -} +class I2CDriver { +private: + inline void _setSDA(bool value, int delay) const { + _setSDA(value); + delayMicroseconds(delay); + } + inline void _setSCL(bool value, int delay) const { + _setSCL(value); + delayMicroseconds(delay); + } + inline void _setCS(bool value, int delay) const { + _setCS(value); + delayMicroseconds(delay); + } + inline void _setReset(bool value, int delay) const { + _setReset(value); + delayMicroseconds(delay); + } -static inline bool getDIO1Wire(void) { - return (SYS573D_FPGA_DS_BUS / SYS573D_FPGA_DS_BUS_DS2401) & 1; -} + virtual bool _getSDA(void) const { return true; } + virtual void _setSDA(bool value) const {} + virtual void _setSCL(bool value) const {} + virtual void _setCS(bool value) const {} + virtual void _setReset(bool value) const {} -static inline void setDIO1Wire(bool value) { - SYS573D_FPGA_DS_BUS = (value ^ 1) * SYS573D_FPGA_DS_BUS_DS2401; -} +public: + void start(void) const; + void startWithCS(int csDelay = 0) const; + void stop(void) const; + void stopWithCS(int csDelay = 0) const; + + bool getACK(void) const; + void sendACK(bool value) const; + uint8_t readByte(void) const; + void writeByte(uint8_t value) const; + + void readBytes(uint8_t *data, size_t length) const; + bool writeBytes( + const uint8_t *data, size_t length, int lastACKDelay = 0 + ) const; + + uint32_t resetX76(void) const; + uint32_t resetZS01(void) const; +}; + +class CartI2CDriver : public I2CDriver { +private: + bool _getSDA(void) const; + void _setSDA(bool value) const; + void _setSCL(bool value) const; + void _setCS(bool value) const; + void _setReset(bool value) const; +}; + +class DigitalIOI2CDriver : public I2CDriver { +private: + bool _getSDA(void) const; + void _setSDA(bool value) const; + void _setSCL(bool value) const; +}; + +extern const CartI2CDriver cartI2C; +extern const DigitalIOI2CDriver digitalIOI2C; + +/* 1-wire driver */ + +class OneWireDriver { +private: + inline void _set(bool value, int delay) const { + _set(value); + delayMicroseconds(delay); + } + + virtual bool _get(void) const { return true; } + virtual void _set(bool value) const {} + +public: + bool reset(void) const; + + uint8_t readByte(void) const; + void writeByte(uint8_t value) const; +}; + +class CartDS2401Driver : public OneWireDriver { +private: + bool _get(void) const; + void _set(bool value) const; +}; + +class DigitalIODS2401Driver : public OneWireDriver { +private: + bool _get(void) const; + void _set(bool value) const; +}; + +class DigitalIODS2433Driver : public OneWireDriver { +private: + bool _get(void) const; + void _set(bool value) const; +}; + +extern const CartDS2401Driver cartDS2401; +extern const DigitalIODS2401Driver digitalIODS2401; +extern const DigitalIODS2433Driver digitalIODS2433; /* Other APIs */ @@ -171,30 +258,9 @@ void getRTCTime(util::Date &output); void setRTCTime(const util::Date &value, bool stop = false); bool isRTCBatteryLow(void); -bool loadBitstream(const uint8_t *data, size_t length); -bool loadRawBitstream(const uint8_t *data, size_t length); -void initKonamiBitstream(void); - -void i2cStart(void); -void i2cStartWithCS(int csDelay = 0); -void i2cStop(void); -void i2cStopWithCS(int csDelay = 0); - -uint8_t i2cReadByte(void); -void i2cWriteByte(uint8_t value); -void i2cSendACK(bool ack); -bool i2cGetACK(void); -void i2cReadBytes(uint8_t *data, size_t length); -bool i2cWriteBytes(const uint8_t *data, size_t length, int lastACKDelay = 0); - -uint32_t i2cResetX76(void); -uint32_t i2cResetZS01(void); - -bool dsCartReset(void); -bool dsDIOReset(void); -uint8_t dsCartReadByte(void); -uint8_t dsDIOReadByte(void); -void dsCartWriteByte(uint8_t value); -void dsDIOWriteByte(uint8_t value); +bool isDigitalIOPresent(void); +bool loadDigitalIOBitstream(const uint8_t *data, size_t length); +bool loadDigitalIORawBitstream(const uint8_t *data, size_t length); +void initDigitalIOFPGA(void); } diff --git a/src/common/rom.cpp b/src/common/rom.cpp index ef3df2d..e9276fb 100644 --- a/src/common/rom.cpp +++ b/src/common/rom.cpp @@ -224,8 +224,12 @@ const util::ExecutableHeader *FlashRegion::getBootExecutableHeader(void) const { for (size_t i = 1; i < length; i <<= 1) crc = (crc >> 8) ^ table[(crc ^ data[i]) & 0xff]; - if (~crc != *crcPtr) + if (~crc != *crcPtr) { + LOG_ROM("CRC32 mismatch"); + LOG_ROM("exp=0x%08x", ~crc); + LOG_ROM("got=0x%08x", *crcPtr); return nullptr; + } return header; } diff --git a/src/main/app/cartworkers.cpp b/src/main/app/cartworkers.cpp index 78b5727..0c7e7d3 100644 --- a/src/main/app/cartworkers.cpp +++ b/src/main/app/cartworkers.cpp @@ -98,7 +98,9 @@ _cartInitDone: return true; } - ready = io::loadBitstream(bitstream.as(), bitstream.length); + ready = io::loadDigitalIOBitstream( + bitstream.as(), bitstream.length + ); bitstream.destroy(); if (!ready) { @@ -107,7 +109,7 @@ _cartInitDone: } delayMicroseconds(5000); // Probably not necessary - io::initKonamiBitstream(); + io::initDigitalIOFPGA(); auto error = _cartDriver->readSystemID(); diff --git a/src/main/app/tests.cpp b/src/main/app/tests.cpp index f60970c..d5f10a1 100644 --- a/src/main/app/tests.cpp +++ b/src/main/app/tests.cpp @@ -205,19 +205,19 @@ void AudioTestScreen::playBoth(ui::Context &ctx) { } void AudioTestScreen::enableAmp(ui::Context &ctx) { - io::setMiscOutput(io::MISC_AMP_ENABLE, true); + io::setMiscOutput(io::MISC_OUT_AMP_ENABLE, true); } void AudioTestScreen::disableAmp(ui::Context &ctx) { - io::setMiscOutput(io::MISC_AMP_ENABLE, false); + io::setMiscOutput(io::MISC_OUT_AMP_ENABLE, false); } void AudioTestScreen::enableCDDA(ui::Context &ctx) { - io::setMiscOutput(io::MISC_CDDA_ENABLE, true); + io::setMiscOutput(io::MISC_OUT_CDDA_ENABLE, true); } void AudioTestScreen::disableCDDA(ui::Context &ctx) { - io::setMiscOutput(io::MISC_CDDA_ENABLE, false); + io::setMiscOutput(io::MISC_OUT_CDDA_ENABLE, false); } void AudioTestScreen::show(ui::Context &ctx, bool goBack) { @@ -236,8 +236,8 @@ void AudioTestScreen::update(ui::Context &ctx) { if (ctx.buttons.pressed(ui::BTN_START)) { if (ctx.buttons.held(ui::BTN_LEFT) || ctx.buttons.held(ui::BTN_RIGHT)) { #if 0 - io::setMiscOutput(io::MISC_AMP_ENABLE, false); - io::setMiscOutput(io::MISC_CDDA_ENABLE, false); + io::setMiscOutput(io::MISC_OUT_AMP_ENABLE, false); + io::setMiscOutput(io::MISC_OUT_CDDA_ENABLE, false); #endif ctx.show(APP->_testMenuScreen, true, true); diff --git a/src/main/cart/cartio.cpp b/src/main/cart/cartio.cpp index 4f58f87..037808f 100644 --- a/src/main/cart/cartio.cpp +++ b/src/main/cart/cartio.cpp @@ -117,6 +117,13 @@ DriverError DummyDriver::setDataKey(const uint8_t *key) { /* Functions common to all cartridge drivers */ +enum DS2401Command : uint8_t { + _DS2401_READ_ROM = 0x33, + _DS2401_MATCH_ROM = 0x55, + _DS2401_SKIP_ROM = 0xcc, + _DS2401_SEARCH_ROM = 0xf0 +}; + // TODO: _ZS01_SEND_DELAY and _ZS01_PACKET_DELAY could be tweaked to make the // tool faster, however setting both to 30000 results in bricked carts when // attempting to reflash. @@ -129,7 +136,7 @@ static constexpr int _ZS01_PACKET_DELAY = 300000; DriverError CartDriver::readSystemID(void) { auto enable = disableInterrupts(); - if (!io::dsDIOReset()) { + if (!io::digitalIODS2401.reset()) { if (enable) enableInterrupts(); @@ -139,9 +146,9 @@ DriverError CartDriver::readSystemID(void) { _dump.flags |= DUMP_HAS_SYSTEM_ID; - io::dsDIOWriteByte(0x33); + io::digitalIODS2401.writeByte(_DS2401_READ_ROM); for (int i = 0; i < 8; i++) - _dump.systemID.data[i] = io::dsDIOReadByte(); + _dump.systemID.data[i] = io::digitalIODS2401.readByte(); if (enable) enableInterrupts(); @@ -155,7 +162,7 @@ DriverError CartDriver::readSystemID(void) { DriverError X76Driver::readCartID(void) { auto enable = disableInterrupts(); - if (!io::dsCartReset()) { + if (!io::cartDS2401.reset()) { if (enable) enableInterrupts(); @@ -165,9 +172,9 @@ DriverError X76Driver::readCartID(void) { _dump.flags |= DUMP_HAS_CART_ID; - io::dsCartWriteByte(0x33); + io::cartDS2401.writeByte(_DS2401_READ_ROM); for (int i = 0; i < 8; i++) - _dump.cartID.data[i] = io::dsCartReadByte(); + _dump.cartID.data[i] = io::cartDS2401.readByte(); if (enable) enableInterrupts(); @@ -182,26 +189,26 @@ DriverError X76Driver::_x76Command( uint8_t pollByte, uint8_t cmd, int param ) const { delayMicroseconds(_X76_PACKET_DELAY); - io::i2cStartWithCS(); + io::cartI2C.startWithCS(); - io::i2cWriteByte(cmd); - if (!io::i2cGetACK()) { - io::i2cStopWithCS(); + io::cartI2C.writeByte(cmd); + if (!io::cartI2C.getACK()) { + io::cartI2C.stopWithCS(); LOG_CART_IO("NACK while sending cmd=0x%02x", cmd); return X76_NACK; } if (param >= 0) { - io::i2cWriteByte(param); - if (!io::i2cGetACK()) { - io::i2cStopWithCS(); + io::cartI2C.writeByte(param); + if (!io::cartI2C.getACK()) { + io::cartI2C.stopWithCS(); LOG_CART_IO("NACK while sending param=0x%02x", param); return X76_NACK; } } - if (!io::i2cWriteBytes(_dump.dataKey, sizeof(_dump.dataKey))) { - io::i2cStopWithCS(); + if (!io::cartI2C.writeBytes(_dump.dataKey, sizeof(_dump.dataKey))) { + io::cartI2C.stopWithCS(); LOG_CART_IO("NACK while sending data key"); return X76_NACK; } @@ -218,13 +225,13 @@ DriverError X76Driver::_x76Command( for (int i = _X76_MAX_ACK_POLLS; i; i--) { delayMicroseconds(_X76_WRITE_DELAY); - io::i2cStart(); - io::i2cWriteByte(pollByte); - if (io::i2cGetACK()) + io::cartI2C.start(); + io::cartI2C.writeByte(pollByte); + if (io::cartI2C.getACK()) return NO_ERROR; } - io::i2cStopWithCS(); + io::cartI2C.stopWithCS(); LOG_CART_IO("ACK polling timeout (wrong key?)"); return X76_POLL_FAIL; } @@ -255,18 +262,18 @@ DriverError X76F041Driver::readPrivateData(void) { if (error) return error; - io::i2cReadByte(); // Ignore "secure read setup" byte - io::i2cStart(); + io::cartI2C.readByte(); // Ignore "secure read setup" byte + io::cartI2C.start(); - io::i2cWriteByte(i & 0xff); - if (!io::i2cGetACK()) { - io::i2cStopWithCS(); + io::cartI2C.writeByte(i & 0xff); + if (!io::cartI2C.getACK()) { + io::cartI2C.stopWithCS(); LOG_CART_IO("NACK after resending addr=0x%02x", i & 0xff); return X76_NACK; } - io::i2cReadBytes(&_dump.data[i], 128); - io::i2cStopWithCS(); + io::cartI2C.readBytes(&_dump.data[i], 128); + io::cartI2C.stopWithCS(); } _dump.flags |= DUMP_PRIVATE_DATA_OK; @@ -278,8 +285,8 @@ DriverError X76F041Driver::readPrivateData(void) { return error; util::clear(_dump.config); - io::i2cReadBytes(_dump.config, 5); - io::i2cStopWithCS(); + io::cartI2C.readBytes(_dump.config, 5); + io::cartI2C.stopWithCS(); _dump.flags |= DUMP_CONFIG_OK; return NO_ERROR; @@ -294,8 +301,8 @@ DriverError X76F041Driver::writeData(void) { if (error) return error; - auto ok = io::i2cWriteBytes(&_dump.data[i], 8); - io::i2cStopWithCS(_X76_WRITE_DELAY); + auto ok = io::cartI2C.writeBytes(&_dump.data[i], 8); + io::cartI2C.stopWithCS(_X76_WRITE_DELAY); if (!ok) { LOG_CART_IO("NACK while sending data bytes"); @@ -309,8 +316,8 @@ DriverError X76F041Driver::writeData(void) { if (error) return error; - auto ok = io::i2cWriteBytes(_dump.config, 5); - io::i2cStopWithCS(_X76_WRITE_DELAY); + auto ok = io::cartI2C.writeBytes(_dump.config, 5); + io::cartI2C.stopWithCS(_X76_WRITE_DELAY); if (!ok) { LOG_CART_IO("NACK while sending config registers"); @@ -327,7 +334,7 @@ DriverError X76F041Driver::erase(void) { if (error) return error; - io::i2cStopWithCS(_X76_WRITE_DELAY); + io::cartI2C.stopWithCS(_X76_WRITE_DELAY); util::clear(_dump.dataKey); return NO_ERROR; @@ -343,14 +350,14 @@ DriverError X76F041Driver::setDataKey(const uint8_t *key) { // The X76F041 requires the key to be sent twice as a way of ensuring it // gets received correctly. for (int i = 2; i; i--) { - if (!io::i2cWriteBytes(key, sizeof(_dump.dataKey))) { - io::i2cStopWithCS(_X76_WRITE_DELAY); + if (!io::cartI2C.writeBytes(key, sizeof(_dump.dataKey))) { + io::cartI2C.stopWithCS(_X76_WRITE_DELAY); LOG_CART_IO("NACK while setting new data key"); return X76_NACK; } } - io::i2cStopWithCS(_X76_WRITE_DELAY); + io::cartI2C.stopWithCS(_X76_WRITE_DELAY); _dump.copyKeyFrom(key); return NO_ERROR; @@ -370,9 +377,9 @@ DriverError X76F100Driver::readPrivateData(void) { if (error) return error; - //io::i2cStart(); - io::i2cReadBytes(_dump.data, 112); - io::i2cStopWithCS(); + //io::cartI2C.Start(); + io::cartI2C.readBytes(_dump.data, 112); + io::cartI2C.stopWithCS(); _dump.flags |= DUMP_PRIVATE_DATA_OK; return NO_ERROR; @@ -387,8 +394,8 @@ DriverError X76F100Driver::writeData(void) { if (error) return error; - auto ok = io::i2cWriteBytes(&_dump.data[i], 8); - io::i2cStopWithCS(_X76_WRITE_DELAY); + auto ok = io::cartI2C.writeBytes(&_dump.data[i], 8); + io::cartI2C.stopWithCS(_X76_WRITE_DELAY); if (!ok) { LOG_CART_IO("NACK while sending data bytes"); @@ -411,8 +418,8 @@ DriverError X76F100Driver::erase(void) { if (error) return error; - auto ok = io::i2cWriteBytes(dummy, 8); - io::i2cStopWithCS(_X76_WRITE_DELAY); + auto ok = io::cartI2C.writeBytes(dummy, 8); + io::cartI2C.stopWithCS(_X76_WRITE_DELAY); if (!ok) { LOG_CART_IO("NACK while sending data bytes"); @@ -433,8 +440,8 @@ DriverError X76F100Driver::setDataKey(const uint8_t *key) { if (error) return error; - auto ok = io::i2cWriteBytes(key, sizeof(_dump.dataKey)); - io::i2cStopWithCS(_X76_WRITE_DELAY); + auto ok = io::cartI2C.writeBytes(key, sizeof(_dump.dataKey)); + io::cartI2C.stopWithCS(_X76_WRITE_DELAY); if (!ok) { LOG_CART_IO("NACK while setting new data key"); @@ -450,7 +457,7 @@ DriverError X76F100Driver::setDataKey(const uint8_t *key) { DriverError ZS01Driver::_transact(ZS01Packet &request, ZS01Packet &response) { delayMicroseconds(_ZS01_PACKET_DELAY); - io::i2cStart(); + io::cartI2C.start(); #if 0 char buffer[48]; @@ -459,16 +466,16 @@ DriverError ZS01Driver::_transact(ZS01Packet &request, ZS01Packet &response) { LOG_CART_IO("S: %s", buffer); #endif - if (!io::i2cWriteBytes( + if (!io::cartI2C.writeBytes( &request.command, sizeof(ZS01Packet), _ZS01_SEND_DELAY )) { - io::i2cStop(); + io::cartI2C.stop(); LOG_CART_IO("NACK while sending request packet"); return ZS01_NACK; } - io::i2cReadBytes(&response.command, sizeof(ZS01Packet)); - io::i2cStop(); + io::cartI2C.readBytes(&response.command, sizeof(ZS01Packet)); + io::cartI2C.stop(); #if 0 util::hexToString(buffer, &response.command, sizeof(ZS01Packet), ' '); @@ -651,14 +658,14 @@ CartDriver *newCartDriver(CartDump &dump) { } #ifdef ENABLE_ZS01_CART_DRIVER - uint32_t id1 = io::i2cResetZS01(); + auto id1 = io::cartI2C.resetZS01(); LOG_CART_IO("detecting ZS01: 0x%08x", id1); if (id1 == _ID_ZS01) return new ZS01Driver(dump); #endif - uint32_t id2 = io::i2cResetX76(); + auto id2 = io::cartI2C.resetX76(); LOG_CART_IO("detecting X76: 0x%08x", id2); switch (id2) { diff --git a/src/main/main.cpp b/src/main/main.cpp index 95b032e..764852e 100644 --- a/src/main/main.cpp +++ b/src/main/main.cpp @@ -41,7 +41,7 @@ int main(int argc, const char **argv) { gpu::enableDisplay(true); spu::setMasterVolume(spu::MAX_VOLUME / 2); - io::setMiscOutput(io::MISC_SPU_ENABLE, true); + io::setMiscOutput(io::MISC_OUT_SPU_ENABLE, true); app->run(args.resourcePtr, args.resourceLength); diff --git a/src/ps1/registers573.h b/src/ps1/registers573.h index 651f0e2..0aa19d1 100644 --- a/src/ps1/registers573.h +++ b/src/ps1/registers573.h @@ -21,9 +21,9 @@ /* System 573 base hardware */ typedef enum { - SYS573_MISC_OUT_ADC_MOSI = 1 << 0, + SYS573_MISC_OUT_ADC_DI = 1 << 0, SYS573_MISC_OUT_ADC_CS = 1 << 1, - SYS573_MISC_OUT_ADC_SCK = 1 << 2, + SYS573_MISC_OUT_ADC_CLK = 1 << 2, SYS573_MISC_OUT_COIN_COUNT1 = 1 << 3, SYS573_MISC_OUT_COIN_COUNT2 = 1 << 4, SYS573_MISC_OUT_AMP_ENABLE = 1 << 5, @@ -33,7 +33,7 @@ typedef enum { } Sys573MiscOutputFlag; typedef enum { - SYS573_MISC_IN_ADC_MISO = 1 << 0, + SYS573_MISC_IN_ADC_DO = 1 << 0, SYS573_MISC_IN_ADC_SARS = 1 << 1, SYS573_MISC_IN_CART_SDA = 1 << 2, SYS573_MISC_IN_JVS_SENSE = 1 << 3, @@ -137,6 +137,11 @@ typedef enum { SYS573D_CPLD_CTRL_UNKNOWN = 1 << 15 } Sys573DCPLDControlFlag; +typedef enum { + SYS573D_FPGA_MP3_I2C_SDA = 1 << 12, + SYS573D_FPGA_MP3_I2C_SCL = 1 << 13 +} Sys573DFPGAMP3I2CFlag; + typedef enum { SYS573D_FPGA_DS_BUS_DS2433 = 1 << 8, SYS573D_FPGA_DS_BUS_DS2401 = 1 << 12 @@ -144,6 +149,8 @@ typedef enum { #define SYS573D_FPGA_MAGIC _MMIO16(DEV0_BASE | 0x640080) +#define SYS573D_FPGA_NET_ID _MMIO16(DEV0_BASE | 0x640090) + #define SYS573D_FPGA_MP3_PTR_H _MMIO16(DEV0_BASE | 0x6400a0) #define SYS573D_FPGA_MP3_PTR_L _MMIO16(DEV0_BASE | 0x6400a2) #define SYS573D_FPGA_MP3_ENDPTR_H _MMIO16(DEV0_BASE | 0x6400a4)