Question

It would be nice to Vec[Mem] for say set-associative caches.

Unfortunately Chisel doesn't support Vec[Mem] construct:

val tag_ram2    = Vec.fill(num_ways) {Mem(new TagType(), num_sets , seqRead = true )}

Indeed:

inferred type arguments [Chisel.Mem[cache.TagType]] do not conform to method fill's type     parameter bounds [T <: Chisel.Data]
[error] Error occurred in an application involving default arguments.
[error]     val tag_ram2    = Vec.fill(num_ways) {Mem(new TagType(), num_sets , seqRead = true )}
[error]                               ^
[error] /home/asamoilov/work/projects/my-chisel/Cache.scala:139: type mismatch;
[error]  found   : Chisel.Mem[cache.TagType]
[error]  required: T
[error] Error occurred in an application involving default arguments.
[error]     val tag_ram2    = Vec.fill(num_ways) {Mem(new TagType(), num_sets , seqRead = true )}

However a simple workaround works fine:

val tag_ram2    = Array.fill(num_ways) {Mem(new TagType(), num_sets , seqRead = true )}
[...]
    is (read_tag) {

        set_idx := req_idx % UInt(num_sets) // FIXME
        for (way_no <- 0 until num_ways) {
            tag_read_vec(way_no) := tag_ram2(way_no)(set_idx)
        }
        controller_state := compare_tag
    }

And for writing tags (of cause under some when(...) clause)

            for (way_no <- 0 until num_ways) {
                when (UInt(way_no) === way_idx) {
                    printf("writing to way %d set %d tag %x\n", way_idx, set_idx, tag_write.toBits)
                    tag_ram2(way_no)(set_idx) := tag_write
                }
            }

Comments, proposals for improving proposed scheme? Thanks!

Was it helpful?

Solution

For the tags array, try using a 1-d vector of Bits that's (n_tag_sz*n_ways) in width. On a cache access, you read out the entire row anyways, and you want to store that in something as dense as possible. So like this:

val tag_array = Mem(Bits(width = tagbits*n_ways), n_sets, seqRead = true)  

And here's a snippet of psuedo-code for an i-cache's memory banks, which covers 3 cycles (s0,s1,s2) for ifgen, ic_access, and ic_response:

val s1_tag_match = Vec.fill(n_ways){Bool()}
val s2_tag_hit = Vec.fill(n_ways){Bool()}
val s2_dout = Vec.fill(n_ways){Reg(Bits())}

for (i <- 0 until n_ways) 
{
   // notice each cycle of refill gets its own line
   val data_array = Mem(Bits(width = n_code_width), n_sets*REFILL_CYCLES, seqRead = true)
   val s1_raddr = Reg(UInt())
   // refill
   when (io.mem.resp.valid && repl_way === UInt(i)) 
   {
      data_array(Cat(s2_idx,rf_cnt)) := io.mem.resp.bits.data
   }
   // read enable
   .elsewhen (s0_valid) 
   {
      s1_raddr := s0_raddr
   }

   // read
   when (s1_valid && s1_tag_match(i) && ready) 
   { 
      s2_dout(i) := data_array(s1_raddr) 
   }
 }

 io.resp.bits.data := Mux1H(s2_tag_hit, s2_dout)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top