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