1

I am trying to modify the accumulator generator example to load two accesses at once, for example to load two indices from one array. All I changed is that when the first memory response comes in, I increment a counter and send out another. But I get a cache exception. My code for the accelerator is below. It only has a few changes from the accumulator.

What’s confusing too me is that the first access works and I get the data, and for now, I’m using the same address with the second access. So why wouldn’t this work?

val regfile = Mem(4, UInt(width = 16.W))
val busy = Reg(init = Vec.fill(4){Bool(false)})

val cmd = Queue(io.cmd)
val funct = cmd.bits.inst.funct
val addr = cmd.bits.rs2(log2Up(4)-1,0)
val doLoad = funct === UInt(0)
val doRead = funct === UInt(1)
val doWrite = funct === UInt(2)
val doAccum = funct === UInt(3)
val memRespTag = io.mem.resp.bits.tag

// datapath
val addend = cmd.bits.rs1
val accum = regfile(addr)
val wdata = Mux(doWrite, addend, accum + addend)

val counter = RegInit(0.U)

when (cmd.fire() && (doWrite || doAccum)) {
  regfile(addr) := wdata
}

when (io.mem.resp.valid) {
regfile(memRespTag) := io.mem.resp.bits.data
busy(memRespTag) := Bool(false)
when(counter === 0.U) {
  counter := 1.U
}
}

// control
when (io.mem.req.fire()) {
busy(counter) := Bool(true)
}

val doResp = cmd.bits.inst.xd
val stallReg = busy(counter)
val stallLoad = doLoad && !io.mem.req.ready
val stallResp = doResp && !io.resp.ready

cmd.ready := !stallReg && !stallLoad && !stallResp // command resolved if no stalls AND not issuing a load that will need a request

// PROC RESPONSE INTERFACE
io.resp.valid := cmd.valid && doResp && !stallReg && !stallLoad
// valid response if valid command, need a response, and no stalls
io.resp.bits.rd := cmd.bits.inst.rd
// Must respond with the appropriate tag or undefined behavior
io.resp.bits.data := accum
// Semantics is to always send out prior accumulator register value

io.busy := cmd.valid || busy.reduce(_||_)
// Be busy when have pending memory requests or committed possibility of pending requests
io.interrupt := Bool(false)
// Set this true to trigger an interrupt on the processor (please refer to supervisor documentation)

io.mem.req.valid := ((cmd.valid && doLoad) || counter === 1.U ) && !stallReg && !stallResp
io.mem.req.bits.addr := addend
io.mem.req.bits.tag := addr
io.mem.req.bits.cmd := M_XRD // perform a load (M_XWR for stores)
io.mem.req.bits.size := log2Ceil(8).U
io.mem.req.bits.signed := Bool(false)
io.mem.req.bits.data := Bits(0) // we're not performing any stores...
io.mem.req.bits.phys := Bool(false)
  • Can you provide more information? The commit of rocket-chip you are using and details about the error message would be very helpful. – Jack Koenig Oct 31 '19 at 16:50

1 Answers1

1

I managed to read multiple locations from io.mem interface but still struggling with multiple writes. Initially, i also faced same exception because i provided invalid memory address (no memory was existed with that address) at the time of io.mem request is triggered. Here, in your case after toggling counter to value 1 from 0. It remains high. So there is no control from cmd.valid. In this case cmd.valid is important as value (addend) assigned to io.mem.req.bits.addr signal is only valid when cmd.valid is high. You can make interface independent of cmd.valid.You have to modify interface accordingly.

So, conclusion is,Sample valid address for io.mem.req interface.From my experience you can read as many locations as you want with single custom command.

Thanks & Regards, Sanket,