refactor(Frontend): replace NamedUInt with EnumUInt (#4529)
	
		
			
	
		
	
	
		
			
				
	
				EMU Test / Changes Detection (push) Has been cancelled
				
					Details
				
			
		
			
				
	
				EMU Test / Generate Verilog (push) Has been cancelled
				
					Details
				
			
		
			
				
	
				EMU Test / EMU - Basics (push) Has been cancelled
				
					Details
				
			
		
			
				
	
				EMU Test / EMU - CHI (push) Has been cancelled
				
					Details
				
			
		
			
				
	
				EMU Test / EMU - Performance (push) Has been cancelled
				
					Details
				
			
		
			
				
	
				EMU Test / EMU - MC (push) Has been cancelled
				
					Details
				
			
		
			
				
	
				EMU Test / SIMV - Basics (push) Has been cancelled
				
					Details
				
			
		
			
				
	
				EMU Test / Upload Artifacts (push) Has been cancelled
				
					Details
				
			
		
			
				
	
				EMU Test / Check Submodules (push) Has been cancelled
				
					Details
				
			
		
			
				
	
				EMU Test / Check Format (push) Has been cancelled
				
					Details
				
			
		
	
				
					
				
			
				
	
				EMU Test / Changes Detection (push) Has been cancelled
				
					Details
				
			
		
			
				
	
				EMU Test / Generate Verilog (push) Has been cancelled
				
					Details
				
			
		
			
				
	
				EMU Test / EMU - Basics (push) Has been cancelled
				
					Details
				
			
		
			
				
	
				EMU Test / EMU - CHI (push) Has been cancelled
				
					Details
				
			
		
			
				
	
				EMU Test / EMU - Performance (push) Has been cancelled
				
					Details
				
			
		
			
				
	
				EMU Test / EMU - MC (push) Has been cancelled
				
					Details
				
			
		
			
				
	
				EMU Test / SIMV - Basics (push) Has been cancelled
				
					Details
				
			
		
			
				
	
				EMU Test / Upload Artifacts (push) Has been cancelled
				
					Details
				
			
		
			
				
	
				EMU Test / Check Submodules (push) Has been cancelled
				
					Details
				
			
		
			
				
	
				EMU Test / Check Format (push) Has been cancelled
				
					Details
				
			
		
	Use EnumUInt introduced by #4528 to do some compile-time check. Also: - add `class ExceptionType` to replace `ExceptionType.hasException(xxx)` with `xxx.hasException`, etc. - apply CamelCase to `BrType`.
This commit is contained in:
		
							parent
							
								
									3bfc5a3c90
								
							
						
					
					
						commit
						cbea99c932
					
				|  | @ -33,12 +33,12 @@ object PreDecodeInst { | ||||||
| 
 | 
 | ||||||
|   val brTable = Array( |   val brTable = Array( | ||||||
|     // C_JAL     -> List(BrType.jal), |     // C_JAL     -> List(BrType.jal), | ||||||
|     C_EBREAK  -> List(BrType.notCFI), // c.ebreak should not be decoded as jalr, higher priority than c.jalr |     C_EBREAK  -> List(BrType.NotCfi), // c.ebreak should not be decoded as jalr, higher priority than c.jalr | ||||||
|     C_J       -> List(BrType.jal), |     C_J       -> List(BrType.Jal), | ||||||
|     C_JALR    -> List(BrType.jalr), |     C_JALR    -> List(BrType.Jalr), | ||||||
|     C_BRANCH  -> List(BrType.branch), |     C_BRANCH  -> List(BrType.Branch), | ||||||
|     JAL       -> List(BrType.jal), |     JAL       -> List(BrType.Jal), | ||||||
|     JALR      -> List(BrType.jalr), |     JALR      -> List(BrType.Jalr), | ||||||
|     BRANCH    -> List(BrType.branch) |     BRANCH    -> List(BrType.Branch) | ||||||
|   ) |   ) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -82,9 +82,9 @@ object Itype extends NamedUInt(4) { | ||||||
|   def jumpTypeGen(brType: UInt, rd: OpRegType, rs: OpRegType): UInt = { |   def jumpTypeGen(brType: UInt, rd: OpRegType, rs: OpRegType): UInt = { | ||||||
| 
 | 
 | ||||||
|     val isEqualRdRs = rd === rs |     val isEqualRdRs = rd === rs | ||||||
|     val isJal       = brType === BrType.jal |     val isJal       = brType === BrType.Jal | ||||||
|     val isJalr      = brType === BrType.jalr |     val isJalr      = brType === BrType.Jalr | ||||||
|     val isBranch    = brType === BrType.branch |     val isBranch    = brType === BrType.Branch | ||||||
| 
 | 
 | ||||||
|     // push to RAS when rd is link, pop from RAS when rs is link |     // push to RAS when rd is link, pop from RAS when rs is link | ||||||
|     def isUninferableCall      = isJalr && rd.isLink && (!rs.isLink || rs.isLink && isEqualRdRs)  //8   push |     def isUninferableCall      = isJalr && rd.isLink && (!rs.isLink || rs.isLink && isEqualRdRs)  //8   push | ||||||
|  |  | ||||||
|  | @ -24,7 +24,7 @@ import ftq.FtqRedirectSramEntry | ||||||
| import ftq.FtqRfComponents | import ftq.FtqRfComponents | ||||||
| import org.chipsalliance.cde.config.Parameters | import org.chipsalliance.cde.config.Parameters | ||||||
| import utility._ | import utility._ | ||||||
| import utils.NamedUInt | import utils.EnumUInt | ||||||
| import xiangshan._ | import xiangshan._ | ||||||
| import xiangshan.backend.GPAMemEntry | import xiangshan.backend.GPAMemEntry | ||||||
| import xiangshan.backend.fu.PMPRespBundle | import xiangshan.backend.fu.PMPRespBundle | ||||||
|  | @ -88,7 +88,7 @@ class FtqICacheInfo(implicit p: Parameters) extends XSBundle with HasICacheParam | ||||||
| 
 | 
 | ||||||
| class FtqToPrefetchBundle(implicit p: Parameters) extends XSBundle { | class FtqToPrefetchBundle(implicit p: Parameters) extends XSBundle { | ||||||
|   val req:              FtqICacheInfo = new FtqICacheInfo |   val req:              FtqICacheInfo = new FtqICacheInfo | ||||||
|   val backendException: UInt          = ExceptionType() |   val backendException: ExceptionType = new ExceptionType | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| class FtqToFetchBundle(implicit p: Parameters) extends XSBundle with HasICacheParameters { | class FtqToFetchBundle(implicit p: Parameters) extends XSBundle with HasICacheParameters { | ||||||
|  | @ -152,138 +152,94 @@ class mmioCommitRead(implicit p: Parameters) extends XSBundle { | ||||||
|   val mmioLastCommit = Input(Bool()) |   val mmioLastCommit = Input(Bool()) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| object ExceptionType extends NamedUInt(2) { | class ExceptionType extends Bundle { | ||||||
|   def none: UInt = "b00".U(width.W) |   val value: UInt = ExceptionType.Value() | ||||||
|   def pf:   UInt = "b01".U(width.W) // instruction page fault |  | ||||||
|   def gpf:  UInt = "b10".U(width.W) // instruction guest page fault |  | ||||||
|   def af:   UInt = "b11".U(width.W) // instruction access fault |  | ||||||
| 
 | 
 | ||||||
|   def hasException(e: UInt):             Bool = e =/= none |   def isNone: Bool = value === ExceptionType.Value.None | ||||||
|   def hasException(e: Vec[UInt]):        Bool = e.map(_ =/= none).reduce(_ || _) |   def isPf:   Bool = value === ExceptionType.Value.Pf | ||||||
|   def hasException(e: IndexedSeq[UInt]): Bool = hasException(VecInit(e)) |   def isGpf:  Bool = value === ExceptionType.Value.Gpf | ||||||
|  |   def isAf:   Bool = value === ExceptionType.Value.Af | ||||||
| 
 | 
 | ||||||
|   def fromOH(has_pf: Bool, has_gpf: Bool, has_af: Bool): UInt = { |   def hasException: Bool = value =/= ExceptionType.Value.None | ||||||
|  | 
 | ||||||
|  |   /** merge exception from multiple sources, the leftmost one has higher priority | ||||||
|  |    * @example {{{ | ||||||
|  |    *   val itlbException = ExceptionType(io.itlb.resp.bits) | ||||||
|  |    *   val pmpException = ExceptionType(io.pmp.resp) | ||||||
|  |    * | ||||||
|  |    *   // itlb has higher priority than pmp, as when itlb has exception, pAddr is not valid | ||||||
|  |    *   val exception = itlbException || pmpException | ||||||
|  |    * }}} | ||||||
|  |    */ | ||||||
|  |   def ||(that: ExceptionType): ExceptionType = | ||||||
|  |     Mux(this.hasException, this, that) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | object ExceptionType { | ||||||
|  |   private object Value extends EnumUInt(4) { | ||||||
|  |     def None: UInt = 0.U(width.W) | ||||||
|  |     def Pf:   UInt = 1.U(width.W) // instruction page fault | ||||||
|  |     def Gpf:  UInt = 2.U(width.W) // instruction guest page fault | ||||||
|  |     def Af:   UInt = 3.U(width.W) // instruction access fault | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   def apply(that: UInt): ExceptionType = { | ||||||
|  |     Value.assertLegal(that) | ||||||
|  |     val e = Wire(new ExceptionType) | ||||||
|  |     e.value := that | ||||||
|  |     e | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   def None: ExceptionType = apply(Value.None) | ||||||
|  |   def Pf:   ExceptionType = apply(Value.Pf) | ||||||
|  |   def Gpf:  ExceptionType = apply(Value.Gpf) | ||||||
|  |   def Af:   ExceptionType = apply(Value.Af) | ||||||
|  | 
 | ||||||
|  |   def apply(hasPf: Bool, hasGpf: Bool, hasAf: Bool): ExceptionType = { | ||||||
|     assert( |     assert( | ||||||
|       PopCount(VecInit(has_pf, has_gpf, has_af)) <= 1.U, |       PopCount(VecInit(hasPf, hasGpf, hasAf)) <= 1.U, | ||||||
|       "ExceptionType.fromOH receives input that is not one-hot: pf=%d, gpf=%d, af=%d", |       "ExceptionType receives input that is not one-hot: pf=%d, gpf=%d, af=%d", | ||||||
|       has_pf, |       hasPf, | ||||||
|       has_gpf, |       hasGpf, | ||||||
|       has_af |       hasAf | ||||||
|     ) |     ) | ||||||
|     // input is at-most-one-hot encoded, so we don't worry about priority here. |     // input is at-most-one-hot encoded, so we don't worry about priority here. | ||||||
|     MuxCase( |     MuxCase( | ||||||
|       none, |       None, | ||||||
|       Seq( |       Seq( | ||||||
|         has_pf  -> pf, |         hasPf  -> Pf, | ||||||
|         has_gpf -> gpf, |         hasGpf -> Gpf, | ||||||
|         has_af  -> af |         hasAf  -> Af | ||||||
|       ) |       ) | ||||||
|     ) |     ) | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   // only af is used most frequently (pmp / ecc / tilelink), so we define a shortcut | ||||||
|  |   // we cannot use default parameter in apply(), as it is overloaded and scala won't allow | ||||||
|  |   def apply(hasAf: Bool): ExceptionType = | ||||||
|  |     apply(hasPf = false.B, hasGpf = false.B, hasAf = hasAf) | ||||||
|  | 
 | ||||||
|   // raise pf/gpf/af according to itlb response |   // raise pf/gpf/af according to itlb response | ||||||
|   def fromTlbResp(resp: TlbResp, useDup: Int = 0): UInt = { |   def fromTlbResp(resp: TlbResp, useDup: Int = 0): ExceptionType = { | ||||||
|     require(useDup >= 0 && useDup < resp.excp.length) |     require(useDup >= 0 && useDup < resp.excp.length) | ||||||
|     // itlb is guaranteed to respond at most one exception |     // itlb is guaranteed to respond at most one exception | ||||||
|     fromOH( |     apply( | ||||||
|       resp.excp(useDup).pf.instr, |       hasPf = resp.excp(useDup).pf.instr, | ||||||
|       resp.excp(useDup).gpf.instr, |       hasGpf = resp.excp(useDup).gpf.instr, | ||||||
|       resp.excp(useDup).af.instr |       hasAf = resp.excp(useDup).af.instr | ||||||
|     ) |     ) | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   // raise af if pmp check failed |   // raise af if pmp check failed | ||||||
|   def fromPMPResp(resp: PMPRespBundle): UInt = |   def fromPmpResp(resp: PMPRespBundle): ExceptionType = | ||||||
|     Mux(resp.instr, af, none) |     apply(hasAf = resp.instr) | ||||||
| 
 |  | ||||||
|   // raise af if meta/data array ecc check failed or l2 cache respond with tilelink corrupt |  | ||||||
|   /* FIXME: RISC-V Machine ISA v1.13 (draft) introduced a "hardware error" exception, described as: |  | ||||||
|    * > A Hardware Error exception is a synchronous exception triggered when corrupted or |  | ||||||
|    * > uncorrectable data is accessed explicitly or implicitly by an instruction. In this context, |  | ||||||
|    * > "data" encompasses all types of information used within a RISC-V hart. Upon a hardware |  | ||||||
|    * > error exception, the xepc register is set to the address of the instruction that attempted to |  | ||||||
|    * > access corrupted data, while the xtval register is set either to 0 or to the virtual address |  | ||||||
|    * > of an instruction fetch, load, or store that attempted to access corrupted data. The priority |  | ||||||
|    * > of Hardware Error exception is implementation-defined, but any given occurrence is |  | ||||||
|    * > generally expected to be recognized at the point in the overall priority order at which the |  | ||||||
|    * > hardware error is discovered. |  | ||||||
|    * Maybe it's better to raise hardware error instead of access fault when ECC check failed. |  | ||||||
|    * But it's draft and XiangShan backend does not implement this exception code yet, so we still raise af here. |  | ||||||
|    */ |  | ||||||
|   def fromECC(enable: Bool, corrupt: Bool): UInt = |  | ||||||
|     Mux(enable && corrupt, af, none) |  | ||||||
| 
 |  | ||||||
|   def fromTilelink(corrupt: Bool): UInt = |  | ||||||
|     Mux(corrupt, af, none) |  | ||||||
| 
 |  | ||||||
|   /**Generates exception mux tree |  | ||||||
|    * |  | ||||||
|    * Exceptions that are further to the left in the parameter list have higher priority |  | ||||||
|    * @example |  | ||||||
|    * {{{ |  | ||||||
|    *   val itlb_exception = ExceptionType.fromTlbResp(io.itlb.resp.bits) |  | ||||||
|    *   // so as pmp_exception, meta_corrupt |  | ||||||
|    *   // ExceptionType.merge(itlb_exception, pmp_exception, meta_corrupt) is equivalent to: |  | ||||||
|    *   Mux( |  | ||||||
|    *     itlb_exception =/= none, |  | ||||||
|    *     itlb_exception, |  | ||||||
|    *     Mux(pmp_exception =/= none, pmp_exception, meta_corrupt) |  | ||||||
|    *   ) |  | ||||||
|    * }}} |  | ||||||
|    */ |  | ||||||
|   def merge(exceptions: UInt*): UInt = { |  | ||||||
| //    // recursively generate mux tree |  | ||||||
| //    if (exceptions.length == 1) { |  | ||||||
| //      require(exceptions.head.getWidth == width) |  | ||||||
| //      exceptions.head |  | ||||||
| //    } else { |  | ||||||
| //      Mux(exceptions.head =/= none, exceptions.head, merge(exceptions.tail: _*)) |  | ||||||
| //    } |  | ||||||
|     // use MuxCase with default |  | ||||||
|     exceptions.foreach(e => require(e.getWidth == width)) |  | ||||||
|     val mapping = exceptions.init.map(e => (e =/= none) -> e) |  | ||||||
|     val default = exceptions.last |  | ||||||
|     MuxCase(default, mapping) |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   /**Generates exception mux tree for multi-port exception vectors |  | ||||||
|    * |  | ||||||
|    * Exceptions that are further to the left in the parameter list have higher priority |  | ||||||
|    * @example |  | ||||||
|    * {{{ |  | ||||||
|    *   val itlb_exception = VecInit((0 until PortNumber).map(i => ExceptionType.fromTlbResp(io.itlb(i).resp.bits))) |  | ||||||
|    *   // so as pmp_exception, meta_corrupt |  | ||||||
|    *   // ExceptionType.merge(itlb_exception, pmp_exception, meta_corrupt) is equivalent to: |  | ||||||
|    *   VecInit((0 until PortNumber).map(i => Mux( |  | ||||||
|    *     itlb_exception(i) =/= none, |  | ||||||
|    *     itlb_exception(i), |  | ||||||
|    *     Mux(pmp_exception(i) =/= none, pmp_exception(i), meta_corrupt(i)) |  | ||||||
|    *   )) |  | ||||||
|    * }}} |  | ||||||
|    */ |  | ||||||
|   def merge(exceptionVecs: Vec[UInt]*): Vec[UInt] = { |  | ||||||
| //    // recursively generate mux tree |  | ||||||
| //    if (exceptionVecs.length == 1) { |  | ||||||
| //      exceptionVecs.head.foreach(e => require(e.getWidth == width)) |  | ||||||
| //      exceptionVecs.head |  | ||||||
| //    } else { |  | ||||||
| //      require(exceptionVecs.head.length == exceptionVecs.last.length) |  | ||||||
| //      VecInit((exceptionVecs.head zip merge(exceptionVecs.tail: _*)).map{ case (high, low) => |  | ||||||
| //        Mux(high =/= none, high, low) |  | ||||||
| //      }) |  | ||||||
| //    } |  | ||||||
|     // merge port-by-port |  | ||||||
|     val length = exceptionVecs.head.length |  | ||||||
|     exceptionVecs.tail.foreach(vec => require(vec.length == length)) |  | ||||||
|     VecInit((0 until length).map(i => merge(exceptionVecs.map(_(i)): _*))) |  | ||||||
|   } |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| object BrType extends NamedUInt(2) { | object BrType extends EnumUInt(4) { | ||||||
|   def notCFI: UInt = "b00".U(width.W) |   def NotCfi: UInt = 0.U(width.W) | ||||||
|   def branch: UInt = "b01".U(width.W) |   def Branch: UInt = 1.U(width.W) | ||||||
|   def jal:    UInt = "b10".U(width.W) |   def Jal:    UInt = 2.U(width.W) | ||||||
|   def jalr:   UInt = "b11".U(width.W) |   def Jalr:   UInt = 3.U(width.W) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| class PreDecodeInfo extends Bundle { // 8 bit | class PreDecodeInfo extends Bundle { // 8 bit | ||||||
|  | @ -293,10 +249,10 @@ class PreDecodeInfo extends Bundle { // 8 bit | ||||||
|   val isCall = Bool() |   val isCall = Bool() | ||||||
|   val isRet  = Bool() |   val isRet  = Bool() | ||||||
|   // val excType = UInt(3.W) |   // val excType = UInt(3.W) | ||||||
|   def isBr   = brType === BrType.branch |   def isBr   = brType === BrType.Branch | ||||||
|   def isJal  = brType === BrType.jal |   def isJal  = brType === BrType.Jal | ||||||
|   def isJalr = brType === BrType.jalr |   def isJalr = brType === BrType.Jalr | ||||||
|   def notCFI = brType === BrType.notCFI |   def notCFI = brType === BrType.NotCfi | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| class FetchToIBuffer(implicit p: Parameters) extends XSBundle { | class FetchToIBuffer(implicit p: Parameters) extends XSBundle { | ||||||
|  | @ -307,7 +263,7 @@ class FetchToIBuffer(implicit p: Parameters) extends XSBundle { | ||||||
|   val foldpc           = Vec(PredictWidth, UInt(MemPredPCWidth.W)) |   val foldpc           = Vec(PredictWidth, UInt(MemPredPCWidth.W)) | ||||||
|   val ftqOffset        = Vec(PredictWidth, ValidUndirectioned(UInt(log2Ceil(PredictWidth).W))) |   val ftqOffset        = Vec(PredictWidth, ValidUndirectioned(UInt(log2Ceil(PredictWidth).W))) | ||||||
|   val backendException = Vec(PredictWidth, Bool()) |   val backendException = Vec(PredictWidth, Bool()) | ||||||
|   val exceptionType    = Vec(PredictWidth, ExceptionType()) |   val exceptionType    = Vec(PredictWidth, new ExceptionType) | ||||||
|   val crossPageIPFFix  = Vec(PredictWidth, Bool()) |   val crossPageIPFFix  = Vec(PredictWidth, Bool()) | ||||||
|   val illegalInstr     = Vec(PredictWidth, Bool()) |   val illegalInstr     = Vec(PredictWidth, Bool()) | ||||||
|   val triggered        = Vec(PredictWidth, TriggerAction()) |   val triggered        = Vec(PredictWidth, TriggerAction()) | ||||||
|  |  | ||||||
|  | @ -49,6 +49,41 @@ class IBufferIO(implicit p: Parameters) extends XSBundle { | ||||||
|   val stallReason          = new StallReasonIO(DecodeWidth) |   val stallReason          = new StallReasonIO(DecodeWidth) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | object IBufferExceptionType extends EnumUInt(8) { | ||||||
|  |   def None:        UInt = "b000".U(width.W) | ||||||
|  |   def NonCrossPF:  UInt = "b001".U(width.W) | ||||||
|  |   def NonCrossGPF: UInt = "b010".U(width.W) | ||||||
|  |   def NonCrossAF:  UInt = "b011".U(width.W) | ||||||
|  |   def RvcII:       UInt = "b100".U(width.W) // illegal instruction | ||||||
|  |   def CrossPF:     UInt = "b101".U(width.W) | ||||||
|  |   def CrossGPF:    UInt = "b110".U(width.W) | ||||||
|  |   def CrossAF:     UInt = "b111".U(width.W) | ||||||
|  | 
 | ||||||
|  |   def cvtFromFetchExcpAndCrossPageAndRVCII(fetchExcp: ExceptionType, crossPage: Bool, rvcIll: Bool): UInt = | ||||||
|  |     MuxCase( | ||||||
|  |       0.U, | ||||||
|  |       Seq( | ||||||
|  |         crossPage              -> Cat(1.U(1.W), fetchExcp.value), | ||||||
|  |         fetchExcp.hasException -> fetchExcp.value, | ||||||
|  |         rvcIll                 -> this.RvcII | ||||||
|  |       ) | ||||||
|  |     ) | ||||||
|  | 
 | ||||||
|  |   def isRVCII(uint: UInt): Bool = { | ||||||
|  |     this.checkInputWidth(uint) | ||||||
|  |     uint(2) && uint(1, 0) === 0.U | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   def isCrossPage(uint: UInt): Bool = { | ||||||
|  |     this.checkInputWidth(uint) | ||||||
|  |     uint(2) && uint(1, 0) =/= 0.U | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   def isPF(uint:  UInt): Bool = uint(1, 0) === this.NonCrossPF(1, 0) | ||||||
|  |   def isGPF(uint: UInt): Bool = uint(1, 0) === this.NonCrossGPF(1, 0) | ||||||
|  |   def isAF(uint:  UInt): Bool = uint(1, 0) === this.NonCrossAF(1, 0) | ||||||
|  | } | ||||||
|  | 
 | ||||||
| class IBufEntry(implicit p: Parameters) extends XSBundle { | class IBufEntry(implicit p: Parameters) extends XSBundle { | ||||||
|   val inst             = UInt(32.W) |   val inst             = UInt(32.W) | ||||||
|   val pc               = PrunedAddr(VAddrBits) |   val pc               = PrunedAddr(VAddrBits) | ||||||
|  | @ -109,48 +144,6 @@ class IBufEntry(implicit p: Parameters) extends XSBundle { | ||||||
|     cf.debug_seqNum                      := debug_seqNum |     cf.debug_seqNum                      := debug_seqNum | ||||||
|     cf |     cf | ||||||
|   } |   } | ||||||
| 
 |  | ||||||
|   object IBufferExceptionType extends NamedUInt(3) { |  | ||||||
|     def None        = "b000".U |  | ||||||
|     def NonCrossPF  = "b001".U |  | ||||||
|     def NonCrossGPF = "b010".U |  | ||||||
|     def NonCrossAF  = "b011".U |  | ||||||
|     // illegal instruction |  | ||||||
|     def rvcII    = "b100".U |  | ||||||
|     def CrossPF  = "b101".U |  | ||||||
|     def CrossGPF = "b110".U |  | ||||||
|     def CrossAF  = "b111".U |  | ||||||
| 
 |  | ||||||
|     def cvtFromFetchExcpAndCrossPageAndRVCII(fetchExcp: UInt, crossPage: Bool, rvcIll: Bool): UInt = { |  | ||||||
|       require( |  | ||||||
|         fetchExcp.getWidth == ExceptionType.width, |  | ||||||
|         s"The width(${fetchExcp.getWidth}) of fetchExcp should be equal to " + |  | ||||||
|           s"the width(${ExceptionType.width}) of frontend.ExceptionType." |  | ||||||
|       ) |  | ||||||
|       MuxCase( |  | ||||||
|         0.U, |  | ||||||
|         Seq( |  | ||||||
|           crossPage     -> Cat(1.U(1.W), fetchExcp), |  | ||||||
|           fetchExcp.orR -> fetchExcp, |  | ||||||
|           rvcIll        -> this.rvcII |  | ||||||
|         ) |  | ||||||
|       ) |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     def isRVCII(uint: UInt): Bool = { |  | ||||||
|       this.checkInputWidth(uint) |  | ||||||
|       uint(2) && uint(1, 0) === 0.U |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     def isCrossPage(uint: UInt): Bool = { |  | ||||||
|       this.checkInputWidth(uint) |  | ||||||
|       uint(2) && uint(1, 0) =/= 0.U |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     def isPF(uint:  UInt): Bool = uint(1, 0) === this.NonCrossPF(1, 0) |  | ||||||
|     def isGPF(uint: UInt): Bool = uint(1, 0) === this.NonCrossGPF(1, 0) |  | ||||||
|     def isAF(uint:  UInt): Bool = uint(1, 0) === this.NonCrossAF(1, 0) |  | ||||||
|   } |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| class IBuffer(implicit p: Parameters) extends XSModule with HasCircularQueuePtrHelper with HasPerfEvents { | class IBuffer(implicit p: Parameters) extends XSModule with HasCircularQueuePtrHelper with HasPerfEvents { | ||||||
|  |  | ||||||
|  | @ -159,13 +159,13 @@ class Ftq(implicit p: Parameters) extends FtqModule | ||||||
|   // raises IPF or IAF, which is ifuWbPtr_write or IfuPtr_write. |   // raises IPF or IAF, which is ifuWbPtr_write or IfuPtr_write. | ||||||
|   // Only when IFU has written back that FTQ entry can backendIpf and backendIaf be false because this |   // Only when IFU has written back that FTQ entry can backendIpf and backendIaf be false because this | ||||||
|   // makes sure that IAF and IPF are correctly raised instead of being flushed by redirect requests. |   // makes sure that IAF and IPF are correctly raised instead of being flushed by redirect requests. | ||||||
|   val backendException  = RegInit(ExceptionType.none) |   val backendException  = RegInit(ExceptionType.None) | ||||||
|   val backendPcFaultPtr = RegInit(FtqPtr(false.B, 0.U)) |   val backendPcFaultPtr = RegInit(FtqPtr(false.B, 0.U)) | ||||||
|   when(fromBackendRedirect.valid) { |   when(fromBackendRedirect.valid) { | ||||||
|     backendException := ExceptionType.fromOH( |     backendException := ExceptionType( | ||||||
|       has_pf = fromBackendRedirect.bits.cfiUpdate.backendIPF, |       hasPf = fromBackendRedirect.bits.cfiUpdate.backendIPF, | ||||||
|       has_gpf = fromBackendRedirect.bits.cfiUpdate.backendIGPF, |       hasGpf = fromBackendRedirect.bits.cfiUpdate.backendIGPF, | ||||||
|       has_af = fromBackendRedirect.bits.cfiUpdate.backendIAF |       hasAf = fromBackendRedirect.bits.cfiUpdate.backendIAF | ||||||
|     ) |     ) | ||||||
|     when( |     when( | ||||||
|       fromBackendRedirect.bits.cfiUpdate.backendIPF || fromBackendRedirect.bits.cfiUpdate.backendIGPF || |       fromBackendRedirect.bits.cfiUpdate.backendIPF || fromBackendRedirect.bits.cfiUpdate.backendIGPF || | ||||||
|  | @ -174,7 +174,7 @@ class Ftq(implicit p: Parameters) extends FtqModule | ||||||
|       backendPcFaultPtr := ifuWbPtr_write |       backendPcFaultPtr := ifuWbPtr_write | ||||||
|     } |     } | ||||||
|   }.elsewhen(ifuWbPtr =/= backendPcFaultPtr) { |   }.elsewhen(ifuWbPtr =/= backendPcFaultPtr) { | ||||||
|     backendException := ExceptionType.none |     backendException := ExceptionType.None | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   // ********************************************************************** |   // ********************************************************************** | ||||||
|  | @ -473,7 +473,7 @@ class Ftq(implicit p: Parameters) extends FtqModule | ||||||
|     copy.ftqIdx := ifuPtr |     copy.ftqIdx := ifuPtr | ||||||
|   } |   } | ||||||
|   io.toICache.fetchReq.bits.isBackendException := |   io.toICache.fetchReq.bits.isBackendException := | ||||||
|     ExceptionType.hasException(backendException) && backendPcFaultPtr === ifuPtr |     backendException.hasException && backendPcFaultPtr === ifuPtr | ||||||
| 
 | 
 | ||||||
|   io.toICache.prefetchReq.valid := toPrefetchEntryToSend && pfPtr =/= bpuPtr |   io.toICache.prefetchReq.valid := toPrefetchEntryToSend && pfPtr =/= bpuPtr | ||||||
|   io.toICache.prefetchReq.bits.req.fromFtqPcBundle(toPrefetchPcBundle) |   io.toICache.prefetchReq.bits.req.fromFtqPcBundle(toPrefetchPcBundle) | ||||||
|  | @ -481,7 +481,7 @@ class Ftq(implicit p: Parameters) extends FtqModule | ||||||
|   io.toICache.prefetchReq.bits.backendException := Mux( |   io.toICache.prefetchReq.bits.backendException := Mux( | ||||||
|     backendPcFaultPtr === pfPtr, |     backendPcFaultPtr === pfPtr, | ||||||
|     backendException, |     backendException, | ||||||
|     ExceptionType.none |     ExceptionType.None | ||||||
|   ) |   ) | ||||||
|   // io.toICache.fetchReq.bits.bypassSelect := last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtr |   // io.toICache.fetchReq.bits.bypassSelect := last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtr | ||||||
|   // io.toICache.fetchReq.bits.bpuBypassWrite.zipWithIndex.map{case(bypassWrtie, i) => |   // io.toICache.fetchReq.bits.bpuBypassWrite.zipWithIndex.map{case(bypassWrtie, i) => | ||||||
|  |  | ||||||
|  | @ -161,14 +161,14 @@ class ReplacerVictimBundle(implicit p: Parameters) extends ICacheBundle { | ||||||
| /* ***** MainPipe ***** */ | /* ***** MainPipe ***** */ | ||||||
| // ICache(MainPipe) -> IFU | // ICache(MainPipe) -> IFU | ||||||
| class ICacheRespBundle(implicit p: Parameters) extends ICacheBundle { | class ICacheRespBundle(implicit p: Parameters) extends ICacheBundle { | ||||||
|   val doubleline:         Bool            = Bool() |   val doubleline:         Bool               = Bool() | ||||||
|   val vAddr:              Vec[PrunedAddr] = Vec(PortNumber, PrunedAddr(VAddrBits)) |   val vAddr:              Vec[PrunedAddr]    = Vec(PortNumber, PrunedAddr(VAddrBits)) | ||||||
|   val data:               UInt            = UInt(blockBits.W) |   val data:               UInt               = UInt(blockBits.W) | ||||||
|   val pAddr:              Vec[PrunedAddr] = Vec(PortNumber, PrunedAddr(PAddrBits)) |   val pAddr:              Vec[PrunedAddr]    = Vec(PortNumber, PrunedAddr(PAddrBits)) | ||||||
|   val exception:          Vec[UInt]       = Vec(PortNumber, ExceptionType()) |   val exception:          Vec[ExceptionType] = Vec(PortNumber, new ExceptionType) | ||||||
|   val pmpMmio:            Vec[Bool]       = Vec(PortNumber, Bool()) |   val pmpMmio:            Vec[Bool]          = Vec(PortNumber, Bool()) | ||||||
|   val itlbPbmt:           Vec[UInt]       = Vec(PortNumber, UInt(Pbmt.width.W)) |   val itlbPbmt:           Vec[UInt]          = Vec(PortNumber, UInt(Pbmt.width.W)) | ||||||
|   val isBackendException: Bool            = Bool() |   val isBackendException: Bool               = Bool() | ||||||
|   /* NOTE: GPAddrBits(=50bit) is not enough for gpAddr here, refer to PR#3795 |   /* NOTE: GPAddrBits(=50bit) is not enough for gpAddr here, refer to PR#3795 | ||||||
|    * Sv48*4 only allows 50bit gpAddr, when software violates this requirement |    * Sv48*4 only allows 50bit gpAddr, when software violates this requirement | ||||||
|    * it needs to fill the mtval2 register with the full XLEN(=64bit) gpAddr, |    * it needs to fill the mtval2 register with the full XLEN(=64bit) gpAddr, | ||||||
|  | @ -181,11 +181,11 @@ class ICacheRespBundle(implicit p: Parameters) extends ICacheBundle { | ||||||
| 
 | 
 | ||||||
| /* ***** PrefetchPipe ***** */ | /* ***** PrefetchPipe ***** */ | ||||||
| class PrefetchReqBundle(implicit p: Parameters) extends ICacheBundle { | class PrefetchReqBundle(implicit p: Parameters) extends ICacheBundle { | ||||||
|   val startAddr:        PrunedAddr = PrunedAddr(VAddrBits) |   val startAddr:        PrunedAddr    = PrunedAddr(VAddrBits) | ||||||
|   val nextlineStart:    PrunedAddr = PrunedAddr(VAddrBits) |   val nextlineStart:    PrunedAddr    = PrunedAddr(VAddrBits) | ||||||
|   val ftqIdx:           FtqPtr     = new FtqPtr |   val ftqIdx:           FtqPtr        = new FtqPtr | ||||||
|   val isSoftPrefetch:   Bool       = Bool() |   val isSoftPrefetch:   Bool          = Bool() | ||||||
|   val backendException: UInt       = ExceptionType() |   val backendException: ExceptionType = new ExceptionType | ||||||
| 
 | 
 | ||||||
|   def crossCacheline: Bool = startAddr(blockOffBits - 1) === 1.U |   def crossCacheline: Bool = startAddr(blockOffBits - 1) === 1.U | ||||||
| 
 | 
 | ||||||
|  | @ -214,12 +214,12 @@ class PrefetchReqBundle(implicit p: Parameters) extends ICacheBundle { | ||||||
|  *      to save area, we separate those signals from WayLookupEntry and store only once. |  *      to save area, we separate those signals from WayLookupEntry and store only once. | ||||||
|  */ |  */ | ||||||
| class WayLookupEntry(implicit p: Parameters) extends ICacheBundle { | class WayLookupEntry(implicit p: Parameters) extends ICacheBundle { | ||||||
|   val vSetIdx:       Vec[UInt] = Vec(PortNumber, UInt(idxBits.W)) |   val vSetIdx:       Vec[UInt]          = Vec(PortNumber, UInt(idxBits.W)) | ||||||
|   val waymask:       Vec[UInt] = Vec(PortNumber, UInt(nWays.W)) |   val waymask:       Vec[UInt]          = Vec(PortNumber, UInt(nWays.W)) | ||||||
|   val pTag:          Vec[UInt] = Vec(PortNumber, UInt(tagBits.W)) |   val pTag:          Vec[UInt]          = Vec(PortNumber, UInt(tagBits.W)) | ||||||
|   val itlbException: Vec[UInt] = Vec(PortNumber, ExceptionType()) |   val itlbException: Vec[ExceptionType] = Vec(PortNumber, new ExceptionType) | ||||||
|   val itlbPbmt:      Vec[UInt] = Vec(PortNumber, UInt(Pbmt.width.W)) |   val itlbPbmt:      Vec[UInt]          = Vec(PortNumber, UInt(Pbmt.width.W)) | ||||||
|   val metaCodes:     Vec[UInt] = Vec(PortNumber, UInt(ICacheMetaCodeBits.W)) |   val metaCodes:     Vec[UInt]          = Vec(PortNumber, UInt(ICacheMetaCodeBits.W)) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| class WayLookupGpfEntry(implicit p: Parameters) extends ICacheBundle { | class WayLookupGpfEntry(implicit p: Parameters) extends ICacheBundle { | ||||||
|  | @ -233,14 +233,14 @@ class WayLookupBundle(implicit p: Parameters) extends ICacheBundle { | ||||||
|   val gpf   = new WayLookupGpfEntry |   val gpf   = new WayLookupGpfEntry | ||||||
| 
 | 
 | ||||||
|   // for compatibility |   // for compatibility | ||||||
|   def vSetIdx:           Vec[UInt]  = entry.vSetIdx |   def vSetIdx:           Vec[UInt]          = entry.vSetIdx | ||||||
|   def waymask:           Vec[UInt]  = entry.waymask |   def waymask:           Vec[UInt]          = entry.waymask | ||||||
|   def pTag:              Vec[UInt]  = entry.pTag |   def pTag:              Vec[UInt]          = entry.pTag | ||||||
|   def itlbException:     Vec[UInt]  = entry.itlbException |   def itlbException:     Vec[ExceptionType] = entry.itlbException | ||||||
|   def itlbPbmt:          Vec[UInt]  = entry.itlbPbmt |   def itlbPbmt:          Vec[UInt]          = entry.itlbPbmt | ||||||
|   def metaCodes:         Vec[UInt]  = entry.metaCodes |   def metaCodes:         Vec[UInt]          = entry.metaCodes | ||||||
|   def gpAddr:            PrunedAddr = gpf.gpAddr |   def gpAddr:            PrunedAddr         = gpf.gpAddr | ||||||
|   def isForVSnonLeafPTE: Bool       = gpf.isForVSnonLeafPTE |   def isForVSnonLeafPTE: Bool               = gpf.isForVSnonLeafPTE | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /* ***** Miss ***** */ | /* ***** Miss ***** */ | ||||||
|  |  | ||||||
|  | @ -27,7 +27,7 @@ import freechips.rocketchip.regmapper.RegReadFn | ||||||
| import freechips.rocketchip.regmapper.RegWriteFn | import freechips.rocketchip.regmapper.RegWriteFn | ||||||
| import freechips.rocketchip.tilelink.TLRegisterNode | import freechips.rocketchip.tilelink.TLRegisterNode | ||||||
| import org.chipsalliance.cde.config.Parameters | import org.chipsalliance.cde.config.Parameters | ||||||
| import utils.NamedUInt | import utils.EnumUInt | ||||||
| import xiangshan.frontend.PrunedAddrInit | import xiangshan.frontend.PrunedAddrInit | ||||||
| 
 | 
 | ||||||
| // currently for ECC control only | // currently for ECC control only | ||||||
|  | @ -61,7 +61,7 @@ class ICacheCtrlUnit(params: ICacheCtrlUnitParameters)(implicit p: Parameters) e | ||||||
| 
 | 
 | ||||||
|     // eccCtrl.ierror: inject error code |     // eccCtrl.ierror: inject error code | ||||||
|     private def nInjError: Int = 8 |     private def nInjError: Int = 8 | ||||||
|     private object EccCtrlInjError extends NamedUInt(log2Up(nInjError)) { |     private object EccCtrlInjError extends EnumUInt(nInjError) { | ||||||
|       def NotEnabled:    UInt = 0.U(width.W) // try to inject when ECC check is not enabled |       def NotEnabled:    UInt = 0.U(width.W) // try to inject when ECC check is not enabled | ||||||
|       def TargetInvalid: UInt = 1.U(width.W) // try to inject to invalid(rsvd) eccCtrl.itarget |       def TargetInvalid: UInt = 1.U(width.W) // try to inject to invalid(rsvd) eccCtrl.itarget | ||||||
|       def NotFound:      UInt = 2.U(width.W) // try to inject to eccIAddr.pAddr does not exist in ICache |       def NotFound:      UInt = 2.U(width.W) // try to inject to eccIAddr.pAddr does not exist in ICache | ||||||
|  | @ -78,7 +78,7 @@ class ICacheCtrlUnit(params: ICacheCtrlUnitParameters)(implicit p: Parameters) e | ||||||
|     } |     } | ||||||
|     // eccCtrl.istatus: inject status |     // eccCtrl.istatus: inject status | ||||||
|     private def nInjStatus: Int = 8 |     private def nInjStatus: Int = 8 | ||||||
|     private object EccCtrlInjStatus extends NamedUInt(log2Up(nInjStatus)) { |     private object EccCtrlInjStatus extends EnumUInt(nInjStatus) { | ||||||
|       def Idle:     UInt = 0.U(width.W) |       def Idle:     UInt = 0.U(width.W) | ||||||
|       def Working:  UInt = 1.U(width.W) |       def Working:  UInt = 1.U(width.W) | ||||||
|       def Injected: UInt = 2.U(width.W) |       def Injected: UInt = 2.U(width.W) | ||||||
|  | @ -94,7 +94,7 @@ class ICacheCtrlUnit(params: ICacheCtrlUnitParameters)(implicit p: Parameters) e | ||||||
|     } |     } | ||||||
|     // eccCtrl.itarget: inject target |     // eccCtrl.itarget: inject target | ||||||
|     private def nInjTarget: Int = 4 |     private def nInjTarget: Int = 4 | ||||||
|     private object EccCtrlInjTarget extends NamedUInt(log2Up(nInjTarget)) { |     private object EccCtrlInjTarget extends EnumUInt(nInjTarget) { | ||||||
|       def MetaArray: UInt = 0.U(width.W) |       def MetaArray: UInt = 0.U(width.W) | ||||||
|       def DataArray: UInt = 2.U(width.W) |       def DataArray: UInt = 2.U(width.W) | ||||||
|       @unused |       @unused | ||||||
|  | @ -151,7 +151,7 @@ class ICacheCtrlUnit(params: ICacheCtrlUnitParameters)(implicit p: Parameters) e | ||||||
| 
 | 
 | ||||||
|     // inject FSM |     // inject FSM | ||||||
|     private def nInjectFsmState: Int = 5 |     private def nInjectFsmState: Int = 5 | ||||||
|     private object InjectFsmState extends NamedUInt(log2Up(nInjectFsmState)) { |     private object InjectFsmState extends EnumUInt(nInjectFsmState) { | ||||||
|       // scala ask identifier that begins with uppercase cannot be used in pattern matching like `X :: Nil = Enum()` |       // scala ask identifier that begins with uppercase cannot be used in pattern matching like `X :: Nil = Enum()` | ||||||
|       // but we want UpperCamelCase for constants for better readability, so we dont use Enum() here |       // but we want UpperCamelCase for constants for better readability, so we dont use Enum() here | ||||||
|       def Idle:         UInt = 0.U(width.W) |       def Idle:         UInt = 0.U(width.W) | ||||||
|  |  | ||||||
|  | @ -224,14 +224,11 @@ class ICacheMainPipe(implicit p: Parameters) extends ICacheModule | ||||||
|     p.bits.size := 3.U |     p.bits.size := 3.U | ||||||
|     p.bits.cmd  := TlbCmd.exec |     p.bits.cmd  := TlbCmd.exec | ||||||
|   } |   } | ||||||
|   private val s1_pmpException = VecInit(fromPmp.map(ExceptionType.fromPMPResp)) |   private val s1_pmpException = VecInit(fromPmp.map(ExceptionType.fromPmpResp)) | ||||||
|   private val s1_pmpMmio      = VecInit(fromPmp.map(_.mmio)) |   private val s1_pmpMmio      = VecInit(fromPmp.map(_.mmio)) | ||||||
| 
 | 
 | ||||||
|   // merge s1 itlb/pmp exceptions, itlb has the highest priority, pmp next |   // merge s1 itlb/pmp exceptions, itlb has the highest priority, pmp next | ||||||
|   private val s1_exceptionOut = ExceptionType.merge( |   private val s1_exceptionOut = VecInit((s1_itlbException zip s1_pmpException).map { case (i, p) => i || p }) | ||||||
|     s1_itlbException, |  | ||||||
|     s1_pmpException |  | ||||||
|   ) |  | ||||||
| 
 | 
 | ||||||
|   /** |   /** | ||||||
|     ****************************************************************************** |     ****************************************************************************** | ||||||
|  | @ -418,7 +415,7 @@ class ICacheMainPipe(implicit p: Parameters) extends ICacheModule | ||||||
|   private val s2_shouldFetch = VecInit((0 until PortNumber).map { i => |   private val s2_shouldFetch = VecInit((0 until PortNumber).map { i => | ||||||
|     (!s2_hits(i) || s2_corruptRefetch(i)) && |     (!s2_hits(i) || s2_corruptRefetch(i)) && | ||||||
|     (if (i == 0) true.B else s2_doubleline) && |     (if (i == 0) true.B else s2_doubleline) && | ||||||
|     !ExceptionType.hasException(s2_exception.take(i + 1)) && |     s2_exception.take(i + 1).map(_.isNone).reduce(_ && _) && | ||||||
|     s2_isMmio.take(i + 1).map(!_).reduce(_ && _) |     s2_isMmio.take(i + 1).map(!_).reduce(_ && _) | ||||||
|   }) |   }) | ||||||
| 
 | 
 | ||||||
|  | @ -446,14 +443,11 @@ class ICacheMainPipe(implicit p: Parameters) extends ICacheModule | ||||||
|   private val s2_fetchFinish = !s2_shouldFetch.reduce(_ || _) |   private val s2_fetchFinish = !s2_shouldFetch.reduce(_ || _) | ||||||
| 
 | 
 | ||||||
|   // also raise af if l2 corrupt is detected |   // also raise af if l2 corrupt is detected | ||||||
|   private val s2_l2Exception = VecInit(s2_l2Corrupt.map(ExceptionType.fromTilelink)) |   private val s2_l2Exception = VecInit(s2_l2Corrupt.map(corrupt => ExceptionType(hasAf = corrupt))) | ||||||
|   // NOTE: do NOT raise af if meta/data corrupt is detected, they are automatically recovered by re-fetching from L2 |   // NOTE: do NOT raise af if meta/data corrupt is detected, they are automatically recovered by re-fetching from L2 | ||||||
| 
 | 
 | ||||||
|   // merge s2 exceptions, itlb has the highest priority, then l2 |   // merge s2 exceptions, itlb/pmp has the highest priority, then l2 | ||||||
|   private val s2_exceptionOut = ExceptionType.merge( |   private val s2_exceptionOut = VecInit((s2_exception zip s2_l2Exception).map { case (in, l2) => in || l2 }) | ||||||
|     s2_exception, // includes itlb/pmp exception |  | ||||||
|     s2_l2Exception |  | ||||||
|   ) |  | ||||||
| 
 | 
 | ||||||
|   /** |   /** | ||||||
|     ****************************************************************************** |     ****************************************************************************** | ||||||
|  | @ -468,7 +462,7 @@ class ICacheMainPipe(implicit p: Parameters) extends ICacheModule | ||||||
|   toIfu.bits.pAddr              := s2_pAddr |   toIfu.bits.pAddr              := s2_pAddr | ||||||
|   (0 until PortNumber).foreach { i => |   (0 until PortNumber).foreach { i => | ||||||
|     val needThisLine = if (i == 0) true.B else s2_doubleline |     val needThisLine = if (i == 0) true.B else s2_doubleline | ||||||
|     toIfu.bits.exception(i) := Mux(needThisLine, s2_exceptionOut(i), ExceptionType.none) |     toIfu.bits.exception(i) := Mux(needThisLine, s2_exceptionOut(i), ExceptionType.None) | ||||||
|     toIfu.bits.pmpMmio(i)   := Mux(needThisLine, s2_pmpMmio(i), false.B) |     toIfu.bits.pmpMmio(i)   := Mux(needThisLine, s2_pmpMmio(i), false.B) | ||||||
|     toIfu.bits.itlbPbmt(i)  := Mux(needThisLine, s2_itlbPbmt(i), Pbmt.pma) |     toIfu.bits.itlbPbmt(i)  := Mux(needThisLine, s2_itlbPbmt(i), Pbmt.pma) | ||||||
|   } |   } | ||||||
|  | @ -507,11 +501,11 @@ class ICacheMainPipe(implicit p: Parameters) extends ICacheModule | ||||||
|   io.perf.hit0Miss1    := s2_hits(0) && !s2_hits(1) && s2_doubleline |   io.perf.hit0Miss1    := s2_hits(0) && !s2_hits(1) && s2_doubleline | ||||||
|   io.perf.miss0Hit1    := !s2_hits(0) && s2_hits(1) && s2_doubleline |   io.perf.miss0Hit1    := !s2_hits(0) && s2_hits(1) && s2_doubleline | ||||||
|   io.perf.miss0Miss1   := !s2_hits(0) && !s2_hits(1) && s2_doubleline |   io.perf.miss0Miss1   := !s2_hits(0) && !s2_hits(1) && s2_doubleline | ||||||
|   io.perf.hit0Except1  := s2_hits(0) && ExceptionType.hasException(s2_exception(1)) && s2_doubleline |   io.perf.hit0Except1  := s2_hits(0) && s2_exception(1).hasException && s2_doubleline | ||||||
|   io.perf.miss0Except1 := !s2_hits(0) && ExceptionType.hasException(s2_exception(1)) && s2_doubleline |   io.perf.miss0Except1 := !s2_hits(0) && s2_exception(1).hasException && s2_doubleline | ||||||
|   io.perf.bankHit(0)   := s2_hits(0) |   io.perf.bankHit(0)   := s2_hits(0) | ||||||
|   io.perf.bankHit(1)   := s2_hits(1) && s2_doubleline |   io.perf.bankHit(1)   := s2_hits(1) && s2_doubleline | ||||||
|   io.perf.except0      := ExceptionType.hasException(s2_exception(0)) |   io.perf.except0      := s2_exception(0).hasException | ||||||
|   io.perf.hit          := s2_hits(0) && (!s2_doubleline || s2_hits(1)) |   io.perf.hit          := s2_hits(0) && (!s2_doubleline || s2_hits(1)) | ||||||
| 
 | 
 | ||||||
|   /** <PERF> fetch bubble generated by icache miss */ |   /** <PERF> fetch bubble generated by icache miss */ | ||||||
|  | @ -553,7 +547,7 @@ class ICacheMainPipe(implicit p: Parameters) extends ICacheModule | ||||||
|     */ |     */ | ||||||
|   if (env.EnableDifftest) { |   if (env.EnableDifftest) { | ||||||
|     val discards = (0 until PortNumber).map { i => |     val discards = (0 until PortNumber).map { i => | ||||||
|       ExceptionType.hasException(toIfu.bits.exception(i)) || |       toIfu.bits.exception(i).hasException || | ||||||
|       toIfu.bits.pmpMmio(i) || |       toIfu.bits.pmpMmio(i) || | ||||||
|       Pbmt.isUncache(toIfu.bits.itlbPbmt(i)) |       Pbmt.isUncache(toIfu.bits.itlbPbmt(i)) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -22,13 +22,12 @@ import utility.DataHoldBypass | ||||||
| import utility.PriorityMuxDefault | import utility.PriorityMuxDefault | ||||||
| import utility.ValidHold | import utility.ValidHold | ||||||
| import utility.XSPerfAccumulate | import utility.XSPerfAccumulate | ||||||
| import utils.NamedUInt | import utils.EnumUInt | ||||||
| import xiangshan.cache.mmu.Pbmt | import xiangshan.cache.mmu.Pbmt | ||||||
| import xiangshan.cache.mmu.TlbCmd | import xiangshan.cache.mmu.TlbCmd | ||||||
| import xiangshan.cache.mmu.TlbRequestIO | import xiangshan.cache.mmu.TlbRequestIO | ||||||
| import xiangshan.cache.mmu.ValidHoldBypass // FIXME: should move this to utility? | import xiangshan.cache.mmu.ValidHoldBypass // FIXME: should move this to utility? | ||||||
| import xiangshan.frontend.ExceptionType | import xiangshan.frontend.ExceptionType | ||||||
| import xiangshan.frontend.PrunedAddr |  | ||||||
| import xiangshan.frontend.PrunedAddrInit | import xiangshan.frontend.PrunedAddrInit | ||||||
| import xiangshan.frontend.ftq.BpuFlushInfo | import xiangshan.frontend.ftq.BpuFlushInfo | ||||||
| 
 | 
 | ||||||
|  | @ -117,7 +116,7 @@ class ICachePrefetchPipe(implicit p: Parameters) extends ICacheModule | ||||||
|   private val s1_backendException = RegEnable(s0_backendException, 0.U.asTypeOf(s0_backendException), s0_fire) |   private val s1_backendException = RegEnable(s0_backendException, 0.U.asTypeOf(s0_backendException), s0_fire) | ||||||
| 
 | 
 | ||||||
|   private def nS1FsmState: Int = 5 |   private def nS1FsmState: Int = 5 | ||||||
|   private object S1FsmState extends NamedUInt(log2Up(nS1FsmState)) { |   private object S1FsmState extends EnumUInt(nS1FsmState) { | ||||||
|     def Idle:       UInt = 0.U(width.W) |     def Idle:       UInt = 0.U(width.W) | ||||||
|     def ItlbResend: UInt = 1.U(width.W) |     def ItlbResend: UInt = 1.U(width.W) | ||||||
|     def MetaResend: UInt = 2.U(width.W) |     def MetaResend: UInt = 2.U(width.W) | ||||||
|  | @ -185,7 +184,7 @@ class ICachePrefetchPipe(implicit p: Parameters) extends ICacheModule | ||||||
|     Mux(tlbValidPulse(i), s1_pAddrWire(i), s1_pAddrReg(i)) |     Mux(tlbValidPulse(i), s1_pAddrWire(i), s1_pAddrReg(i)) | ||||||
|   }) |   }) | ||||||
|   private val s1_itlbExceptionRaw = VecInit((0 until PortNumber).map { i => |   private val s1_itlbExceptionRaw = VecInit((0 until PortNumber).map { i => | ||||||
|     DataHoldBypass(ExceptionType.fromTlbResp(fromItlb(i).bits), 0.U(ExceptionType.width.W), tlbValidPulse(i)) |     DataHoldBypass(ExceptionType.fromTlbResp(fromItlb(i).bits), ExceptionType.None, tlbValidPulse(i)) | ||||||
|   }) |   }) | ||||||
|   private val s1_itlbPbmt = VecInit((0 until PortNumber).map { i => |   private val s1_itlbPbmt = VecInit((0 until PortNumber).map { i => | ||||||
|     DataHoldBypass(fromItlb(i).bits.pbmt(0), 0.U.asTypeOf(fromItlb(i).bits.pbmt(0)), tlbValidPulse(i)) |     DataHoldBypass(fromItlb(i).bits.pbmt(0), 0.U.asTypeOf(fromItlb(i).bits.pbmt(0)), tlbValidPulse(i)) | ||||||
|  | @ -207,10 +206,7 @@ class ICachePrefetchPipe(implicit p: Parameters) extends ICacheModule | ||||||
|   // merge backend exception and itlb exception |   // merge backend exception and itlb exception | ||||||
|   // for area concern, we don't have 64 bits vaddr in frontend, but spec asks page fault when high bits are not all 0/1 |   // for area concern, we don't have 64 bits vaddr in frontend, but spec asks page fault when high bits are not all 0/1 | ||||||
|   // this check is finished in backend, and passed to frontend with redirect, we see it as a part of itlb exception |   // this check is finished in backend, and passed to frontend with redirect, we see it as a part of itlb exception | ||||||
|   private val s1_itlbException = ExceptionType.merge( |   private val s1_itlbException = VecInit((s1_backendException zip s1_itlbExceptionRaw).map { case (b, i) => b || i }) | ||||||
|     s1_backendException, |  | ||||||
|     s1_itlbExceptionRaw |  | ||||||
|   ) |  | ||||||
|   // debug |   // debug | ||||||
|   dontTouch(s1_itlbExceptionRaw) |   dontTouch(s1_itlbExceptionRaw) | ||||||
|   dontTouch(s1_itlbException) |   dontTouch(s1_itlbException) | ||||||
|  | @ -221,7 +217,7 @@ class ICachePrefetchPipe(implicit p: Parameters) extends ICacheModule | ||||||
|    *       see GPAMem: https://github.com/OpenXiangShan/XiangShan/blob/344cf5d55568dd40cd658a9ee66047a505eeb504/src/main/scala/xiangshan/backend/GPAMem.scala#L33-L34 |    *       see GPAMem: https://github.com/OpenXiangShan/XiangShan/blob/344cf5d55568dd40cd658a9ee66047a505eeb504/src/main/scala/xiangshan/backend/GPAMem.scala#L33-L34 | ||||||
|    *       see also: https://github.com/OpenXiangShan/XiangShan/blob/344cf5d55568dd40cd658a9ee66047a505eeb504/src/main/scala/xiangshan/frontend/IFU.scala#L374-L375 |    *       see also: https://github.com/OpenXiangShan/XiangShan/blob/344cf5d55568dd40cd658a9ee66047a505eeb504/src/main/scala/xiangshan/frontend/IFU.scala#L374-L375 | ||||||
|    */ |    */ | ||||||
|   private val s1_itlbExceptionIsGpf = VecInit(s1_itlbException.map(_ === ExceptionType.gpf)) |   private val s1_itlbExceptionIsGpf = VecInit(s1_itlbException.map(_.isGpf)) | ||||||
|   private val s1_gpAddr = PriorityMuxDefault( |   private val s1_gpAddr = PriorityMuxDefault( | ||||||
|     s1_itlbExceptionIsGpf zip (0 until PortNumber).map(i => s1_gpAddrRaw(i) - (i << blockOffBits).U), |     s1_itlbExceptionIsGpf zip (0 until PortNumber).map(i => s1_gpAddrRaw(i) - (i << blockOffBits).U), | ||||||
|     0.U.asTypeOf(s1_gpAddrRaw(0)) |     0.U.asTypeOf(s1_gpAddrRaw(0)) | ||||||
|  | @ -326,7 +322,7 @@ class ICachePrefetchPipe(implicit p: Parameters) extends ICacheModule | ||||||
|     toWayLookup.bits.itlbException(i) := Mux( |     toWayLookup.bits.itlbException(i) := Mux( | ||||||
|       excpValid, |       excpValid, | ||||||
|       s1_itlbException(i), // includes backend exception |       s1_itlbException(i), // includes backend exception | ||||||
|       ExceptionType.none |       ExceptionType.None | ||||||
|     ) |     ) | ||||||
|     toWayLookup.bits.itlbPbmt(i) := Mux(excpValid, s1_itlbPbmt(i), Pbmt.pma) |     toWayLookup.bits.itlbPbmt(i) := Mux(excpValid, s1_itlbPbmt(i), Pbmt.pma) | ||||||
|   } |   } | ||||||
|  | @ -359,15 +355,12 @@ class ICachePrefetchPipe(implicit p: Parameters) extends ICacheModule | ||||||
|     p.bits.size := 3.U |     p.bits.size := 3.U | ||||||
|     p.bits.cmd  := TlbCmd.exec |     p.bits.cmd  := TlbCmd.exec | ||||||
|   } |   } | ||||||
|   private val s1_pmpException = VecInit(fromPmp.map(ExceptionType.fromPMPResp)) |   private val s1_pmpException = VecInit(fromPmp.map(ExceptionType.fromPmpResp)) | ||||||
|   private val s1_pmpMmio      = VecInit(fromPmp.map(_.mmio)) |   private val s1_pmpMmio      = VecInit(fromPmp.map(_.mmio)) | ||||||
| 
 | 
 | ||||||
|   // merge s1 itlb/pmp exceptions, itlb has the highest priority, pmp next |   // merge s1 itlb/pmp exceptions, itlb has the highest priority, pmp next | ||||||
|   // for timing consideration, meta_corrupt is not merged, and it will NOT cancel prefetch |   // here, itlb exception includes backend exception | ||||||
|   private val s1_exceptionOut = ExceptionType.merge( |   private val s1_exceptionOut = VecInit((s1_itlbException zip s1_pmpException).map { case (i, p) => i || p }) | ||||||
|     s1_itlbException, // includes backend exception |  | ||||||
|     s1_pmpException |  | ||||||
|   ) |  | ||||||
| 
 | 
 | ||||||
|   // merge pmp mmio and itlb pbmt |   // merge pmp mmio and itlb pbmt | ||||||
|   private val s1_isMmio = VecInit((s1_pmpMmio zip s1_itlbPbmt).map { case (mmio, pbmt) => |   private val s1_isMmio = VecInit((s1_pmpMmio zip s1_itlbPbmt).map { case (mmio, pbmt) => | ||||||
|  | @ -503,7 +496,7 @@ class ICachePrefetchPipe(implicit p: Parameters) extends ICacheModule | ||||||
|    */ |    */ | ||||||
|   private val s2_miss = VecInit((0 until PortNumber).map { i => |   private val s2_miss = VecInit((0 until PortNumber).map { i => | ||||||
|     !s2_hits(i) && (if (i == 0) true.B else s2_doubleline) && |     !s2_hits(i) && (if (i == 0) true.B else s2_doubleline) && | ||||||
|     !ExceptionType.hasException(s2_exception.take(i + 1)) && |     s2_exception.take(i + 1).map(_.isNone).reduce(_ && _) && | ||||||
|     s2_isMmio.take(i + 1).map(!_).reduce(_ && _) |     s2_isMmio.take(i + 1).map(!_).reduce(_ && _) | ||||||
|   }) |   }) | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -123,7 +123,7 @@ class ICacheWayLookup(implicit p: Parameters) extends ICacheModule with ICacheMi | ||||||
|   io.write.ready := !full && !gpfStall |   io.write.ready := !full && !gpfStall | ||||||
|   when(io.write.fire) { |   when(io.write.fire) { | ||||||
|     entries(writePtr.value) := io.write.bits.entry |     entries(writePtr.value) := io.write.bits.entry | ||||||
|     when(io.write.bits.itlbException.map(_ === ExceptionType.gpf).reduce(_ || _)) { |     when(io.write.bits.itlbException.map(_.isGpf).reduce(_ || _)) { | ||||||
|       // if gpfEntry is bypassed, we don't need to save it |       // if gpfEntry is bypassed, we don't need to save it | ||||||
|       // note this will override the read (L156) |       // note this will override the read (L156) | ||||||
|       gpfEntry.valid := !(canBypass && io.read.fire) |       gpfEntry.valid := !(canBypass && io.read.fire) | ||||||
|  |  | ||||||
|  | @ -18,7 +18,7 @@ package xiangshan.frontend.ifu | ||||||
| import chisel3._ | import chisel3._ | ||||||
| import chisel3.util._ | import chisel3.util._ | ||||||
| import org.chipsalliance.cde.config.Parameters | import org.chipsalliance.cde.config.Parameters | ||||||
| import utils.NamedUInt | import utils.EnumUInt | ||||||
| import xiangshan.frontend.PrunedAddr | import xiangshan.frontend.PrunedAddr | ||||||
| 
 | 
 | ||||||
| /* *** | /* *** | ||||||
|  | @ -32,14 +32,14 @@ import xiangshan.frontend.PrunedAddr | ||||||
|  * *** */ |  * *** */ | ||||||
| 
 | 
 | ||||||
| /* ***** PreDecode ***** */ | /* ***** PreDecode ***** */ | ||||||
| object PreDecodeFaultType extends NamedUInt(3) { | object PreDecodeFaultType extends EnumUInt(7) { | ||||||
|   def noFault:      UInt = "b000".U(width.W) |   def NoFault:      UInt = 0.U(width.W) | ||||||
|   def jalFault:     UInt = "b001".U(width.W) // not CFI taken or invalid instruction taken |   def JalFault:     UInt = 1.U(width.W) // not CFI taken or invalid instruction taken | ||||||
|   def retFault:     UInt = "b010".U(width.W) // not CFI taken or invalid instruction taken |   def RetFault:     UInt = 2.U(width.W) // not CFI taken or invalid instruction taken | ||||||
|   def targetFault:  UInt = "b011".U(width.W) |   def TargetFault:  UInt = 3.U(width.W) | ||||||
|   def notCfiFault:  UInt = "b100".U(width.W) // not CFI taken or invalid instruction taken |   def NotCfiFault:  UInt = 4.U(width.W) // not CFI taken or invalid instruction taken | ||||||
|   def invalidTaken: UInt = "b101".U(width.W) |   def InvalidTaken: UInt = 5.U(width.W) | ||||||
|   def jalrFault:    UInt = "b110".U(width.W) |   def JalrFault:    UInt = 6.U(width.W) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /* ***** Ifu last half ***** */ | /* ***** Ifu last half ***** */ | ||||||
|  |  | ||||||
|  | @ -31,14 +31,14 @@ trait PreDecodeHelper extends HasXSParameter { | ||||||
|   def isLink(reg: UInt): Bool = reg === 1.U || reg === 5.U |   def isLink(reg: UInt): Bool = reg === 1.U || reg === 5.U | ||||||
| 
 | 
 | ||||||
|   def getBrType(inst: UInt): UInt = |   def getBrType(inst: UInt): UInt = | ||||||
|     ListLookup(inst, List(BrType.notCFI), PreDecodeInst.brTable).head |     ListLookup(inst, List(BrType.NotCfi), PreDecodeInst.brTable).head | ||||||
| 
 | 
 | ||||||
|   def getBrInfo(inst: UInt): (UInt, Bool, Bool) = { |   def getBrInfo(inst: UInt): (UInt, Bool, Bool) = { | ||||||
|     val brType = getBrType(inst) |     val brType = getBrType(inst) | ||||||
|     val rd     = Mux(isRVC(inst), inst(12), inst(11, 7)) |     val rd     = Mux(isRVC(inst), inst(12), inst(11, 7)) | ||||||
|     val rs     = Mux(isRVC(inst), Mux(brType === BrType.jal, 0.U, inst(11, 7)), inst(19, 15)) |     val rs     = Mux(isRVC(inst), Mux(brType === BrType.Jal, 0.U, inst(11, 7)), inst(19, 15)) | ||||||
|     val isCall = (brType === BrType.jal && !isRVC(inst) || brType === BrType.jalr) && isLink(rd) // Only for RV64 |     val isCall = (brType === BrType.Jal && !isRVC(inst) || brType === BrType.Jalr) && isLink(rd) // Only for RV64 | ||||||
|     val isRet  = brType === BrType.jalr && isLink(rs) && !isCall |     val isRet  = brType === BrType.Jalr && isLink(rs) && !isCall | ||||||
|     (brType, isCall, isRet) |     (brType, isCall, isRet) | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -32,7 +32,7 @@ import utility.XSDebug | ||||||
| import utility.XSError | import utility.XSError | ||||||
| import utility.XSPerfAccumulate | import utility.XSPerfAccumulate | ||||||
| import utility.XSPerfHistogram | import utility.XSPerfHistogram | ||||||
| import utils.NamedUInt | import utils.EnumUInt | ||||||
| import xiangshan.FrontendTdataDistributeIO | import xiangshan.FrontendTdataDistributeIO | ||||||
| import xiangshan.RedirectLevel | import xiangshan.RedirectLevel | ||||||
| import xiangshan.RobCommitInfo | import xiangshan.RobCommitInfo | ||||||
|  | @ -331,21 +331,19 @@ class Ifu(implicit p: Parameters) extends IfuModule | ||||||
| 
 | 
 | ||||||
|   // FIXME: raise af if one fetch block crosses the cacheable/un-cacheable boundary, might not correct |   // FIXME: raise af if one fetch block crosses the cacheable/un-cacheable boundary, might not correct | ||||||
|   private val s2_mmioMismatchException = VecInit(Seq( |   private val s2_mmioMismatchException = VecInit(Seq( | ||||||
|     ExceptionType.none, // mark the exception only on the second line |     ExceptionType.None, // mark the exception only on the second line | ||||||
|     Mux( |     ExceptionType(hasAf = | ||||||
|       // not double-line, skip check |       // if not double-line, skip check | ||||||
|       !fromICache.bits.doubleline || ( |       fromICache.bits.doubleline && ( | ||||||
|         // is double-line, ask for consistent pmp_mmio and itlb_pbmt value |         // is double-line, ask for consistent pmp_mmio and itlb_pbmt value | ||||||
|         fromICache.bits.pmpMmio(0) === fromICache.bits.pmpMmio(1) && |         fromICache.bits.pmpMmio(0) =/= fromICache.bits.pmpMmio(1) || | ||||||
|           fromICache.bits.itlbPbmt(0) === fromICache.bits.itlbPbmt(1) |           fromICache.bits.itlbPbmt(0) =/= fromICache.bits.itlbPbmt(1) | ||||||
|       ), |       ) | ||||||
|       ExceptionType.none, |  | ||||||
|       ExceptionType.af |  | ||||||
|     ) |     ) | ||||||
|   )) |   )) | ||||||
| 
 | 
 | ||||||
|   // merge exceptions |   // merge exceptions | ||||||
|   private val s2_exception = ExceptionType.merge(s2_exceptionIn, s2_mmioMismatchException) |   private val s2_exception = VecInit((s2_exceptionIn zip s2_mmioMismatchException).map { case (in, m) => in || m }) | ||||||
| 
 | 
 | ||||||
|   // we need only the first port, as the second is asked to be the same |   // we need only the first port, as the second is asked to be the same | ||||||
|   private val s2_pmpMmio  = fromICache.bits.pmpMmio(0) |   private val s2_pmpMmio  = fromICache.bits.pmpMmio(0) | ||||||
|  | @ -379,7 +377,7 @@ class Ifu(implicit p: Parameters) extends IfuModule | ||||||
|   private val s2_instrRange = s2_jumpRange & s2_ftrRange |   private val s2_instrRange = s2_jumpRange & s2_ftrRange | ||||||
|   private val s2_exceptionVec = VecInit((0 until PredictWidth).map(i => |   private val s2_exceptionVec = VecInit((0 until PredictWidth).map(i => | ||||||
|     MuxCase( |     MuxCase( | ||||||
|       ExceptionType.none, |       ExceptionType.None, | ||||||
|       Seq( |       Seq( | ||||||
|         !isNextLine(s2_pc(i), s2_ftqReq.startAddr)                   -> s2_exception(0), |         !isNextLine(s2_pc(i), s2_ftqReq.startAddr)                   -> s2_exception(0), | ||||||
|         (isNextLine(s2_pc(i), s2_ftqReq.startAddr) && s2_doubleline) -> s2_exception(1) |         (isNextLine(s2_pc(i), s2_ftqReq.startAddr) && s2_doubleline) -> s2_exception(1) | ||||||
|  | @ -454,9 +452,9 @@ class Ifu(implicit p: Parameters) extends IfuModule | ||||||
|    */ |    */ | ||||||
|   private val s2_crossPageExceptionVec = VecInit((0 until PredictWidth).map { i => |   private val s2_crossPageExceptionVec = VecInit((0 until PredictWidth).map { i => | ||||||
|     Mux( |     Mux( | ||||||
|       isLastInLine(s2_pc(i)) && !s2_pd(i).isRVC && s2_doubleline && !ExceptionType.hasException(s2_exception(0)), |       isLastInLine(s2_pc(i)) && !s2_pd(i).isRVC && s2_doubleline && s2_exception(0).isNone, | ||||||
|       s2_exception(1), |       s2_exception(1), | ||||||
|       ExceptionType.none |       ExceptionType.None | ||||||
|     ) |     ) | ||||||
|   }) |   }) | ||||||
|   XSPerfAccumulate("fetch_bubble_icache_not_resp", s2_valid && !icacheRespAllValid) |   XSPerfAccumulate("fetch_bubble_icache_not_resp", s2_valid && !icacheRespAllValid) | ||||||
|  | @ -563,7 +561,7 @@ class Ifu(implicit p: Parameters) extends IfuModule | ||||||
| 
 | 
 | ||||||
|   /* *** mmio *** */ |   /* *** mmio *** */ | ||||||
|   private def nMmioFsmState = 11 |   private def nMmioFsmState = 11 | ||||||
|   private object MmioFsmState extends NamedUInt(log2Up(nMmioFsmState)) { |   private object MmioFsmState extends EnumUInt(nMmioFsmState) { | ||||||
|     def Idle:           UInt = 0.U(width.W) |     def Idle:           UInt = 0.U(width.W) | ||||||
|     def WaitLastCommit: UInt = 1.U(width.W) |     def WaitLastCommit: UInt = 1.U(width.W) | ||||||
|     def SendReq:        UInt = 2.U(width.W) |     def SendReq:        UInt = 2.U(width.W) | ||||||
|  | @ -580,7 +578,7 @@ class Ifu(implicit p: Parameters) extends IfuModule | ||||||
|   private val mmioState = RegInit(MmioFsmState.Idle) |   private val mmioState = RegInit(MmioFsmState.Idle) | ||||||
| 
 | 
 | ||||||
|   private val mmioData       = RegInit(VecInit(Seq.fill(2)(0.U(16.W)))) |   private val mmioData       = RegInit(VecInit(Seq.fill(2)(0.U(16.W)))) | ||||||
|   private val mmioException  = RegInit(0.U(ExceptionType.width.W)) |   private val mmioException  = RegInit(ExceptionType.None) | ||||||
|   private val mmioIsRvc      = RegInit(false.B) |   private val mmioIsRvc      = RegInit(false.B) | ||||||
|   private val mmioHasResend  = RegInit(false.B) |   private val mmioHasResend  = RegInit(false.B) | ||||||
|   private val mmioResendAddr = RegInit(PrunedAddrInit(0.U(PAddrBits.W))) |   private val mmioResendAddr = RegInit(PrunedAddrInit(0.U(PAddrBits.W))) | ||||||
|  | @ -591,7 +589,7 @@ class Ifu(implicit p: Parameters) extends IfuModule | ||||||
|   private def mmioReset(): Unit = { |   private def mmioReset(): Unit = { | ||||||
|     mmioState := MmioFsmState.Idle |     mmioState := MmioFsmState.Idle | ||||||
|     mmioData.foreach(_ := 0.U) |     mmioData.foreach(_ := 0.U) | ||||||
|     mmioException               := ExceptionType.none |     mmioException               := ExceptionType.None | ||||||
|     mmioIsRvc                   := false.B |     mmioIsRvc                   := false.B | ||||||
|     mmioHasResend               := false.B |     mmioHasResend               := false.B | ||||||
|     mmioResendAddr              := PrunedAddrInit(0.U(PAddrBits.W)) |     mmioResendAddr              := PrunedAddrInit(0.U(PAddrBits.W)) | ||||||
|  | @ -607,7 +605,7 @@ class Ifu(implicit p: Parameters) extends IfuModule | ||||||
| 
 | 
 | ||||||
|   // do mmio fetch only when pmp/pbmt shows it is a un-cacheable address and no exception occurs |   // do mmio fetch only when pmp/pbmt shows it is a un-cacheable address and no exception occurs | ||||||
|   private val s3_reqIsMmio = |   private val s3_reqIsMmio = | ||||||
|     s3_valid && (s3_pmpMmio || Pbmt.isUncache(s3_itlbPbmt)) && !ExceptionType.hasException(s3_exception) |     s3_valid && (s3_pmpMmio || Pbmt.isUncache(s3_itlbPbmt)) && s3_exception.map(_.isNone).reduce(_ && _) | ||||||
|   private val mmioCommit = VecInit(io.robCommits.map { commit => |   private val mmioCommit = VecInit(io.robCommits.map { commit => | ||||||
|     commit.valid && commit.bits.ftqIdx === s3_ftqReq.ftqIdx && commit.bits.ftqOffset === 0.U |     commit.valid && commit.bits.ftqIdx === s3_ftqReq.ftqIdx && commit.bits.ftqOffset === 0.U | ||||||
|   }).asUInt.orR |   }).asUInt.orR | ||||||
|  | @ -682,9 +680,9 @@ class Ifu(implicit p: Parameters) extends IfuModule | ||||||
|     is(MmioFsmState.WaitResp) { |     is(MmioFsmState.WaitResp) { | ||||||
|       when(fromUncache.fire) { |       when(fromUncache.fire) { | ||||||
|         val respIsRVC = isRVC(fromUncache.bits.data(1, 0)) |         val respIsRVC = isRVC(fromUncache.bits.data(1, 0)) | ||||||
|         val exception = ExceptionType.fromTilelink(fromUncache.bits.corrupt) |         val exception = ExceptionType(hasAf = fromUncache.bits.corrupt) | ||||||
|         // when response is not RVC, and lower bits of pAddr is 6 => request crosses 8B boundary, need resend |         // when response is not RVC, and lower bits of pAddr is 6 => request crosses 8B boundary, need resend | ||||||
|         val needResend = !respIsRVC && s3_pAddr(0)(2, 1) === 3.U && !ExceptionType.hasException(exception) |         val needResend = !respIsRVC && s3_pAddr(0)(2, 1) === 3.U && exception.isNone | ||||||
|         mmioState     := Mux(needResend, MmioFsmState.SendTlb, MmioFsmState.WaitCommit) |         mmioState     := Mux(needResend, MmioFsmState.SendTlb, MmioFsmState.WaitCommit) | ||||||
|         mmioException := exception |         mmioException := exception | ||||||
|         mmioIsRvc     := respIsRVC |         mmioIsRvc     := respIsRVC | ||||||
|  | @ -702,16 +700,13 @@ class Ifu(implicit p: Parameters) extends IfuModule | ||||||
|       when(io.itlb.resp.fire) { |       when(io.itlb.resp.fire) { | ||||||
|         // we are using a blocked tlb, so resp.fire must have !resp.bits.miss |         // we are using a blocked tlb, so resp.fire must have !resp.bits.miss | ||||||
|         assert(!io.itlb.resp.bits.miss, "blocked mode iTLB miss when resp.fire") |         assert(!io.itlb.resp.bits.miss, "blocked mode iTLB miss when resp.fire") | ||||||
|         val tlbException = ExceptionType.fromTlbResp(io.itlb.resp.bits) |         val itlbException = ExceptionType.fromTlbResp(io.itlb.resp.bits) | ||||||
|         // if itlb re-check respond pbmt mismatch with previous check, must be access fault |         // if itlb re-check respond pbmt mismatch with previous check, must be access fault | ||||||
|         val pbmtMismatchException = Mux( |         val pbmtMismatchException = ExceptionType(hasAf = io.itlb.resp.bits.pbmt(0) =/= s3_itlbPbmt) | ||||||
|           io.itlb.resp.bits.pbmt(0) =/= s3_itlbPbmt, |         // merge, itlbException has higher priority | ||||||
|           ExceptionType.af, |         val exception = itlbException || pbmtMismatchException | ||||||
|           ExceptionType.none |  | ||||||
|         ) |  | ||||||
|         val exception = ExceptionType.merge(tlbException, pbmtMismatchException) |  | ||||||
|         // if tlb has exception, abort checking pmp, just send instr & exception to iBuffer and wait for commit |         // if tlb has exception, abort checking pmp, just send instr & exception to iBuffer and wait for commit | ||||||
|         mmioState := Mux(ExceptionType.hasException(exception), MmioFsmState.WaitCommit, MmioFsmState.SendPmp) |         mmioState := Mux(exception.hasException, MmioFsmState.WaitCommit, MmioFsmState.SendPmp) | ||||||
|         // also save itlb response |         // also save itlb response | ||||||
|         mmioException               := exception |         mmioException               := exception | ||||||
|         mmioResendAddr              := io.itlb.resp.bits.paddr(0) |         mmioResendAddr              := io.itlb.resp.bits.paddr(0) | ||||||
|  | @ -721,16 +716,13 @@ class Ifu(implicit p: Parameters) extends IfuModule | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     is(MmioFsmState.SendPmp) { |     is(MmioFsmState.SendPmp) { | ||||||
|       val pmpException = ExceptionType.fromPMPResp(io.pmp.resp) |       val pmpException = ExceptionType.fromPmpResp(io.pmp.resp) | ||||||
|       // if pmp re-check respond mismatch with previous check, must be access fault |       // if pmp re-check respond mismatch with previous check, must be access fault | ||||||
|       val mmioMismatchException = Mux( |       val mmioMismatchException = ExceptionType(hasAf = io.pmp.resp.mmio =/= s3_pmpMmio) | ||||||
|         io.pmp.resp.mmio =/= s3_pmpMmio, |       // merge, pmpException has higher priority | ||||||
|         ExceptionType.af, |       val exception = pmpException || mmioMismatchException | ||||||
|         ExceptionType.none |  | ||||||
|       ) |  | ||||||
|       val exception = ExceptionType.merge(pmpException, mmioMismatchException) |  | ||||||
|       // if pmp has exception, abort sending request, just send instr & exception to iBuffer and wait for commit |       // if pmp has exception, abort sending request, just send instr & exception to iBuffer and wait for commit | ||||||
|       mmioState := Mux(ExceptionType.hasException(exception), MmioFsmState.WaitCommit, MmioFsmState.ResendReq) |       mmioState := Mux(exception.hasException, MmioFsmState.WaitCommit, MmioFsmState.ResendReq) | ||||||
|       // also save pmp response |       // also save pmp response | ||||||
|       mmioException := exception |       mmioException := exception | ||||||
|     } |     } | ||||||
|  | @ -742,7 +734,7 @@ class Ifu(implicit p: Parameters) extends IfuModule | ||||||
|     is(MmioFsmState.WaitResendResp) { |     is(MmioFsmState.WaitResendResp) { | ||||||
|       when(fromUncache.fire) { |       when(fromUncache.fire) { | ||||||
|         mmioState     := MmioFsmState.WaitCommit |         mmioState     := MmioFsmState.WaitCommit | ||||||
|         mmioException := ExceptionType.fromTilelink(fromUncache.bits.corrupt) |         mmioException := ExceptionType(hasAf = fromUncache.bits.corrupt) | ||||||
|         mmioData(1)   := fromUncache.bits.data(15, 0) |         mmioData(1)   := fromUncache.bits.data(15, 0) | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|  | @ -860,8 +852,10 @@ class Ifu(implicit p: Parameters) extends IfuModule | ||||||
|     a.bits  := i.U |     a.bits  := i.U | ||||||
|     a.valid := checkerOutStage1.fixedTaken(i) && !s3_reqIsMmio |     a.valid := checkerOutStage1.fixedTaken(i) && !s3_reqIsMmio | ||||||
|   } |   } | ||||||
|   io.toIBuffer.bits.foldpc        := s3_foldPc |   io.toIBuffer.bits.foldpc := s3_foldPc | ||||||
|   io.toIBuffer.bits.exceptionType := ExceptionType.merge(s3_exceptionVec, s3_crossPageExceptionVec) |   io.toIBuffer.bits.exceptionType := VecInit((s3_exceptionVec zip s3_crossPageExceptionVec).map { case (e, ce) => | ||||||
|  |     e || ce // merge, cross page fix has lower priority | ||||||
|  |   }) | ||||||
|   // backendException only needs to be set for the first instruction. |   // backendException only needs to be set for the first instruction. | ||||||
|   // Other instructions in the same block may have pf or af set, |   // Other instructions in the same block may have pf or af set, | ||||||
|   // which is a side effect of the first instruction and actually not necessary. |   // which is a side effect of the first instruction and actually not necessary. | ||||||
|  | @ -869,7 +863,7 @@ class Ifu(implicit p: Parameters) extends IfuModule | ||||||
|     case 0 => s3_isBackendException |     case 0 => s3_isBackendException | ||||||
|     case _ => false.B |     case _ => false.B | ||||||
|   } |   } | ||||||
|   io.toIBuffer.bits.crossPageIPFFix := s3_crossPageExceptionVec.map(ExceptionType.hasException) |   io.toIBuffer.bits.crossPageIPFFix := s3_crossPageExceptionVec.map(_.hasException) | ||||||
|   io.toIBuffer.bits.illegalInstr    := s3_ill |   io.toIBuffer.bits.illegalInstr    := s3_ill | ||||||
|   io.toIBuffer.bits.triggered       := s3_triggered |   io.toIBuffer.bits.triggered       := s3_triggered | ||||||
| 
 | 
 | ||||||
|  | @ -899,8 +893,8 @@ class Ifu(implicit p: Parameters) extends IfuModule | ||||||
|   // s3_gpAddr is valid iff gpf is detected |   // s3_gpAddr is valid iff gpf is detected | ||||||
|   io.toBackend.gpaddrMem_wen := s3_toIBufferValid && Mux( |   io.toBackend.gpaddrMem_wen := s3_toIBufferValid && Mux( | ||||||
|     s3_reqIsMmio, |     s3_reqIsMmio, | ||||||
|     mmioException === ExceptionType.gpf, |     mmioException.isGpf, | ||||||
|     s3_exception.map(_ === ExceptionType.gpf).reduce(_ || _) |     s3_exception.map(_.isGpf).reduce(_ || _) | ||||||
|   ) |   ) | ||||||
|   io.toBackend.gpaddrMem_waddr        := s3_ftqReq.ftqIdx.value |   io.toBackend.gpaddrMem_waddr        := s3_ftqReq.ftqIdx.value | ||||||
|   io.toBackend.gpaddrMem_wdata.gpaddr := Mux(s3_reqIsMmio, mmioResendGpAddr.toUInt, s3_gpAddr.toUInt) |   io.toBackend.gpaddrMem_wdata.gpaddr := Mux(s3_reqIsMmio, mmioResendGpAddr.toUInt, s3_gpAddr.toUInt) | ||||||
|  | @ -951,7 +945,7 @@ class Ifu(implicit p: Parameters) extends IfuModule | ||||||
| 
 | 
 | ||||||
|     io.toIBuffer.bits.exceptionType(0) := mmioException |     io.toIBuffer.bits.exceptionType(0) := mmioException | ||||||
|     // exception can happen in next page only when resend |     // exception can happen in next page only when resend | ||||||
|     io.toIBuffer.bits.crossPageIPFFix(0) := mmioHasResend && ExceptionType.hasException(mmioException) |     io.toIBuffer.bits.crossPageIPFFix(0) := mmioHasResend && mmioException.hasException | ||||||
|     io.toIBuffer.bits.illegalInstr(0)    := mmioRvcExpander.io.ill |     io.toIBuffer.bits.illegalInstr(0)    := mmioRvcExpander.io.ill | ||||||
| 
 | 
 | ||||||
|     io.toIBuffer.bits.enqEnable := s3_mmioRange.asUInt |     io.toIBuffer.bits.enqEnable := s3_mmioRange.asUInt | ||||||
|  | @ -1053,12 +1047,12 @@ class Ifu(implicit p: Parameters) extends IfuModule | ||||||
| 
 | 
 | ||||||
|   /* write back flush type */ |   /* write back flush type */ | ||||||
|   private val checkFaultType    = wbCheckResultStage2.faultType |   private val checkFaultType    = wbCheckResultStage2.faultType | ||||||
|   private val checkJalFault     = wbValid && checkFaultType.map(_ === PreDecodeFaultType.jalFault).reduce(_ || _) |   private val checkJalFault     = wbValid && checkFaultType.map(_ === PreDecodeFaultType.JalFault).reduce(_ || _) | ||||||
|   private val checkJalrFault    = wbValid && checkFaultType.map(_ === PreDecodeFaultType.jalrFault).reduce(_ || _) |   private val checkJalrFault    = wbValid && checkFaultType.map(_ === PreDecodeFaultType.JalrFault).reduce(_ || _) | ||||||
|   private val checkRetFault     = wbValid && checkFaultType.map(_ === PreDecodeFaultType.retFault).reduce(_ || _) |   private val checkRetFault     = wbValid && checkFaultType.map(_ === PreDecodeFaultType.RetFault).reduce(_ || _) | ||||||
|   private val checkTargetFault  = wbValid && checkFaultType.map(_ === PreDecodeFaultType.targetFault).reduce(_ || _) |   private val checkTargetFault  = wbValid && checkFaultType.map(_ === PreDecodeFaultType.TargetFault).reduce(_ || _) | ||||||
|   private val checkNotCFIFault  = wbValid && checkFaultType.map(_ === PreDecodeFaultType.notCfiFault).reduce(_ || _) |   private val checkNotCFIFault  = wbValid && checkFaultType.map(_ === PreDecodeFaultType.NotCfiFault).reduce(_ || _) | ||||||
|   private val checkInvalidTaken = wbValid && checkFaultType.map(_ === PreDecodeFaultType.invalidTaken).reduce(_ || _) |   private val checkInvalidTaken = wbValid && checkFaultType.map(_ === PreDecodeFaultType.InvalidTaken).reduce(_ || _) | ||||||
| 
 | 
 | ||||||
|   XSPerfAccumulate("predecode_flush_jalFault", checkJalFault) |   XSPerfAccumulate("predecode_flush_jalFault", checkJalFault) | ||||||
|   XSPerfAccumulate("predecode_flush_jalrFault", checkJalrFault) |   XSPerfAccumulate("predecode_flush_jalrFault", checkJalrFault) | ||||||
|  |  | ||||||
|  | @ -139,14 +139,14 @@ class PredChecker(implicit p: Parameters) extends IfuModule { | ||||||
| 
 | 
 | ||||||
|   io.resp.stage2Out.faultType.zipWithIndex.foreach { case (faultType, i) => |   io.resp.stage2Out.faultType.zipWithIndex.foreach { case (faultType, i) => | ||||||
|     faultType := MuxCase( |     faultType := MuxCase( | ||||||
|       PreDecodeFaultType.noFault, |       PreDecodeFaultType.NoFault, | ||||||
|       Seq( |       Seq( | ||||||
|         jalFaultVecNext(i)  -> PreDecodeFaultType.jalFault, |         jalFaultVecNext(i)  -> PreDecodeFaultType.JalFault, | ||||||
|         jalrFaultVecNext(i) -> PreDecodeFaultType.jalrFault, |         jalrFaultVecNext(i) -> PreDecodeFaultType.JalrFault, | ||||||
|         retFaultVecNext(i)  -> PreDecodeFaultType.retFault, |         retFaultVecNext(i)  -> PreDecodeFaultType.RetFault, | ||||||
|         targetFault(i)      -> PreDecodeFaultType.targetFault, |         targetFault(i)      -> PreDecodeFaultType.TargetFault, | ||||||
|         notCFITakenNext(i)  -> PreDecodeFaultType.notCfiFault, |         notCFITakenNext(i)  -> PreDecodeFaultType.NotCfiFault, | ||||||
|         invalidTakenNext(i) -> PreDecodeFaultType.invalidTaken |         invalidTakenNext(i) -> PreDecodeFaultType.InvalidTaken | ||||||
|       ) |       ) | ||||||
|     ) |     ) | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  | @ -21,7 +21,7 @@ import freechips.rocketchip.tilelink.TLBundleA | ||||||
| import freechips.rocketchip.tilelink.TLBundleD | import freechips.rocketchip.tilelink.TLBundleD | ||||||
| import freechips.rocketchip.tilelink.TLEdgeOut | import freechips.rocketchip.tilelink.TLEdgeOut | ||||||
| import org.chipsalliance.cde.config.Parameters | import org.chipsalliance.cde.config.Parameters | ||||||
| import utils.NamedUInt | import utils.EnumUInt | ||||||
| 
 | 
 | ||||||
| // One miss entry deals with one mmio request | // One miss entry deals with one mmio request | ||||||
| class InstrUncacheEntry(edge: TLEdgeOut)(implicit p: Parameters) extends InstrUncacheModule { | class InstrUncacheEntry(edge: TLEdgeOut)(implicit p: Parameters) extends InstrUncacheModule { | ||||||
|  | @ -40,7 +40,7 @@ class InstrUncacheEntry(edge: TLEdgeOut)(implicit p: Parameters) extends InstrUn | ||||||
|   val io: InstrUncacheEntryIO = IO(new InstrUncacheEntryIO(edge)) |   val io: InstrUncacheEntryIO = IO(new InstrUncacheEntryIO(edge)) | ||||||
| 
 | 
 | ||||||
|   private def nState: Int = 4 |   private def nState: Int = 4 | ||||||
|   private object State extends NamedUInt(log2Up(nState)) { |   private object State extends EnumUInt(nState) { | ||||||
|     def Invalid:    UInt = 0.U(width.W) |     def Invalid:    UInt = 0.U(width.W) | ||||||
|     def RefillReq:  UInt = 1.U(width.W) |     def RefillReq:  UInt = 1.U(width.W) | ||||||
|     def RefillResp: UInt = 2.U(width.W) |     def RefillResp: UInt = 2.U(width.W) | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue