From 44051e5098aeb6b4054c3c0a263366eb0d077ea6 Mon Sep 17 00:00:00 2001 From: CGH0S7 <776459475@qq.com> Date: Fri, 25 Apr 2025 00:36:49 +0800 Subject: [PATCH] cachelab finished again --- cachelab/Cache | Bin 49312 -> 49544 bytes cachelab/Cache.bak | 1930 ------------------------------------------- cachelab/Cache.bak2 | 403 --------- cachelab/Cache.c | 1536 +++++++++++++++++++++------------- cachelab/Makefile | 5 +- 5 files changed, 963 insertions(+), 2911 deletions(-) delete mode 100644 cachelab/Cache.bak delete mode 100644 cachelab/Cache.bak2 diff --git a/cachelab/Cache b/cachelab/Cache index 7d65892c969abfb93c19d7e3721fcdfd443de422..a34c3053dc87260ae1c9ec805f71d8f2c8cffa99 100755 GIT binary patch literal 49544 zcmeIb3w%>m_CI>kHV|GpQNgJXG+@D2p|%Lx3e|?Da3U#|msSBo>4R2ETiZm6;#f(G zJrg1w#n+6E#c_PisOTWpCoPW_b#yAe^*36OmJ_N{#Q{Vm_q+DqCrLv)`uqL<_kQl@ zUJf*S@3q%nd+oK>Ui)$OPHxL~&WJG>B>jn%E|(}}9m^q^BE$5uh#<(6(j+rJ&yhw; zgOHA6FrJ^u1LX3@65BU42{?hN+-8v<9iA=l^ib!JLMk`V(=78GJ(MgwP34Rf73t`3 z)HNJW5B2;|eU&_4iVB;~<#0WWEJw0wdPw9)g$<(JC2^;51i@DfQdDk}z>f}lg&_1$ zmnX@D{&EG~=r9v`^klM6Ns2DlD9S~L2?AdasSbK5q`%trlsYlAGAQgwgnGGoUG74P zNAstrGX=gL>U`#ka%EnQa6%~LQYJ#ZzBwpI^8B@rZXR<*eFN!l2`LJX9*Sz2Oi}so0QhLox8g7Q*#$s<^1O2ZI;RdG|4#>?(>ws3+XjFi9e~c01K{5>0RGwm@b4J_ z{`&#wEFS>>i~;08{nU!T=x0CZjEx2&{Vw3A^aFp6!Q&<;yYs8uE*D4b7xB7z^X;yzEO(7-S&=(8zbb!45ok#aTwGOD zWJeZH6;u`FyNd{wrwfY;Dppih6;)Tyb0cd7huV3XRURs@9RaGIX zLgg$q8}&z47p|U|30I!QtGUYKj;QCvss%TF(E4&cNvf!HmzEboVh~ora#umga#wMF zX_-V7(no%wR8&*yma5%V?g~#?nN(0#QLtPpE-v#_mq;s$R;;MFsfg#IP(@`?IVH*v zfO3A-G6^KgP=u2BFRkDymkVP|fzZ&3{8B0fWmZYWl~twX?qUfdA#|6kpeEl{Tw0!A zMiK?-f|4q!fDf}%~9J@Fios>LVFiALz+VVkK#NPgK?Sg`eN(pa0x0GCrv~j(dPpj zet$2f5k~1!0UKFbicS(IO&96SEI(FqinQm8&#;&YS^M0kG_PZ0cc9%Y|RO*}#Hcphb+Pc-oa!O!4P_PMEvCkTEfkFw9^ zCY~VpSv<-CY~Vtb9j_}e%! z@fn}PQckIFamNHZ6z>kxc2-4j%9{WO$NdAJ^0}FaQM!ck0-ZrT^ z^cqT27Y*dH^v#r}t{KQ==_*Q7mkgw^^bM4zt{AYg^ioQXptOahucI_|y@15hb15xT zy7xE$RN#omYzgu>QaGCEPVl`sVfDVSb8j_sS5=f zS^7*$Q`ZU9vh=BxCYKwiWa*)lrY;m%!qPF6rmhpnW$9ygB28T;kjc{DQJT6+Acdt5 zP@1|(z{=8lDNS7?U}5P`DNS7>AhGmrN>f(|^!`lkf0NQyN_VpKHcFG}2Re{O_}_YL z*VwMkPCaZ}V0(>h$Tr`hey{ka462Z%1&V*--^(Ovp8BKW&)8lF>%9G|hD=E+RD5yc zXz)$^n9FNp>iRwK(5a+Q?)y&TJ__Fi*1W+i*482T-)Vyi5wAJ z>DfRP8nRQr?)hCKK5ehF-f#^o(*S(9r zqIjnzNOD~Tauwg%38^irGa(*g2(Cb$KjTON0`*hv3JBOfv@BsbN})$=m84pOb^t)2 z{^&<7>LAn?U@>=sHTAHfrYNdCAra8G2-*&gEs}P}Pbi{(PHT0^p|)$+TrNpIs z&@FP^QFI{iut@PQN~lDeoa*X?B~G<4p~Rv7m*QKUV0l@}lq5*l;oWJ_KAZvcolMG4 zqB#(%HV<_;{3GK)Q?8>`2sOHLn$>NZHbky3M~8K)oyCpv7R8`=TMV^7Slx$ee;DHa zMtR+Ui3G9MGYInY9x%vTh9Z0AAVvQ3J5}E(>D%Nr>AV&ty+f{x2d<)iq$IT~{*^(+ zdwh_*b}r~Ee#MZZ?r|i&;qd-ome<}uFz<21eory=c!SL8urUuV%laJq=vzyl9pp+DY+2Qv85}= z$XlS=+8;CIJMMxvec3Qlic?zmo(Ca+DtiY*rrxg&a@}fp?w2g*leVxF+p4S|1=LHb4}AomKMducw)t!4Ea=lIA{?Fm*OoWl`* z#(;uO>;i)J6nwK*MBNVde*>ewzlddLA{$ta2{5+pFsu6SFifEGf1@;zcLN#OXHqRb zBJWF6>Vs~hmiGfIxA6k_s54-e=&qGgU^MG&#?Kn4@TjXejX4zf(m*B)WC9nnzExvT zTKC6kw*%r(x7B?n*Ll$UQd?4Yryf?@$#{R9u<|11B~14v14agj@RRCu)pu=bZ_*L( zHk95Imt*Kue^lF?hIgH+K~b+Ykr!Aryt3{y&#UTt>bFU~PIZ1lrbGSMY1pHvixN^C zt(|cIrOonBi*Z6+ilWMjI@9F88RdTjN3q&LG_3wJACR2*$Rwf0JJEDSt{Vl>IMGkz z8QEEWdyIv;Z>~daQ_Fy_{%lh}LN$t0eJ{f78=bxa6Z2n+ce_RL?ld|4s}l^`IMk&0 zs=?%51rFnCN~+mMo#}@>Z?n36AZmw`$nz0RA8K-{A8DT-2?oJgp7%hE_n1Mx z4VCYB963t+w(cK+DgPNx;a&jzSwB7TqkEV?D>x1Hk&lLQS2mCbUY(Gpl*X)>-DWeU zrvP5Mi{eUar}g$$1{ktSQHRP~-c!^zZ6rn#c+GoQ$@%c0aNy}NvNxGbj$0R-ER9oq zZptO%zSEWEZ^kR6al2wLnw}gfWZ6XBB+_82yhB@-#Fh{v=1f+?4 zi_<^l%WKe`?gcqT-3havFowGFk<=Dv($DBK{$+^Gh&KmD8h+Hpnw!dcJ>fx+Ch z8&KN&vvE4}8YnhgzS9Wt`m=vh?yp@PSDB2?M#k%(GKaJOu8Tyd4o}e5gPdIUjjt9CX@Es_Y6aQD^LqfX4f5->po@vYjOe`owZkKTB7b`qi6uWSbGa4UN(_9 z)Ppc4Xy%7{@~3UoMH02um&0+B31pz9R9&LemzcA>3w~g~wv{yxJs2h1P_mtsq_K*e zvGEBcoob?%rqlQU6#`kibc!I_1OQozl`Jq36P_6;b_P)?wNPjBKhJyChrDNXTW{aS z0IEe{n#W7dK}oF)g?J-R z0~9S-NR{x>)4(8Tz>8$o(~%K)10E1aAD%}nM~-ps@2F){-YH-$ev1#dGKzTL3I-CG z-a7*uVanu|X9Bqy!ykNtJs~BvB}eU4F%zcod=V!w`a0Cu0krzhI@r%ad?VSZ-AoTAOpFe9j>zv=lZ;Ds#%x2GE(+@yQ--Nc~}9zN2e{|unIJ&;5; zueLhWW0?ew`BdH_Bmo`&})GX4IM`6ig{WfLs_N4fa=~GWoUI(EiSsZe zgmXUOJWS&*3FZV4WyM8>wT^B!YZi z7N!Vrr0yatywFU~5`g^~JFjKR-ExquEpT3+c2vvtN1(V+JKS>pexw5zqoZksD8YN! zF%qLckA`sWC7c-? zXDG+Hh2zwQaHl?1LIbb;4x#e>)z@Bp~^=pUv?)3_$e%^h( zx%1JnuyXQe*r4d(sD-ym()ZyafWONaFuqAa`cd~N7~ADQg0Z`Y1Uuz(Yaw9?3uqPs ze0Xsv>uIB3~kE0$K4}AV4NUe3U(ID=i0;NiND$m56ViOix()~ zj2K`-fnDwqiZA05z=NZDS3}eVV7ATZ1i-L(dzjzt5tCoq-y(W}Wxx%i^c&OXZ?s9# z;v^Z)Q~aY3Q%|AM^>f-&)7F1Y(*7K6e4C+YzZC%WAY^_cCHx~k{rOZV^EnCPP}E(i zyCWF-= zlZbyQ#Q*rd{QvVSo&OBZ|LX$4_;dacZB}_*`v3A1w+wZ7XaRV zN}&C)E}=j4muMCC)sL_AV2Z+{752x1M?x_^Wc zn{n#R*clnC%TL~NjUoNb-^Qu$s%>yrinraGL3(!&s=Y$;?AfmNMrymbk?6fn^c4Td zU}_L6ev1-2>akUzIfm?C-g2cO{aes`hplXt+qaQsGUz>+dsyvduqX6f^gs2e2>b9i z4E!x6TGs!-pZ92{+eF-bxgGqRz#rCw?>PO&?Z?n9)T4@e3@bDf_#ELh>~i?mSqxUl zthLiseE2CTgnf`dFG>t|+89B5(E zAWKRxblBSL1~Ag61(JG9{T9-A0Yc4`w_qLIA#ZsD1%`q3K@R_X3#~P&8BRlsyrss_ zmT7=53iprnHunhZpJk@~02#Cz8iq0>*=B_jnEV&07@l{}Q(C)Cw5#C#vR5&Dh?Eg) zAogCsZ%qGz98}pLi?;quGWA=4nJsB+D4}L!8qa)+@aJKAg9f4(s39su?}|uzlYW67 z;}5(Mi+%We;HcnF@p&X|7?JUL7+b_EdezZ0pa-#EOZ&~(Y@WYh9@tYqBFFVF2b$XY z^+*F=^kqz^<+xqe3@3^ZmEyd)TT-9 z1J3jslV_izehhAFVN%;5W9$U>LWRMkk8NtJ;*Z;n!5#;($d+MPyWmMWj$n0V*i|f7 z*bNr7*N!zBnZDsDMigjRPO@7p+Ctir^6p4$R$yHb8`2>C5$Oz*T9Y;&egtzEnN8yW zkhk=z?u4@uz?@-3m>bRVPliX?3*+mC@qGs;u+f9L>1AjF&}wgvfpW2j?592h(vt7HCmiHc80aMM~Ul$I6$fk1XU}^nQ4W z_5Wt(WGtQz6Ot^dhHYm!8u*J&%XFAe5;VOH8yOeGz{++aE_YT5alaP%$|S|D?JTbB27%mZmvLuxTvm za{P~w733H&wOW(_iDQqhjQGSZ=8;I5He%jC8g>TXg-x~KC}=tTOR@))V&-O7kJz!n zgFTFRY6~_pP#u{|3T@A&^~A!%LhcUr9cD1ZC`q3z2MUe1sXyf;eeMJk)*SyU#1pZf z=rFVq-zhnUZy3LV%g>4%!HSj#HXN$`9N7AH*!mZq15_)o(2fm`5Ob&!0v-7VtQPyY zsDrA7Tr9+DqSMgfG-$9`Ma?q>zJedX{NPvnv+6_r`m>Zs>4k?4OtS0HI4ptwSN`pI z6}o!Jzx96CkAE8!<=<|h)%q{_w|ilh@NXBfmD8{FZ>^R8EC03z#ebE5Q}MF*f9>B! zqBh;X#e?8~)4zRy_otEmZ5&CefB&W)MIW+V?d_Cp>WA=j7#tnyPYWEaU&X=Q&9iy; zp-=pnt#-lJ4T7Ufboxh)|Mpa=0UjJLg`i%{%sP6K`Zpx9AI!S=VnnXH4< zHY{Q>a{bw~AzQG`+humNc8vgwMt_b0okuBn1H8&xoCXUvB@!)oGh~k+@?{gWjpcquCero(g}4SB`5rui!clb8XJ`Y{WR%X*$sv&q0$<%4R3%(c=wxWw&R3@F?`tIycE9eAYct;m!A@N0W_ciX91fc zI}Jyvp=cioctUMWjN~3q`>b}g(~dXc^Ajx86I=HWQiil^3CyvhS@3!mWP>bgJ)vnI zv3){~ve4@EgKShWaVdmqq1FgzL_?@tX9WB59c`h8%?&lohL}@5`fJtUP^G~0n86Ix zwp7-(3&U+AmBo{X2E%#-v)Ha5;Nb=`G}gewY(rFUVBR;pfu!sBuozEh;M+`dcZC{w zFVbXhoG(hV#Z?_qK4Z3J>4uZRHg9RRID7Ym79Ot>cfgD=;h8YCaC|n{z_==BY0r8BkW9v*4%Js%mcrJw+g6fu!XX@*~(?ZTL8~rBA~AJ zA9;OUAYtuBc)Ull_Umn;J{h=?X8aMN8s0}#umXrG2RISK8jZ)a9>9S45soZfZKE-B zfdiA!`Ht4F;}+PwT`~=s+3HsqF>$V{;?Z{JU z_rPHiPt-FN-|z&vuAcEm*8+$)tZ`9Lu5&Qw7>w~OPzt`oYb7v<4P6Xm!~D1690Z(W zL6Fue#N+D0I*; za*|O<+(|}IgE%m|7=nSB$vp&RM_YEVfp|*iLutgnAvIG_)A994pKZ7|aE<0>_ z2-(r%+vweYE@Wr-XQO4kv=(GCoWUqiI~+rf`fnvH$eXvoIiwxveBB5Hj>^ztPehAh z%gerKykQX(S;Ih<>Vwh(GkC+iUBkn&kM-Y*u1>bdw9Q3N7D7%Mi@YHnFjnLWHX-|h z50GoIM9{sGJXyhaSl%;v(My5-%+A@cs*7zG$6|&yJS42xu%V&#V5K*wpkG;m3HT`? ztLT=Mfi~7}e&YkhcrA_>hX`y7u*5H=$b7u2&P9awkCz~vhxgA8asE(g&!#>uIYJ?N z1^R3KZuf6NZw}D0f}flES$66h*{PqU2I-B;VLD;rAKuY3p6v_N9&@@E)*hSZF0MV6 z;~C=c#uykJ&LUn(Z*`xAjm6qy4$nsn054+WXC%^FJzaI5x#M!w94VV34s}{Wc3q1b zlX;KWFT!3Y4#Kq?Z0sFs&)>)oIj}j%lMh9BJl6gvi_l&u;Pua2p8ovc>ra2K_)JRu z8~i|}1A8Dohec@~ciz~#eGh*3mczT}s55n!QreO}cE)*%x=m?4U`_2%x3wOyq;B)s zOkT|}rUM#^Q(_I&X1o@TBb_=o>Y68G*&Q{MXq-4$D2y?nnqlw(DX8it2k zN7OvehwxH>C%-5Vng72U>m+PT+wit&?@@>PZ)_%#*Y|b}CO;1a*A&w0SyNahN@_<) z9vC^lv8MLg)E&0guPnCI9ZZxHF_m=sR#|MmnIs_l7>pfQ`o|7dd^nYf6K8)za~!^v zkW#ObbVxb!anC4j559$v4-kB0VTSGY^a8u*fcF*%X&(-3r72TS_k7kzo>`C=t)6ax zQLaow90SW*=C(1DP4N%^nk4r!y?F8N=~dp_s~p*_jM-+BU)-s@*NL&DXE+-NF+Fw2 z_MM8FMO&@$;k_g-=dH9oNfU1Pu#pK`_Iv2gm|kP>z-w(BTT!vH$b#AEHsw@rv5)|W zp2IgY-mVtd6?I`6oeH?{DrAUIueLH)9e+9`7xF#D0M~e-wr6&-5Dlt6A7nfl7 zJEfriDueoweaxHh9mF{}?-xNEcGnU?yzXJvlCu*?-A=VFv!N`(G}}Kiv|mk!%IbG} ze$%szzxPzsIar}ua_T>GFL0`#+SOg>O`q)aU1wzk3`c#62|Za=OzHouj`!sa$K=Ed zjtug%J?U>(5Atp|sCmQ5INPUV8lOd8<{{yZ?zI5}0FnaB zF~{`&GpPL;1ZY1G&cr|Q5){LTg5y$TBVPi~>04q&zrp_IJnX+J*v_uD&{168?|rMR z3g*^RZ;Y4g9wBUXnMLufQ z>&r?chl|dlSP7G8VDPZTdvCzYCTwR8c_$dmso&?m3da$N#~hpmvj*t>I{2rIsl&!cNB|~5qHZ~&to!_V;pPvMw{HZvz5s@FUe~R}$ z5jP94;fia34>66;t zCuO8^K5hX&LE(xYTk=?9{2N#}uFsD?S$fWG%&yz*an%0kkn0Z6ZiPP^lj)swY~H(* z6&s%E@Zr)x+%9GW_wYruPBb7%dkU>&_b`lFb#*9w*mtqw~z>YmWW2InF;Wt(`G)!vjz#Io0oQaJL2ZC-H)(@`4ve7L*(89Qh4G-u0b)eJiRJ zr++i@z=bxI*Z$RYr!k^p200Z>J^+y7`wgbncd@_Ly{P;}3_^P4+sKh}ohuV8b9&pZ7i@>w?Pq4n2uerAMA6o?WkD}nt5R?pKo%Ned` z18bO33YVHFO3gzl<=q1z&3z~5wUGAI>9pQdw|P4aq(h)6L$;Bvya|jq0uzy|k23?| zJWlhB(3KzMT}`h92g&nV0_^>|fAoWCWbv)p>K-RfpfIQL!1?T`+{^74>0g822?o{? zm;TX}C*pq1aqk3f&u(oQ0{wgh83<0^XUu|+q9bGHvBLbkm`Vvd3~C+0&) z;n2)Zoa@1iSt;1=Xdg^?4qw?$nA}JjlrZV}TCRH$k=k3OiE{lO7Be9B5sTqnL;c%` zwHwbD_4zWA5KI3;zS9qu{8htIhaw}--2z2W(< zi0MEh7#St0qyKd^wec-{QX9dL`vUCL3{R;2VIqI$Q~Se(a^2&|^iA9dEWdNKWJ`ZX zUjGlE+touCj`jgc^Es@f$ViOKkyddzWCxZuY^oEwNLY&^l5fQIK)^)&ermMmuG(7- zl6##}V4MZ8t#(?%M1L-J*!8s`k+RXADpcKxIK={UkPC^j zYfnt3FK-8c#7T06O9(s;3@EgF9<-KLAC&9!NWgyMy9Ai>FbLUIOZw;XooRqm6MPx> z0;t@NwQoC253HVcBCC7V(It$ZD;PhyIzO$Dj?d^o(m&5YTC1o1;M!F&mtpaUSo(H3 zXFDD0y1!?5?d34`8iQv94$k4=4SH1lVb1|yMsObN#b^W#hkB`@-JX6#UUxdmiq4n* zvAmv)L><))#CGHR_(W1v@);OF>ki=p1KNey*NFL2>cPoOVEINr2Xx!Z#CBjLF+1f! z0Q|EI&>)1?$~6R2-0dEPW@pOxw1-rbS@)6W3w1;Vt9G%dHc$#GP*C6i3EF2&pF{p( z0cw92hn~mdpf~A-AC7)#8``+=LQjJKJv^rxd&i5xgy_Z$b#}(;*sG^R7(! zp*Fg-kXd)c^SL_e`?=KOz4)XS2WVVP|M<7(V{N1q9P2sF?!OY=v)y1%-?jQwTW#7z zH`es_pK&ZNr@qCrM;*19m48H(M^$qDQ=q}_ey1Mpc@eDq0ez*%!W>bR!M!fMV|9aq z4&`%x0R6n-=?>gP9>QmwlN;I2v*4zA8((UrHqJs7LdwsuA+-+tqWeakXCu$;o0*5( z&2rr<$n+k?tAfkWFl`)YVEklWSFSssK$BWXRy(yfk%bpKm?>)yv*>=Dqt`Ydx>d4* zBehMtgO&c8ZQx+FEZ5-(BvyLxASOg;TxM_Y=`h_a6Ah;{$j!rE&T{OoR9msPv&5+` zPjspUDaC5mqSO|wztixi;IHI_-J@D?E@`o>PR_A=mF7m0xGe+Mg4=IdlyTdQXo%ZS zkbuXg^E@VS>&^qG?s?$SJs4;9uO(sQ4$Stg6du&3A|wQCa~#oFU7H!Sw zhH!Hu-Y3KKPx&)$)51RC51s}f7psX=z;oVpJ t>EcFq(h}mmP5pUm4G7?Rzm`Ug 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 -#include "common.h" - -// debug=1:输出额外调试信息 -int debug = 0; - -#define MAX_AGE 3 - -// 组相联Data Cache -// 容量为16384字节,4路组相联,每行容纳16个字节 -#define DCACHE_SIZE 16384 -#define DCACHE_LINES_PER_SET 4 -#define DCACHE_BYTES_PER_LINE 16 // 必须是8字节的倍数 - -// 下面参数是自动计算的,你无须需改 -#define DCACHE_BYTES_PER_LINE_ADDR_BITS GET_LOG_OF_2(DCACHE_BYTES_PER_LINE) -#define DCACHE_SET (DCACHE_SIZE/(DCACHE_BYTES_PER_LINE*DCACHE_LINES_PER_SET)) -#define DCACHE_SET_ADDR_BITS GET_LOG_OF_2(DCACHE_SET) - -// Cache行的结构,包括Valid、Age、Tag和Data。你所有的状态信息,只能记录在Cache行中! -struct DCACHE_LineStruct -{ - UINT8 Valid; - UINT8 Age; - UINT64 Tag; - UINT8 Data[DCACHE_BYTES_PER_LINE]; -}; - -struct DCACHE_SetStruct { - struct DCACHE_LineStruct Line[4]; // 4路组相联Cache,每组有4行 -} DCache[DCACHE_SET]; - - -// DCache初始化代码,模拟器启动时,会调用此InitDataCache函数 -void InitDataCache() -{ - // 遍历每个组 - for (int set_idx = 0; set_idx < DCACHE_SET; set_idx++) { - struct DCACHE_SetStruct *set = &DCache[set_idx]; - // 遍历每组中的四个Cache行 - for (int line_idx = 0; line_idx < DCACHE_LINES_PER_SET; line_idx++) { - set->Line[line_idx].Valid = 0; // 有效位置0 - set->Line[line_idx].Age = line_idx; // 年龄依次设置为0、1、2、3 - } - } -} - -// 在第Set组中,从4路中,找到需要替换的Cache行 -int GetReplaceLine(UINT32 Set) -{ - struct DCACHE_SetStruct *set = &DCache[Set]; - int invalid_line = -1; - int max_age = -1; - int replace_line = 0; - - for (int i = 0; i < DCACHE_LINES_PER_SET; i++) { - struct DCACHE_LineStruct *line = &set->Line[i]; - if (line->Valid == 0) { - // 发现无效行,记录第一个找到的无效行 - if (invalid_line == -1) { - invalid_line = i; - } - } else { - // 更新最大年龄和对应的行号 - if (line->Age > max_age) { - max_age = line->Age; - replace_line = i; - } - } - } - - // 优先返回无效行,否则返回年龄最大的有效行 - return (invalid_line != -1) ? invalid_line : replace_line; -} - -// 更新Age,在第Set组中,将HitLine指定的Cache行的Age设置为0,其他行的Age要相应调整 -void UpdateAge(UINT32 Set, int HitLine) -{ - struct DCACHE_SetStruct *set = &DCache[Set]; - UINT8 old_age = set->Line[HitLine].Age; // 保存命中行原来的年龄 - set->Line[HitLine].Age = 0; // 命中行年龄置0 - - // 调整其他行的年龄 - for (int i = 0; i < DCACHE_LINES_PER_SET; i++) { - if (i == HitLine) continue; // 跳过命中行 - if (set->Line[i].Age < old_age) { - set->Line[i].Age += 1; // 原年龄小于命中行原年龄的加1 - } - } -} -// Data Cache访问接口,Cache模拟器会调用此接口,来实现对你的Data Cache访问 -// Address: 访存字节地址 -// Operation: 操作:读操作('L')、写操作('S')、读-修改-写操作('M') -// DataSize: 数据大小:1字节、2字节、4字节、8字节 -// StoreValue: 当执行写操作的时候,需要写入的数据 -// LoadResult: 当执行读操作的时候,从Cache读出的数据 -// 返回值:'M'表示Miss;'H'表示Hit -UINT8 AccessDataCache(UINT64 Address, UINT8 Operation, UINT8 DataSize, - UINT64 StoreValue, UINT64* LoadResult) -{ - UINT32 Set; - UINT8 Block; - UINT64 Tag; - UINT8 MissFlag = 'M'; - UINT64 ReadValue; - int HitLine = 0; - UINT64 HitLineAddress = 0; - - *LoadResult = 0; - - - // Address被划分为 Tag + Set + Block - - // Set Cache的组索引(每组4行) - Set = (Address >> DCACHE_BYTES_PER_LINE_ADDR_BITS) % DCACHE_SET; - Block = Address % DCACHE_BYTES_PER_LINE; - Tag = (Address >> DCACHE_BYTES_PER_LINE_ADDR_BITS) >> DCACHE_SET_ADDR_BITS; // 地址去掉DCACHE_SET、DCACHE_BYTES_PER_LINE,剩下的作为Tag。警告!不能将整个地址作为Tag!! - - // 1. 首先需要检查对应的DCache行,其Valid位是否有效?Tag是否与AddressTag相等? - // 2. 如果Valid有效,且AddressTag相等,则意味着Cache访问“命中” - // 3. 如果“命中”,需要进一步判断是要读('L')还是写('S')或者是修改('M')? - MissFlag = 'M'; - for (int i = 0; i < DCACHE_LINES_PER_SET; i++) - { - if (DCache[Set].Line[i].Valid == 1 && DCache[Set].Line[i].Tag == Tag) - { - MissFlag = 'H'; - HitLine = i; - HitLineAddress = ((DCache[Set].Line[HitLine].Tag << DCACHE_SET_ADDR_BITS) << - DCACHE_BYTES_PER_LINE_ADDR_BITS) | ((UINT64)Set << - DCACHE_BYTES_PER_LINE_ADDR_BITS); // 从Tag中恢复旧的地址 - break; - } - } - if (MissFlag == 'H') - { - if (Operation == 'L') // 读操作。从DCache对应行中,读取数据,注意数据宽度与对齐要求 - { - ReadValue = 0; - switch (DataSize) - { - case 1: // 1个字节 - ReadValue = DCache[Set].Line[HitLine].Data[Block + 0]; - break; - case 2: // 2个字节 - Block = Block & 0xFE; // 需对齐到2字节边界 - ReadValue = DCache[Set].Line[HitLine].Data[Block + 1]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 0]; - break; - case 4: // 4个字节 - Block = Block & 0xFC; // 需对齐到4字节边界 - ReadValue = DCache[Set].Line[HitLine].Data[Block + 3]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 2]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 1]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 0]; - break; - case 8: // 8个字节 - Block = Block & 0xF8; // 需对齐到8字节边界 - ReadValue = DCache[Set].Line[HitLine].Data[Block + 7]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 6]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 5]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 4]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 3]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 2]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 1]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 0]; - break; - } - *LoadResult = ReadValue; - if (debug) - printf("[%s] Address=%016llX Operation=%c DataSize=%u StoreValue=%016llX ReadValue=%016llX\n", - __func__, Address, Operation, DataSize, StoreValue, ReadValue); - } - else if (Operation == 'S' || Operation == 'M') // 写操作(修改操作在此等价于写操作) - { - if (debug) - printf("[%s] Address=%016llX Operation=%c DataSize=%u StoreValue=%016llX\n", - __func__, Address, Operation, DataSize, StoreValue); - switch (DataSize) - { - case 1: // 1个字节 - DCache[Set].Line[HitLine].Data[Block + 0] = StoreValue & 0xFF; - break; - case 2: // 2个字节 - Block = Block & 0xFE; // 需对齐到2字节边界 - DCache[Set].Line[HitLine].Data[Block + 0] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 1] = StoreValue & 0xFF; - break; - case 4: // 4个字节 - Block = Block & 0xFC; // 需对齐到4字节边界 - DCache[Set].Line[HitLine].Data[Block + 0] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 1] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 2] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 3] = StoreValue & 0xFF; - break; - case 8: // 8个字节 - Block = Block & 0xF8; // 需对齐到8字节边界 - DCache[Set].Line[HitLine].Data[Block + 0] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 1] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 2] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 3] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 4] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 5] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 6] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 7] = StoreValue & 0xFF; - break; - } - // 写穿透:每次更新Cache行,都需要把数据同时写入Memory - StoreCacheLineToMemory(HitLineAddress, DCache[Set].Line[HitLine].Data, DCACHE_BYTES_PER_LINE); - } - UpdateAge(Set, HitLine); - } - else - { - if (debug) - printf("[%s] Address=%016llX Operation=%c DataSize=%u StoreValue=%016llX\n", - __func__, Address, Operation, DataSize, StoreValue); - if (Operation == 'L') // 读操作 - { - // 读操作不需要做事情,因为已经MISS了。Cache模拟器会直接从Memory中读取数据,而不需要DCache提供 - // 需要从Memory中读入新的行(真实情况下,这个LoadCacheLineFromMemory需要很长时间的) - HitLine = GetReplaceLine(Set); - LoadCacheLineFromMemory(Address, DCache[Set].Line[HitLine].Data, DCACHE_BYTES_PER_LINE); - DCache[Set].Line[HitLine].Valid = 1; - DCache[Set].Line[HitLine].Tag = Tag; - UpdateAge(Set, HitLine); - } - else if (Operation == 'S' || Operation == 'M') // 写操作(修改操作在此等价于写操作) - { - // 写操作,需要将新的StoreValue写到Memory中 - // 由于存储器访问每次都是8个字节,所以首先需要把旧的8个字节读取回来,然后根据需要更新 - UINT64 AlignAddress = Address & 0xFFFFFFFFFFFFFFF8; // 地址必须对齐到8字节边界 - UINT8 Offset; // 在8字节中的第几个字节? - UINT64 ReadData = (DataSize == 8) ? 0 : ReadMemory(AlignAddress); - UINT64 WriteData = ReadData; - switch (DataSize) - { - case 1: // 1个字节,要确定写入8个字节中的哪1个字节? - Offset = Address & 0x07; // 0~7 - WriteData = (ReadData & ~(0xFF<<8*Offset)) | ((StoreValue &0xFF) << 8*Offset); - break; - case 2: // 2个字节,要确定写入8个字节中的哪2个字节? - Offset = Address & 0x06; // 0、2、4、6 - WriteData = (ReadData & ~(0xFFFF<<8*Offset)) | ((StoreValue &0xFFFF) << 8*Offset); - break; - case 4: // 4个字节,要确定写入8个字节中的哪4个字节? - Offset = Address & 0x04; // 0、4 - WriteData = (ReadData & ~(0xFFFFFFFF << 8*Offset)) | ((StoreValue &0xFFFFFFFF) << 8*Offset); - break; - case 8: // 8个字节 - WriteData = StoreValue; - break; - } - WriteMemory(AlignAddress, WriteData); - // 写非分配。所以对于MISS的写操作,不在Cache中分配行 - } - } - return MissFlag; -} - -#ifdef ICACHE_ENABLE - -/* 指令Cache实现部分,可选实现 */ -void InitInstCache(void) -{ - return; -} - -UINT8 AccessInstCache(UINT64 Address, UINT8 Operation, UINT8 InstSize, - UINT64* InstResult) -{ - // ICache只有Operation = 'I'的操作,只会读。不会写 - // 返回值'M' = Miss,'H'=Hit - return 'M'; -} -#endif - -3 -#include -#include "common.h" - -// debug=1:输出额外调试信息 -int debug = 0; - -#define MAX_AGE 3 - -// 组相联Data Cache -// 容量为16384字节,4路组相联,每行容纳16个字节 -#define DCACHE_SIZE 16384 -#define DCACHE_LINES_PER_SET 4 -#define DCACHE_BYTES_PER_LINE 16 // 必须是8字节的倍数 - -// 下面参数是自动计算的,你无须需改 -#define DCACHE_BYTES_PER_LINE_ADDR_BITS GET_LOG_OF_2(DCACHE_BYTES_PER_LINE) -#define DCACHE_SET (DCACHE_SIZE/(DCACHE_BYTES_PER_LINE*DCACHE_LINES_PER_SET)) -#define DCACHE_SET_ADDR_BITS GET_LOG_OF_2(DCACHE_SET) - -// Cache行的结构,包括Valid、Age、Dirty、Tag和Data。你所有的状态信息,只能记录在Cache行中! -struct DCACHE_LineStruct -{ - UINT8 Valid; - UINT8 Age; - UINT8 Dirty; - UINT64 Tag; - UINT8 Data[DCACHE_BYTES_PER_LINE]; -}; - -struct DCACHE_SetStruct { - struct DCACHE_LineStruct Line[4]; // 4路组相联Cache,每组有4行 -} DCache[DCACHE_SET]; - - -// DCache初始化代码,模拟器启动时,会调用此InitDataCache函数 -void InitDataCache() -{ - // *********** 你需要在下面书写代码 *********** - for (int i = 0; i < DCACHE_SET; i++) - { - for (int j = 0; j < 4; j++) - { - DCache[i].Line[j].Valid = 0; - DCache[i].Line[j].Age = j; - DCache[i].Line[j].Dirty = j; - DCache[i].Line[j].Tag = 0; - } - } - // *********** 你需要在上面书写代码 *********** -} - -// 在第Set组中,从4路中,找到需要替换的Cache行 -// 如果4行中,有某行的Valid=0,则返回该行行号 -// 否则,返回Age最大的行的行号 -int GetReplaceLine(UINT32 Set) -{ - // *********** 你需要在下面书写代码 *********** - int replace_line = -1; - UINT8 max_age = 0; - - for (int i = 0; i < 4; i++) - { - if (!DCache[Set].Line[i].Valid) - { - return i; - } - if (DCache[Set].Line[i].Age > max_age) - { - max_age = DCache[Set].Line[i].Age; - replace_line = i; - } - } - return replace_line; - // *********** 你需要在上面书写代码 *********** -} - -// 更新Age,在第Set组中,将HitLine指定的Cache行的Age设置为0,其他行的Age要相应调整 -// 注意!要确保4行的Age分别为0~3,且唯一 -void UpdateAge(UINT32 Set, int HitLine) -{ - // *********** 你需要在下面书写代码 *********** - UINT8 old_age = DCache[Set].Line[HitLine].Age; - DCache[Set].Line[HitLine].Age = 0; - - for (int i = 0; i < 4; i++) - { - if (i != HitLine && DCache[Set].Line[i].Valid) - { - if (DCache[Set].Line[i].Age < old_age) - { - DCache[Set].Line[i].Age++; - } - } - } - // *********** 你需要在上面书写代码 *********** -} - -// Data Cache访问接口,Cache模拟器会调用此接口,来实现对你的Data Cache访问 -// Address: 访存字节地址 -// Operation: 操作:读操作('L')、写操作('S')、读-修改-写操作('M') -// DataSize: 数据大小:1字节、2字节、4字节、8字节 -// StoreValue: 当执行写操作的时候,需要写入的数据 -// LoadResult: 当执行读操作的时候,从Cache读出的数据 -// 返回值:'M'表示Miss;'H'表示Hit -UINT8 AccessDataCache(UINT64 Address, UINT8 Operation, UINT8 DataSize, - UINT64 StoreValue, UINT64* LoadResult) -{ - UINT32 Set; - UINT8 Block; - UINT64 Tag; - UINT8 MissFlag = 'M'; - UINT64 ReadValue; - int HitLine = 0; - UINT64 HitLineAddress = 0; - - *LoadResult = 0; - - - // Address被划分为 Tag + Set + Block - - // Set Cache的组索引(每组4行) - Set = (Address >> DCACHE_BYTES_PER_LINE_ADDR_BITS) % DCACHE_SET; - Block = Address % DCACHE_BYTES_PER_LINE; - Tag = (Address >> DCACHE_BYTES_PER_LINE_ADDR_BITS) >> DCACHE_SET_ADDR_BITS; // 地址去掉DCACHE_SET、DCACHE_BYTES_PER_LINE,剩下的作为Tag。警告!不能将整个地址作为Tag!! - - // 1. 首先需要检查对应的DCache行,其Valid位是否有效?Tag是否与AddressTag相等? - // 2. 如果Valid有效,且AddressTag相等,则意味着Cache访问“命中” - // 3. 如果“命中”,需要进一步判断是要读('L')还是写('S')或者是修改('M')? - MissFlag = 'M'; - for (int i = 0; i < DCACHE_LINES_PER_SET; i++) - { - if (DCache[Set].Line[i].Valid == 1 && DCache[Set].Line[i].Tag == Tag) - { - MissFlag = 'H'; - HitLine = i; - HitLineAddress = ((DCache[Set].Line[HitLine].Tag << DCACHE_SET_ADDR_BITS) << - DCACHE_BYTES_PER_LINE_ADDR_BITS) | ((UINT64)Set << - DCACHE_BYTES_PER_LINE_ADDR_BITS); // 从Tag中恢复旧的地址 - break; - } - } - if (MissFlag == 'H') - { - UpdateAge(Set, HitLine); - if (Operation == 'L') // 读操作。从DCache对应行中,读取数据,注意数据宽度与对齐要求 - { - ReadValue = 0; - switch (DataSize) - { - case 1: // 1个字节 - ReadValue = DCache[Set].Line[HitLine].Data[Block + 0]; - break; - case 2: // 2个字节 - Block = Block & 0xFE; // 需对齐到2字节边界 - ReadValue = DCache[Set].Line[HitLine].Data[Block + 1]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 0]; - break; - case 4: // 4个字节 - Block = Block & 0xFC; // 需对齐到4字节边界 - ReadValue = DCache[Set].Line[HitLine].Data[Block + 3]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 2]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 1]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 0]; - break; - case 8: // 8个字节 - Block = Block & 0xF8; // 需对齐到8字节边界 - ReadValue = DCache[Set].Line[HitLine].Data[Block + 7]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 6]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 5]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 4]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 3]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 2]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 1]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 0]; - break; - } - *LoadResult = ReadValue; - if (debug) - printf("[%s] Address=%016llX Operation=%c DataSize=%u StoreValue=%016llX ReadValue=%016llX\n", - __func__, Address, Operation, DataSize, StoreValue, ReadValue); - } - else if (Operation == 'S' || Operation == 'M') // 写操作(修改操作在此等价于写操作) - { - if (debug) - printf("[%s] Address=%016llX Operation=%c DataSize=%u StoreValue=%016llX\n", - __func__, Address, Operation, DataSize, StoreValue); - switch (DataSize) - { - case 1: // 1个字节 - DCache[Set].Line[HitLine].Data[Block + 0] = StoreValue & 0xFF; - break; - case 2: // 2个字节 - Block = Block & 0xFE; // 需对齐到2字节边界 - DCache[Set].Line[HitLine].Data[Block + 0] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 1] = StoreValue & 0xFF; - break; - case 4: // 4个字节 - Block = Block & 0xFC; // 需对齐到4字节边界 - DCache[Set].Line[HitLine].Data[Block + 0] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 1] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 2] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 3] = StoreValue & 0xFF; - break; - case 8: // 8个字节 - Block = Block & 0xF8; // 需对齐到8字节边界 - DCache[Set].Line[HitLine].Data[Block + 0] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 1] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 2] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 3] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 4] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 5] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 6] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 7] = StoreValue & 0xFF; - break; - } - // 写穿透:每次更新Cache行,都需要把数据同时写入Memory - //StoreCacheLineToMemory(HitLineAddress, DCache[Set].Line[HitLine].Data, DCACHE_BYTES_PER_LINE); - DCache[Set].Line[HitLine].Dirty = 1; //标记脏数据 - } - UpdateAge(Set, HitLine); - } - else - { - if (debug) - printf("[%s] Address=%016llX Operation=%c DataSize=%u StoreValue=%016llX\n", - __func__, Address, Operation, DataSize, StoreValue); - if (Operation == 'L' || Operation == 'M' || Operation == 'S') // 读操作 - { - // 需要从Memory中读入新的行(真实情况下,这个LoadCacheLineFromMemory需要很长时间的) - int ReLine = GetReplaceLine(Set); - UINT64 ReLineAddress = 0; - - //写回:当被替换的数据为脏数据时,我们需要先将该行数据首先写入到Memory中,再执行替换 - if(DCache[Set].Line[ReLine].Dirty == 1 && DCache[Set].Line[ReLine].Valid == 1) - { - ReLineAddress = (DCache[Set].Line[ReLine].Tag << (DCACHE_SET_ADDR_BITS + DCACHE_BYTES_PER_LINE_ADDR_BITS)) | ((UINT64)Set << DCACHE_BYTES_PER_LINE_ADDR_BITS); // 从Tag中恢复旧的地址 - StoreCacheLineToMemory(ReLineAddress, DCache[Set].Line[ReLine].Data, DCACHE_BYTES_PER_LINE); - } - - //开始替换,加载新数据 - LoadCacheLineFromMemory(Address, DCache[Set].Line[ReLine].Data, DCACHE_BYTES_PER_LINE); - DCache[Set].Line[ReLine].Valid = 1; - DCache[Set].Line[ReLine].Tag = Tag; - DCache[Set].Line[ReLine].Dirty = 0; - UpdateAge(Set, ReLine); - - if(Operation == 'M' || Operation == 'S') - { - switch (DataSize) - { - case 1: // 1个字节 - DCache[Set].Line[ReLine].Data[Block + 0] = StoreValue & 0xFF; - break; - case 2: // 2个字节 - Block = Block & 0xFE; // 需对齐到2字节边界 - DCache[Set].Line[ReLine].Data[Block + 0] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[ReLine].Data[Block + 1] = StoreValue & 0xFF; - break; - case 4: // 4个字节 - Block = Block & 0xFC; // 需对齐到4字节边界 - DCache[Set].Line[ReLine].Data[Block + 0] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[ReLine].Data[Block + 1] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[ReLine].Data[Block + 2] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[ReLine].Data[Block + 3] = StoreValue & 0xFF; - break; - case 8: // 8个字节 - Block = Block & 0xF8; // 需对齐到8字节边界 - DCache[Set].Line[ReLine].Data[Block + 0] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[ReLine].Data[Block + 1] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[ReLine].Data[Block + 2] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[ReLine].Data[Block + 3] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[ReLine].Data[Block + 4] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[ReLine].Data[Block + 5] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[ReLine].Data[Block + 6] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[ReLine].Data[Block + 7] = StoreValue & 0xFF; - break; - } - DCache[Set].Line[ReLine].Dirty = 1; - } - UpdateAge(Set, ReLine); - } - } - return MissFlag; -} - -#ifdef ICACHE_ENABLE - -/* 指令Cache实现部分,可选实现 */ -void InitInstCache(void) -{ - return; -} - -UINT8 AccessInstCache(UINT64 Address, UINT8 Operation, UINT8 InstSize, - UINT64* InstResult) -{ - // ICache只有Operation = 'I'的操作,只会读。不会写 - // 返回值'M' = Miss,'H'=Hit - return 'M'; -} -#endif - -4 -#include -#include "common.h" - -// debug=1:输出额外调试信息 -int debug = 0; - -// 组相联Data Cache -// 容量为16384字节,4路组相联,每行容纳16个字节 -#define DCACHE_SIZE 16384 -#define DCACHE_LINES_PER_SET 4 -#define DCACHE_BYTES_PER_LINE 16 // 必须是8字节的倍数 - -// 下面参数是自动计算的,你无须需改 -#define DCACHE_BYTES_PER_LINE_ADDR_BITS GET_LOG_OF_2(DCACHE_BYTES_PER_LINE) -#define DCACHE_SET (DCACHE_SIZE/(DCACHE_BYTES_PER_LINE*DCACHE_LINES_PER_SET)) -#define DCACHE_SET_ADDR_BITS GET_LOG_OF_2(DCACHE_SET) - -// Cache行的结构,包括Valid、Age、Dirty、Tag和Data。你所有的状态信息,只能记录在Cache行中! -struct DCACHE_LineStruct -{ - UINT8 Valid; - UINT8 Age; - UINT8 Dirty; - UINT64 Tag; - UINT8 Data[DCACHE_BYTES_PER_LINE]; -}; - -struct DCACHE_SetStruct { - struct DCACHE_LineStruct Line[4]; // 4路组相联Cache,每组有4行 -} DCache[DCACHE_SET]; - - -// DCache初始化代码,模拟器启动时,会调用此InitDataCache函数 -void InitDataCache() -{ - // *********** 你需要在下面书写代码 *********** - for (int i = 0; i < DCACHE_SET; i++) - { - for (int j = 0; j < 4; j++) - { - DCache[i].Line[j].Valid = 0; - DCache[i].Line[j].Age = j; - DCache[i].Line[j].Dirty = j; - DCache[i].Line[j].Tag = 0; - } - } - // *********** 你需要在上面书写代码 *********** -} - -// 在第Set组中,从4路中,找到需要替换的Cache行 -// 如果4行中,有某行的Valid=0,则返回该行行号 -// 否则,返回Age=0的行的行号 -int GetReplaceLine(UINT32 Set) -{ - // *********** 你需要在下面书写代码 *********** - int replace_line = -1; - - for (int i = 0; i < 4; i++) - { - if (!DCache[Set].Line[i].Valid) - { - return i; - } - if (DCache[Set].Line[i].Age == 0) - { - replace_line = i; - } - } - return replace_line; - // *********** 你需要在上面书写代码 *********** - return -1; -} - -// 更新Age,在第Set组中,将HitLine指定的Cache行的Age设置为0,其他行的Age要相应调整 -// 注意!要确保4行的Age分别为0~3,且唯一 -void UpdateAge(UINT32 Set, int HitLine) -{ - // *********** 你需要在下面书写代码 *********** - UINT8 old_age = DCache[Set].Line[HitLine].Age; - DCache[Set].Line[HitLine].Age = 0; - - for (int i = 0; i < 4; i++) - { - if (i != HitLine && DCache[Set].Line[i].Valid) - { - if (DCache[Set].Line[i].Age < old_age) - { - DCache[Set].Line[i].Age++; - } - } - } - // *********** 你需要在上面书写代码 *********** -} - -// Data Cache访问接口,Cache模拟器会调用此接口,来实现对你的Data Cache访问 -// Address: 访存字节地址 -// Operation: 操作:读操作('L')、写操作('S')、读-修改-写操作('M') -// DataSize: 数据大小:1字节、2字节、4字节、8字节 -// StoreValue: 当执行写操作的时候,需要写入的数据 -// LoadResult: 当执行读操作的时候,从Cache读出的数据 -// 返回值:'M'表示Miss;'H'表示Hit -UINT8 AccessDataCache(UINT64 Address, UINT8 Operation, UINT8 DataSize, - UINT64 StoreValue, UINT64* LoadResult) -{ - UINT32 Set; - UINT8 Block; - UINT64 Tag; - UINT8 MissFlag = 'M'; - UINT64 ReadValue; - int HitLine = 0; - UINT64 HitLineAddress = 0; - - *LoadResult = 0; - - - // Address被划分为 Tag + Set + Block - - // Set Cache的组索引(每组4行) - Set = (Address >> DCACHE_BYTES_PER_LINE_ADDR_BITS) % DCACHE_SET; - Block = Address % DCACHE_BYTES_PER_LINE; - Tag = (Address >> DCACHE_BYTES_PER_LINE_ADDR_BITS) >> DCACHE_SET_ADDR_BITS; // 地址去掉DCACHE_SET、DCACHE_BYTES_PER_LINE,剩下的作为Tag。警告!不能将整个地址作为Tag!! - - // 1. 首先需要检查对应的DCache行,其Valid位是否有效?Tag是否与AddressTag相等? - // 2. 如果Valid有效,且AddressTag相等,则意味着Cache访问“命中” - // 3. 如果“命中”,需要进一步判断是要读('L')还是写('S')或者是修改('M')? - MissFlag = 'M'; - for (int i = 0; i < DCACHE_LINES_PER_SET; i++) - { - if (DCache[Set].Line[i].Valid == 1 && DCache[Set].Line[i].Tag == Tag) - { - MissFlag = 'H'; - HitLine = i; - HitLineAddress = ((DCache[Set].Line[HitLine].Tag << DCACHE_SET_ADDR_BITS) << - DCACHE_BYTES_PER_LINE_ADDR_BITS) | ((UINT64)Set << - DCACHE_BYTES_PER_LINE_ADDR_BITS); // 从Tag中恢复旧的地址 - break; - } - } - if (MissFlag == 'H') - { - UpdateAge(Set, HitLine); - if (Operation == 'L') // 读操作。从DCache对应行中,读取数据,注意数据宽度与对齐要求 - { - ReadValue = 0; - switch (DataSize) - { - case 1: // 1个字节 - ReadValue = DCache[Set].Line[HitLine].Data[Block + 0]; - break; - case 2: // 2个字节 - Block = Block & 0xFE; // 需对齐到2字节边界 - ReadValue = DCache[Set].Line[HitLine].Data[Block + 1]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 0]; - break; - case 4: // 4个字节 - Block = Block & 0xFC; // 需对齐到4字节边界 - ReadValue = DCache[Set].Line[HitLine].Data[Block + 3]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 2]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 1]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 0]; - break; - case 8: // 8个字节 - Block = Block & 0xF8; // 需对齐到8字节边界 - ReadValue = DCache[Set].Line[HitLine].Data[Block + 7]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 6]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 5]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 4]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 3]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 2]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 1]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 0]; - break; - } - *LoadResult = ReadValue; - if (debug) - printf("[%s] Address=%016llX Operation=%c DataSize=%u StoreValue=%016llX ReadValue=%016llX\n", - __func__, Address, Operation, DataSize, StoreValue, ReadValue); - } - else if (Operation == 'S' || Operation == 'M') // 写操作(修改操作在此等价于写操作) - { - if (debug) - printf("[%s] Address=%016llX Operation=%c DataSize=%u StoreValue=%016llX\n", - __func__, Address, Operation, DataSize, StoreValue); - switch (DataSize) - { - case 1: // 1个字节 - DCache[Set].Line[HitLine].Data[Block + 0] = StoreValue & 0xFF; - break; - case 2: // 2个字节 - Block = Block & 0xFE; // 需对齐到2字节边界 - DCache[Set].Line[HitLine].Data[Block + 0] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 1] = StoreValue & 0xFF; - break; - case 4: // 4个字节 - Block = Block & 0xFC; // 需对齐到4字节边界 - DCache[Set].Line[HitLine].Data[Block + 0] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 1] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 2] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 3] = StoreValue & 0xFF; - break; - case 8: // 8个字节 - Block = Block & 0xF8; // 需对齐到8字节边界 - DCache[Set].Line[HitLine].Data[Block + 0] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 1] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 2] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 3] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 4] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 5] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 6] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 7] = StoreValue & 0xFF; - break; - } - // 写穿透:每次更新Cache行,都需要把数据同时写入Memory - //StoreCacheLineToMemory(HitLineAddress, DCache[Set].Line[HitLine].Data, DCACHE_BYTES_PER_LINE); - DCache[Set].Line[HitLine].Dirty = 1; //标记脏数据 - } - UpdateAge(Set, HitLine); - } - else - { - if (debug) - printf("[%s] Address=%016llX Operation=%c DataSize=%u StoreValue=%016llX\n", - __func__, Address, Operation, DataSize, StoreValue); - if (Operation == 'L' || Operation == 'M' || Operation == 'S') // 读操作 - { - // 需要从Memory中读入新的行(真实情况下,这个LoadCacheLineFromMemory需要很长时间的) - int ReLine = GetReplaceLine(Set); - UINT64 ReLineAddress = 0; - - //写回:当被替换的数据为脏数据时,我们需要先将该行数据首先写入到Memory中,再执行替换 - if(DCache[Set].Line[ReLine].Dirty == 1 && DCache[Set].Line[ReLine].Valid == 1) - { - ReLineAddress = (DCache[Set].Line[ReLine].Tag << (DCACHE_SET_ADDR_BITS + DCACHE_BYTES_PER_LINE_ADDR_BITS)) | ((UINT64)Set << DCACHE_BYTES_PER_LINE_ADDR_BITS); // 从Tag中恢复旧的地址 - StoreCacheLineToMemory(ReLineAddress, DCache[Set].Line[ReLine].Data, DCACHE_BYTES_PER_LINE); - } - - //开始替换,加载新数据 - LoadCacheLineFromMemory(Address, DCache[Set].Line[ReLine].Data, DCACHE_BYTES_PER_LINE); - DCache[Set].Line[ReLine].Valid = 1; - DCache[Set].Line[ReLine].Tag = Tag; - DCache[Set].Line[ReLine].Dirty = 0; - UpdateAge(Set, ReLine); - - if(Operation == 'M' || Operation == 'S') - { - switch (DataSize) - { - case 1: // 1个字节 - DCache[Set].Line[ReLine].Data[Block + 0] = StoreValue & 0xFF; - break; - case 2: // 2个字节 - Block = Block & 0xFE; // 需对齐到2字节边界 - DCache[Set].Line[ReLine].Data[Block + 0] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[ReLine].Data[Block + 1] = StoreValue & 0xFF; - break; - case 4: // 4个字节 - Block = Block & 0xFC; // 需对齐到4字节边界 - DCache[Set].Line[ReLine].Data[Block + 0] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[ReLine].Data[Block + 1] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[ReLine].Data[Block + 2] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[ReLine].Data[Block + 3] = StoreValue & 0xFF; - break; - case 8: // 8个字节 - Block = Block & 0xF8; // 需对齐到8字节边界 - DCache[Set].Line[ReLine].Data[Block + 0] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[ReLine].Data[Block + 1] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[ReLine].Data[Block + 2] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[ReLine].Data[Block + 3] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[ReLine].Data[Block + 4] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[ReLine].Data[Block + 5] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[ReLine].Data[Block + 6] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[ReLine].Data[Block + 7] = StoreValue & 0xFF; - break; - } - DCache[Set].Line[ReLine].Dirty = 1; - } - UpdateAge(Set, ReLine); - } - } - return MissFlag; -} - -#ifdef ICACHE_ENABLE - -/* 指令Cache实现部分,可选实现 */ -void InitInstCache(void) -{ - return; -} - -UINT8 AccessInstCache(UINT64 Address, UINT8 Operation, UINT8 InstSize, - UINT64* InstResult) -{ - // ICache只有Operation = 'I'的操作,只会读。不会写 - // 返回值'M' = Miss,'H'=Hit - return 'M'; -} -#endif - -5 -#include -#include "common.h" - -int debug = 0; - -#define DCACHE_SIZE 16384 -#define DCACHE_LINES_PER_SET 4 -#define DCACHE_BYTES_PER_LINE 16 - -#define DCACHE_BYTES_PER_LINE_ADDR_BITS GET_LOG_OF_2(DCACHE_BYTES_PER_LINE) -#define DCACHE_SET (DCACHE_SIZE/(DCACHE_BYTES_PER_LINE*DCACHE_LINES_PER_SET)) -#define DCACHE_SET_ADDR_BITS GET_LOG_OF_2(DCACHE_SET) - -struct DCACHE_LineStruct { - UINT8 Valid; - UINT8 Age; - UINT8 Dirty; - UINT64 Tag; - UINT8 Data[DCACHE_BYTES_PER_LINE]; -}; - -struct DCACHE_SetStruct { - struct DCACHE_LineStruct Line[4]; -} DCache[DCACHE_SET]; - -void InitDataCache() { - for (int s = 0; s < DCACHE_SET; s++) - { - for (int l = 0; l < 4; l++) { - DCache[s].Line[l].Valid = 0; - DCache[s].Line[l].Age = 0; - DCache[s].Line[l].Dirty = 0; - DCache[s].Line[l].Tag = 0; - } - } -} - -int GetReplaceLine(UINT32 Set) { - // 查找无效行 - for (int i = 0; i < 4; i++) { - if (!DCache[Set].Line[i].Valid) return i; - } - - // 查找最大Age行 - int max_age = 0, replace_line = 0; - for (int i = 0; i < 4; i++) { - if (DCache[Set].Line[i].Age > max_age) { - max_age = DCache[Set].Line[i].Age; - replace_line = i; - } - } - return replace_line; -} - -void UpdateAge(UINT32 Set, int HitLine) { - DCache[Set].Line[HitLine].Age = 0; - for (int i = 0; i < 4; i++) { - if (i != HitLine && DCache[Set].Line[i].Valid) { - DCache[Set].Line[i].Age = (DCache[Set].Line[i].Age < 3) ? - DCache[Set].Line[i].Age + 1 : 3; - } - } -} - -UINT8 AccessDataCache(UINT64 Address, UINT8 Operation, UINT8 DataSize, - UINT64 StoreValue, UINT64* LoadResult) -{ - UINT32 Set = (Address >> DCACHE_BYTES_PER_LINE_ADDR_BITS) % DCACHE_SET; - UINT8 Block = Address % DCACHE_BYTES_PER_LINE; - UINT64 Tag = Address >> (DCACHE_BYTES_PER_LINE_ADDR_BITS + DCACHE_SET_ADDR_BITS); - UINT8 MissFlag = 'M'; - int HitLine = -1; - - // 检查命中 - for (int i = 0; i < 4; i++) { - if (DCache[Set].Line[i].Valid && DCache[Set].Line[i].Tag == Tag) { - HitLine = i; - MissFlag = 'H'; - break; - } - } - - if (MissFlag == 'H') { - // 处理数据对齐 - switch (DataSize) { - case 2: Block &= 0xFE; break; - case 4: Block &= 0xFC; break; - case 8: Block &= 0xF8; break; - } - - if (Operation == 'L') { - *LoadResult = 0; - for (int i = DataSize-1; i >= 0; i--) { - *LoadResult = (*LoadResult << 8) | DCache[Set].Line[HitLine].Data[Block+i]; - } - } else { - for (int i = 0; i < DataSize; i++) { - DCache[Set].Line[HitLine].Data[Block+i] = (StoreValue >> (i*8)) & 0xFF; - } - DCache[Set].Line[HitLine].Dirty = 1; - } - } else { - if (Operation == 'L' || Operation == 'S' || Operation == 'M') { - int ReplaceLine = GetReplaceLine(Set); - struct DCACHE_LineStruct *line = &DCache[Set].Line[ReplaceLine]; - - // 写回脏数据 - if (line->Valid && line->Dirty) { - UINT64 old_addr = (line->Tag << (DCACHE_SET_ADDR_BITS + DCACHE_BYTES_PER_LINE_ADDR_BITS)) - | (Set << DCACHE_BYTES_PER_LINE_ADDR_BITS); - StoreCacheLineToMemory(old_addr, line->Data, DCACHE_BYTES_PER_LINE); - } - - // 加载新行 - LoadCacheLineFromMemory(Address, line->Data, DCACHE_BYTES_PER_LINE); - line->Valid = 1; - line->Tag = Tag; - line->Dirty = (Operation == 'L') ? 0 : 1; - - // 更新Age状态 - UpdateAge(Set, ReplaceLine); - - // 处理数据对齐 - switch (DataSize) { - case 2: Block &= 0xFE; break; - case 4: Block &= 0xFC; break; - case 8: Block &= 0xF8; break; - } - - // 处理写操作 - if (Operation != 'L') { - for (int i = 0; i < DataSize; i++) { - line->Data[Block+i] = (StoreValue >> (i*8)) & 0xFF; - } - line->Dirty = 1; - } - - // 返回读数据 - if (Operation == 'L') { - *LoadResult = 0; - for (int i = DataSize-1; i >= 0; i--) { - *LoadResult = (*LoadResult << 8) | line->Data[Block+i]; - } - } - } - } - - return MissFlag; -} - -#ifdef ICACHE_ENABLE -void InitInstCache(void) { return; } -UINT8 AccessInstCache(UINT64 a, UINT8 b, UINT8 c, UINT64* d) { return 'M'; } -#endif - -6 -#include -#include "common.h" - -// debug=1:输出额外调试信息 -int debug = 0; - -// 组相联Data Cache -// 容量为16384字节,4路组相联,每行容纳16个字节 -#define DCACHE_SIZE 16384 -#define DCACHE_LINES_PER_SET 4 -#define DCACHE_BYTES_PER_LINE 16 // 必须是8字节的倍数 - -// 下面参数是自动计算的,你无须需改 -#define DCACHE_BYTES_PER_LINE_ADDR_BITS GET_LOG_OF_2(DCACHE_BYTES_PER_LINE) -#define DCACHE_SET (DCACHE_SIZE/(DCACHE_BYTES_PER_LINE*DCACHE_LINES_PER_SET)) -#define DCACHE_SET_ADDR_BITS GET_LOG_OF_2(DCACHE_SET) - -// Cache行的结构,包括Valid、Age、Dirty、Tag和Data。你所有的状态信息,只能记录在Cache行中! -struct DCACHE_LineStruct -{ - UINT8 Valid; - UINT8 NRU; - UINT8 Dirty; - UINT64 Tag; - UINT8 Data[DCACHE_BYTES_PER_LINE]; -}; - -struct DCACHE_SetStruct { - struct DCACHE_LineStruct Line[4]; // 4路组相联Cache,每组有4行 -} DCache[DCACHE_SET]; - - -// DCache初始化代码,模拟器启动时,会调用此InitDataCache函数 -void InitDataCache() -{ - // *********** 你需要在下面书写代码 *********** - for (int i = 0; i < DCACHE_SET; i++) - { - for (int j = 0; j < 4; j++) - { - DCache[i].Line[j].Valid = 0; - DCache[i].Line[j].NRU = 1; - DCache[i].Line[j].Dirty = 0; - DCache[i].Line[j].Tag = 0; - } - } - // *********** 你需要在上面书写代码 *********** -} - -// 在第Set组中,从4路中,找到需要替换的Cache行 -// 如果4行中,有某行的Valid=0,则返回该行行号 -// 否则,返回NRU位为1的行号 -int GetReplaceLine(UINT32 Set) -{ - // *********** 你需要在下面书写代码 *********** - int replace_line = -1; - - for (int i = 0; i < 4; i++) - { - if (!DCache[Set].Line[i].Valid) - { - return i; - } - if (DCache[Set].Line[i].NRU == 1) - { - replace_line = i; - break; - } - } - - //全部为0时,重置为0并返回首行 - if(replace_line == -1) - { - for(int i = 0; i < 4; i++) - { - DCache[Set].Line[i].NRU = 1; - } - replace_line = 0; - } - return replace_line; - // *********** 你需要在上面书写代码 *********** - return -1; -} - - -// Data Cache访问接口,Cache模拟器会调用此接口,来实现对你的Data Cache访问 -// Address: 访存字节地址 -// Operation: 操作:读操作('L')、写操作('S')、读-修改-写操作('M') -// DataSize: 数据大小:1字节、2字节、4字节、8字节 -// StoreValue: 当执行写操作的时候,需要写入的数据 -// LoadResult: 当执行读操作的时候,从Cache读出的数据 -// 返回值:'M'表示Miss;'H'表示Hit -UINT8 AccessDataCache(UINT64 Address, UINT8 Operation, UINT8 DataSize, - UINT64 StoreValue, UINT64* LoadResult) -{ - UINT32 Set; - UINT8 Block; - UINT64 Tag; - UINT8 MissFlag = 'M'; - UINT64 ReadValue; - int HitLine = 0; - UINT64 HitLineAddress = 0; - - *LoadResult = 0; - - - // Address被划分为 Tag + Set + Block - - // Set Cache的组索引(每组4行) - Set = (Address >> DCACHE_BYTES_PER_LINE_ADDR_BITS) % DCACHE_SET; - Block = Address % DCACHE_BYTES_PER_LINE; - Tag = (Address >> DCACHE_BYTES_PER_LINE_ADDR_BITS) >> DCACHE_SET_ADDR_BITS; // 地址去掉DCACHE_SET、DCACHE_BYTES_PER_LINE,剩下的作为Tag。警告!不能将整个地址作为Tag!! - - // 1. 首先需要检查对应的DCache行,其Valid位是否有效?Tag是否与AddressTag相等? - // 2. 如果Valid有效,且AddressTag相等,则意味着Cache访问“命中” - // 3. 如果“命中”,需要进一步判断是要读('L')还是写('S')或者是修改('M')? - MissFlag = 'M'; - for (int i = 0; i < DCACHE_LINES_PER_SET; i++) - { - if (DCache[Set].Line[i].Valid == 1 && DCache[Set].Line[i].Tag == Tag) - { - MissFlag = 'H'; - HitLine = i; - HitLineAddress = ((DCache[Set].Line[HitLine].Tag << DCACHE_SET_ADDR_BITS) << - DCACHE_BYTES_PER_LINE_ADDR_BITS) | ((UINT64)Set << - DCACHE_BYTES_PER_LINE_ADDR_BITS); // 从Tag中恢复旧的地址 - break; - } - } - if (MissFlag == 'H') - { - //UpdateAge(Set, HitLine); - DCache[Set].Line[HitLine].NRU = 0; - if (Operation == 'L') // 读操作。从DCache对应行中,读取数据,注意数据宽度与对齐要求 - { - ReadValue = 0; - switch (DataSize) - { - case 1: // 1个字节 - ReadValue = DCache[Set].Line[HitLine].Data[Block + 0]; - break; - case 2: // 2个字节 - Block = Block & 0xFE; // 需对齐到2字节边界 - ReadValue = DCache[Set].Line[HitLine].Data[Block + 1]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 0]; - break; - case 4: // 4个字节 - Block = Block & 0xFC; // 需对齐到4字节边界 - ReadValue = DCache[Set].Line[HitLine].Data[Block + 3]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 2]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 1]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 0]; - break; - case 8: // 8个字节 - Block = Block & 0xF8; // 需对齐到8字节边界 - ReadValue = DCache[Set].Line[HitLine].Data[Block + 7]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 6]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 5]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 4]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 3]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 2]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 1]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 0]; - break; - } - *LoadResult = ReadValue; - if (debug) - printf("[%s] Address=%016llX Operation=%c DataSize=%u StoreValue=%016llX ReadValue=%016llX\n", - __func__, Address, Operation, DataSize, StoreValue, ReadValue); - } - else if (Operation == 'S' || Operation == 'M') // 写操作(修改操作在此等价于写操作) - { - if (debug) - printf("[%s] Address=%016llX Operation=%c DataSize=%u StoreValue=%016llX\n", - __func__, Address, Operation, DataSize, StoreValue); - switch (DataSize) - { - case 1: // 1个字节 - DCache[Set].Line[HitLine].Data[Block + 0] = StoreValue & 0xFF; - break; - case 2: // 2个字节 - Block = Block & 0xFE; // 需对齐到2字节边界 - DCache[Set].Line[HitLine].Data[Block + 0] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 1] = StoreValue & 0xFF; - break; - case 4: // 4个字节 - Block = Block & 0xFC; // 需对齐到4字节边界 - DCache[Set].Line[HitLine].Data[Block + 0] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 1] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 2] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 3] = StoreValue & 0xFF; - break; - case 8: // 8个字节 - Block = Block & 0xF8; // 需对齐到8字节边界 - DCache[Set].Line[HitLine].Data[Block + 0] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 1] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 2] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 3] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 4] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 5] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 6] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 7] = StoreValue & 0xFF; - break; - } - // 写穿透:每次更新Cache行,都需要把数据同时写入Memory - //StoreCacheLineToMemory(HitLineAddress, DCache[Set].Line[HitLine].Data, DCACHE_BYTES_PER_LINE); - DCache[Set].Line[HitLine].Dirty = 1; //标记脏数据 - } - //UpdateAge(Set, HitLine); - } - else - { - if (debug) - printf("[%s] Address=%016llX Operation=%c DataSize=%u StoreValue=%016llX\n", - __func__, Address, Operation, DataSize, StoreValue); - if (Operation == 'L' || Operation == 'M' || Operation == 'S') // 读操作 - { - // 需要从Memory中读入新的行(真实情况下,这个LoadCacheLineFromMemory需要很长时间的) - int ReLine = GetReplaceLine(Set); - UINT64 ReLineAddress = 0; - - //写回:当被替换的数据为脏数据时,我们需要先将该行数据首先写入到Memory中,再执行替换 - if(DCache[Set].Line[ReLine].Dirty == 1 && DCache[Set].Line[ReLine].Valid == 1) - { - ReLineAddress = (DCache[Set].Line[ReLine].Tag << (DCACHE_SET_ADDR_BITS + DCACHE_BYTES_PER_LINE_ADDR_BITS)) | ((UINT64)Set << DCACHE_BYTES_PER_LINE_ADDR_BITS); // 从Tag中恢复旧的地址 - StoreCacheLineToMemory(ReLineAddress, DCache[Set].Line[ReLine].Data, DCACHE_BYTES_PER_LINE); - } - - //开始替换,加载新数据 - LoadCacheLineFromMemory(Address, DCache[Set].Line[ReLine].Data, DCACHE_BYTES_PER_LINE); - DCache[Set].Line[ReLine].Valid = 1; - DCache[Set].Line[ReLine].Tag = Tag; - DCache[Set].Line[ReLine].Dirty = 0; - DCache[Set].Line[ReLine].NRU = 0; - //UpdateAge(Set, ReLine); - - if(Operation == 'M' || Operation == 'S') - { - switch (DataSize) - { - case 1: // 1个字节 - DCache[Set].Line[ReLine].Data[Block + 0] = StoreValue & 0xFF; - break; - case 2: // 2个字节 - Block = Block & 0xFE; // 需对齐到2字节边界 - DCache[Set].Line[ReLine].Data[Block + 0] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[ReLine].Data[Block + 1] = StoreValue & 0xFF; - break; - case 4: // 4个字节 - Block = Block & 0xFC; // 需对齐到4字节边界 - DCache[Set].Line[ReLine].Data[Block + 0] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[ReLine].Data[Block + 1] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[ReLine].Data[Block + 2] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[ReLine].Data[Block + 3] = StoreValue & 0xFF; - break; - case 8: // 8个字节 - Block = Block & 0xF8; // 需对齐到8字节边界 - DCache[Set].Line[ReLine].Data[Block + 0] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[ReLine].Data[Block + 1] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[ReLine].Data[Block + 2] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[ReLine].Data[Block + 3] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[ReLine].Data[Block + 4] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[ReLine].Data[Block + 5] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[ReLine].Data[Block + 6] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[ReLine].Data[Block + 7] = StoreValue & 0xFF; - break; - } - DCache[Set].Line[ReLine].Dirty = 1; - } - //UpdateAge(Set, ReLine); - } - } - return MissFlag; -} - -#ifdef ICACHE_ENABLE - -/* 指令Cache实现部分,可选实现 */ -void InitInstCache(void) -{ - return; -} - -UINT8 AccessInstCache(UINT64 Address, UINT8 Operation, UINT8 InstSize, - UINT64* InstResult) -{ - // ICache只有Operation = 'I'的操作,只会读。不会写 - // 返回值'M' = Miss,'H'=Hit - return 'M'; -} -#endif - - -7 -#include -#include "common.h" - -int debug = 0; - -#define DCACHE_SIZE 16384 -#define DCACHE_LINES_PER_SET 4 -#define DCACHE_BYTES_PER_LINE 16 - -#define DCACHE_BYTES_PER_LINE_ADDR_BITS GET_LOG_OF_2(DCACHE_BYTES_PER_LINE) -#define DCACHE_SET (DCACHE_SIZE/(DCACHE_BYTES_PER_LINE*DCACHE_LINES_PER_SET)) -#define DCACHE_SET_ADDR_BITS GET_LOG_OF_2(DCACHE_SET) - -struct DCACHE_LineStruct { - UINT8 Valid; - UINT8 NRU; // 3位RRPV实现 - UINT8 Dirty; - UINT64 Tag; - UINT8 Data[DCACHE_BYTES_PER_LINE]; -}; - -struct DCACHE_SetStruct { - struct DCACHE_LineStruct Line[4]; -} DCache[DCACHE_SET]; - -void InitDataCache() -{ - for (int s = 0; s < DCACHE_SET; s++) - { - for (int l = 0; l < 4; l++) - { - DCache[s].Line[l].Valid = 0; - DCache[s].Line[l].NRU = 6; // 初始化为最大值 - DCache[s].Line[l].Dirty = 0; - DCache[s].Line[l].Tag = 0; - } - } -} - -int GetReplaceLine(UINT32 Set) -{ - // 优先替换无效行 - for (int i = 0; i < 4; i++) { - if (!DCache[Set].Line[i].Valid) return i; - } - - // 查找NRU=7的行 - for (int i = 0; i < 4; i++) { - if (DCache[Set].Line[i].NRU == 7) return i; - } - - while(1) - { - // 所有行NRU加1(最大保持7) - for (int i = 0; i < 4; i++) { - DCache[Set].Line[i].NRU = (DCache[Set].Line[i].NRU < 7) ? - DCache[Set].Line[i].NRU + 1 : 7; - } - - // 再次查找 - for (int i = 0; i < 4; i++) { - if (DCache[Set].Line[i].NRU == 7) return i; - } - } - - return 0; // 保底返回首行 -} - -UINT8 AccessDataCache(UINT64 Address, UINT8 Operation, UINT8 DataSize, - UINT64 StoreValue, UINT64* LoadResult) -{ - UINT32 Set = (Address >> DCACHE_BYTES_PER_LINE_ADDR_BITS) % DCACHE_SET; - UINT8 Block = Address % DCACHE_BYTES_PER_LINE; - UINT64 Tag = Address >> (DCACHE_BYTES_PER_LINE_ADDR_BITS + DCACHE_SET_ADDR_BITS); - UINT8 MissFlag = 'M'; - int HitLine = -1; - - // 命中检测 - for (int i = 0; i < 4; i++) { - if (DCache[Set].Line[i].Valid && DCache[Set].Line[i].Tag == Tag) { - HitLine = i; - MissFlag = 'H'; - DCache[Set].Line[i].NRU = 0; // 命中行NRU置0 - break; - } - } - - if (MissFlag == 'H') { - if (Operation == 'L') { // 读命中 - *LoadResult = 0; - for (int i = DataSize-1; i >= 0; i--) { - *LoadResult = (*LoadResult << 8) | DCache[Set].Line[HitLine].Data[Block+i]; - } - } - else { // 写命中 - for (int i = 0; i < DataSize; i++) { - DCache[Set].Line[HitLine].Data[Block+i] = (StoreValue >> (i*8)) & 0xFF; - } - DCache[Set].Line[HitLine].Dirty = 1; - } - } - else { // 未命中处理 - if (Operation == 'L' || Operation == 'S' || Operation == 'M') { - int ReplaceLine = GetReplaceLine(Set); - struct DCACHE_LineStruct *line = &DCache[Set].Line[ReplaceLine]; - - // 写回脏数据 - if (line->Valid && line->Dirty) { - UINT64 old_addr = (line->Tag << (DCACHE_SET_ADDR_BITS + DCACHE_BYTES_PER_LINE_ADDR_BITS)) - | (Set << DCACHE_BYTES_PER_LINE_ADDR_BITS); - StoreCacheLineToMemory(old_addr, line->Data, DCACHE_BYTES_PER_LINE); - } - - // 加载新行(写分配) - LoadCacheLineFromMemory(Address, line->Data, DCACHE_BYTES_PER_LINE); - line->Valid = 1; - line->Tag = Tag; - line->NRU = 6; // 初始NRU设为6 - line->Dirty = 0; - - // 写操作处理 - if (Operation != 'L') { - for (int i = 0; i < DataSize; i++) { - line->Data[Block+i] = (StoreValue >> (i*8)) & 0xFF; - } - line->Dirty = 1; - } - - // 读操作设置结果 - if (Operation == 'L') { - *LoadResult = 0; - for (int i = DataSize-1; i >= 0; i--) { - *LoadResult = (*LoadResult << 8) | line->Data[Block+i]; - } - } - } - } - return MissFlag; -} - -#ifdef ICACHE_ENABLE -void InitInstCache(void) { return; } -UINT8 AccessInstCache(UINT64 a, UINT8 b, UINT8 c, UINT64* d) { return 'M'; } -#endif - -9 -#include -#include "common.h" - -// debug=1:输出额外调试信息 -int debug = 0; - - -// 全相联Data Cache -// 容量为16384字节,每行容纳16个字节 -#define DCACHE_SIZE 16384 -#define DCACHE_BYTES_PER_LINE 16 // 必须是8字节的倍数 - -// 下面参数是自动计算的,你无须需改 -#define DCACHE_BYTES_PER_LINE_ADDR_BITS GET_LOG_OF_2(DCACHE_BYTES_PER_LINE) -#define DCACHE_LINES (DCACHE_SIZE/DCACHE_BYTES_PER_LINE) - -#define MAX_AGE (DCACHE_LINES-1) // 每1行有一个唯一的Age - -// Cache行的结构,包括Valid、Age、Dirty、Tag和Data。你所有的状态信息,只能记录在Cache行中! -struct DCACHE_LineStruct -{ - UINT8 Valid; - UINT16 Age; - UINT8 Dirty; - UINT64 Tag; - UINT8 Data[DCACHE_BYTES_PER_LINE]; -}; - -struct DCACHE_SetStruct { - struct DCACHE_LineStruct Line[DCACHE_LINES]; -} DCache; - - -// DCache初始化代码,模拟器启动时,会调用此InitDataCache函数 -void InitDataCache() -{ - // *********** 你需要在下面书写代码 *********** - for (int i = 0; i < DCACHE_LINES; i++) - { - DCache.Line[i].Valid = 0; - DCache.Line[i].Age = i; - DCache.Line[i].Tag = 0; - DCache.Line[i].Dirty = 0; - } - // *********** 你需要在上面书写代码 *********** -} - -// 从所有行中,找到需要替换的Cache行 -// 如果有某行的Valid=0,则返回该行行号 -// 否则,返回Age最大的行的行号 -int GetReplaceLine() -{ - // *********** 你需要在下面书写代码 *********** - int replace_line = -1; - UINT8 max_age = 0; - - for (int i = 0; i < DCACHE_LINES; i++) - { - if (!DCache.Line[i].Valid) - { - return i; - } - if (DCache.Line[i].Age > max_age) - { - max_age = DCache.Line[i].Age; - replace_line = i; - } - } - return replace_line; - // *********** 你需要在上面书写代码 *********** - return -1; -} - -// 更新Age,将HitLine指定的Cache行的Age设置为0,其他行的Age要相应调整 -// 注意!要确保所有行的Age分别为0~MAX_AGE,且唯一 -void UpdateAge(int HitLine) -{ - // *********** 你需要在下面书写代码 *********** - UINT8 old_age = DCache.Line[HitLine].Age; - DCache.Line[HitLine].Age = 0; - - for (int i = 0; i < DCACHE_LINES; i++) - { - if (i != HitLine && DCache.Line[i].Valid) - { - if (DCache.Line[i].Age < old_age) - { - DCache.Line[i].Age++; - } - } - } - // *********** 你需要在上面书写代码 *********** -} - -// Data Cache访问接口,Cache模拟器会调用此接口,来实现对你的Data Cache访问 -// Address: 访存字节地址 -// Operation: 操作:读操作('L')、写操作('S')、读-修改-写操作('M') -// DataSize: 数据大小:1字节、2字节、4字节、8字节 -// StoreValue: 当执行写操作的时候,需要写入的数据 -// LoadResult: 当执行读操作的时候,从Cache读出的数据 -// 返回值:'M'表示Miss;'H'表示Hit -UINT8 AccessDataCache(UINT64 Address, UINT8 Operation, UINT8 DataSize, - UINT64 StoreValue, UINT64* LoadResult) -{ - //UINT32 Set; - UINT8 Block; - UINT64 Tag; - UINT8 MissFlag = 'M'; - UINT64 ReadValue; - int HitLine = 0; - UINT64 HitLineAddress = 0; - - *LoadResult = 0; - - - // Address被划分为 Tag + Set + Block - - // Set Cache的组索引(每组4行) - //Set = (Address >> DCACHE_BYTES_PER_LINE_ADDR_BITS) % DCACHE_SET; - Block = Address % DCACHE_BYTES_PER_LINE; - //Tag = (Address >> DCACHE_BYTES_PER_LINE_ADDR_BITS) >> DCACHE_SET_ADDR_BITS; // 地址去掉DCACHE_SET、DCACHE_BYTES_PER_LINE,剩下的作为Tag。警告!不能将整个地址作为Tag!! - Tag = (Address >> DCACHE_BYTES_PER_LINE_ADDR_BITS); - - // 1. 首先需要检查对应的DCache行,其Valid位是否有效?Tag是否与AddressTag相等? - // 2. 如果Valid有效,且AddressTag相等,则意味着Cache访问“命中” - // 3. 如果“命中”,需要进一步判断是要读('L')还是写('S')或者是修改('M')? - MissFlag = 'M'; - for (int i = 0; i < DCACHE_LINES; i++) - { - if (DCache.Line[i].Valid == 1 && DCache.Line[i].Tag == Tag) - { - MissFlag = 'H'; - HitLine = i; - // HitLineAddress = ((DCache.Line[HitLine].Tag << DCACHE_SET_ADDR_BITS) << - // DCACHE_BYTES_PER_LINE_ADDR_BITS) | ((UINT64)Set << - // DCACHE_BYTES_PER_LINE_ADDR_BITS); // 从Tag中恢复旧的地址 - break; - } - } - if (MissFlag == 'H') - { - if (Operation == 'L') // 读操作。从DCache对应行中,读取数据,注意数据宽度与对齐要求 - { - ReadValue = 0; - switch (DataSize) - { - case 1: // 1个字节 - ReadValue = DCache.Line[HitLine].Data[Block + 0]; - break; - case 2: // 2个字节 - Block = Block & 0xFE; // 需对齐到2字节边界 - ReadValue = DCache.Line[HitLine].Data[Block + 1]; - ReadValue = ReadValue << 8; - ReadValue |= DCache.Line[HitLine].Data[Block + 0]; - break; - case 4: // 4个字节 - Block = Block & 0xFC; // 需对齐到4字节边界 - ReadValue = DCache.Line[HitLine].Data[Block + 3]; - ReadValue = ReadValue << 8; - ReadValue |= DCache.Line[HitLine].Data[Block + 2]; - ReadValue = ReadValue << 8; - ReadValue |= DCache.Line[HitLine].Data[Block + 1]; - ReadValue = ReadValue << 8; - ReadValue |= DCache.Line[HitLine].Data[Block + 0]; - break; - case 8: // 8个字节 - Block = Block & 0xF8; // 需对齐到8字节边界 - ReadValue = DCache.Line[HitLine].Data[Block + 7]; - ReadValue = ReadValue << 8; - ReadValue |= DCache.Line[HitLine].Data[Block + 6]; - ReadValue = ReadValue << 8; - ReadValue |= DCache.Line[HitLine].Data[Block + 5]; - ReadValue = ReadValue << 8; - ReadValue |= DCache.Line[HitLine].Data[Block + 4]; - ReadValue = ReadValue << 8; - ReadValue |= DCache.Line[HitLine].Data[Block + 3]; - ReadValue = ReadValue << 8; - ReadValue |= DCache.Line[HitLine].Data[Block + 2]; - ReadValue = ReadValue << 8; - ReadValue |= DCache.Line[HitLine].Data[Block + 1]; - ReadValue = ReadValue << 8; - ReadValue |= DCache.Line[HitLine].Data[Block + 0]; - break; - } - *LoadResult = ReadValue; - if (debug) - printf("[%s] Address=%016llX Operation=%c DataSize=%u StoreValue=%016llX ReadValue=%016llX\n", - __func__, Address, Operation, DataSize, StoreValue, ReadValue); - } - else if (Operation == 'S' || Operation == 'M') // 写操作(修改操作在此等价于写操作) - { - if (debug) - printf("[%s] Address=%016llX Operation=%c DataSize=%u StoreValue=%016llX\n", - __func__, Address, Operation, DataSize, StoreValue); - switch (DataSize) - { - case 1: // 1个字节 - DCache.Line[HitLine].Data[Block + 0] = StoreValue & 0xFF; - break; - case 2: // 2个字节 - Block = Block & 0xFE; // 需对齐到2字节边界 - DCache.Line[HitLine].Data[Block + 0] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache.Line[HitLine].Data[Block + 1] = StoreValue & 0xFF; - break; - case 4: // 4个字节 - Block = Block & 0xFC; // 需对齐到4字节边界 - DCache.Line[HitLine].Data[Block + 0] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache.Line[HitLine].Data[Block + 1] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache.Line[HitLine].Data[Block + 2] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache.Line[HitLine].Data[Block + 3] = StoreValue & 0xFF; - break; - case 8: // 8个字节 - Block = Block & 0xF8; // 需对齐到8字节边界 - DCache.Line[HitLine].Data[Block + 0] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache.Line[HitLine].Data[Block + 1] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache.Line[HitLine].Data[Block + 2] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache.Line[HitLine].Data[Block + 3] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache.Line[HitLine].Data[Block + 4] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache.Line[HitLine].Data[Block + 5] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache.Line[HitLine].Data[Block + 6] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache.Line[HitLine].Data[Block + 7] = StoreValue & 0xFF; - break; - } - // 写穿透:每次更新Cache行,都需要把数据同时写入Memory - //StoreCacheLineToMemory(HitLineAddress, DCache[Set].Line[HitLine].Data, DCACHE_BYTES_PER_LINE); - DCache.Line[HitLine].Dirty = 1; //标记脏数据 - } - UpdateAge(HitLine); - } - else - { - if (debug) - printf("[%s] Address=%016llX Operation=%c DataSize=%u StoreValue=%016llX\n", - __func__, Address, Operation, DataSize, StoreValue); - if (Operation == 'L' || Operation == 'M' || Operation == 'S') // 读操作 - { - // 需要从Memory中读入新的行(真实情况下,这个LoadCacheLineFromMemory需要很长时间的) - int ReLine = GetReplaceLine(); - UINT64 ReLineAddress = 0; - - //写回:当被替换的数据为脏数据时,我们需要先将该行数据首先写入到Memory中,再执行替换 - if(DCache.Line[ReLine].Dirty == 1 && DCache.Line[ReLine].Valid == 1) - { - ReLineAddress = DCache.Line[ReLine].Tag << DCACHE_BYTES_PER_LINE_ADDR_BITS; // 从Tag中恢复旧的地址 - StoreCacheLineToMemory(ReLineAddress, DCache.Line[ReLine].Data, DCACHE_BYTES_PER_LINE); - } - - //开始替换,加载新数据 - LoadCacheLineFromMemory(Address, DCache.Line[ReLine].Data, DCACHE_BYTES_PER_LINE); - DCache.Line[ReLine].Valid = 1; - DCache.Line[ReLine].Tag = Tag; - DCache.Line[ReLine].Dirty = 0; - UpdateAge(ReLine); - - if(Operation == 'M' || Operation == 'S') - { - switch (DataSize) - { - case 1: // 1个字节 - DCache.Line[ReLine].Data[Block + 0] = StoreValue & 0xFF; - break; - case 2: // 2个字节 - Block = Block & 0xFE; // 需对齐到2字节边界 - DCache.Line[ReLine].Data[Block + 0] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache.Line[ReLine].Data[Block + 1] = StoreValue & 0xFF; - break; - case 4: // 4个字节 - Block = Block & 0xFC; // 需对齐到4字节边界 - DCache.Line[ReLine].Data[Block + 0] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache.Line[ReLine].Data[Block + 1] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache.Line[ReLine].Data[Block + 2] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache.Line[ReLine].Data[Block + 3] = StoreValue & 0xFF; - break; - case 8: // 8个字节 - Block = Block & 0xF8; // 需对齐到8字节边界 - DCache.Line[ReLine].Data[Block + 0] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache.Line[ReLine].Data[Block + 1] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache.Line[ReLine].Data[Block + 2] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache.Line[ReLine].Data[Block + 3] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache.Line[ReLine].Data[Block + 4] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache.Line[ReLine].Data[Block + 5] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache.Line[ReLine].Data[Block + 6] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache.Line[ReLine].Data[Block + 7] = StoreValue & 0xFF; - break; - } - DCache.Line[ReLine].Dirty = 1; - } - //UpdateAge(ReLine); - } - } - return MissFlag; -} - -#ifdef ICACHE_ENABLE - -/* 指令Cache实现部分,可选实现 */ -void InitInstCache(void) -{ - return; -} - -UINT8 AccessInstCache(UINT64 Address, UINT8 Operation, UINT8 InstSize, - UINT64* InstResult) -{ - // ICache只有Operation = 'I'的操作,只会读。不会写 - // 返回值'M' = Miss,'H'=Hit - return 'M'; -} -#endif - diff --git a/cachelab/Cache.bak2 b/cachelab/Cache.bak2 deleted file mode 100644 index 316bc9d..0000000 --- a/cachelab/Cache.bak2 +++ /dev/null @@ -1,403 +0,0 @@ -/////////////////////////////////////////////////////////////////////// -//// Copyright 2022 by mars. // -/////////////////////////////////////////////////////////////////////// - -#include -#include - -#include "common.h" - -#define DEBUG 0 - -#define GET_POWER_OF_2(X) (X == 0x00 ? 0 : \ - X == 0x01 ? 0 : \ - X == 0x02 ? 1 : \ - X == 0x04 ? 2 : \ - X == 0x08 ? 3 : \ - X == 0x10 ? 4 : \ - X == 0x20 ? 5 : \ - X == 0x40 ? 6 : \ - X == 0x80 ? 7 : \ - X == 0x100 ? 8 : \ - X == 0x200 ? 9 : \ - X == 0x400 ? 10 : \ - X == 0x800 ? 11 : \ - X == 0x1000 ? 12 : \ - X == 0x2000 ? 13 : \ - X == 0x4000 ? 14 : \ - X == 0x8000 ? 15 : \ - X == 0x10000 ? 16 : \ - X == 0x20000 ? 17 : \ - X == 0x40000 ? 18 : \ - X == 0x80000 ? 19 : \ - X == 0x100000 ? 20 : \ - X == 0x200000 ? 21 : \ - X == 0x400000 ? 22 : \ - X == 0x800000 ? 23 : \ - X == 0x1000000 ? 24 : \ - X == 0x2000000 ? 25 : \ - X == 0x4000000 ? 26 : \ - X == 0x8000000 ? 27 : \ - X == 0x10000000 ? 28 : \ - X == 0x20000000 ? 29 : \ - X == 0x40000000 ? 30 : \ - X == 0x80000000 ? 31 : \ - X == 0x100000000 ? 32 : 0) - -/* - 全相联Data Cache,16KB大小 - 每行存放64个字节 -*/ -#define DCACHE_SIZE 16384 -#define DCACHE_DATA_PER_LINE 128 // 必须是8字节的倍数 -#define DCACHE_DATA_PER_LINE_ADDR_BITS GET_POWER_OF_2(DCACHE_DATA_PER_LINE) // 必须与上面设置一致,即64字节,需要6位地址 -#define DCACHE_LINES (DCACHE_SIZE/DCACHE_DATA_PER_LINE) -#define MAX_AGE (DCACHE_LINES-1) // 每行有一个唯一的Age - -// Cache行的结构,包括Valid、Age、Dirty、Tag和Data。你所有的状态信息,只能记录在Cache行中! -struct DCACHE_LineStruct -{ - UINT8 Valid; - UINT16 Age; - UINT8 Dirty; - UINT64 Tag; - UINT8 Data[DCACHE_DATA_PER_LINE]; -} DCache[DCACHE_LINES]; - -/* - DCache初始化代码,一般需要把DCache的有效位Valid设置为0 - 模拟器启动时,会调用此InitDataCache函数 -*/ -void InitDataCache() -{ - UINT32 i; - printf("[%s] +-----------------------------------+\n", __func__); - printf("[%s] | 威震天的Data Cache初始化ing.... |\n", __func__); - printf("[%s] +-----------------------------------+\n", __func__); - for (i = 0; i < DCACHE_LINES; i++) { - DCache[i].Valid = 0; - DCache[i].Age = i; - DCache[i].Dirty = 0; - } -} - -/* - 从Memory中读入一行数据到Data Cache中 -*/ -void LoadDataCacheLineFromMemory(UINT64 Address, UINT32 CacheLineIndex) -{ - // 一次性从Memory中将DCACHE_DATA_PER_LINE数据读入某个Data Cache行 - // 提供了一个函数,一次可以读入8个字节 - UINT32 i; - UINT64 ReadData; - UINT64 AlignAddress; - UINT64* pp; - - AlignAddress = Address & ~(DCACHE_DATA_PER_LINE - 1); // 地址必须对齐到DCACHE_DATA_PER_LINE (64)字节边界 - pp = (UINT64*)DCache[CacheLineIndex].Data; - for (i = 0; i < DCACHE_DATA_PER_LINE / 8; i++) - { - ReadData = ReadMemory(AlignAddress + 8LL * i); - if (DEBUG) - printf("[%s] Address=%016llX ReadData=%016llX\n", __func__, AlignAddress + 8LL * i, ReadData); - pp[i] = ReadData; - } -} - -/* - 将Data Cache中的一行数据,写入存储器 -*/ -void StoreDataCacheLineToMemory(UINT64 Address, UINT32 CacheLineIndex) -{ - // 一次性将DCACHE_DATA_PER_LINE数据从某个Data Cache行写入Memory中 - // 提供了一个函数,一次可以写入8个字节 - UINT32 i; - UINT64 WriteData; - UINT64 AlignAddress; - UINT64* pp; - - AlignAddress = Address & ~(DCACHE_DATA_PER_LINE - 1); // 地址必须对齐到DCACHE_DATA_PER_LINE (64)字节边界 - pp = (UINT64*)DCache[CacheLineIndex].Data; - WriteData = 0; - for (i = 0; i < DCACHE_DATA_PER_LINE / 8; i++) - { - WriteData = pp[i]; - WriteMemory(AlignAddress + 8LL * i, WriteData); - if (DEBUG) - printf("[%s] Address=%016llX WriteData=%016llX\n", __func__, AlignAddress + 8LL * i, WriteData); - } -} - -// 从所有行中,找到需要替换的Cache行 -// 如果有某行的Valid=0,则返回该行行号 -// 否则,返回Age最大的行的行号 -int GetReplaceLine() -{ - int replace_line = -1; - UINT16 max_age = 0; - - for (int i = 0; i < DCACHE_LINES; i++) - { - if (!DCache[i].Valid) - { - return i; - } - if (DCache[i].Age > max_age) - { - max_age = DCache[i].Age; - replace_line = i; - } - } - return replace_line; -} - -// 更新Age,将HitLine指定的Cache行的Age设置为0,其他行的Age要相应调整 -// 注意!要确保所有行的Age分别为0~MAX_AGE,且唯一 -// void UpdateAge(int HitLine) -// { -// for (int i = 0; i < DCACHE_LINES; i++) { -// if (i != HitLine && DCache[i].Valid && DCache[i].Age < MAX_AGE) { -// DCache[i].Age++; -// } -// } -// DCache[HitLine].Age = 0; -// } - -void UpdateAge(int HitLine) -{ - UINT16 old_age = DCache[HitLine].Age; - DCache[HitLine].Age = 0; - - for (int i = 0; i < DCACHE_LINES; i++) - { - if (i != HitLine && DCache[i].Valid) - { - if (DCache[i].Age < old_age) - { - DCache[i].Age++; - } - } - } -} - -/* - Data Cache访问接口,系统模拟器会调用此接口,来实现对你的Data Cache访问 - Address: 访存字节地址 - Operation: 操作:读操作('L')、写操作('S')、读-修改-写操作('M') - DataSize: 数据大小:1字节、2字节、4字节、8字节 - StoreValue: 当执行写操作的时候,需要写入的数据 - LoadResult: 当执行读操作的时候,从Cache读出的数据 -*/ -UINT8 AccessDataCache(UINT64 Address, UINT8 Operation, UINT8 DataSize, UINT64 StoreValue, UINT64* LoadResult) -{ - UINT8 BlockOffset; - UINT64 AddressTag; - UINT8 MissFlag = 'M'; - UINT64 ReadValue; - int HitLine = -1; - - *LoadResult = 0; - - // 全相联中,Address被切分为 AddressTag 和 BlockOffset - BlockOffset = Address % DCACHE_DATA_PER_LINE; - AddressTag = Address >> DCACHE_DATA_PER_LINE_ADDR_BITS; - - // 查找是否命中 - for (int i = 0; i < DCACHE_LINES; i++) { - if (DCache[i].Valid == 1 && DCache[i].Tag == AddressTag) { - MissFlag = 'H'; - HitLine = i; - break; - } - } - - if (MissFlag == 'H') // 命中! - { - if (Operation == 'L') // 读操作 - { - ReadValue = 0; - switch (DataSize) - { - case 1: // 1个字节 - ReadValue = DCache[HitLine].Data[BlockOffset + 0]; - break; - case 2: // 2个字节 - BlockOffset = BlockOffset & 0xFE; // 需对齐到2字节边界 - ReadValue = DCache[HitLine].Data[BlockOffset + 1]; ReadValue = ReadValue << 8; - ReadValue |= DCache[HitLine].Data[BlockOffset + 0]; - break; - case 4: // 4个字节 - BlockOffset = BlockOffset & 0xFC; // 需对齐到4字节边界 - ReadValue = DCache[HitLine].Data[BlockOffset + 3]; ReadValue = ReadValue << 8; - ReadValue |= DCache[HitLine].Data[BlockOffset + 2]; ReadValue = ReadValue << 8; - ReadValue |= DCache[HitLine].Data[BlockOffset + 1]; ReadValue = ReadValue << 8; - ReadValue |= DCache[HitLine].Data[BlockOffset + 0]; - break; - case 8: // 8个字节 - BlockOffset = BlockOffset & 0xF8; // 需对齐到8字节边界 - ReadValue = DCache[HitLine].Data[BlockOffset + 7]; ReadValue = ReadValue << 8; - ReadValue |= DCache[HitLine].Data[BlockOffset + 6]; ReadValue = ReadValue << 8; - ReadValue |= DCache[HitLine].Data[BlockOffset + 5]; ReadValue = ReadValue << 8; - ReadValue |= DCache[HitLine].Data[BlockOffset + 4]; ReadValue = ReadValue << 8; - ReadValue |= DCache[HitLine].Data[BlockOffset + 3]; ReadValue = ReadValue << 8; - ReadValue |= DCache[HitLine].Data[BlockOffset + 2]; ReadValue = ReadValue << 8; - ReadValue |= DCache[HitLine].Data[BlockOffset + 1]; ReadValue = ReadValue << 8; - ReadValue |= DCache[HitLine].Data[BlockOffset + 0]; - break; - } - *LoadResult = ReadValue; - if (DEBUG) - printf("[%s] Address=%016llX Operation=%c DataSize=%u StoreValue=%016llX ReadValue=%016llX\n", __func__, Address, Operation, DataSize, StoreValue, ReadValue); - } - else if (Operation == 'S' || Operation == 'M') // 写操作(修改操作在此等价于写操作) - { - if (DEBUG) - printf("[%s] Address=%016llX Operation=%c DataSize=%u StoreValue=%016llX\n", __func__, Address, Operation, DataSize, StoreValue); - switch (DataSize) - { - case 1: // 1个字节 - DCache[HitLine].Data[BlockOffset + 0] = StoreValue & 0xFF; - break; - case 2: // 2个字节 - BlockOffset = BlockOffset & 0xFE; // 需对齐到2字节边界 - DCache[HitLine].Data[BlockOffset + 0] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[HitLine].Data[BlockOffset + 1] = StoreValue & 0xFF; - break; - case 4: // 4个字节 - BlockOffset = BlockOffset & 0xFC; // 需对齐到4字节边界 - DCache[HitLine].Data[BlockOffset + 0] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[HitLine].Data[BlockOffset + 1] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[HitLine].Data[BlockOffset + 2] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[HitLine].Data[BlockOffset + 3] = StoreValue & 0xFF; - break; - case 8: // 8个字节 - BlockOffset = BlockOffset & 0xF8; // 需对齐到8字节边界 - DCache[HitLine].Data[BlockOffset + 0] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[HitLine].Data[BlockOffset + 1] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[HitLine].Data[BlockOffset + 2] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[HitLine].Data[BlockOffset + 3] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[HitLine].Data[BlockOffset + 4] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[HitLine].Data[BlockOffset + 5] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[HitLine].Data[BlockOffset + 6] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[HitLine].Data[BlockOffset + 7] = StoreValue & 0xFF; - break; - } - // 写回策略:数据只写入Cache,并设置脏位 - DCache[HitLine].Dirty = 1; - } - // 更新访问时间 - UpdateAge(HitLine); - } - else - { - if (DEBUG) - printf("[%s] Address=%016llX Operation=%c DataSize=%u StoreValue=%016llX\n", __func__, Address, Operation, DataSize, StoreValue); - - // 不命中, 获取要替换的行 - int ReplaceLine = GetReplaceLine(); - - // 如果要替换的行有效且脏,则需要写回到内存 - if (DCache[ReplaceLine].Valid == 1 && DCache[ReplaceLine].Dirty == 1) - { - UINT64 OldAddress = DCache[ReplaceLine].Tag << DCACHE_DATA_PER_LINE_ADDR_BITS; - StoreDataCacheLineToMemory(OldAddress, ReplaceLine); - } - - // 需要从Memory中读入新的行 - LoadDataCacheLineFromMemory(Address, ReplaceLine); - DCache[ReplaceLine].Valid = 1; - DCache[ReplaceLine].Tag = AddressTag; - DCache[ReplaceLine].Dirty = 0; - - if (Operation == 'S' || Operation == 'M') // 写操作(修改操作在此等价于写操作) - { - // 写操作,需要将新的StoreValue更新到CacheLine中 - switch (DataSize) - { - case 1: // 1个字节 - DCache[ReplaceLine].Data[BlockOffset + 0] = StoreValue & 0xFF; - break; - case 2: // 2个字节 - BlockOffset = BlockOffset & 0xFE; // 需对齐到2字节边界 - DCache[ReplaceLine].Data[BlockOffset + 0] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[ReplaceLine].Data[BlockOffset + 1] = StoreValue & 0xFF; - break; - case 4: // 4个字节 - BlockOffset = BlockOffset & 0xFC; // 需对齐到4字节边界 - DCache[ReplaceLine].Data[BlockOffset + 0] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[ReplaceLine].Data[BlockOffset + 1] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[ReplaceLine].Data[BlockOffset + 2] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[ReplaceLine].Data[BlockOffset + 3] = StoreValue & 0xFF; - break; - case 8: // 8个字节 - BlockOffset = BlockOffset & 0xF8; // 需对齐到8字节边界 - DCache[ReplaceLine].Data[BlockOffset + 0] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[ReplaceLine].Data[BlockOffset + 1] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[ReplaceLine].Data[BlockOffset + 2] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[ReplaceLine].Data[BlockOffset + 3] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[ReplaceLine].Data[BlockOffset + 4] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[ReplaceLine].Data[BlockOffset + 5] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[ReplaceLine].Data[BlockOffset + 6] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[ReplaceLine].Data[BlockOffset + 7] = StoreValue & 0xFF; - break; - } - DCache[ReplaceLine].Dirty = 1; - } - // 更新访问时间 - UpdateAge(ReplaceLine); - - if (Operation == 'L') // 读操作需要返回读取的值 - { - ReadValue = 0; - switch (DataSize) - { - case 1: // 1个字节 - ReadValue = DCache[ReplaceLine].Data[BlockOffset + 0]; - break; - case 2: // 2个字节 - BlockOffset = BlockOffset & 0xFE; // 需对齐到2字节边界 - ReadValue = DCache[ReplaceLine].Data[BlockOffset + 1]; ReadValue = ReadValue << 8; - ReadValue |= DCache[ReplaceLine].Data[BlockOffset + 0]; - break; - case 4: // 4个字节 - BlockOffset = BlockOffset & 0xFC; // 需对齐到4字节边界 - ReadValue = DCache[ReplaceLine].Data[BlockOffset + 3]; ReadValue = ReadValue << 8; - ReadValue |= DCache[ReplaceLine].Data[BlockOffset + 2]; ReadValue = ReadValue << 8; - ReadValue |= DCache[ReplaceLine].Data[BlockOffset + 1]; ReadValue = ReadValue << 8; - ReadValue |= DCache[ReplaceLine].Data[BlockOffset + 0]; - break; - case 8: // 8个字节 - BlockOffset = BlockOffset & 0xF8; // 需对齐到8字节边界 - ReadValue = DCache[ReplaceLine].Data[BlockOffset + 7]; ReadValue = ReadValue << 8; - ReadValue |= DCache[ReplaceLine].Data[BlockOffset + 6]; ReadValue = ReadValue << 8; - ReadValue |= DCache[ReplaceLine].Data[BlockOffset + 5]; ReadValue = ReadValue << 8; - ReadValue |= DCache[ReplaceLine].Data[BlockOffset + 4]; ReadValue = ReadValue << 8; - ReadValue |= DCache[ReplaceLine].Data[BlockOffset + 3]; ReadValue = ReadValue << 8; - ReadValue |= DCache[ReplaceLine].Data[BlockOffset + 2]; ReadValue = ReadValue << 8; - ReadValue |= DCache[ReplaceLine].Data[BlockOffset + 1]; ReadValue = ReadValue << 8; - ReadValue |= DCache[ReplaceLine].Data[BlockOffset + 0]; - break; - } - *LoadResult = ReadValue; - } - } - return MissFlag; -} - -/* 指令Cache实现部分,可选实现 */ -void InitInstCache(void) -{ - return; -} - -void LoadInstCacheLineFromMemory(UINT64 Address, UINT32 CacheLineAddress) -{ - return; -} - -UINT8 AccessInstCache(UINT64 Address, UINT8 Operation, UINT8 InstSize, UINT64* InstResult) -{ - // 返回值'M' = Miss,'H'=Hit - return 'M'; -} - diff --git a/cachelab/Cache.c b/cachelab/Cache.c index 316c5f1..e27448b 100644 --- a/cachelab/Cache.c +++ b/cachelab/Cache.c @@ -1,614 +1,998 @@ -/// -// Copyright 2022 by mars. // -/// - +#include "common.h" #include -#include - -#include "common.h" - -#define DEBUG 0 - -#define GET_POWER_OF_2(X) (X == 0x00 ? 0 : \ - X == 0x01 ? 0 : \ - X == 0x02 ? 1 : \ - X == 0x04 ? 2 : \ - X == 0x08 ? 3 : \ - X == 0x10 ? 4 : \ - X == 0x20 ? 5 : \ - X == 0x40 ? 6 : \ - X == 0x80 ? 7 : \ - X == 0x100 ? 8 : \ - X == 0x200 ? 9 : \ - X == 0x400 ? 10 : \ - X == 0x800 ? 11 : \ - X == 0x1000 ? 12 : \ - X == 0x2000 ? 13 : \ - X == 0x4000 ? 14 : \ - X == 0x8000 ? 15 : \ - X == 0x10000 ? 16 : \ - X == 0x20000 ? 17 : \ - X == 0x40000 ? 18 : \ - X == 0x80000 ? 19 : \ - X == 0x100000 ? 20 : \ - X == 0x200000 ? 21 : \ - X == 0x400000 ? 22 : \ - X == 0x800000 ? 23 : \ - X == 0x1000000 ? 24 : \ - X == 0x2000000 ? 25 : \ - X == 0x4000000 ? 26 : \ - X == 0x8000000 ? 27 : \ - X == 0x10000000 ? 28 : \ - X == 0x20000000 ? 29 : \ - X == 0x40000000 ? 30 : \ - X == 0x80000000 ? 31 : \ - X == 0x100000000 ? 32 : 0) - + +#define DEBUG 0 + +#define GET_POWER_OF_2(X) __builtin_ctz(X) + /* - 组相联映射Data Cache,16KB大小 - 每行存放16个字节,共1024行 + 组相联映射Data Cache,16KB大小 + 每行存放16个字节,共1024行 */ -#define DCACHE_LINE_PER_SET 256 -#define DCACHE_SIZE 16384 -#define DCACHE_DATA_PER_LINE 16 // 必须是8字节的倍数 -#define DCACHE_DATA_PER_LINE_ADDR_BITS GET_POWER_OF_2(DCACHE_DATA_PER_LINE) // 必须与上面设置一致,即64字节,需要6位地址 -#define DCACHE_SET (DCACHE_SIZE/DCACHE_DATA_PER_LINE/DCACHE_LINE_PER_SET) -#define DCACHE_SET_ADDR_BITS GET_POWER_OF_2(DCACHE_SET) // 必须与上面设置一致,即256行,需要8位地址 - -// DCache行的结构,包括Valid、Tag、Age、Dirty和Data。你所有的状态信息,只能记录在Cache行中! -struct DCACHE_LineStruct -{ - UINT8 Valid; - UINT8 Age; - UINT8 Dirty; - UINT64 Tag; - UINT8 Data[DCACHE_DATA_PER_LINE]; +#define DCACHE_LINE_PER_SET 256 +#define DCACHE_SIZE 16384 +#define DCACHE_DATA_PER_LINE 16 // 必须是8字节的倍数 +#define DCACHE_DATA_PER_LINE_ADDR_BITS \ + GET_POWER_OF_2( \ + DCACHE_DATA_PER_LINE) // 必须与上面设置一致,即64字节,需要6位地址 +#define DCACHE_SET (DCACHE_SIZE / DCACHE_DATA_PER_LINE / DCACHE_LINE_PER_SET) +#define DCACHE_SET_ADDR_BITS \ + GET_POWER_OF_2(DCACHE_SET) // 必须与上面设置一致,即256行,需要8位地址 + +/* + L2 Cache配置,1MB大小 + 每行存放128个字节,共4096行 +*/ +#define L2CACHE_LINE_PER_SET 4096 +#define L2CACHE_SIZE 1048576 +#define L2CACHE_DATA_PER_LINE 128 // 必须是8字节的倍数 +#define L2CACHE_DATA_PER_LINE_ADDR_BITS GET_POWER_OF_2(L2CACHE_DATA_PER_LINE) +#define L2CACHE_SET \ + (L2CACHE_SIZE / L2CACHE_DATA_PER_LINE / L2CACHE_LINE_PER_SET) +#define L2CACHE_SET_ADDR_BITS GET_POWER_OF_2(L2CACHE_SET) + +/* + 组相联映射Instruction Cache,16KB大小 + 每行存放16个字节,共1024行 +*/ +#define ICACHE_LINE_PER_SET 64 +#define ICACHE_SIZE 16384 +#define ICACHE_DATA_PER_LINE 16 // 必须是8字节的倍数 +#define ICACHE_DATA_PER_LINE_ADDR_BITS GET_POWER_OF_2(ICACHE_DATA_PER_LINE) +#define ICACHE_SET (ICACHE_SIZE / ICACHE_DATA_PER_LINE / ICACHE_LINE_PER_SET) +#define ICACHE_SET_ADDR_BITS GET_POWER_OF_2(ICACHE_SET) + +// DCache行的结构 +struct DCACHE_LineStruct { + UINT8 Valid; + UINT8 Age; + UINT8 Dirty; + UINT64 Tag; + UINT8 Data[DCACHE_DATA_PER_LINE]; }; - -struct DCACHE_Set -{ - struct DCACHE_LineStruct Line[DCACHE_LINE_PER_SET]; -}DCache[DCACHE_SET]; - + +struct DCACHE_Set { + struct DCACHE_LineStruct Line[DCACHE_LINE_PER_SET]; +} DCache[DCACHE_SET]; + +// L2Cache行的结构 +struct L2CACHE_LineStruct { + UINT8 Valid; + UINT8 Age; + UINT8 Dirty; + UINT64 Tag; + UINT8 Data[L2CACHE_DATA_PER_LINE]; +}; + +struct L2CACHE_Set { + struct L2CACHE_LineStruct Line[L2CACHE_LINE_PER_SET]; +} L2Cache[L2CACHE_SET]; + +// ICache行的结构 +struct ICACHE_LineStruct { + UINT8 Valid; + UINT8 Age; + UINT64 Tag; + UINT8 Data[ICACHE_DATA_PER_LINE]; +}; + +struct ICACHE_Set { + struct ICACHE_LineStruct Line[ICACHE_LINE_PER_SET]; +} ICache[ICACHE_SET]; + +// 函数声明部分 - 防止隐式声明错误 +void LoadDataCacheLineFromMemory(UINT64 Address, UINT32 set, UINT8 line); +void StoreDataCacheLineToMemory(UINT64 Address, UINT32 set, UINT8 line); +void LoadInstCacheLineFromMemory(UINT64 Address, UINT32 set, UINT8 line); +void InitL2Cache(void); + /* - DCache初始化代码,一般需要把DCache的有效位Valid设置为0 - 模拟器启动时,会调用此InitDataCache函数 + DCache初始化代码,一般需要把DCache的有效位Valid设置为0 + 模拟器启动时,会调用此InitDataCache函数 */ -void InitDataCache() -{ - UINT32 i, j; - printf("[%s] +-----------------------------------+\n", __func__); - printf("[%s] | derder的Data Cache初始化ing.... |\n", __func__); - printf("[%s] +-----------------------------------+\n", __func__); - for (i = 0; i < DCACHE_SET; i++) - { - for (j = 0; j < DCACHE_LINE_PER_SET; j++) - { - DCache[i].Line[j].Valid = 0; - DCache[i].Line[j].Dirty = 0; - DCache[i].Line[j].Tag = 0; - DCache[i].Line[j].Age = j; - } - } +void InitDataCache() { + UINT32 i, j; + printf("[%s] +-----------------------------------+\n", __func__); + printf("[%s] | Cikki 的Data Cache初始化ing.... |\n", __func__); + printf("[%s] +-----------------------------------+\n", __func__); + for (i = 0; i < DCACHE_SET; i++) { + for (j = 0; j < DCACHE_LINE_PER_SET; j++) { + DCache[i].Line[j].Valid = 0; + DCache[i].Line[j].Dirty = 0; + DCache[i].Line[j].Tag = 0; + DCache[i].Line[j].Age = j; + } + } } - + +/* + L2Cache初始化代码 +*/ +void InitL2Cache() { + UINT32 i, j; + printf("[%s] +-----------------------------------+\n", __func__); + printf("[%s] | Cikki 的L2 Cache初始化ing.... |\n", __func__); + printf("[%s] +-----------------------------------+\n", __func__); + for (i = 0; i < L2CACHE_SET; i++) { + for (j = 0; j < L2CACHE_LINE_PER_SET; j++) { + L2Cache[i].Line[j].Valid = 0; + L2Cache[i].Line[j].Dirty = 0; + L2Cache[i].Line[j].Tag = 0; + L2Cache[i].Line[j].Age = j; + } + } +} + +/* + ICache初始化代码 +*/ +void InitInstCache(void) { + UINT32 i, j; + printf("[%s] +-----------------------------------+\n", __func__); + printf("[%s] | Cikki 的Inst Cache初始化ing.... |\n", __func__); + printf("[%s] +-----------------------------------+\n", __func__); + for (i = 0; i < ICACHE_SET; i++) { + for (j = 0; j < ICACHE_LINE_PER_SET; j++) { + ICache[i].Line[j].Valid = 0; + ICache[i].Line[j].Tag = 0; + ICache[i].Line[j].Age = j; + } + } + + // 初始化L2缓存 + InitL2Cache(); +} + // 在第Set组中,从DCACHE_LINE_PER_SET路中,找到需要替换的Cache行 // 如果DCACHE_LINE_PER_SET行中,有某行的Valid=0,则返回该行行号 // 否则,返回Age最大的行的行号 -UINT8 GetReplaceLineData(UINT32 Set) -{ - int max_index = 0; - int max_age = -1; - for (int i = 0; i < DCACHE_LINE_PER_SET; i++) - { - if (DCache[Set].Line[i].Valid == 0) - return i; - if (DCache[Set].Line[i].Age > max_age) - { - max_index = i; - max_age = DCache[Set].Line[i].Age; - } - } - - return max_index; +UINT8 GetReplaceLineData(UINT32 Set) { + int max_index = 0; + int max_age = -1; + for (int i = 0; i < DCACHE_LINE_PER_SET; i++) { + if (DCache[Set].Line[i].Valid == 0) + return i; + if (DCache[Set].Line[i].Age > max_age) { + max_index = i; + max_age = DCache[Set].Line[i].Age; + } + } + + return max_index; } - + +// 在L2 Cache的第Set组中找到需要替换的行 +UINT8 GetReplaceLineL2(UINT32 Set) { + int max_index = 0; + int max_age = -1; + for (int i = 0; i < L2CACHE_LINE_PER_SET; i++) { + if (L2Cache[Set].Line[i].Valid == 0) + return i; + if (L2Cache[Set].Line[i].Age > max_age) { + max_index = i; + max_age = L2Cache[Set].Line[i].Age; + } + } + + return max_index; +} + +// LRU替换策略 - ICache +UINT8 GetReplaceLineInst(UINT32 Set) { + int max_index = 0; + int max_age = -1; + for (int i = 0; i < ICACHE_LINE_PER_SET; i++) { + if (ICache[Set].Line[i].Valid == 0) + return i; + if (ICache[Set].Line[i].Age > max_age) { + max_index = i; + max_age = ICache[Set].Line[i].Age; + } + } + + return max_index; +} + // 更新Age,在第Set组中,将HitLine指定的Cache行的Age设置为0,其他行的Age要相应调整 -// 注意!要确保DCACHE_LINE_PER_SET行的Age分别为0~DCACHE_LINE_PER_SET-1,且唯一 -void UpdateAgeData(UINT32 Set, UINT8 HitLine) -{ - int HitAge = DCache[Set].Line[HitLine].Age; - DCache[Set].Line[HitLine].Age = 0; - for (int i = 0; i < DCACHE_LINE_PER_SET; i++) - { - if (i != HitLine && DCache[Set].Line[i].Age < HitAge) - DCache[Set].Line[i].Age++; - } +// 确保DCACHE_LINE_PER_SET行的Age分别为0~DCACHE_LINE_PER_SET-1,且唯一 +void UpdateAgeData(UINT32 Set, UINT8 HitLine) { + UINT8 old_age = DCache[Set].Line[HitLine].Age; + for (int i = 0; i < DCACHE_LINE_PER_SET; ++i) { + if (DCache[Set].Line[i].Age < old_age) + DCache[Set].Line[i].Age++; + } + DCache[Set].Line[HitLine].Age = 0; } - + +// 更新L2 Cache的Age +void UpdateAgeL2(UINT32 Set, UINT8 HitLine) { + UINT8 old_age = L2Cache[Set].Line[HitLine].Age; + for (int i = 0; i < L2CACHE_LINE_PER_SET; ++i) { + if (L2Cache[Set].Line[i].Age < old_age) + L2Cache[Set].Line[i].Age++; + } + L2Cache[Set].Line[HitLine].Age = 0; +} + +// 更新Age - ICache +void UpdateAgeInst(UINT32 Set, UINT8 HitLine) { + int HitAge = ICache[Set].Line[HitLine].Age; + ICache[Set].Line[HitLine].Age = 0; + for (int i = 0; i < ICACHE_LINE_PER_SET; i++) { + if (i != HitLine && ICache[Set].Line[i].Age < HitAge) + ICache[Set].Line[i].Age++; + } +} + /* - 从Memory中读入一行数据到Data Cache中 + 从Memory中读入一行数据到Data Cache中 */ -void LoadDataCacheLineFromMemory(UINT64 Address, UINT32 set, UINT8 line) -{ - // 一次性从Memory中将DCACHE_DATA_PER_LINE数据读入某个Data Cache行 - // 提供了一个函数,一次可以读入8个字节 - - // 地址对齐到缓存行边界 - const UINT64 AlignAddress = Address & ~(DCACHE_DATA_PER_LINE - 1); - UINT64* const cache_line_ptr = (UINT64*)DCache[set].Line[line].Data; - +void LoadDataCacheLineFromMemory(UINT64 Address, UINT32 set, UINT8 line) { + // 一次性从Memory中将DCACHE_DATA_PER_LINE数据读入某个Data Cache行 + // 提供了一个函数,一次可以读入8个字节 + + // 地址对齐到缓存行边界 + const UINT64 AlignAddress = Address & ~(DCACHE_DATA_PER_LINE - 1); + UINT64 *const cache_line_ptr = (UINT64 *)DCache[set].Line[line].Data; + + if (DEBUG) { + printf("[%s] Loading cache line (set=%u, line=%u) from memory %016llX\n", + __func__, set, line, AlignAddress); + } + + // 分8字节块读取 + for (UINT32 i = 0; i < DCACHE_DATA_PER_LINE / sizeof(UINT64); i++) { + const UINT64 read_addr = AlignAddress + i * sizeof(UINT64); + const UINT64 data = ReadMemory(read_addr); + + cache_line_ptr[i] = data; + if (DEBUG) { - printf("[%s] Loading cache line (set=%u, line=%u) from memory %016llX\n", - __func__, set, line, AlignAddress); + printf(" [LOAD] Address=%016llX -> Data=%016llX\n", read_addr, data); } - - // 分8字节块读取 - for (UINT32 i = 0; i < DCACHE_DATA_PER_LINE / sizeof(UINT64); i++) { - const UINT64 read_addr = AlignAddress + i * sizeof(UINT64); - const UINT64 data = ReadMemory(read_addr); - - cache_line_ptr[i] = data; - - if (DEBUG) { - printf(" [LOAD] Address=%016llX -> Data=%016llX\n", read_addr, data); - } - } - + } } - + /* - 将Data Cache中的一行数据,写入存储器 + 从内存加载一行数据到指令缓存中 */ -void StoreDataCacheLineToMemory(UINT64 Address, UINT32 set,UINT8 line) -{ - // 一次性将DCACHE_DATA_PER_LINE数据从某个Data Cache行写入Memory中 - // 提供了一个函数,一次可以写入8个字节 - - // 地址对齐到缓存行边界 - const UINT64 AlignAddress = Address & ~(DCACHE_DATA_PER_LINE - 1); - UINT64* const cache_line_ptr = (UINT64*)DCache[set].Line[line].Data; - +void LoadInstCacheLineFromMemory(UINT64 Address, UINT32 set, UINT8 line) { + // 一次性从Memory中将ICACHE_DATA_PER_LINE数据读入某个Instruction Cache行 + // 提供了一个函数,一次可以读入8个字节 + + // 地址对齐到缓存行边界 + const UINT64 AlignAddress = Address & ~(ICACHE_DATA_PER_LINE - 1); + UINT64 *const cache_line_ptr = (UINT64 *)ICache[set].Line[line].Data; + + if (DEBUG) { + printf("[%s] Loading cache line (set=%u, line=%u) from memory %016llX\n", + __func__, set, line, AlignAddress); + } + + // 分8字节块读取 + for (UINT32 i = 0; i < ICACHE_DATA_PER_LINE / sizeof(UINT64); i++) { + const UINT64 read_addr = AlignAddress + i * sizeof(UINT64); + const UINT64 data = ReadMemory(read_addr); + + cache_line_ptr[i] = data; + if (DEBUG) { - printf("[%s] Storing cache line (set=%u, line=%u) to memory %016llX\n", - __func__, set, line, AlignAddress); + printf(" [LOAD] Address=%016llX -> Data=%016llX\n", read_addr, data); } - - // 分8字节块写入 - for (UINT32 i = 0; i < DCACHE_DATA_PER_LINE / sizeof(UINT64); i++) { - const UINT64 write_addr = AlignAddress + i * sizeof(UINT64); - const UINT64 data = cache_line_ptr[i]; - - WriteMemory(write_addr, data); - - if (DEBUG) { - printf(" [STORE] Address=%016llX <- Data=%016llX\n", write_addr, data); - } + } +} + +/* + 将Data Cache中的一行数据,写入存储器 +*/ +void StoreDataCacheLineToMemory(UINT64 Address, UINT32 set, UINT8 line) { + // 一次性将DCACHE_DATA_PER_LINE数据从某个Data Cache行写入Memory中 + // 提供了一个函数,一次可以写入8个字节 + + // 地址对齐到缓存行边界 + const UINT64 AlignAddress = Address & ~(DCACHE_DATA_PER_LINE - 1); + UINT64 *const cache_line_ptr = (UINT64 *)DCache[set].Line[line].Data; + + if (DEBUG) { + printf("[%s] Storing cache line (set=%u, line=%u) to memory %016llX\n", + __func__, set, line, AlignAddress); + } + + // 分8字节块写入 + for (UINT32 i = 0; i < DCACHE_DATA_PER_LINE / sizeof(UINT64); i++) { + const UINT64 write_addr = AlignAddress + i * sizeof(UINT64); + const UINT64 data = cache_line_ptr[i]; + + WriteMemory(write_addr, data); + + if (DEBUG) { + printf(" [STORE] Address=%016llX <- Data=%016llX\n", write_addr, data); } + } } - + /* - Data Cache访问接口,系统模拟器会调用此接口,来实现对你的Data Cache访问 - Address: 访存字节地址 - Operation: 操作:读操作('L')、写操作('S')、读-修改-写操作('M') - DataSize: 数据大小:1字节、2字节、4字节、8字节 - StoreValue: 当执行写操作的时候,需要写入的数据 - LoadResult: 当执行读操作的时候,从Cache读出的数据 + 从L2 Cache中读取数据到L1 DCache中 + 如果L2命中,则从L2读取数据 + 如果L2未命中,则从内存读取数据并更新L2 */ -UINT8 AccessDataCache(UINT64 Address, UINT8 Operation, UINT8 DataSize, UINT64 StoreValue, UINT64* LoadResult) -{ - UINT8 Block; - UINT32 Set; - UINT64 Tag; - UINT8 MissFlag = 'M'; - UINT64 ReadValue; - UINT8 HitLine; - - *LoadResult = 0; - - /* - * 组相联映射中,Address被切分为 Tag,Set,Block - */ - - Set = (Address >> DCACHE_DATA_PER_LINE_ADDR_BITS) % DCACHE_SET; - Block = Address % DCACHE_DATA_PER_LINE; - Tag = Address >> (DCACHE_DATA_PER_LINE_ADDR_BITS + DCACHE_SET_ADDR_BITS); - - // 检查命中 - for (int i = 0; i < DCACHE_LINE_PER_SET; i++) { - if (DCache[Set].Line[i].Valid && DCache[Set].Line[i].Tag == Tag) { - HitLine = i; - MissFlag = 'H'; - break; - } - } - - if(MissFlag=='H') - { - if (Operation == 'L') // 读操作 - { - ReadValue = 0; - switch (DataSize) - { - case 1: // 1个字节 - ReadValue = DCache[Set].Line[HitLine].Data[Block + 0]; - break; - case 2: // 2个字节 - Block = Block & 0xFE; // 需对齐到2字节边界 - ReadValue = DCache[Set].Line[HitLine].Data[Block + 1]; ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 0]; - break; - case 4: // 4个字节 - Block = Block & 0xFC; // 需对齐到4字节边界 - ReadValue = DCache[Set].Line[HitLine].Data[Block + 3]; ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 2]; ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 1]; ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 0]; - break; - case 8: // 8个字节 - Block = Block & 0xF8; // 需对齐到8字节边界 - ReadValue = DCache[Set].Line[HitLine].Data[Block + 7]; ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 6]; ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 5]; ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 4]; ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 3]; ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 2]; ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 1]; ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 0]; - break; - } - *LoadResult = ReadValue; - if (DEBUG) - printf("[%s] Address=%016llX Operation=%c DataSize=%u StoreValue=%016llX ReadValue=%016llX\n", __func__, Address, Operation, DataSize, StoreValue, ReadValue); - } - else if (Operation == 'S' || Operation == 'M') // 写操作(修改操作在此等价于写操作) - { - if (DEBUG) - printf("[%s] Address=%016llX Operation=%c DataSize=%u StoreValue=%016llX\n", __func__, Address, Operation, DataSize, StoreValue); - switch (DataSize) - { - case 1: // 1个字节 - DCache[Set].Line[HitLine].Data[Block + 0] = StoreValue & 0xFF; - break; - case 2: // 2个字节 - Block = Block & 0xFE; // 需对齐到2字节边界 - DCache[Set].Line[HitLine].Data[Block + 0] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 1] = StoreValue & 0xFF; - break; - case 4: // 4个字节 - Block = Block & 0xFC; // 需对齐到4字节边界 - DCache[Set].Line[HitLine].Data[Block + 0] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 1] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 2] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 3] = StoreValue & 0xFF; - break; - case 8: // 8个字节 - Block = Block & 0xF8; // 需对齐到8字节边界 - DCache[Set].Line[HitLine].Data[Block + 0] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 1] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 2] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 3] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 4] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 5] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 6] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 7] = StoreValue & 0xFF; - break; - } - DCache[Set].Line[HitLine].Dirty = 1; - } - UpdateAgeData(Set, HitLine); - } - else if(MissFlag=='M') - { - if (DEBUG) - printf("[%s] Address=%016llX Operation=%c DataSize=%u StoreValue=%016llX\n", __func__, Address, Operation, DataSize, StoreValue); - UINT8 replace_Line = GetReplaceLineData(Set); - - if (Operation == 'L') // 读操作 - { - // 写回脏行 - if (DCache[Set].Line[replace_Line].Valid && DCache[Set].Line[replace_Line].Dirty) - { - UINT64 victim_addr = (DCache[Set].Line[replace_Line].Tag <<(DCACHE_DATA_PER_LINE_ADDR_BITS + DCACHE_SET_ADDR_BITS)) |(Set << DCACHE_DATA_PER_LINE_ADDR_BITS); - StoreDataCacheLineToMemory(victim_addr,Set,replace_Line); - } - - // 加载新数据 - LoadDataCacheLineFromMemory(Address,Set,replace_Line); - - DCache[Set].Line[replace_Line].Valid = 1; - DCache[Set].Line[replace_Line].Tag = Tag; - DCache[Set].Line[replace_Line].Dirty = 0; - - ReadValue = 0; - switch (DataSize) - { - case 1: // 1个字节 - ReadValue = DCache[Set].Line[replace_Line].Data[Block + 0]; - break; - case 2: // 2个字节 - Block = Block & 0xFE; // 需对齐到2字节边界 - ReadValue = DCache[Set].Line[replace_Line].Data[Block + 1]; ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[replace_Line].Data[Block + 0]; - break; - case 4: // 4个字节 - Block = Block & 0xFC; // 需对齐到4字节边界 - ReadValue = DCache[Set].Line[replace_Line].Data[Block + 3]; ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[replace_Line].Data[Block + 2]; ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[replace_Line].Data[Block + 1]; ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[replace_Line].Data[Block + 0]; - break; - case 8: // 8个字节 - Block = Block & 0xF8; // 需对齐到8字节边界 - ReadValue = DCache[Set].Line[replace_Line].Data[Block + 7]; ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[replace_Line].Data[Block + 6]; ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[replace_Line].Data[Block + 5]; ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[replace_Line].Data[Block + 4]; ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[replace_Line].Data[Block + 3]; ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[replace_Line].Data[Block + 2]; ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[replace_Line].Data[Block + 1]; ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[replace_Line].Data[Block + 0]; - break; - } - *LoadResult = ReadValue; - } - else if (Operation == 'S' || Operation == 'M') // 写操作(修改操作在此等价于写操作) - { - // 写回脏行 - if (DCache[Set].Line[replace_Line].Valid && DCache[Set].Line[replace_Line].Dirty) - { - UINT64 victim_addr = (DCache[Set].Line[replace_Line].Tag << (DCACHE_DATA_PER_LINE_ADDR_BITS + DCACHE_SET_ADDR_BITS)) | (Set << DCACHE_DATA_PER_LINE_ADDR_BITS); - StoreDataCacheLineToMemory(victim_addr,Set,replace_Line); - } - - // 加载新数据 - LoadDataCacheLineFromMemory(Address, Set, replace_Line); - - DCache[Set].Line[replace_Line].Valid = 1; - DCache[Set].Line[replace_Line].Tag = Tag; - DCache[Set].Line[replace_Line].Dirty = 0; - - // 写操作,需要将新的StoreValue更新到CacheLine中 - switch (DataSize) - { - case 1: // 1个字节 - DCache[Set].Line[replace_Line].Data[Block + 0] = StoreValue & 0xFF; - break; - case 2: // 2个字节 - Block = Block & 0xFE; // 需对齐到2字节边界 - DCache[Set].Line[replace_Line].Data[Block + 0] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[Set].Line[replace_Line].Data[Block + 1] = StoreValue & 0xFF; - break; - case 4: // 4个字节 - Block = Block & 0xFC; // 需对齐到4字节边界 - DCache[Set].Line[replace_Line].Data[Block + 0] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[Set].Line[replace_Line].Data[Block + 1] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[Set].Line[replace_Line].Data[Block + 2] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[Set].Line[replace_Line].Data[Block + 3] = StoreValue & 0xFF; - break; - case 8: // 8个字节 - Block = Block & 0xF8; // 需对齐到8字节边界 - DCache[Set].Line[replace_Line].Data[Block + 0] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[Set].Line[replace_Line].Data[Block + 1] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[Set].Line[replace_Line].Data[Block + 2] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[Set].Line[replace_Line].Data[Block + 3] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[Set].Line[replace_Line].Data[Block + 4] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[Set].Line[replace_Line].Data[Block + 5] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[Set].Line[replace_Line].Data[Block + 6] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[Set].Line[replace_Line].Data[Block + 7] = StoreValue & 0xFF; - break; - } - DCache[Set].Line[replace_Line].Dirty = 1; - UpdateAgeData(Set, replace_Line); - } - UpdateAgeData(Set, replace_Line); - } - return MissFlag; +UINT8 LoadDataFromL2ToL1(UINT64 Address, UINT32 L1_set, UINT8 L1_line) { + UINT32 L2_set = (Address >> L2CACHE_DATA_PER_LINE_ADDR_BITS) % L2CACHE_SET; + UINT64 L2_tag = + Address >> (L2CACHE_DATA_PER_LINE_ADDR_BITS + L2CACHE_SET_ADDR_BITS); + UINT8 L2_hit = 0; + UINT8 L2_line = 0; + + // 检查L2 Cache是否命中 + for (int i = 0; i < L2CACHE_LINE_PER_SET; i++) { + if (L2Cache[L2_set].Line[i].Valid && + L2Cache[L2_set].Line[i].Tag == L2_tag) { + L2_hit = 1; + L2_line = i; + break; + } + } + + if (L2_hit) { + // L2命中,从L2读取数据到L1 + if (DEBUG) { + printf("[%s] L2 Cache hit! Loading from L2 to L1 (Address=%016llX)\n", + __func__, Address); + } + + // 由于L2缓存行可能比L1大,需要找到正确的偏移量 + UINT64 L1_aligned_addr = Address & ~(DCACHE_DATA_PER_LINE - 1); + UINT64 L2_aligned_addr = Address & ~(L2CACHE_DATA_PER_LINE - 1); + UINT32 offset_in_L2 = (L1_aligned_addr - L2_aligned_addr); + + // 从L2复制数据到L1 + for (int i = 0; i < DCACHE_DATA_PER_LINE; i++) { + DCache[L1_set].Line[L1_line].Data[i] = + L2Cache[L2_set].Line[L2_line].Data[offset_in_L2 + i]; + } + + // 更新L2的LRU信息 + UpdateAgeL2(L2_set, L2_line); + return 'H'; // L2命中 + } else { + // L2未命中,从内存加载数据 + if (DEBUG) { + printf("[%s] L2 Cache miss! Loading from memory (Address=%016llX)\n", + __func__, Address); + } + + // 首先从内存加载到L1 + LoadDataCacheLineFromMemory(Address, L1_set, L1_line); + + // 然后更新L2 + UINT8 L2_replace_line = GetReplaceLineL2(L2_set); + + // 如果L2中要替换的行是脏的,需要先写回内存 + if (L2Cache[L2_set].Line[L2_replace_line].Valid && + L2Cache[L2_set].Line[L2_replace_line].Dirty) { + UINT64 victim_addr = + (L2Cache[L2_set].Line[L2_replace_line].Tag + << (L2CACHE_DATA_PER_LINE_ADDR_BITS + L2CACHE_SET_ADDR_BITS)) | + (L2_set << L2CACHE_DATA_PER_LINE_ADDR_BITS); + + // 写回内存 + for (UINT32 i = 0; i < L2CACHE_DATA_PER_LINE / sizeof(UINT64); i++) { + const UINT64 write_addr = victim_addr + i * sizeof(UINT64); + const UINT64 *data_ptr = (UINT64 *)&L2Cache[L2_set] + .Line[L2_replace_line] + .Data[i * sizeof(UINT64)]; + WriteMemory(write_addr, *data_ptr); + } + } + + // 从内存加载数据到L2 + UINT64 L2_aligned_addr = Address & ~(L2CACHE_DATA_PER_LINE - 1); + for (UINT32 i = 0; i < L2CACHE_DATA_PER_LINE / sizeof(UINT64); i++) { + const UINT64 read_addr = L2_aligned_addr + i * sizeof(UINT64); + const UINT64 data = ReadMemory(read_addr); + UINT64 *data_ptr = (UINT64 *)&L2Cache[L2_set] + .Line[L2_replace_line] + .Data[i * sizeof(UINT64)]; + *data_ptr = data; + } + + // 更新L2缓存行信息 + L2Cache[L2_set].Line[L2_replace_line].Valid = 1; + L2Cache[L2_set].Line[L2_replace_line].Dirty = 0; + L2Cache[L2_set].Line[L2_replace_line].Tag = L2_tag; + UpdateAgeL2(L2_set, L2_replace_line); + + return 'M'; // L2未命中 + } } - + /* - 组相联映射Instruction Cache,16KB大小 - 每行存放16个字节,共1024行 + 将L1 DCache中的一行数据写入L2 Cache */ -#define ICACHE_LINE_PER_SET 64 -#define ICACHE_SIZE 16384 -#define ICACHE_DATA_PER_LINE 16 // 必须是8字节的倍数 -#define ICACHE_DATA_PER_LINE_ADDR_BITS GET_POWER_OF_2(ICACHE_DATA_PER_LINE) -#define ICACHE_SET (ICACHE_SIZE/ICACHE_DATA_PER_LINE/ICACHE_LINE_PER_SET) -#define ICACHE_SET_ADDR_BITS GET_POWER_OF_2(ICACHE_SET) - -// ICache行的结构 -struct ICACHE_LineStruct -{ - UINT8 Valid; - UINT8 Age; - UINT64 Tag; - UINT8 Data[ICACHE_DATA_PER_LINE]; -}; - -struct ICACHE_Set -{ - struct ICACHE_LineStruct Line[ICACHE_LINE_PER_SET]; -}ICache[ICACHE_SET]; - - -void InitInstCache(void) -{ - UINT32 i, j; - printf("[%s] +-----------------------------------+\n", __func__); - printf("[%s] | derder的Inst Cache初始化ing.... |\n", __func__); - printf("[%s] +-----------------------------------+\n", __func__); - for (i = 0; i < ICACHE_SET; i++) +void StoreDataFromL1ToL2(UINT64 Address, UINT32 L1_set, UINT8 L1_line) { + UINT32 L2_set = (Address >> L2CACHE_DATA_PER_LINE_ADDR_BITS) % L2CACHE_SET; + UINT64 L2_tag = + Address >> (L2CACHE_DATA_PER_LINE_ADDR_BITS + L2CACHE_SET_ADDR_BITS); + UINT8 L2_hit = 0; + UINT8 L2_line = 0; + + // 检查L2 Cache是否命中 + for (int i = 0; i < L2CACHE_LINE_PER_SET; i++) { + if (L2Cache[L2_set].Line[i].Valid && + L2Cache[L2_set].Line[i].Tag == L2_tag) { + L2_hit = 1; + L2_line = i; + break; + } + } + + if (!L2_hit) { + // L2未命中,需要分配一个新的L2缓存行 + L2_line = GetReplaceLineL2(L2_set); + + // 如果要替换的L2行是脏的,需要先写回内存 + if (L2Cache[L2_set].Line[L2_line].Valid && + L2Cache[L2_set].Line[L2_line].Dirty) { + UINT64 victim_addr = + (L2Cache[L2_set].Line[L2_line].Tag + << (L2CACHE_DATA_PER_LINE_ADDR_BITS + L2CACHE_SET_ADDR_BITS)) | + (L2_set << L2CACHE_DATA_PER_LINE_ADDR_BITS); + + // 写回内存 + for (UINT32 i = 0; i < L2CACHE_DATA_PER_LINE / sizeof(UINT64); i++) { + const UINT64 write_addr = victim_addr + i * sizeof(UINT64); + const UINT64 *data_ptr = + (UINT64 *)&L2Cache[L2_set].Line[L2_line].Data[i * sizeof(UINT64)]; + WriteMemory(write_addr, *data_ptr); + } + } + + // 从内存加载完整的L2缓存行 + UINT64 L2_aligned_addr = Address & ~(L2CACHE_DATA_PER_LINE - 1); + for (UINT32 i = 0; i < L2CACHE_DATA_PER_LINE / sizeof(UINT64); i++) { + const UINT64 read_addr = L2_aligned_addr + i * sizeof(UINT64); + const UINT64 data = ReadMemory(read_addr); + UINT64 *data_ptr = + (UINT64 *)&L2Cache[L2_set].Line[L2_line].Data[i * sizeof(UINT64)]; + *data_ptr = data; + } + + L2Cache[L2_set].Line[L2_line].Valid = 1; + L2Cache[L2_set].Line[L2_line].Tag = L2_tag; + } + + // 更新L2缓存行中对应的数据 + UINT64 L1_aligned_addr = Address & ~(DCACHE_DATA_PER_LINE - 1); + UINT64 L2_aligned_addr = Address & ~(L2CACHE_DATA_PER_LINE - 1); + UINT32 offset_in_L2 = (L1_aligned_addr - L2_aligned_addr); + + // 从L1复制数据到L2 + for (int i = 0; i < DCACHE_DATA_PER_LINE; i++) { + L2Cache[L2_set].Line[L2_line].Data[offset_in_L2 + i] = + DCache[L1_set].Line[L1_line].Data[i]; + } + + // 标记L2缓存行为脏 + L2Cache[L2_set].Line[L2_line].Dirty = 1; + UpdateAgeL2(L2_set, L2_line); +} + +/* + 从L2 Cache中加载指令到I-Cache + 如果L2缓存命中,则从L2读取数据 + 如果L2缓存未命中,则从内存读取数据并同时更新L2缓存 +*/ +UINT8 LoadInstFromL2ToICache(UINT64 Address, UINT32 I_set, UINT8 I_line) { + UINT32 L2_set = (Address >> L2CACHE_DATA_PER_LINE_ADDR_BITS) % L2CACHE_SET; + UINT64 L2_tag = + Address >> (L2CACHE_DATA_PER_LINE_ADDR_BITS + L2CACHE_SET_ADDR_BITS); + UINT8 L2_hit = 0; + UINT8 L2_line = 0; + + // 检查L2 Cache是否命中 + for (int i = 0; i < L2CACHE_LINE_PER_SET; i++) { + if (L2Cache[L2_set].Line[i].Valid && + L2Cache[L2_set].Line[i].Tag == L2_tag) { + L2_hit = 1; + L2_line = i; + break; + } + } + + if (L2_hit) { + // L2命中,从L2读取数据到I-Cache + if (DEBUG) { + printf("[%s] L2 Cache hit! Loading instruction from L2 to I-Cache " + "(Address=%016llX)\n", + __func__, Address); + } + + // 由于L2缓存行可能比I-Cache大,需要找到正确的偏移量 + UINT64 I_aligned_addr = Address & ~(ICACHE_DATA_PER_LINE - 1); + UINT64 L2_aligned_addr = Address & ~(L2CACHE_DATA_PER_LINE - 1); + UINT32 offset_in_L2 = (I_aligned_addr - L2_aligned_addr); + + // 从L2复制数据到I-Cache + for (int i = 0; i < ICACHE_DATA_PER_LINE; i++) { + ICache[I_set].Line[I_line].Data[i] = + L2Cache[L2_set].Line[L2_line].Data[offset_in_L2 + i]; + } + + // 更新L2的LRU信息 + UpdateAgeL2(L2_set, L2_line); + return 'H'; // L2命中 + } else { + // L2未命中,从内存加载数据 + if (DEBUG) { + printf("[%s] L2 Cache miss! Loading instruction from memory " + "(Address=%016llX)\n", + __func__, Address); + } + + // 首先从内存加载到I-Cache + LoadInstCacheLineFromMemory(Address, I_set, I_line); + + // 然后更新L2 + UINT8 L2_replace_line = GetReplaceLineL2(L2_set); + + // 如果L2中要替换的行是脏的,需要先写回内存 + if (L2Cache[L2_set].Line[L2_replace_line].Valid && + L2Cache[L2_set].Line[L2_replace_line].Dirty) { + UINT64 victim_addr = + (L2Cache[L2_set].Line[L2_replace_line].Tag + << (L2CACHE_DATA_PER_LINE_ADDR_BITS + L2CACHE_SET_ADDR_BITS)) | + (L2_set << L2CACHE_DATA_PER_LINE_ADDR_BITS); + + // 写回内存 + for (UINT32 i = 0; i < L2CACHE_DATA_PER_LINE / sizeof(UINT64); i++) { + const UINT64 write_addr = victim_addr + i * sizeof(UINT64); + const UINT64 *data_ptr = (UINT64 *)&L2Cache[L2_set] + .Line[L2_replace_line] + .Data[i * sizeof(UINT64)]; + WriteMemory(write_addr, *data_ptr); + } + } + // 从内存加载数据到L2 + UINT64 L2_aligned_addr = Address & ~(L2CACHE_DATA_PER_LINE - 1); + for (UINT32 i = 0; i < L2CACHE_DATA_PER_LINE / sizeof(UINT64); i++) { + const UINT64 read_addr = L2_aligned_addr + i * sizeof(UINT64); + const UINT64 data = ReadMemory(read_addr); + UINT64 *data_ptr = (UINT64 *)&L2Cache[L2_set] + .Line[L2_replace_line] + .Data[i * sizeof(UINT64)]; + *data_ptr = data; + } + + // 更新L2缓存行信息 + L2Cache[L2_set].Line[L2_replace_line].Valid = 1; + L2Cache[L2_set].Line[L2_replace_line].Dirty = 0; + L2Cache[L2_set].Line[L2_replace_line].Tag = L2_tag; + UpdateAgeL2(L2_set, L2_replace_line); + + return 'M'; // L2未命中 + } +} + +/* + * 访问数据缓存的主函数 + * 参数: + * Address - 访问的内存地址 + * Operation - 'L'表示读取,'S'表示写入,'M'表示修改(先读后写) + * DataSize - 访问的数据大小(1、2、4或8字节) + * StoreValue - 要写入的数据(如果是写入操作) + * LoadResult - 指向读取结果的指针(如果是读取操作) + * 返回值: + * 'H' - 缓存命中 + * 'M' - 缓存未命中 + */ +UINT8 AccessDataCache(UINT64 Address, UINT8 Operation, UINT8 DataSize, + UINT64 StoreValue, UINT64 *LoadResult) { + UINT32 Set = (Address >> DCACHE_DATA_PER_LINE_ADDR_BITS) % DCACHE_SET; + UINT8 Block = Address % DCACHE_DATA_PER_LINE; + UINT64 Tag = + Address >> (DCACHE_DATA_PER_LINE_ADDR_BITS + DCACHE_SET_ADDR_BITS); + UINT8 HitLine; + UINT8 MissFlag = 'M'; + UINT64 ReadValue = 0; + + // 仅用于处理函数实现,实际不使用结果 + char _unused_L2Result; + + // 检查命中 + for (int i = 0; i < DCACHE_LINE_PER_SET; i++) { + if (DCache[Set].Line[i].Valid && DCache[Set].Line[i].Tag == Tag) { + HitLine = i; + MissFlag = 'H'; + break; + } + } + + if (MissFlag == 'H') // Cache命中 + { + if (Operation == 'L') // 读操作 { - for (j = 0; j < ICACHE_LINE_PER_SET; j++) - { - ICache[i].Line[j].Valid = 0; - ICache[i].Line[j].Tag = 0; - ICache[i].Line[j].Age = j; - } + // 读取数据,注意这里要按DataSize读取 + switch (DataSize) { + case 1: // 1个字节 + ReadValue = DCache[Set].Line[HitLine].Data[Block]; + break; + case 2: // 2个字节 + Block = Block & 0xFE; // 需对齐到2字节边界 + ReadValue = DCache[Set].Line[HitLine].Data[Block + 1]; + ReadValue = ReadValue << 8; + ReadValue |= DCache[Set].Line[HitLine].Data[Block + 0]; + break; + case 4: // 4个字节 + Block = Block & 0xFC; // 需对齐到4字节边界 + ReadValue = DCache[Set].Line[HitLine].Data[Block + 3]; + ReadValue = ReadValue << 8; + ReadValue |= DCache[Set].Line[HitLine].Data[Block + 2]; + ReadValue = ReadValue << 8; + ReadValue |= DCache[Set].Line[HitLine].Data[Block + 1]; + ReadValue = ReadValue << 8; + ReadValue |= DCache[Set].Line[HitLine].Data[Block + 0]; + break; + case 8: // 8个字节 + Block = Block & 0xF8; // 需对齐到8字节边界 + ReadValue = DCache[Set].Line[HitLine].Data[Block + 7]; + ReadValue = ReadValue << 8; + ReadValue |= DCache[Set].Line[HitLine].Data[Block + 6]; + ReadValue = ReadValue << 8; + ReadValue |= DCache[Set].Line[HitLine].Data[Block + 5]; + ReadValue = ReadValue << 8; + ReadValue |= DCache[Set].Line[HitLine].Data[Block + 4]; + ReadValue = ReadValue << 8; + ReadValue |= DCache[Set].Line[HitLine].Data[Block + 3]; + ReadValue = ReadValue << 8; + ReadValue |= DCache[Set].Line[HitLine].Data[Block + 2]; + ReadValue = ReadValue << 8; + ReadValue |= DCache[Set].Line[HitLine].Data[Block + 1]; + ReadValue = ReadValue << 8; + ReadValue |= DCache[Set].Line[HitLine].Data[Block + 0]; + break; + } + *LoadResult = ReadValue; + + if (DEBUG) { + printf("[%s] Address=%016llX Operation=%c DataSize=%u " + "StoreValue=%016llX ReadValue=%016llX\n", + __func__, Address, Operation, DataSize, StoreValue, ReadValue); + } + } else if (Operation == 'S' || + Operation == 'M') // 写操作(修改操作在此等价于写操作) + { + if (DEBUG) { + printf("[%s] Address=%016llX Operation=%c DataSize=%u " + "StoreValue=%016llX\n", + __func__, Address, Operation, DataSize, StoreValue); + } + + // 写操作,需要将新的StoreValue更新到CacheLine中 + switch (DataSize) { + case 1: // 1个字节 + DCache[Set].Line[HitLine].Data[Block + 0] = StoreValue & 0xFF; + break; + case 2: // 2个字节 + Block = Block & 0xFE; // 需对齐到2字节边界 + DCache[Set].Line[HitLine].Data[Block + 0] = StoreValue & 0xFF; + StoreValue = StoreValue >> 8; + DCache[Set].Line[HitLine].Data[Block + 1] = StoreValue & 0xFF; + break; + case 4: // 4个字节 + Block = Block & 0xFC; // 需对齐到4字节边界 + DCache[Set].Line[HitLine].Data[Block + 0] = StoreValue & 0xFF; + StoreValue = StoreValue >> 8; + DCache[Set].Line[HitLine].Data[Block + 1] = StoreValue & 0xFF; + StoreValue = StoreValue >> 8; + DCache[Set].Line[HitLine].Data[Block + 2] = StoreValue & 0xFF; + StoreValue = StoreValue >> 8; + DCache[Set].Line[HitLine].Data[Block + 3] = StoreValue & 0xFF; + break; + case 8: // 8个字节 + Block = Block & 0xF8; // 需对齐到8字节边界 + DCache[Set].Line[HitLine].Data[Block + 0] = StoreValue & 0xFF; + StoreValue = StoreValue >> 8; + DCache[Set].Line[HitLine].Data[Block + 1] = StoreValue & 0xFF; + StoreValue = StoreValue >> 8; + DCache[Set].Line[HitLine].Data[Block + 2] = StoreValue & 0xFF; + StoreValue = StoreValue >> 8; + DCache[Set].Line[HitLine].Data[Block + 3] = StoreValue & 0xFF; + StoreValue = StoreValue >> 8; + DCache[Set].Line[HitLine].Data[Block + 4] = StoreValue & 0xFF; + StoreValue = StoreValue >> 8; + DCache[Set].Line[HitLine].Data[Block + 5] = StoreValue & 0xFF; + StoreValue = StoreValue >> 8; + DCache[Set].Line[HitLine].Data[Block + 6] = StoreValue & 0xFF; + StoreValue = StoreValue >> 8; + DCache[Set].Line[HitLine].Data[Block + 7] = StoreValue & 0xFF; + break; + } + DCache[Set].Line[HitLine].Dirty = 1; + + // 写直达,同时更新L2 + StoreDataFromL1ToL2(Address, Set, HitLine); } -} - -//LRU替换策略 -UINT8 GetReplaceLineInst(UINT32 Set) -{ - int max_index = 0; - int max_age = -1; - for (int i = 0; i < ICACHE_LINE_PER_SET; i++) - { - if (ICache[Set].Line[i].Valid == 0) - return i; - if (ICache[Set].Line[i].Age > max_age) - { - max_index = i; - max_age = ICache[Set].Line[i].Age; - } - } - - return max_index; -} - -// 更新Age,在第Set组中,将HitLine指定的Cache行的Age设置为0,其他行的Age要相应调整 -// 注意!要确保ICACHE_LINE_PER_SET行的Age分别为0~ICACHE_LINE_PER_SET-1,且唯一 -void UpdateAgeInst(UINT32 Set, UINT8 HitLine) -{ - int HitAge = ICache[Set].Line[HitLine].Age; - ICache[Set].Line[HitLine].Age = 0; - for (int i = 0; i < ICACHE_LINE_PER_SET; i++) - { - if (i != HitLine && ICache[Set].Line[i].Age < HitAge) - ICache[Set].Line[i].Age++; - } -} - -void LoadInstCacheLineFromMemory(UINT64 Address, UINT32 set, UINT8 line) -{ - // 一次性从Memory中将ICACHE_DATA_PER_LINE数据读入某个Instruction Cache行 - // 提供了一个函数,一次可以读入8个字节 - - // 地址对齐到缓存行边界 - const UINT64 AlignAddress = Address & ~(ICACHE_DATA_PER_LINE - 1); - UINT64* const cache_line_ptr = (UINT64*)ICache[set].Line[line].Data; - + UpdateAgeData(Set, HitLine); + } else // Cache未命中 + { + UINT8 replace_Line = GetReplaceLineData(Set); if (DEBUG) { - printf("[%s] Loading cache line (set=%u, line=%u) from memory %016llX\n", - __func__, set, line, AlignAddress); + printf( + "[%s] Address=%016llX Operation=%c DataSize=%u StoreValue=%016llX\n", + __func__, Address, Operation, DataSize, StoreValue); } - - // 分8字节块读取 - for (UINT32 i = 0; i < ICACHE_DATA_PER_LINE / sizeof(UINT64); i++) { - const UINT64 read_addr = AlignAddress + i * sizeof(UINT64); - const UINT64 data = ReadMemory(read_addr); - - cache_line_ptr[i] = data; - - if (DEBUG) { - printf(" [LOAD] Address=%016llX -> Data=%016llX\n", read_addr, data); - } + + if (Operation == 'L') // 读操作 + { + // 写回脏行到L2 + if (DCache[Set].Line[replace_Line].Valid && + DCache[Set].Line[replace_Line].Dirty) { + UINT64 victim_addr = + (DCache[Set].Line[replace_Line].Tag + << (DCACHE_DATA_PER_LINE_ADDR_BITS + DCACHE_SET_ADDR_BITS)) | + (Set << DCACHE_DATA_PER_LINE_ADDR_BITS); + StoreDataFromL1ToL2(victim_addr, Set, replace_Line); + } + + // 先从L2加载新行到L1 + _unused_L2Result = LoadDataFromL2ToL1(Address, Set, replace_Line); + + DCache[Set].Line[replace_Line].Valid = 1; + DCache[Set].Line[replace_Line].Tag = Tag; + DCache[Set].Line[replace_Line].Dirty = 0; + + // 再读取数据,按DataSize读取 + switch (DataSize) { + case 1: // 1个字节 + ReadValue = DCache[Set].Line[replace_Line].Data[Block]; + break; + case 2: // 2个字节 + Block = Block & 0xFE; // 需对齐到2字节边界 + ReadValue = DCache[Set].Line[replace_Line].Data[Block + 1]; + ReadValue = ReadValue << 8; + ReadValue |= DCache[Set].Line[replace_Line].Data[Block + 0]; + break; + case 4: // 4个字节 + Block = Block & 0xFC; // 需对齐到4字节边界 + ReadValue = DCache[Set].Line[replace_Line].Data[Block + 3]; + ReadValue = ReadValue << 8; + ReadValue |= DCache[Set].Line[replace_Line].Data[Block + 2]; + ReadValue = ReadValue << 8; + ReadValue |= DCache[Set].Line[replace_Line].Data[Block + 1]; + ReadValue = ReadValue << 8; + ReadValue |= DCache[Set].Line[replace_Line].Data[Block + 0]; + break; + case 8: // 8个字节 + Block = Block & 0xF8; // 需对齐到8字节边界 + ReadValue = DCache[Set].Line[replace_Line].Data[Block + 7]; + ReadValue = ReadValue << 8; + ReadValue |= DCache[Set].Line[replace_Line].Data[Block + 6]; + ReadValue = ReadValue << 8; + ReadValue |= DCache[Set].Line[replace_Line].Data[Block + 5]; + ReadValue = ReadValue << 8; + ReadValue |= DCache[Set].Line[replace_Line].Data[Block + 4]; + ReadValue = ReadValue << 8; + ReadValue |= DCache[Set].Line[replace_Line].Data[Block + 3]; + ReadValue = ReadValue << 8; + ReadValue |= DCache[Set].Line[replace_Line].Data[Block + 2]; + ReadValue = ReadValue << 8; + ReadValue |= DCache[Set].Line[replace_Line].Data[Block + 1]; + ReadValue = ReadValue << 8; + ReadValue |= DCache[Set].Line[replace_Line].Data[Block + 0]; + break; + } + *LoadResult = ReadValue; + } else if (Operation == 'S' || + Operation == 'M') // 写操作(修改操作在此等价于写操作) + { + // 写回脏行到L2 + if (DCache[Set].Line[replace_Line].Valid && + DCache[Set].Line[replace_Line].Dirty) { + UINT64 victim_addr = + (DCache[Set].Line[replace_Line].Tag + << (DCACHE_DATA_PER_LINE_ADDR_BITS + DCACHE_SET_ADDR_BITS)) | + (Set << DCACHE_DATA_PER_LINE_ADDR_BITS); + StoreDataFromL1ToL2(victim_addr, Set, replace_Line); + } + + // 先从L2加载新行到L1 + _unused_L2Result = LoadDataFromL2ToL1(Address, Set, replace_Line); + + DCache[Set].Line[replace_Line].Valid = 1; + DCache[Set].Line[replace_Line].Tag = Tag; + DCache[Set].Line[replace_Line].Dirty = 0; + + // 写操作,需要将新的StoreValue更新到CacheLine中 + switch (DataSize) { + case 1: // 1个字节 + DCache[Set].Line[replace_Line].Data[Block + 0] = StoreValue & 0xFF; + break; + case 2: // 2个字节 + Block = Block & 0xFE; // 需对齐到2字节边界 + DCache[Set].Line[replace_Line].Data[Block + 0] = StoreValue & 0xFF; + StoreValue = StoreValue >> 8; + DCache[Set].Line[replace_Line].Data[Block + 1] = StoreValue & 0xFF; + break; + case 4: // 4个字节 + Block = Block & 0xFC; // 需对齐到4字节边界 + DCache[Set].Line[replace_Line].Data[Block + 0] = StoreValue & 0xFF; + StoreValue = StoreValue >> 8; + DCache[Set].Line[replace_Line].Data[Block + 1] = StoreValue & 0xFF; + StoreValue = StoreValue >> 8; + DCache[Set].Line[replace_Line].Data[Block + 2] = StoreValue & 0xFF; + StoreValue = StoreValue >> 8; + DCache[Set].Line[replace_Line].Data[Block + 3] = StoreValue & 0xFF; + break; + case 8: // 8个字节 + Block = Block & 0xF8; // 需对齐到8字节边界 + DCache[Set].Line[replace_Line].Data[Block + 0] = StoreValue & 0xFF; + StoreValue = StoreValue >> 8; + DCache[Set].Line[replace_Line].Data[Block + 1] = StoreValue & 0xFF; + StoreValue = StoreValue >> 8; + DCache[Set].Line[replace_Line].Data[Block + 2] = StoreValue & 0xFF; + StoreValue = StoreValue >> 8; + DCache[Set].Line[replace_Line].Data[Block + 3] = StoreValue & 0xFF; + StoreValue = StoreValue >> 8; + DCache[Set].Line[replace_Line].Data[Block + 4] = StoreValue & 0xFF; + StoreValue = StoreValue >> 8; + DCache[Set].Line[replace_Line].Data[Block + 5] = StoreValue & 0xFF; + StoreValue = StoreValue >> 8; + DCache[Set].Line[replace_Line].Data[Block + 6] = StoreValue & 0xFF; + StoreValue = StoreValue >> 8; + DCache[Set].Line[replace_Line].Data[Block + 7] = StoreValue & 0xFF; + break; + } + DCache[Set].Line[replace_Line].Dirty = 1; + + // 写直达,同时更新L2 + StoreDataFromL1ToL2(Address, Set, replace_Line); } - + UpdateAgeData(Set, replace_Line); + } + + // 返回L1的命中/未命中标志 + return MissFlag; } - -UINT8 AccessInstCache(UINT64 Address, UINT8 Operation, UINT8 InstSize, UINT64* InstResult) -{ - UINT32 set = (Address >> ICACHE_DATA_PER_LINE_ADDR_BITS) % ICACHE_SET; - UINT8 block = Address % ICACHE_DATA_PER_LINE; - UINT64 tag = Address >> (ICACHE_DATA_PER_LINE_ADDR_BITS + ICACHE_SET_ADDR_BITS); - UINT8 HitLine; - UINT8 MissFlag = 'M'; - UINT64 ReadValue = 0; - - *InstResult = 0; - - // 检查命中 - for (int i = 0; i < ICACHE_LINE_PER_SET; i++) { - if (ICache[set].Line[i].Valid && ICache[set].Line[i].Tag == tag) { - HitLine = i; - MissFlag = 'H'; - break; - } + +/* + * 访问指令缓存的主函数 + * 参数: + * Address - 访问的内存地址 + * Operation - 通常只用于读取指令,但我们保留此参数以保持接口一致 + * InstSize - 指令大小(通常为4字节,但支持1、2、4、8字节) + * InstResult - 指向读取结果的指针 + * 返回值: + * 'H' - 缓存命中 + * 'M' - 缓存未命中 + */ +UINT8 AccessInstCache(UINT64 Address, UINT8 Operation, UINT8 InstSize, + UINT64 *InstResult) { + UINT32 set = (Address >> ICACHE_DATA_PER_LINE_ADDR_BITS) % ICACHE_SET; + UINT8 block = Address % ICACHE_DATA_PER_LINE; + UINT64 tag = + Address >> (ICACHE_DATA_PER_LINE_ADDR_BITS + ICACHE_SET_ADDR_BITS); + UINT8 HitLine; + UINT8 MissFlag = 'M'; + UINT64 ReadValue = 0; + + // 仅用于处理函数实现,实际不使用结果 + char _unused_L2Result; + + *InstResult = 0; + + // 检查命中 + for (int i = 0; i < ICACHE_LINE_PER_SET; i++) { + if (ICache[set].Line[i].Valid && ICache[set].Line[i].Tag == tag) { + HitLine = i; + MissFlag = 'H'; + break; } - - if (MissFlag == 'H') { - // 命中处理 - switch (InstSize) { - case 1: // 8位指令 - block = block & 0xFF; // 对齐到1字节边界 - ReadValue = ICache[set].Line[HitLine].Data[block + 0]; - break; - case 2: // 16位指令 - block = block & 0xFE; // 对齐到2字节边界 - ReadValue = ICache[set].Line[HitLine].Data[block + 1]; ReadValue = ReadValue << 8; - ReadValue |= ICache[set].Line[HitLine].Data[block + 0]; - break; - case 4: // 32位指令 - block = block & 0xFC; // 对齐到4字节边界 - ReadValue = ICache[set].Line[HitLine].Data[block + 3]; ReadValue = ReadValue << 8; - ReadValue |= ICache[set].Line[HitLine].Data[block + 2]; ReadValue = ReadValue << 8; - ReadValue |= ICache[set].Line[HitLine].Data[block + 1]; ReadValue = ReadValue << 8; - ReadValue |= ICache[set].Line[HitLine].Data[block + 0]; - break; - case 8: // 64位指令(如RISC-V的128位指令集扩展) - block = block & 0xF8; // 对齐到8字节边界 - ReadValue = ICache[set].Line[HitLine].Data[block + 7]; ReadValue = ReadValue << 8; - ReadValue |= ICache[set].Line[HitLine].Data[block + 6]; ReadValue = ReadValue << 8; - ReadValue |= ICache[set].Line[HitLine].Data[block + 5]; ReadValue = ReadValue << 8; - ReadValue |= ICache[set].Line[HitLine].Data[block + 4]; ReadValue = ReadValue << 8; - ReadValue |= ICache[set].Line[HitLine].Data[block + 3]; ReadValue = ReadValue << 8; - ReadValue |= ICache[set].Line[HitLine].Data[block + 2]; ReadValue = ReadValue << 8; - ReadValue |= ICache[set].Line[HitLine].Data[block + 1]; ReadValue = ReadValue << 8; - ReadValue |= ICache[set].Line[HitLine].Data[block + 0]; - break; - default: - // 不支持的指令长度 - return 'M'; - } - *InstResult = ReadValue; - UpdateAgeInst(set, HitLine); - } - else - { - // 未命中处理 - UINT8 replace_line = GetReplaceLineInst(set); - LoadInstCacheLineFromMemory(Address, set, replace_line); - - // 重新读取指令 - switch (InstSize) { - case 1: - block = block & 0xFF; - ReadValue = ICache[set].Line[replace_line].Data[block + 0]; - break; - case 2: - block = block & 0xFE; - ReadValue = ICache[set].Line[replace_line].Data[block + 1]; ReadValue = ReadValue << 8; - ReadValue |= ICache[set].Line[replace_line].Data[block + 0]; - break; - case 4: - block = block & 0xFC; - ReadValue = ICache[set].Line[replace_line].Data[block + 3]; ReadValue = ReadValue << 8; - ReadValue |= ICache[set].Line[replace_line].Data[block + 2]; ReadValue = ReadValue << 8; - ReadValue |= ICache[set].Line[replace_line].Data[block + 1]; ReadValue = ReadValue << 8; - ReadValue |= ICache[set].Line[replace_line].Data[block + 0]; - break; - case 8: - block = block & 0xF8; - ReadValue = ICache[set].Line[replace_line].Data[block + 7]; ReadValue = ReadValue << 8; - ReadValue |= ICache[set].Line[replace_line].Data[block + 6]; ReadValue = ReadValue << 8; - ReadValue |= ICache[set].Line[replace_line].Data[block + 5]; ReadValue = ReadValue << 8; - ReadValue |= ICache[set].Line[replace_line].Data[block + 4]; ReadValue = ReadValue << 8; - ReadValue |= ICache[set].Line[replace_line].Data[block + 3]; ReadValue = ReadValue << 8; - ReadValue |= ICache[set].Line[replace_line].Data[block + 2]; ReadValue = ReadValue << 8; - ReadValue |= ICache[set].Line[replace_line].Data[block + 1]; ReadValue = ReadValue << 8; - ReadValue |= ICache[set].Line[replace_line].Data[block + 0]; - break; - default: - // 不支持的指令长度 - return 'M'; - } - *InstResult = ReadValue; - ICache[set].Line[replace_line].Valid = 1; - ICache[set].Line[replace_line].Tag = tag; - UpdateAgeInst(set, replace_line); + } + + if (MissFlag == 'H') { + // 命中处理 + switch (InstSize) { + case 1: // 8位指令 + block = block & 0xFF; // 对齐到1字节边界 + ReadValue = ICache[set].Line[HitLine].Data[block + 0]; + break; + case 2: // 16位指令 + block = block & 0xFE; // 对齐到2字节边界 + ReadValue = ICache[set].Line[HitLine].Data[block + 1]; + ReadValue = ReadValue << 8; + ReadValue |= ICache[set].Line[HitLine].Data[block + 0]; + break; + case 4: // 32位指令 + block = block & 0xFC; // 对齐到4字节边界 + ReadValue = ICache[set].Line[HitLine].Data[block + 3]; + ReadValue = ReadValue << 8; + ReadValue |= ICache[set].Line[HitLine].Data[block + 2]; + ReadValue = ReadValue << 8; + ReadValue |= ICache[set].Line[HitLine].Data[block + 1]; + ReadValue = ReadValue << 8; + ReadValue |= ICache[set].Line[HitLine].Data[block + 0]; + break; + case 8: // 64位指令(如RISC-V的128位指令集扩展) + block = block & 0xF8; // 对齐到8字节边界 + ReadValue = ICache[set].Line[HitLine].Data[block + 7]; + ReadValue = ReadValue << 8; + ReadValue |= ICache[set].Line[HitLine].Data[block + 6]; + ReadValue = ReadValue << 8; + ReadValue |= ICache[set].Line[HitLine].Data[block + 5]; + ReadValue = ReadValue << 8; + ReadValue |= ICache[set].Line[HitLine].Data[block + 4]; + ReadValue = ReadValue << 8; + ReadValue |= ICache[set].Line[HitLine].Data[block + 3]; + ReadValue = ReadValue << 8; + ReadValue |= ICache[set].Line[HitLine].Data[block + 2]; + ReadValue = ReadValue << 8; + ReadValue |= ICache[set].Line[HitLine].Data[block + 1]; + ReadValue = ReadValue << 8; + ReadValue |= ICache[set].Line[HitLine].Data[block + 0]; + break; + default: + // 不支持的指令长度 + return 'M'; } - return MissFlag; + *InstResult = ReadValue; + UpdateAgeInst(set, HitLine); + } else { + // 未命中处理 + UINT8 replace_line = GetReplaceLineInst(set); + + // 从L2加载数据到I-Cache + _unused_L2Result = LoadInstFromL2ToICache(Address, set, replace_line); + + // 重新读取指令 + switch (InstSize) { + case 1: + block = block & 0xFF; + ReadValue = ICache[set].Line[replace_line].Data[block + 0]; + break; + case 2: + block = block & 0xFE; + ReadValue = ICache[set].Line[replace_line].Data[block + 1]; + ReadValue = ReadValue << 8; + ReadValue |= ICache[set].Line[replace_line].Data[block + 0]; + break; + case 4: + block = block & 0xFC; + ReadValue = ICache[set].Line[replace_line].Data[block + 3]; + ReadValue = ReadValue << 8; + ReadValue |= ICache[set].Line[replace_line].Data[block + 2]; + ReadValue = ReadValue << 8; + ReadValue |= ICache[set].Line[replace_line].Data[block + 1]; + ReadValue = ReadValue << 8; + ReadValue |= ICache[set].Line[replace_line].Data[block + 0]; + break; + case 8: + block = block & 0xF8; + ReadValue = ICache[set].Line[replace_line].Data[block + 7]; + ReadValue = ReadValue << 8; + ReadValue |= ICache[set].Line[replace_line].Data[block + 6]; + ReadValue = ReadValue << 8; + ReadValue |= ICache[set].Line[replace_line].Data[block + 5]; + ReadValue = ReadValue << 8; + ReadValue |= ICache[set].Line[replace_line].Data[block + 4]; + ReadValue = ReadValue << 8; + ReadValue |= ICache[set].Line[replace_line].Data[block + 3]; + ReadValue = ReadValue << 8; + ReadValue |= ICache[set].Line[replace_line].Data[block + 2]; + ReadValue = ReadValue << 8; + ReadValue |= ICache[set].Line[replace_line].Data[block + 1]; + ReadValue = ReadValue << 8; + ReadValue |= ICache[set].Line[replace_line].Data[block + 0]; + break; + default: + // 不支持的指令长度 + return 'M'; + } + *InstResult = ReadValue; + ICache[set].Line[replace_line].Valid = 1; + ICache[set].Line[replace_line].Tag = tag; + UpdateAgeInst(set, replace_line); + } + + // 返回I-Cache的命中/未命中标志 + return MissFlag; } diff --git a/cachelab/Makefile b/cachelab/Makefile index 6228e56..ebeeec8 100644 --- a/cachelab/Makefile +++ b/cachelab/Makefile @@ -8,7 +8,8 @@ LDFLAGS += LDLIBS += -lzstd -CPPFLAGS := -Ofast -Wall -Wextra -Winline -Winit-self -Wno-sequence-point\ + +CPPFLAGS := -O3 -Wall -Wextra -Winline -Winit-self -Wno-sequence-point\ -Wno-unused-function -Wno-inline -fPIC -W -Wcast-qual -Wpointer-arith -Icbsl/include #CPPFLAGS := -g @@ -19,7 +20,7 @@ objects = Cache.o CacheHelper.o getopt.o cbsl/src/buffer.o cbsl/src/file.o cbsl/ all: $(PROGRAMS) Cache : $(objects) - icx $(CPPFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS) + gcc $(CPPFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS) rm -f $(objects) clean: