punk@1: // The MIT License punk@1: punk@1: // Copyright (c) 2009 Massachusetts Institute of Technology punk@1: punk@1: // Permission is hereby granted, free of charge, to any person obtaining a copy punk@1: // of this software and associated documentation files (the "Software"), to deal punk@1: // in the Software without restriction, including without limitation the rights punk@1: // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell punk@1: // copies of the Software, and to permit persons to whom the Software is punk@1: // furnished to do so, subject to the following conditions: punk@1: punk@1: // The above copyright notice and this permission notice shall be included in punk@1: // all copies or substantial portions of the Software. punk@1: punk@1: // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR punk@1: // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, punk@1: // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE punk@1: // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER punk@1: // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, punk@1: // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN punk@1: // THE SOFTWARE. punk@1: punk@1: import Connectable::*; punk@1: import GetPut::*; punk@1: import ClientServer::*; punk@1: import RegFile::*; punk@1: import FIFO::*; punk@1: import FIFOF::*; punk@1: import RWire::*; punk@1: punk@1: import BFIFO::*; punk@1: import MemTypes::*; punk@1: import ProcTypes::*; punk@1: import Trace::*; punk@1: punk@1: interface ICacheStats; punk@1: interface Get#(Stat) num_accesses; punk@1: interface Get#(Stat) num_misses; punk@1: interface Get#(Stat) num_evictions; punk@1: endinterface punk@1: punk@1: interface ICache#( type req_t, type resp_t ); punk@1: punk@1: // Interface from processor to cache punk@1: interface Server#(req_t,resp_t) proc_server; punk@1: punk@1: // Interface from cache to main memory punk@1: interface Client#(MainMemReq,MainMemResp) mmem_client; punk@1: punk@1: // Interface for enabling/disabling statistics punk@1: interface Put#(Bool) statsEn_put; punk@1: punk@1: // Interface for collecting statistics punk@1: interface ICacheStats stats; punk@1: punk@1: endinterface punk@1: punk@1: //---------------------------------------------------------------------- punk@1: // Cache Types punk@1: //---------------------------------------------------------------------- punk@1: punk@1: typedef 10 CacheLineIndexSz; punk@1: typedef 20 CacheLineTagSz; punk@1: typedef 32 CacheLineSz; punk@1: punk@1: typedef Bit#(CacheLineIndexSz) CacheLineIndex; punk@1: typedef Bit#(CacheLineTagSz) CacheLineTag; punk@1: typedef Bit#(CacheLineSz) CacheLine; punk@1: punk@1: typedef enum punk@1: { punk@1: Init, punk@1: Access, punk@1: Evict, punk@1: RefillReq, punk@1: RefillResp punk@1: } punk@1: CacheStage punk@1: deriving (Eq,Bits); punk@1: punk@1: //---------------------------------------------------------------------- punk@1: // Helper functions punk@1: //---------------------------------------------------------------------- punk@1: punk@1: function Bit#(AddrSz) getAddr( InstReq req ); punk@1: punk@1: Bit#(AddrSz) addr = ?; punk@1: case ( req ) matches punk@1: tagged LoadReq .ld : addr = ld.addr; punk@1: tagged StoreReq .st : addr = st.addr; punk@1: endcase punk@1: punk@1: return addr; punk@1: punk@1: endfunction punk@1: punk@1: function CacheLineIndex getCacheLineIndex( InstReq req ); punk@1: Bit#(AddrSz) addr = getAddr(req); punk@1: Bit#(CacheLineIndexSz) index = truncate( addr >> 2 ); punk@1: return index; punk@1: endfunction punk@1: punk@1: function CacheLineTag getCacheLineTag( InstReq req ); punk@1: Bit#(AddrSz) addr = getAddr(req); punk@1: Bit#(CacheLineTagSz) tag = truncate( addr >> fromInteger(valueOf(CacheLineIndexSz)) >> 2 ); punk@1: return tag; punk@1: endfunction punk@1: punk@1: function Bit#(AddrSz) getCacheLineAddr( InstReq req ); punk@1: Bit#(AddrSz) addr = getAddr(req); punk@1: return ((addr >> 2) << 2); punk@1: endfunction punk@1: punk@1: //---------------------------------------------------------------------- punk@1: // Main module punk@1: //---------------------------------------------------------------------- punk@1: punk@1: (* doc = "synthesis attribute ram_style mkInstCache distributed;" *) punk@1: (* synthesize *) punk@1: module mkInstCache( ICache#(InstReq,InstResp) ); punk@1: punk@1: //----------------------------------------------------------- punk@1: // State punk@1: punk@1: Reg#(CacheStage) stage <- mkReg(Init); punk@1: punk@1: RegFile#(CacheLineIndex,Maybe#(CacheLineTag)) cacheTagRam <- mkRegFileFull(); punk@1: RegFile#(CacheLineIndex,CacheLine) cacheDataRam <- mkRegFileFull(); punk@1: punk@1: FIFO#(InstReq) reqQ <- mkFIFO(); punk@1: FIFOF#(InstResp) respQ <- mkBFIFOF1(); punk@1: punk@1: FIFO#(MainMemReq) mainMemReqQ <- mkBFIFO1(); punk@1: FIFO#(MainMemResp) mainMemRespQ <- mkFIFO(); punk@1: punk@1: Reg#(CacheLineIndex) initCounter <- mkReg(1); punk@1: punk@1: // Statistics state punk@1: punk@1: Reg#(Bool) statsEn <- mkReg(False); punk@1: punk@1: Reg#(Stat) numAccesses <- mkReg(0); punk@1: Reg#(Stat) numMisses <- mkReg(0); punk@1: Reg#(Stat) numEvictions <- mkReg(0); punk@1: punk@1: //----------------------------------------------------------- punk@1: // Name some wires punk@1: punk@1: let req = reqQ.first(); punk@1: let reqIndex = getCacheLineIndex(req); punk@1: let reqTag = getCacheLineTag(req); punk@1: let reqCacheLineAddr = getCacheLineAddr(req); punk@1: let refill = mainMemRespQ.first(); punk@1: punk@1: //----------------------------------------------------------- punk@1: // Initialize punk@1: punk@1: rule init ( stage == Init ); punk@1: traceTiny("mkInstCacheBlocking", "stage","i"); punk@1: initCounter <= initCounter + 1; punk@1: cacheTagRam.upd(initCounter,Invalid); punk@1: if ( initCounter == 0 ) punk@1: stage <= Access; punk@1: endrule punk@1: punk@1: //----------------------------------------------------------- punk@1: // Cache access rule punk@1: punk@1: rule access ( (stage == Access) && respQ.notFull() ); punk@1: punk@1: // Statistics punk@1: punk@1: if ( statsEn ) punk@1: numAccesses <= numAccesses + 1; punk@1: punk@1: // Check tag and valid bit to see if this is a hit or a miss punk@1: punk@1: Maybe#(CacheLineTag) cacheLineTag = cacheTagRam.sub(reqIndex); punk@1: punk@1: // Handle cache hits ... punk@1: punk@1: if ( isValid(cacheLineTag) && ( unJust(cacheLineTag) == reqTag ) ) punk@1: begin punk@1: traceTiny("mkInstCacheBlocking", "hitMiss","h"); punk@1: reqQ.deq(); punk@1: punk@1: case ( req ) matches punk@1: punk@1: tagged LoadReq .ld : punk@1: respQ.enq( LoadResp { tag : ld.tag, data : cacheDataRam.sub(reqIndex) } ); punk@1: punk@1: tagged StoreReq .st : punk@1: $display( " RTL-ERROR : %m : Stores are not allowed on the inst port!" ); punk@1: punk@1: endcase punk@1: punk@1: end punk@1: punk@1: // Handle cache misses - since lines in instruction cache are punk@1: // never dirty we can always immediately issue a refill request punk@1: punk@1: else punk@1: begin punk@1: traceTiny("mkInstCacheBlocking", "hitMiss","m"); punk@1: if ( statsEn ) punk@1: numMisses <= numMisses + 1; punk@1: if ( statsEn ) punk@1: if ( isJust(cacheLineTag) ) punk@1: numEvictions <= numEvictions + 1; punk@1: punk@1: MainMemReq rfReq punk@1: = LoadReq { tag : 0, punk@1: addr : reqCacheLineAddr }; punk@1: punk@1: mainMemReqQ.enq(rfReq); punk@1: stage <= RefillResp; punk@1: end punk@1: punk@1: endrule punk@1: punk@1: //----------------------------------------------------------- punk@1: // Refill response rule punk@1: punk@1: rule refillResp ( stage == RefillResp ); punk@1: traceTiny("mkInstCacheBlocking", "stage","R"); punk@1: traceTiny("mkInstCacheBlocking", "refill",refill); punk@1: punk@1: // Write the new data into the cache and update the tag punk@1: punk@1: mainMemRespQ.deq(); punk@1: case ( mainMemRespQ.first() ) matches punk@1: punk@1: tagged LoadResp .ld : punk@1: begin punk@1: cacheTagRam.upd(reqIndex,Valid(reqTag)); punk@1: cacheDataRam.upd(reqIndex,ld.data); punk@1: end punk@1: punk@1: tagged StoreResp .st : punk@1: noAction; punk@1: punk@1: endcase punk@1: punk@1: stage <= Access; punk@1: endrule punk@1: punk@1: //----------------------------------------------------------- punk@1: // Methods punk@1: punk@1: interface Client mmem_client; punk@1: interface Get request = fifoToGet(mainMemReqQ); punk@1: interface Put response = fifoToPut(mainMemRespQ); punk@1: endinterface punk@1: punk@1: interface Server proc_server; punk@1: interface Put request = tracePut("mkInstCacheBlocking", "reqTiny",toPut(reqQ)); punk@1: interface Get response = traceGet("mkInstCacheBlocking", "respTiny",toGet(respQ)); punk@1: endinterface punk@1: punk@1: interface Put statsEn_put = toPut(asReg(statsEn)); punk@1: punk@1: interface ICacheStats stats; punk@1: interface Get num_accesses = toGet(asReg(numAccesses)); punk@1: interface Get num_misses = toGet(asReg(numMisses)); punk@1: interface Get num_evictions = toGet(asReg(numEvictions)); punk@1: endinterface punk@1: punk@1: endmodule punk@1: