Skip to content

Commit b120818

Browse files
authored
Merge pull request #39 from ucb-bar/xcpt_handler
Support handling gemmini exceptions through the return value of gemmini instructions
2 parents c0c5711 + 3b92596 commit b120818

5 files changed

Lines changed: 53 additions & 41 deletions

File tree

SPIKE.hash

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
8626fb144e019895767830d850deca7711773e5c
1+
3db7a449d97bf40a101ef541089054e6af59d7df

software/gemmini-rocc-tests

src/main/scala/gemmini/Controller.scala

Lines changed: 30 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -126,8 +126,6 @@ class GemminiModule[T <: Data: Arithmetic, U <: Data, V <: Data]
126126
implicit val edge = outer.node.edges.out.head
127127
val tlb = Module(new FrontendTLB(2, tlb_size, dma_maxbytes))
128128
(tlb.io.clients zip outer.spad.module.io.tlb).foreach(t => t._1 <> t._2)
129-
tlb.io.exp.flush_skip := false.B
130-
tlb.io.exp.flush_retry := false.B
131129

132130
io.ptw.head <> tlb.io.ptw
133131
/*io.ptw.head.req <> tlb.io.ptw.req
@@ -137,7 +135,7 @@ class GemminiModule[T <: Data: Arithmetic, U <: Data, V <: Data]
137135
tlb.io.ptw.pmp := io.ptw.head.pmp
138136
tlb.io.ptw.customCSRs := io.ptw.head.customCSRs*/
139137

140-
spad.module.io.flush := tlb.io.exp.flush()
138+
spad.module.io.flush := tlb.io.exp.flush
141139

142140
/*
143141
//=========================================================================
@@ -181,7 +179,30 @@ class GemminiModule[T <: Data: Arithmetic, U <: Data, V <: Data]
181179
// Incoming commands and ROB
182180
val rob = Module(new ROB(new RoCCCommand, rob_entries, local_addr_t, meshRows*tileRows, meshColumns*tileColumns))
183181

184-
val raw_cmd = Queue(io.cmd)
182+
val raw_cmd_q = Module(new Queue(new RoCCCommand, 2))
183+
val fence_stall = io.cmd.bits.inst.funct === FENCE_CMD && io.busy
184+
raw_cmd_q.io.enq.valid := io.cmd.valid && io.resp.ready && !fence_stall
185+
raw_cmd_q.io.enq.bits := io.cmd.bits
186+
187+
io.resp.valid := io.cmd.valid && raw_cmd_q.io.enq.ready && !fence_stall
188+
io.resp.bits.rd := io.cmd.bits.inst.rd
189+
io.resp.bits.data := 0.U
190+
191+
io.cmd.ready := io.resp.ready && raw_cmd_q.io.enq.ready && !fence_stall
192+
193+
// When TLB is busy with exception, don't enqueue new instructions, instead use RD to pass back exception info
194+
when (tlb.io.exp.interrupt) {
195+
io.cmd.ready := true.B
196+
raw_cmd_q.io.enq.valid := false.B
197+
io.resp.valid := io.cmd.valid
198+
io.resp.bits.data := tlb.io.exp.vaddr
199+
}
200+
201+
tlb.io.exp.flush := io.cmd.fire() && io.cmd.bits.inst.funct === FLUSH_CMD
202+
203+
204+
205+
val raw_cmd = raw_cmd_q.io.deq
185206

186207
// val (compressed_cmd, compressor_busy) = InstCompressor(unrolled_cmd)
187208
// compressed_cmd.ready := false.B
@@ -361,8 +382,8 @@ class GemminiModule[T <: Data: Arithmetic, U <: Data, V <: Data]
361382
rob_completed_arb.io.out.ready := true.B
362383

363384
// Wire up global RoCC signals
364-
io.busy := raw_cmd.valid || loop_unroller_busy || rob.io.busy || spad.module.io.busy
365-
io.interrupt := tlb.io.exp.interrupt
385+
io.busy := (raw_cmd.valid || loop_unroller_busy || rob.io.busy || spad.module.io.busy) && !tlb.io.exp.interrupt
386+
io.interrupt := false.B
366387

367388
rob.io.solitary_preload := ex_controller.io.solitary_preload
368389

@@ -415,32 +436,15 @@ class GemminiModule[T <: Data: Arithmetic, U <: Data, V <: Data]
415436
val risc_funct = unrolled_cmd.bits.inst.funct
416437

417438
val is_flush = risc_funct === FLUSH_CMD
439+
val is_fence = risc_funct === FENCE_CMD
418440
/*
419441
val is_load = (funct === LOAD_CMD) || (funct === CONFIG_CMD && config_cmd_type === CONFIG_LOAD)
420442
val is_store = (funct === STORE_CMD) || (funct === CONFIG_CMD && config_cmd_type === CONFIG_STORE)
421443
val is_ex = (funct === COMPUTE_AND_FLIP_CMD || funct === COMPUTE_AND_STAY_CMD || funct === PRELOAD_CMD) ||
422444
(funct === CONFIG_CMD && config_cmd_type === CONFIG_EX)
423445
*/
424-
425-
when (is_flush) {
426-
// val skip = compressed_cmd.bits.rs1(0)
427-
val skip = unrolled_cmd.bits.rs1(0)
428-
tlb.io.exp.flush_skip := skip
429-
tlb.io.exp.flush_retry := !skip
430-
431-
// compressed_cmd.ready := true.B // TODO should we wait for an acknowledgement from the TLB?
432-
unrolled_cmd.ready := true.B // TODO should we wait for an acknowledgement from the TLB?
433-
}
434-
435-
.otherwise {
436-
rob.io.alloc.valid := true.B
437-
438-
when(rob.io.alloc.fire()) {
439-
// compressed_cmd.ready := true.B
440-
unrolled_cmd.ready := true.B
441-
}
442-
}
443-
446+
unrolled_cmd.ready := is_fence || is_flush || rob.io.alloc.ready
447+
rob.io.alloc.valid := !is_flush && !is_fence
444448
}
445449

