RISC-V Notes

screenshot-2016-11-29-17-00-00

https://riscv.org/wp-content/uploads/2015/01/riscv-rocket-chip-generator-workshop-jan2015.pdf

src/main/scala/uncore/tilelink/Definitions.scala States the following for each steps:

  1. Acquire: used to initiate coherence protocol transactions in order to gain access to a cache blcok’s data with certain permissions enabled. … Acquires may contain data for Put or PutAtomic… After sending acquires, clients must wait for a manager to send them a Uncore Grant message in response
  2. Probe: used to force clients to release data or cede permissions on a cache block. Clients respond to probes with Release messages.
  3. Release: used to release data or permission back to the manager in response to Probe message. Can be used to volunatirly writeback data. (ex. event that dirty data must be evicted on cache miss).
  4. Grant: used to refill data or grant permissions requested of the manger agent via acquire message. Also used to ack the receipt of volunatry writeback from clients in the form of Release.
  5. Finish: used to provide global ordering of Txs. Sent as ack for receipt of grant message. When a Finish message is received, a manager knows it is safe to begin processing other transactions that touch the same cache block.

Cache Miss

On a miss, there is a block of code that adds the miss into the MSHR

// replacement policy
val replacer = p(Replacer)()
val s1_replaced_way_en = UIntToOH(replacer.way)
val s2_replaced_way_en = UIntToOH(RegEnable(replacer.way, s1_clk_en))
val s2_repl_meta = Mux1H(s2_replaced_way_en, wayMap((w: Int) => RegEnable(meta.io.resp(w), s1_clk_en && s1_replaced_way_en(w))).toSeq)

// miss handling
mshrs.io.req.valid := s2_valid_masked && !s2_hit && (isPrefetch(s2_req.cmd) || isRead(s2_req.cmd) || isWrite(s2_req.cmd))
mshrs.io.req.bits := s2_req
mshrs.io.req.bits.tag_match := s2_tag_match
mshrs.io.req.bits.old_meta := Mux(s2_tag_match, L1Metadata(s2_repl_meta.tag, s2_hit_state), s2_repl_meta)
mshrs.io.req.bits.way_en := Mux(s2_tag_match, s2_tag_match_way, s2_replaced_way_en)
mshrs.io.req.bits.data := s2_req.data
when (mshrs.io.req.fire()) { replacer.miss }
io.mem.acquire <> mshrs.io.mem_req

The miss should be processed by the MSHR by issuing an Acquire to the TileLink, and waiting for a Grant that’ll be filled into the mshrs.io.req.bits.way_en way.

In the MSHRFile class, there is a line of code as follows:

val sdq_enq = io.req.valid && io.req.ready && cacheable && isWrite(io.req.bits.cmd)

Thus I’m assuming the sdq stands for a Store Data Queue. Also, as we’re trying to prefetch misses (I think we can ignore this part for now…)

MSHR Issues Acquire Requests

 io.mem_req.valid := state === s_refill_req && fq.io.enq.ready
 io.mem_req.bits := req.old_meta.coh.makeAcquire(
 addr_block = Cat(io.tag, req_idx),
 client_xact_id = Bits(id),
 op_code = req.cmd)

This is a code snippet from the MSHR class.  The individual mshr.io.mem_req are connected via an arbiter in the MSHRFile class mem_req_arb.io. The mem_req_arb‘s out is connected to the io.mem_req which is then connected to the io.mem.acquire in the HellaCache class.

The snippet above sends out a Acquire requests if the state of the current MSHR is a refill request, and is ready to be enqueued into the Finish Queue. The address block is generated from the tag and index, and the op_code carries the command of the request. Also, an id is generated to create an client Transaction ID. However, the id the index of the MSHR in the MSHRFile.

State change: s_refill_req->s_refill_resp

The MSHR state change from the s_refill_req to s_refill_resp happens on an Acquire fire(). The fire() occurs when both the  object’s valid and ready bits are on at the same time.

object ReadyValidIO {
...
def fire(): Bool = target.ready && target.valid
}

Thus the acquire has been fed valid data, and the acquire has been switched to ready. The acquire has been successfully fired, and we’re waiting for a grant response from the uncore.

Check the code from line:304