@@ -87,3 +87,246 @@ object CSR {
8787 mstatus
8888 )
8989}
90+
91+ object Cause {
92+ val InstAddrMisaligned = 0x0 .U
93+ val IllegalInst = 0x2 .U
94+ val Breakpoint = 0x3 .U
95+ val LoadAddrMisaligned = 0x4 .U
96+ val StoreAddrMisaligned = 0x6 .U
97+ val Ecall = 0x8 .U
98+ }
99+
100+ class CSRIO (implicit p : Parameters ) extends Bundle {
101+ val stall = Input (Bool ())
102+ val cmd = Input (UInt (3 .W ))
103+ val in = Input (UInt (xlen.W ))
104+ val out = Output (UInt (xlen.W ))
105+ // excpetion
106+ val pc = Input (UInt (xlen.W ))
107+ val addr = Input (UInt (xlen.W ))
108+ val inst = Input (UInt (xlen.W ))
109+ val illegal = Input (Bool ())
110+ val st_type = Input (UInt (2 .W ))
111+ val ld_type = Input (UInt (3 .W ))
112+ val pc_check = Input (Bool ())
113+ val expt = Output (Bool ())
114+ val evec = Output (UInt (xlen.W ))
115+ val epc = Output (UInt (xlen.W ))
116+ // HTIF
117+ val host = new HostIO
118+ }
119+
120+ class CSR (implicit val p : Parameters ) extends Module {
121+ val io = IO (new CSRIO )
122+
123+ val csr_addr = io.inst(31 , 20 )
124+ val rs1_addr = io.inst(19 , 15 )
125+
126+ // user counters
127+ val time = RegInit (0 .U (xlen.W ))
128+ val timeh = RegInit (0 .U (xlen.W ))
129+ val cycle = RegInit (0 .U (xlen.W ))
130+ val cycleh = RegInit (0 .U (xlen.W ))
131+ val instret = RegInit (0 .U (xlen.W ))
132+ val instreth = RegInit (0 .U (xlen.W ))
133+
134+ val mcpuid = Cat (
135+ 0 .U (2 .W ) /* RV32I */ ,
136+ 0 .U ((xlen - 28 ).W ),
137+ (1 << ('I' - 'A' ) /* Base ISA */ |
138+ 1 << ('U' - 'A' ) /* User Mode */ ).U (26 .W )
139+ )
140+ val mimpid = 0 .U (xlen.W ) // not implemented
141+ val mhartid = 0 .U (xlen.W ) // only one hart
142+
143+ // interrupt enable stack
144+ val PRV = RegInit (CSR .PRV_M )
145+ val PRV1 = RegInit (CSR .PRV_M )
146+ val PRV2 = 0 .U (2 .W )
147+ val PRV3 = 0 .U (2 .W )
148+ val IE = RegInit (false .B )
149+ val IE1 = RegInit (false .B )
150+ val IE2 = false .B
151+ val IE3 = false .B
152+ // virtualization management field
153+ val VM = 0 .U (5 .W )
154+ // memory privilege
155+ val MPRV = false .B
156+ // extention context status
157+ val XS = 0 .U (2 .W )
158+ val FS = 0 .U (2 .W )
159+ val SD = 0 .U (1 .W )
160+ val mstatus = Cat (SD , 0 .U ((xlen - 23 ).W ), VM , MPRV , XS , FS , PRV3 , IE3 , PRV2 , IE2 , PRV1 , IE1 , PRV , IE )
161+ val mtvec = Const .PC_EVEC .U (xlen.W )
162+ val mtdeleg = 0x0 .U (xlen.W )
163+
164+ // interrupt registers
165+ val MTIP = RegInit (false .B )
166+ val HTIP = false .B
167+ val STIP = false .B
168+ val MTIE = RegInit (false .B )
169+ val HTIE = false .B
170+ val STIE = false .B
171+ val MSIP = RegInit (false .B )
172+ val HSIP = false .B
173+ val SSIP = false .B
174+ val MSIE = RegInit (false .B )
175+ val HSIE = false .B
176+ val SSIE = false .B
177+ val mip = Cat (0 .U ((xlen - 8 ).W ), MTIP , HTIP , STIP , false .B , MSIP , HSIP , SSIP , false .B )
178+ val mie = Cat (0 .U ((xlen - 8 ).W ), MTIE , HTIE , STIE , false .B , MSIE , HSIE , SSIE , false .B )
179+
180+ val mtimecmp = Reg (UInt (xlen.W ))
181+
182+ val mscratch = Reg (UInt (xlen.W ))
183+
184+ val mepc = Reg (UInt (xlen.W ))
185+ val mcause = Reg (UInt (xlen.W ))
186+ val mbadaddr = Reg (UInt (xlen.W ))
187+
188+ val mtohost = RegInit (0 .U (xlen.W ))
189+ val mfromhost = Reg (UInt (xlen.W ))
190+ io.host.tohost := mtohost
191+ when(io.host.fromhost.valid) {
192+ mfromhost := io.host.fromhost.bits
193+ }
194+
195+ val csrFile = Seq (
196+ BitPat (CSR .cycle) -> cycle,
197+ BitPat (CSR .time) -> time,
198+ BitPat (CSR .instret) -> instret,
199+ BitPat (CSR .cycleh) -> cycleh,
200+ BitPat (CSR .timeh) -> timeh,
201+ BitPat (CSR .instreth) -> instreth,
202+ BitPat (CSR .cyclew) -> cycle,
203+ BitPat (CSR .timew) -> time,
204+ BitPat (CSR .instretw) -> instret,
205+ BitPat (CSR .cyclehw) -> cycleh,
206+ BitPat (CSR .timehw) -> timeh,
207+ BitPat (CSR .instrethw) -> instreth,
208+ BitPat (CSR .mcpuid) -> mcpuid,
209+ BitPat (CSR .mimpid) -> mimpid,
210+ BitPat (CSR .mhartid) -> mhartid,
211+ BitPat (CSR .mtvec) -> mtvec,
212+ BitPat (CSR .mtdeleg) -> mtdeleg,
213+ BitPat (CSR .mie) -> mie,
214+ BitPat (CSR .mtimecmp) -> mtimecmp,
215+ BitPat (CSR .mtime) -> time,
216+ BitPat (CSR .mtimeh) -> timeh,
217+ BitPat (CSR .mscratch) -> mscratch,
218+ BitPat (CSR .mepc) -> mepc,
219+ BitPat (CSR .mcause) -> mcause,
220+ BitPat (CSR .mbadaddr) -> mbadaddr,
221+ BitPat (CSR .mip) -> mip,
222+ BitPat (CSR .mtohost) -> mtohost,
223+ BitPat (CSR .mfromhost) -> mfromhost,
224+ BitPat (CSR .mstatus) -> mstatus
225+ )
226+
227+ io.out := Lookup (csr_addr, 0 .U , csrFile).asUInt
228+
229+ val privValid = csr_addr(9 , 8 ) <= PRV
230+ val privInst = io.cmd === CSR .P
231+ val isEcall = privInst && ! csr_addr(0 ) && ! csr_addr(8 )
232+ val isEbreak = privInst && csr_addr(0 ) && ! csr_addr(8 )
233+ val isEret = privInst && ! csr_addr(0 ) && csr_addr(8 )
234+ val csrValid = csrFile.map(_._1 === csr_addr).reduce(_ || _)
235+ val csrRO = csr_addr(11 , 10 ).andR || csr_addr === CSR .mtvec || csr_addr === CSR .mtdeleg
236+ val wen = io.cmd === CSR .W || io.cmd(1 ) && rs1_addr.orR
237+ val wdata = MuxLookup (
238+ io.cmd,
239+ 0 .U ,
240+ Seq (
241+ CSR .W -> io.in,
242+ CSR .S -> (io.out | io.in),
243+ CSR .C -> (io.out & ~ io.in)
244+ )
245+ )
246+ val iaddrInvalid = io.pc_check && io.addr(1 )
247+ val laddrInvalid = MuxLookup (
248+ io.ld_type,
249+ false .B ,
250+ Seq (
251+ Control .LD_LW -> io.addr(1 , 0 ).orR,
252+ Control .LD_LH -> io.addr(0 ),
253+ Control .LD_LHU -> io.addr(0 )
254+ )
255+ )
256+
257+ val saddrInvalid = MuxLookup (
258+ io.st_type,
259+ false .B ,
260+ Seq (
261+ Control .ST_SW -> io.addr(1 , 0 ).orR,
262+ Control .ST_SH -> io.addr(0 )
263+ )
264+ )
265+
266+ io.expt := io.illegal || iaddrInvalid || laddrInvalid || saddrInvalid ||
267+ io.cmd(1 , 0 ).orR && (! csrValid || ! privValid) || wen && csrRO ||
268+ (privInst && ! privValid) || isEcall || isEbreak
269+ io.evec := mtvec + (PRV << 6 )
270+ io.epc := mepc
271+
272+ // Counters
273+ time := time + 1 .U
274+ when(time.andR) { timeh := timeh + 1 .U }
275+ cycle := cycle + 1 .U
276+ when(cycle.andR) { cycleh := cycleh + 1 .U }
277+ val isInstRet = io.inst =/= Instructions .NOP && (! io.expt || isEcall || isEbreak) && ! io.stall
278+ when(isInstRet) { instret := instret + 1 .U }
279+ when(isInstRet && instret.andR) { instreth := instreth + 1 .U }
280+
281+ when(! io.stall) {
282+ when(io.expt) {
283+ mepc := io.pc >> 2 << 2
284+ mcause := Mux (
285+ iaddrInvalid,
286+ Cause .InstAddrMisaligned ,
287+ Mux (
288+ laddrInvalid,
289+ Cause .LoadAddrMisaligned ,
290+ Mux (saddrInvalid, Cause .StoreAddrMisaligned , Mux (isEcall, Cause .Ecall + PRV , Mux (isEbreak, Cause .Breakpoint , Cause .IllegalInst )))
291+ )
292+ )
293+ PRV := CSR .PRV_M
294+ IE := false .B
295+ PRV1 := PRV
296+ IE1 := IE
297+ when(iaddrInvalid || laddrInvalid || saddrInvalid) { mbadaddr := io.addr }
298+ }.elsewhen(isEret) {
299+ PRV := PRV1
300+ IE := IE1
301+ PRV1 := CSR .PRV_U
302+ IE1 := true .B
303+ }.elsewhen(wen) {
304+ when(csr_addr === CSR .mstatus) {
305+ PRV1 := wdata(5 , 4 )
306+ IE1 := wdata(3 )
307+ PRV := wdata(2 , 1 )
308+ IE := wdata(0 )
309+ }.elsewhen(csr_addr === CSR .mip) {
310+ MTIP := wdata(7 )
311+ MSIP := wdata(3 )
312+ }.elsewhen(csr_addr === CSR .mie) {
313+ MTIE := wdata(7 )
314+ MSIE := wdata(3 )
315+ }.elsewhen(csr_addr === CSR .mtime) { time := wdata }
316+ .elsewhen(csr_addr === CSR .mtimeh) { timeh := wdata }
317+ .elsewhen(csr_addr === CSR .mtimecmp) { mtimecmp := wdata }
318+ .elsewhen(csr_addr === CSR .mscratch) { mscratch := wdata }
319+ .elsewhen(csr_addr === CSR .mepc) { mepc := wdata >> 2 .U << 2 .U }
320+ .elsewhen(csr_addr === CSR .mcause) { mcause := wdata & (BigInt (1 ) << (xlen - 1 ) | 0xf ).U }
321+ .elsewhen(csr_addr === CSR .mbadaddr) { mbadaddr := wdata }
322+ .elsewhen(csr_addr === CSR .mtohost) { mtohost := wdata }
323+ .elsewhen(csr_addr === CSR .mfromhost) { mfromhost := wdata }
324+ .elsewhen(csr_addr === CSR .cyclew) { cycle := wdata }
325+ .elsewhen(csr_addr === CSR .timew) { time := wdata }
326+ .elsewhen(csr_addr === CSR .instretw) { instret := wdata }
327+ .elsewhen(csr_addr === CSR .cyclehw) { cycleh := wdata }
328+ .elsewhen(csr_addr === CSR .timehw) { timeh := wdata }
329+ .elsewhen(csr_addr === CSR .instrethw) { instreth := wdata }
330+ }
331+ }
332+ }
0 commit comments