446450
/*

src/main/scala/gemmini/FrontendTLB.scala

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,12 @@ class DecoupledTLBReq(val lgMaxSize: Int)(implicit p: Parameters) extends CoreBu
1717
}
1818

1919
class TLBExceptionIO extends Bundle {
20+
// interrupt means we are stalling loads and stores until a gemmini_flush command is received
2021
val interrupt = Output(Bool())
21-
val flush_retry = Input(Bool())
22-
val flush_skip = Input(Bool())
22+
// vaddr of faulting inst. LSB indicates is_Store
23+
val vaddr = Output(UInt(64.W))
2324

24-
def flush(dummy: Int = 0): Bool = flush_retry || flush_skip
25+
val flush = Input(Bool())
2526
}
2627

2728
// TODO can we make TLB hits only take one cycle?
@@ -30,37 +31,44 @@ class DecoupledTLB(entries: Int, maxSize: Int)(implicit edge: TLEdgeOut, p: Para
3031

3132
val lgMaxSize = log2Ceil(maxSize)
3233
val io = new Bundle {
33-
val req = Flipped(Valid(new DecoupledTLBReq(lgMaxSize)))
34+
val req = Flipped(Decoupled(new DecoupledTLBReq(lgMaxSize)))
3435
val resp = new TLBResp
3536
val ptw = new TLBPTWIO
3637

3738
val exp = new TLBExceptionIO
3839
}
3940

4041
val interrupt = RegInit(false.B)
42+
val interrupt_vaddr = Reg(UInt(64.W))
4143
io.exp.interrupt := interrupt
44+
io.exp.vaddr := interrupt_vaddr
45+
46+
io.req.ready := !interrupt
4247

4348
val tlb = Module(new TLB(false, lgMaxSize, TLBConfig(nSets=1, nWays=entries)))
4449
tlb.io.req.valid := io.req.valid
4550
tlb.io.req.bits := io.req.bits.tlb_req
4651
io.resp := tlb.io.resp
4752
tlb.io.kill := false.B
4853

49-
tlb.io.sfence.valid := io.exp.flush()
54+
tlb.io.sfence.valid := io.exp.flush
5055
tlb.io.sfence.bits.rs1 := false.B
5156
tlb.io.sfence.bits.rs2 := false.B
5257
tlb.io.sfence.bits.addr := DontCare
5358
tlb.io.sfence.bits.asid := DontCare
5459

5560
io.ptw <> tlb.io.ptw
5661
tlb.io.ptw.status := io.req.bits.status
57-
val exception = io.req.valid && Mux(io.req.bits.tlb_req.cmd === M_XRD, tlb.io.resp.pf.ld || tlb.io.resp.ae.ld, tlb.io.resp.pf.st || tlb.io.resp.ae.st)
58-
when (exception) { interrupt := true.B }
62+
val xcpt_ld = io.req.valid && (io.req.bits.tlb_req.cmd === M_XRD) && (tlb.io.resp.pf.ld || tlb.io.resp.ae.ld)
63+
val xcpt_st = io.req.valid && (io.req.bits.tlb_req.cmd === M_XWR) && (tlb.io.resp.pf.st || tlb.io.resp.ae.st)
64+
when (!interrupt && (xcpt_ld || xcpt_st)) {
65+
interrupt := true.B
66+
interrupt_vaddr := Cat(tlb.io.req.bits.vaddr >> 1, xcpt_st)
67+
68+
}
5969
when (interrupt && tlb.io.sfence.fire()) {
6070
interrupt := false.B
6171
}
62-
63-
assert(!io.exp.flush_retry || !io.exp.flush_skip, "TLB: flushing with both retry and skip at same time")
6472
}
6573

6674
class FrontendTLBIO(implicit p: Parameters) extends CoreBundle {
@@ -81,9 +89,7 @@ class FrontendTLB(nClients: Int, entries: Int, maxSize: Int)
8189
val lgMaxSize = log2Ceil(coreDataBytes)
8290
val tlbArb = Module(new RRArbiter(new DecoupledTLBReq(lgMaxSize), nClients))
8391
val tlb = Module(new DecoupledTLB(entries, maxSize))
84-
tlb.io.req.valid := tlbArb.io.out.valid
85-
tlb.io.req.bits := tlbArb.io.out.bits
86-
tlbArb.io.out.ready := true.B
92+
tlb.io.req <> tlbArb.io.out
8793

8894
io.ptw <> tlb.io.ptw
8995
io.exp <> tlb.io.exp
@@ -102,7 +108,7 @@ class FrontendTLB(nClients: Int, entries: Int, maxSize: Int)
102108
last_translated_vpn := req.bits.tlb_req.vaddr
103109
last_translated_ppn := tlb.io.resp.paddr
104110
}
105-
when (io.exp.flush()) {
111+
when (io.exp.flush) {
106112
last_translated_valid := false.B
107113
}
108114

src/main/scala/gemmini/GemminiISA.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ object GemminiISA {
2222

2323
val LOAD3_CMD = 14.U
2424

25+
val FENCE_CMD = 127.U
26+
2527
// rs1[2:0] values
2628
val CONFIG_EX = 0.U
2729
val CONFIG_LOAD = 1.U

0 commit comments

Comments
 (0)