Merge remote-tracking branch 'rocket/master' into mono-repo
This commit is contained in:
		
							
								
								
									
										1
									
								
								rocket/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								rocket/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					target
 | 
				
			||||||
							
								
								
									
										24
									
								
								rocket/LICENSE
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								rocket/LICENSE
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,24 @@
 | 
				
			|||||||
 | 
					Copyright (c) 2011-2014, The Regents of the University of California
 | 
				
			||||||
 | 
					(Regents).  All Rights Reserved.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Redistribution and use in source and binary forms, with or without
 | 
				
			||||||
 | 
					modification, are permitted provided that the following conditions are met:
 | 
				
			||||||
 | 
					1. Redistributions of source code must retain the above copyright
 | 
				
			||||||
 | 
					   notice, this list of conditions and the following disclaimer.
 | 
				
			||||||
 | 
					2. Redistributions in binary form must reproduce the above copyright
 | 
				
			||||||
 | 
					   notice, this list of conditions and the following disclaimer in the
 | 
				
			||||||
 | 
					   documentation and/or other materials provided with the distribution.
 | 
				
			||||||
 | 
					3. Neither the name of the Regents nor the
 | 
				
			||||||
 | 
					   names of its contributors may be used to endorse or promote products
 | 
				
			||||||
 | 
					   derived from this software without specific prior written permission.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
 | 
				
			||||||
 | 
					SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
 | 
				
			||||||
 | 
					OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
 | 
				
			||||||
 | 
					BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 | 
				
			||||||
 | 
					THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 | 
				
			||||||
 | 
					PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
 | 
				
			||||||
 | 
					HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
 | 
				
			||||||
 | 
					MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 | 
				
			||||||
							
								
								
									
										29
									
								
								rocket/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								rocket/README.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,29 @@
 | 
				
			|||||||
 | 
					Rocket Core
 | 
				
			||||||
 | 
					===========
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Rocket is a 6-stage single-issue in-order pipeline that executes the 64-bit
 | 
				
			||||||
 | 
					scalar RISC-V ISA.  Rocket implements an MMU that supports page-based virtual
 | 
				
			||||||
 | 
					memory and is able to boot modern operating systems such as Linux.  Rocket
 | 
				
			||||||
 | 
					also has an optional IEEE 754-2008-compliant FPU, which implements both
 | 
				
			||||||
 | 
					single- and double-precision floating-point operations, including fused
 | 
				
			||||||
 | 
					multiply-add.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This repository is not intended to be a self-running repository. To
 | 
				
			||||||
 | 
					instantiate a Rocket core, please use the Rocket chip generator found in the
 | 
				
			||||||
 | 
					rocket-chip git repository.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The following table compares a 32-bit ARM Cortex-A5 core to a 64-bit RISC-V
 | 
				
			||||||
 | 
					Rocket core built in the same TSMC process (40GPLUS). Fourth column is the
 | 
				
			||||||
 | 
					ratio of RISC-V Rocket to ARM Cortex-A5. Both use single-instruction-issue,
 | 
				
			||||||
 | 
					in-order pipelines, yet the RISC-V core is faster, smaller, and uses less
 | 
				
			||||||
 | 
					power.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ISA/Implementation | ARM Cortex-A5 | RISC-V Rocket | R/A
 | 
				
			||||||
 | 
					--- | --- | --- | ---
 | 
				
			||||||
 | 
					ISA Register Width | 32 bits | 64 bits | 2
 | 
				
			||||||
 | 
					Frequency | >1 GHz | >1 GHz | 1
 | 
				
			||||||
 | 
					Dhrystone Performance | 1.57 DMIPS/MHz | 1.72 DMIPS/MHz | 1.1
 | 
				
			||||||
 | 
					Area excluding caches | 0.27 mm<sup>2</sup> | 0.14 mm<sup>2</sup> | 0.5
 | 
				
			||||||
 | 
					Area with 16KB caches | 0.53 mm<sup>2</sup> | 0.39 mm<sup>2</sup> | 0.7
 | 
				
			||||||
 | 
					Area Efficiency | 2.96 DMIPS/MHz/mm<sup>2</sup> | 4.41 DMIPS/MHz/mm<sup>2</sup> | 1.5
 | 
				
			||||||
 | 
					Dynamic Power | <0.08 mW/MHz | 0.034 mW/MHz | >= 0.4
 | 
				
			||||||
							
								
								
									
										10
									
								
								rocket/build.sbt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								rocket/build.sbt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
				
			|||||||
 | 
					organization := "edu.berkeley.cs"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					version := "1.2"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					name := "rocket"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					scalaVersion := "2.11.6"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					libraryDependencies ++= (Seq("chisel", "hardfloat", "uncore", "junctions", "cde").map {
 | 
				
			||||||
 | 
					  dep: String => sys.props.get(dep + "Version") map { "edu.berkeley.cs" %% dep % _ }}).flatten
 | 
				
			||||||
							
								
								
									
										113
									
								
								rocket/src/main/scala/arbiter.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										113
									
								
								rocket/src/main/scala/arbiter.scala
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,113 @@
 | 
				
			|||||||
 | 
					// See LICENSE for license details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package rocket
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import Chisel._
 | 
				
			||||||
 | 
					import cde.{Parameters, Field}
 | 
				
			||||||
 | 
					import junctions.{ParameterizedBundle, DecoupledHelper}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class HellaCacheArbiter(n: Int)(implicit p: Parameters) extends Module
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  val io = new Bundle {
 | 
				
			||||||
 | 
					    val requestor = Vec(n, new HellaCacheIO).flip
 | 
				
			||||||
 | 
					    val mem = new HellaCacheIO
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (n == 1) {
 | 
				
			||||||
 | 
					    io.mem <> io.requestor.head
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    val s1_id = Reg(UInt())
 | 
				
			||||||
 | 
					    val s2_id = Reg(next=s1_id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    io.mem.invalidate_lr := io.requestor.map(_.invalidate_lr).reduce(_||_)
 | 
				
			||||||
 | 
					    io.mem.req.valid := io.requestor.map(_.req.valid).reduce(_||_)
 | 
				
			||||||
 | 
					    io.requestor(0).req.ready := io.mem.req.ready
 | 
				
			||||||
 | 
					    for (i <- 1 until n)
 | 
				
			||||||
 | 
					      io.requestor(i).req.ready := io.requestor(i-1).req.ready && !io.requestor(i-1).req.valid
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (i <- n-1 to 0 by -1) {
 | 
				
			||||||
 | 
					      val req = io.requestor(i).req
 | 
				
			||||||
 | 
					      def connect_s0() = {
 | 
				
			||||||
 | 
					        io.mem.req.bits.cmd := req.bits.cmd
 | 
				
			||||||
 | 
					        io.mem.req.bits.typ := req.bits.typ
 | 
				
			||||||
 | 
					        io.mem.req.bits.addr := req.bits.addr
 | 
				
			||||||
 | 
					        io.mem.req.bits.phys := req.bits.phys
 | 
				
			||||||
 | 
					        io.mem.req.bits.tag := Cat(req.bits.tag, UInt(i, log2Up(n)))
 | 
				
			||||||
 | 
					        s1_id := UInt(i)
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      def connect_s1() = {
 | 
				
			||||||
 | 
					        io.mem.s1_kill := io.requestor(i).s1_kill
 | 
				
			||||||
 | 
					        io.mem.s1_data := io.requestor(i).s1_data
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (i == n-1) {
 | 
				
			||||||
 | 
					        connect_s0()
 | 
				
			||||||
 | 
					        connect_s1()
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        when (req.valid) { connect_s0() }
 | 
				
			||||||
 | 
					        when (s1_id === UInt(i)) { connect_s1() }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (i <- 0 until n) {
 | 
				
			||||||
 | 
					      val resp = io.requestor(i).resp
 | 
				
			||||||
 | 
					      val tag_hit = io.mem.resp.bits.tag(log2Up(n)-1,0) === UInt(i)
 | 
				
			||||||
 | 
					      resp.valid := io.mem.resp.valid && tag_hit
 | 
				
			||||||
 | 
					      io.requestor(i).xcpt := io.mem.xcpt
 | 
				
			||||||
 | 
					      io.requestor(i).ordered := io.mem.ordered
 | 
				
			||||||
 | 
					      io.requestor(i).s2_nack := io.mem.s2_nack && s2_id === UInt(i)
 | 
				
			||||||
 | 
					      resp.bits := io.mem.resp.bits
 | 
				
			||||||
 | 
					      resp.bits.tag := io.mem.resp.bits.tag >> log2Up(n)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      io.requestor(i).replay_next := io.mem.replay_next
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class InOrderArbiter[T <: Data, U <: Data](reqTyp: T, respTyp: U, n: Int)
 | 
				
			||||||
 | 
					    (implicit p: Parameters) extends Module {
 | 
				
			||||||
 | 
					  val io = new Bundle {
 | 
				
			||||||
 | 
					    val in_req = Vec(n, Decoupled(reqTyp)).flip
 | 
				
			||||||
 | 
					    val in_resp = Vec(n, Decoupled(respTyp))
 | 
				
			||||||
 | 
					    val out_req = Decoupled(reqTyp)
 | 
				
			||||||
 | 
					    val out_resp = Decoupled(respTyp).flip
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (n > 1) {
 | 
				
			||||||
 | 
					    val route_q = Module(new Queue(UInt(width = log2Up(n)), 2))
 | 
				
			||||||
 | 
					    val req_arb = Module(new RRArbiter(reqTyp, n))
 | 
				
			||||||
 | 
					    req_arb.io.in <> io.in_req
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    val req_helper = DecoupledHelper(
 | 
				
			||||||
 | 
					      req_arb.io.out.valid,
 | 
				
			||||||
 | 
					      route_q.io.enq.ready,
 | 
				
			||||||
 | 
					      io.out_req.ready)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    io.out_req.bits := req_arb.io.out.bits
 | 
				
			||||||
 | 
					    io.out_req.valid := req_helper.fire(io.out_req.ready)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    route_q.io.enq.bits := req_arb.io.chosen
 | 
				
			||||||
 | 
					    route_q.io.enq.valid := req_helper.fire(route_q.io.enq.ready)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    req_arb.io.out.ready := req_helper.fire(req_arb.io.out.valid)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    val resp_sel = route_q.io.deq.bits
 | 
				
			||||||
 | 
					    val resp_ready = io.in_resp(resp_sel).ready
 | 
				
			||||||
 | 
					    val resp_helper = DecoupledHelper(
 | 
				
			||||||
 | 
					      resp_ready,
 | 
				
			||||||
 | 
					      route_q.io.deq.valid,
 | 
				
			||||||
 | 
					      io.out_resp.valid)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    val resp_valid = resp_helper.fire(resp_ready)
 | 
				
			||||||
 | 
					    for (i <- 0 until n) {
 | 
				
			||||||
 | 
					      io.in_resp(i).bits := io.out_resp.bits
 | 
				
			||||||
 | 
					      io.in_resp(i).valid := resp_valid && resp_sel === UInt(i)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    route_q.io.deq.ready := resp_helper.fire(route_q.io.deq.valid)
 | 
				
			||||||
 | 
					    io.out_resp.ready := resp_helper.fire(io.out_resp.valid)
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    io.out_req <> io.in_req.head
 | 
				
			||||||
 | 
					    io.in_resp.head <> io.out_resp
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										82
									
								
								rocket/src/main/scala/breakpoint.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								rocket/src/main/scala/breakpoint.scala
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,82 @@
 | 
				
			|||||||
 | 
					// See LICENSE for license details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package rocket
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import Chisel._
 | 
				
			||||||
 | 
					import Util._
 | 
				
			||||||
 | 
					import cde.Parameters
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class TDRSelect(implicit p: Parameters) extends CoreBundle()(p) {
 | 
				
			||||||
 | 
					  val tdrmode = Bool()
 | 
				
			||||||
 | 
					  val reserved = UInt(width = xLen - 1 - log2Up(nTDR))
 | 
				
			||||||
 | 
					  val tdrindex = UInt(width = log2Up(nTDR))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def nTDR = p(NBreakpoints)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class BPControl(implicit p: Parameters) extends CoreBundle()(p) {
 | 
				
			||||||
 | 
					  val tdrtype = UInt(width = 4)
 | 
				
			||||||
 | 
					  val bpamaskmax = UInt(width = 5)
 | 
				
			||||||
 | 
					  val reserved = UInt(width = xLen-28)
 | 
				
			||||||
 | 
					  val bpaction = UInt(width = 8)
 | 
				
			||||||
 | 
					  val bpmatch = UInt(width = 4)
 | 
				
			||||||
 | 
					  val m = Bool()
 | 
				
			||||||
 | 
					  val h = Bool()
 | 
				
			||||||
 | 
					  val s = Bool()
 | 
				
			||||||
 | 
					  val u = Bool()
 | 
				
			||||||
 | 
					  val r = Bool()
 | 
				
			||||||
 | 
					  val w = Bool()
 | 
				
			||||||
 | 
					  val x = Bool()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def tdrType = 1
 | 
				
			||||||
 | 
					  def bpaMaskMax = 4
 | 
				
			||||||
 | 
					  def enabled(mstatus: MStatus) = Cat(m, h, s, u)(mstatus.prv)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class BP(implicit p: Parameters) extends CoreBundle()(p) {
 | 
				
			||||||
 | 
					  val control = new BPControl
 | 
				
			||||||
 | 
					  val address = UInt(width = vaddrBits)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def mask(dummy: Int = 0) = {
 | 
				
			||||||
 | 
					    var mask: UInt = control.bpmatch(1)
 | 
				
			||||||
 | 
					    for (i <- 1 until control.bpaMaskMax)
 | 
				
			||||||
 | 
					      mask = Cat(mask(i-1) && address(i-1), mask)
 | 
				
			||||||
 | 
					    mask
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def pow2AddressMatch(x: UInt) =
 | 
				
			||||||
 | 
					    (~x | mask()) === (~address | mask())
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class BreakpointUnit(implicit p: Parameters) extends CoreModule()(p) {
 | 
				
			||||||
 | 
					  val io = new Bundle {
 | 
				
			||||||
 | 
					    val status = new MStatus().asInput
 | 
				
			||||||
 | 
					    val bp = Vec(p(NBreakpoints), new BP).asInput
 | 
				
			||||||
 | 
					    val pc = UInt(INPUT, vaddrBits)
 | 
				
			||||||
 | 
					    val ea = UInt(INPUT, vaddrBits)
 | 
				
			||||||
 | 
					    val xcpt_if = Bool(OUTPUT)
 | 
				
			||||||
 | 
					    val xcpt_ld = Bool(OUTPUT)
 | 
				
			||||||
 | 
					    val xcpt_st = Bool(OUTPUT)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  io.xcpt_if := false
 | 
				
			||||||
 | 
					  io.xcpt_ld := false
 | 
				
			||||||
 | 
					  io.xcpt_st := false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  for (bp <- io.bp) {
 | 
				
			||||||
 | 
					    when (bp.control.enabled(io.status)) {
 | 
				
			||||||
 | 
					      when (bp.pow2AddressMatch(io.pc) && bp.control.x) { io.xcpt_if := true }
 | 
				
			||||||
 | 
					      when (bp.pow2AddressMatch(io.ea) && bp.control.r) { io.xcpt_ld := true }
 | 
				
			||||||
 | 
					      when (bp.pow2AddressMatch(io.ea) && bp.control.w) { io.xcpt_st := true }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (!io.bp.isEmpty) for ((bpl, bph) <- io.bp zip io.bp.tail) {
 | 
				
			||||||
 | 
					    def matches(x: UInt) = !(x < bpl.address) && x < bph.address
 | 
				
			||||||
 | 
					    when (bph.control.enabled(io.status) && bph.control.bpmatch === 1) {
 | 
				
			||||||
 | 
					      when (matches(io.pc) && bph.control.x) { io.xcpt_if := true }
 | 
				
			||||||
 | 
					      when (matches(io.ea) && bph.control.r) { io.xcpt_ld := true }
 | 
				
			||||||
 | 
					      when (matches(io.ea) && bph.control.w) { io.xcpt_st := true }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										272
									
								
								rocket/src/main/scala/btb.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										272
									
								
								rocket/src/main/scala/btb.scala
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,272 @@
 | 
				
			|||||||
 | 
					// See LICENSE for license details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package rocket
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import Chisel._
 | 
				
			||||||
 | 
					import junctions._
 | 
				
			||||||
 | 
					import cde.{Parameters, Field}
 | 
				
			||||||
 | 
					import Util._
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					case object BtbKey extends Field[BtbParameters]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					case class BtbParameters(
 | 
				
			||||||
 | 
					  nEntries: Int = 62,
 | 
				
			||||||
 | 
					  nRAS: Int = 2,
 | 
				
			||||||
 | 
					  updatesOutOfOrder: Boolean = false)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					abstract trait HasBtbParameters extends HasCoreParameters {
 | 
				
			||||||
 | 
					  val matchBits = pgIdxBits
 | 
				
			||||||
 | 
					  val entries = p(BtbKey).nEntries
 | 
				
			||||||
 | 
					  val nRAS = p(BtbKey).nRAS
 | 
				
			||||||
 | 
					  val updatesOutOfOrder = p(BtbKey).updatesOutOfOrder
 | 
				
			||||||
 | 
					  val nPages = ((1 max(log2Up(entries)))+1)/2*2 // control logic assumes 2 divides pages
 | 
				
			||||||
 | 
					  val opaqueBits = log2Up(entries)
 | 
				
			||||||
 | 
					  val nBHT = 1 << log2Up(entries*2)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					abstract class BtbModule(implicit val p: Parameters) extends Module with HasBtbParameters
 | 
				
			||||||
 | 
					abstract class BtbBundle(implicit val p: Parameters) extends ParameterizedBundle()(p)
 | 
				
			||||||
 | 
					  with HasBtbParameters
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class RAS(nras: Int) {
 | 
				
			||||||
 | 
					  def push(addr: UInt): Unit = {
 | 
				
			||||||
 | 
					    when (count < nras) { count := count + 1 }
 | 
				
			||||||
 | 
					    val nextPos = Mux(Bool(isPow2(nras)) || pos < nras-1, pos+1, UInt(0))
 | 
				
			||||||
 | 
					    stack(nextPos) := addr
 | 
				
			||||||
 | 
					    pos := nextPos
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  def peek: UInt = stack(pos)
 | 
				
			||||||
 | 
					  def pop(): Unit = when (!isEmpty) {
 | 
				
			||||||
 | 
					    count := count - 1
 | 
				
			||||||
 | 
					    pos := Mux(Bool(isPow2(nras)) || pos > 0, pos-1, UInt(nras-1))
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  def clear(): Unit = count := UInt(0)
 | 
				
			||||||
 | 
					  def isEmpty: Bool = count === UInt(0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private val count = Reg(UInt(width = log2Up(nras+1)))
 | 
				
			||||||
 | 
					  private val pos = Reg(UInt(width = log2Up(nras)))
 | 
				
			||||||
 | 
					  private val stack = Reg(Vec(nras, UInt()))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class BHTResp(implicit p: Parameters) extends BtbBundle()(p) {
 | 
				
			||||||
 | 
					  val history = UInt(width = log2Up(nBHT).max(1))
 | 
				
			||||||
 | 
					  val value = UInt(width = 2)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// BHT contains table of 2-bit counters and a global history register.
 | 
				
			||||||
 | 
					// The BHT only predicts and updates when there is a BTB hit.
 | 
				
			||||||
 | 
					// The global history:
 | 
				
			||||||
 | 
					//    - updated speculatively in fetch (if there's a BTB hit).
 | 
				
			||||||
 | 
					//    - on a mispredict, the history register is reset (again, only if BTB hit).
 | 
				
			||||||
 | 
					// The counter table:
 | 
				
			||||||
 | 
					//    - each counter corresponds with the address of the fetch packet ("fetch pc").
 | 
				
			||||||
 | 
					//    - updated when a branch resolves (and BTB was a hit for that branch).
 | 
				
			||||||
 | 
					//      The updating branch must provide its "fetch pc".
 | 
				
			||||||
 | 
					class BHT(nbht: Int)(implicit p: Parameters) {
 | 
				
			||||||
 | 
					  val nbhtbits = log2Up(nbht)
 | 
				
			||||||
 | 
					  def get(addr: UInt, update: Bool): BHTResp = {
 | 
				
			||||||
 | 
					    val res = Wire(new BHTResp)
 | 
				
			||||||
 | 
					    val index = addr(nbhtbits+1,2) ^ history
 | 
				
			||||||
 | 
					    res.value := table(index)
 | 
				
			||||||
 | 
					    res.history := history
 | 
				
			||||||
 | 
					    val taken = res.value(0)
 | 
				
			||||||
 | 
					    when (update) { history := Cat(taken, history(nbhtbits-1,1)) }
 | 
				
			||||||
 | 
					    res
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  def update(addr: UInt, d: BHTResp, taken: Bool, mispredict: Bool): Unit = {
 | 
				
			||||||
 | 
					    val index = addr(nbhtbits+1,2) ^ d.history
 | 
				
			||||||
 | 
					    table(index) := Cat(taken, (d.value(1) & d.value(0)) | ((d.value(1) | d.value(0)) & taken))
 | 
				
			||||||
 | 
					    when (mispredict) { history := Cat(taken, d.history(nbhtbits-1,1)) }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private val table = Mem(nbht, UInt(width = 2))
 | 
				
			||||||
 | 
					  val history = Reg(UInt(width = nbhtbits))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// BTB update occurs during branch resolution (and only on a mispredict).
 | 
				
			||||||
 | 
					//  - "pc" is what future fetch PCs will tag match against.
 | 
				
			||||||
 | 
					//  - "br_pc" is the PC of the branch instruction.
 | 
				
			||||||
 | 
					class BTBUpdate(implicit p: Parameters) extends BtbBundle()(p) {
 | 
				
			||||||
 | 
					  val prediction = Valid(new BTBResp)
 | 
				
			||||||
 | 
					  val pc = UInt(width = vaddrBits)
 | 
				
			||||||
 | 
					  val target = UInt(width = vaddrBits)
 | 
				
			||||||
 | 
					  val taken = Bool()
 | 
				
			||||||
 | 
					  val isJump = Bool()
 | 
				
			||||||
 | 
					  val isReturn = Bool()
 | 
				
			||||||
 | 
					  val br_pc = UInt(width = vaddrBits)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// BHT update occurs during branch resolution on all conditional branches.
 | 
				
			||||||
 | 
					//  - "pc" is what future fetch PCs will tag match against.
 | 
				
			||||||
 | 
					class BHTUpdate(implicit p: Parameters) extends BtbBundle()(p) {
 | 
				
			||||||
 | 
					  val prediction = Valid(new BTBResp)
 | 
				
			||||||
 | 
					  val pc = UInt(width = vaddrBits)
 | 
				
			||||||
 | 
					  val taken = Bool()
 | 
				
			||||||
 | 
					  val mispredict = Bool()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class RASUpdate(implicit p: Parameters) extends BtbBundle()(p) {
 | 
				
			||||||
 | 
					  val isCall = Bool()
 | 
				
			||||||
 | 
					  val isReturn = Bool()
 | 
				
			||||||
 | 
					  val returnAddr = UInt(width = vaddrBits)
 | 
				
			||||||
 | 
					  val prediction = Valid(new BTBResp)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//  - "bridx" is the low-order PC bits of the predicted branch (after
 | 
				
			||||||
 | 
					//     shifting off the lowest log(inst_bytes) bits off).
 | 
				
			||||||
 | 
					//  - "mask" provides a mask of valid instructions (instructions are
 | 
				
			||||||
 | 
					//     masked off by the predicted taken branch from the BTB).
 | 
				
			||||||
 | 
					class BTBResp(implicit p: Parameters) extends BtbBundle()(p) {
 | 
				
			||||||
 | 
					  val taken = Bool()
 | 
				
			||||||
 | 
					  val mask = Bits(width = fetchWidth)
 | 
				
			||||||
 | 
					  val bridx = Bits(width = log2Up(fetchWidth))
 | 
				
			||||||
 | 
					  val target = UInt(width = vaddrBits)
 | 
				
			||||||
 | 
					  val entry = UInt(width = opaqueBits)
 | 
				
			||||||
 | 
					  val bht = new BHTResp
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class BTBReq(implicit p: Parameters) extends BtbBundle()(p) {
 | 
				
			||||||
 | 
					   val addr = UInt(width = vaddrBits)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// fully-associative branch target buffer
 | 
				
			||||||
 | 
					// Higher-performance processors may cause BTB updates to occur out-of-order,
 | 
				
			||||||
 | 
					// which requires an extra CAM port for updates (to ensure no duplicates get
 | 
				
			||||||
 | 
					// placed in BTB).
 | 
				
			||||||
 | 
					class BTB(implicit p: Parameters) extends BtbModule {
 | 
				
			||||||
 | 
					  val io = new Bundle {
 | 
				
			||||||
 | 
					    val req = Valid(new BTBReq).flip
 | 
				
			||||||
 | 
					    val resp = Valid(new BTBResp)
 | 
				
			||||||
 | 
					    val btb_update = Valid(new BTBUpdate).flip
 | 
				
			||||||
 | 
					    val bht_update = Valid(new BHTUpdate).flip
 | 
				
			||||||
 | 
					    val ras_update = Valid(new RASUpdate).flip
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val idxs = Reg(Vec(entries, UInt(width=matchBits - log2Up(coreInstBytes))))
 | 
				
			||||||
 | 
					  val idxPages = Reg(Vec(entries, UInt(width=log2Up(nPages))))
 | 
				
			||||||
 | 
					  val tgts = Reg(Vec(entries, UInt(width=matchBits - log2Up(coreInstBytes))))
 | 
				
			||||||
 | 
					  val tgtPages = Reg(Vec(entries, UInt(width=log2Up(nPages))))
 | 
				
			||||||
 | 
					  val pages = Reg(Vec(nPages, UInt(width=vaddrBits - matchBits)))
 | 
				
			||||||
 | 
					  val pageValid = Reg(init = UInt(0, nPages))
 | 
				
			||||||
 | 
					  val idxPagesOH = idxPages.map(UIntToOH(_)(nPages-1,0))
 | 
				
			||||||
 | 
					  val tgtPagesOH = tgtPages.map(UIntToOH(_)(nPages-1,0))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val useRAS = Reg(UInt(width = entries))
 | 
				
			||||||
 | 
					  val isJump = Reg(UInt(width = entries))
 | 
				
			||||||
 | 
					  val brIdx = Reg(Vec(entries, UInt(width=log2Up(fetchWidth))))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private def page(addr: UInt) = addr >> matchBits
 | 
				
			||||||
 | 
					  private def pageMatch(addr: UInt) = {
 | 
				
			||||||
 | 
					    val p = page(addr)
 | 
				
			||||||
 | 
					    pageValid & pages.map(_ === p).toBits
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  private def tagMatch(addr: UInt, pgMatch: UInt) = {
 | 
				
			||||||
 | 
					    val idxMatch = idxs.map(_ === addr(matchBits-1, log2Up(coreInstBytes))).toBits
 | 
				
			||||||
 | 
					    val idxPageMatch = idxPagesOH.map(_ & pgMatch).map(_.orR).toBits
 | 
				
			||||||
 | 
					    idxMatch & idxPageMatch
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val r_btb_update = Pipe(io.btb_update)
 | 
				
			||||||
 | 
					  val update_target = io.req.bits.addr
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val pageHit = pageMatch(io.req.bits.addr)
 | 
				
			||||||
 | 
					  val hitsVec = tagMatch(io.req.bits.addr, pageHit)
 | 
				
			||||||
 | 
					  val hits = hitsVec.toBits
 | 
				
			||||||
 | 
					  val updatePageHit = pageMatch(r_btb_update.bits.pc)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val updateHits = tagMatch(r_btb_update.bits.pc, updatePageHit)
 | 
				
			||||||
 | 
					  val updateHit = if (updatesOutOfOrder) updateHits.orR else r_btb_update.bits.prediction.valid
 | 
				
			||||||
 | 
					  val updateHitAddr = if (updatesOutOfOrder) OHToUInt(updateHits) else r_btb_update.bits.prediction.bits.entry
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // guarantee one-hotness of idx after reset
 | 
				
			||||||
 | 
					  val resetting = Reg(init = Bool(true))
 | 
				
			||||||
 | 
					  val (nextRepl, wrap) = Counter(resetting || (r_btb_update.valid && !updateHit), entries)
 | 
				
			||||||
 | 
					  when (wrap) { resetting := false }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val useUpdatePageHit = updatePageHit.orR
 | 
				
			||||||
 | 
					  val usePageHit = pageHit.orR
 | 
				
			||||||
 | 
					  val doIdxPageRepl = !useUpdatePageHit
 | 
				
			||||||
 | 
					  val nextPageRepl = Reg(UInt(width = log2Ceil(nPages)))
 | 
				
			||||||
 | 
					  val idxPageRepl = Mux(usePageHit, Cat(pageHit(nPages-2,0), pageHit(nPages-1)), UIntToOH(nextPageRepl))
 | 
				
			||||||
 | 
					  val idxPageUpdateOH = Mux(useUpdatePageHit, updatePageHit, idxPageRepl)
 | 
				
			||||||
 | 
					  val idxPageUpdate = OHToUInt(idxPageUpdateOH)
 | 
				
			||||||
 | 
					  val idxPageReplEn = Mux(doIdxPageRepl, idxPageRepl, UInt(0))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val samePage = page(r_btb_update.bits.pc) === page(update_target)
 | 
				
			||||||
 | 
					  val doTgtPageRepl = !samePage && !usePageHit
 | 
				
			||||||
 | 
					  val tgtPageRepl = Mux(samePage, idxPageUpdateOH, Cat(idxPageUpdateOH(nPages-2,0), idxPageUpdateOH(nPages-1)))
 | 
				
			||||||
 | 
					  val tgtPageUpdate = OHToUInt(Mux(usePageHit, pageHit, tgtPageRepl))
 | 
				
			||||||
 | 
					  val tgtPageReplEn = Mux(doTgtPageRepl, tgtPageRepl, UInt(0))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  when (r_btb_update.valid && (doIdxPageRepl || doTgtPageRepl)) {
 | 
				
			||||||
 | 
					    val both = doIdxPageRepl && doTgtPageRepl
 | 
				
			||||||
 | 
					    val next = nextPageRepl + Mux[UInt](both, 2, 1)
 | 
				
			||||||
 | 
					    nextPageRepl := Mux(next >= nPages, next(0), next)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  when (r_btb_update.valid || resetting) {
 | 
				
			||||||
 | 
					    assert(resetting || io.req.bits.addr === r_btb_update.bits.target, "BTB request != I$ target")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    val waddr = Mux(updateHit && !resetting, updateHitAddr, nextRepl)
 | 
				
			||||||
 | 
					    val mask = UIntToOH(waddr)
 | 
				
			||||||
 | 
					    val newIdx = r_btb_update.bits.pc(matchBits-1, log2Up(coreInstBytes))
 | 
				
			||||||
 | 
					    idxs(waddr) := Mux(resetting, Cat(newIdx >> log2Ceil(entries), nextRepl), newIdx)
 | 
				
			||||||
 | 
					    tgts(waddr) := update_target(matchBits-1, log2Up(coreInstBytes))
 | 
				
			||||||
 | 
					    idxPages(waddr) := idxPageUpdate
 | 
				
			||||||
 | 
					    tgtPages(waddr) := tgtPageUpdate
 | 
				
			||||||
 | 
					    useRAS := Mux(r_btb_update.bits.isReturn, useRAS | mask, useRAS & ~mask)
 | 
				
			||||||
 | 
					    isJump := Mux(r_btb_update.bits.isJump, isJump | mask, isJump & ~mask)
 | 
				
			||||||
 | 
					    if (fetchWidth > 1)
 | 
				
			||||||
 | 
					      brIdx(waddr) := r_btb_update.bits.br_pc >> log2Up(coreInstBytes)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    require(nPages % 2 == 0)
 | 
				
			||||||
 | 
					    val idxWritesEven = !idxPageUpdate(0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def writeBank(i: Int, mod: Int, en: UInt, data: UInt) =
 | 
				
			||||||
 | 
					      for (i <- i until nPages by mod)
 | 
				
			||||||
 | 
					        when (en(i)) { pages(i) := data }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    writeBank(0, 2, Mux(idxWritesEven, idxPageReplEn, tgtPageReplEn),
 | 
				
			||||||
 | 
					      Mux(idxWritesEven, page(r_btb_update.bits.pc), page(update_target)))
 | 
				
			||||||
 | 
					    writeBank(1, 2, Mux(idxWritesEven, tgtPageReplEn, idxPageReplEn),
 | 
				
			||||||
 | 
					      Mux(idxWritesEven, page(update_target), page(r_btb_update.bits.pc)))
 | 
				
			||||||
 | 
					    pageValid := pageValid | tgtPageReplEn | idxPageReplEn
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  io.resp.valid := hits.orR
 | 
				
			||||||
 | 
					  io.resp.bits.taken := io.resp.valid
 | 
				
			||||||
 | 
					  io.resp.bits.target := Cat(Mux1H(Mux1H(hitsVec, tgtPagesOH), pages), Mux1H(hitsVec, tgts) << log2Up(coreInstBytes))
 | 
				
			||||||
 | 
					  io.resp.bits.entry := OHToUInt(hits)
 | 
				
			||||||
 | 
					  io.resp.bits.bridx := Mux1H(hitsVec, brIdx)
 | 
				
			||||||
 | 
					  io.resp.bits.mask := Cat((UInt(1) << ~Mux(io.resp.bits.taken, ~io.resp.bits.bridx, UInt(0)))-1, UInt(1))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (nBHT > 0) {
 | 
				
			||||||
 | 
					    val bht = new BHT(nBHT)
 | 
				
			||||||
 | 
					    val isBranch = !(hits & isJump).orR
 | 
				
			||||||
 | 
					    val res = bht.get(io.req.bits.addr, io.req.valid && io.resp.valid && isBranch)
 | 
				
			||||||
 | 
					    val update_btb_hit = io.bht_update.bits.prediction.valid
 | 
				
			||||||
 | 
					    when (io.bht_update.valid && update_btb_hit) {
 | 
				
			||||||
 | 
					      bht.update(io.bht_update.bits.pc, io.bht_update.bits.prediction.bits.bht, io.bht_update.bits.taken, io.bht_update.bits.mispredict)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    when (!res.value(0) && isBranch) { io.resp.bits.taken := false }
 | 
				
			||||||
 | 
					    io.resp.bits.bht := res
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (nRAS > 0) {
 | 
				
			||||||
 | 
					    val ras = new RAS(nRAS)
 | 
				
			||||||
 | 
					    val doPeek = (hits & useRAS).orR
 | 
				
			||||||
 | 
					    when (!ras.isEmpty && doPeek) {
 | 
				
			||||||
 | 
					      io.resp.bits.target := ras.peek
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    when (io.ras_update.valid) {
 | 
				
			||||||
 | 
					      when (io.ras_update.bits.isCall) {
 | 
				
			||||||
 | 
					        ras.push(io.ras_update.bits.returnAddr)
 | 
				
			||||||
 | 
					        when (doPeek) {
 | 
				
			||||||
 | 
					          io.resp.bits.target := io.ras_update.bits.returnAddr
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }.elsewhen (io.ras_update.bits.isReturn && io.ras_update.bits.prediction.valid) {
 | 
				
			||||||
 | 
					        ras.pop()
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										49
									
								
								rocket/src/main/scala/consts.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								rocket/src/main/scala/consts.scala
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,49 @@
 | 
				
			|||||||
 | 
					// See LICENSE for license details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package rocket
 | 
				
			||||||
 | 
					package constants
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import Chisel._
 | 
				
			||||||
 | 
					import scala.math._
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					trait ScalarOpConstants {
 | 
				
			||||||
 | 
					  val SZ_BR = 3
 | 
				
			||||||
 | 
					  val BR_X    = BitPat("b???")
 | 
				
			||||||
 | 
					  val BR_EQ   = UInt(0, 3)
 | 
				
			||||||
 | 
					  val BR_NE   = UInt(1, 3)
 | 
				
			||||||
 | 
					  val BR_J    = UInt(2, 3)
 | 
				
			||||||
 | 
					  val BR_N    = UInt(3, 3)
 | 
				
			||||||
 | 
					  val BR_LT   = UInt(4, 3)
 | 
				
			||||||
 | 
					  val BR_GE   = UInt(5, 3)
 | 
				
			||||||
 | 
					  val BR_LTU  = UInt(6, 3)
 | 
				
			||||||
 | 
					  val BR_GEU  = UInt(7, 3)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val A1_X    = BitPat("b??")
 | 
				
			||||||
 | 
					  val A1_ZERO = UInt(0, 2)
 | 
				
			||||||
 | 
					  val A1_RS1  = UInt(1, 2)
 | 
				
			||||||
 | 
					  val A1_PC   = UInt(2, 2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val IMM_X  = BitPat("b???")
 | 
				
			||||||
 | 
					  val IMM_S  = UInt(0, 3)
 | 
				
			||||||
 | 
					  val IMM_SB = UInt(1, 3)
 | 
				
			||||||
 | 
					  val IMM_U  = UInt(2, 3)
 | 
				
			||||||
 | 
					  val IMM_UJ = UInt(3, 3)
 | 
				
			||||||
 | 
					  val IMM_I  = UInt(4, 3)
 | 
				
			||||||
 | 
					  val IMM_Z  = UInt(5, 3)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val A2_X    = BitPat("b??")
 | 
				
			||||||
 | 
					  val A2_ZERO = UInt(0, 2)
 | 
				
			||||||
 | 
					  val A2_FOUR = UInt(1, 2)
 | 
				
			||||||
 | 
					  val A2_RS2  = UInt(2, 2)
 | 
				
			||||||
 | 
					  val A2_IMM  = UInt(3, 2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val X = BitPat("b?")
 | 
				
			||||||
 | 
					  val N = BitPat("b0")
 | 
				
			||||||
 | 
					  val Y = BitPat("b1")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val SZ_DW = 1
 | 
				
			||||||
 | 
					  val DW_X  = X
 | 
				
			||||||
 | 
					  val DW_32 = N
 | 
				
			||||||
 | 
					  val DW_64 = Y
 | 
				
			||||||
 | 
					  val DW_XPR = Y
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										589
									
								
								rocket/src/main/scala/csr.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										589
									
								
								rocket/src/main/scala/csr.scala
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,589 @@
 | 
				
			|||||||
 | 
					// See LICENSE for license details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package rocket
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import Chisel._
 | 
				
			||||||
 | 
					import Util._
 | 
				
			||||||
 | 
					import Instructions._
 | 
				
			||||||
 | 
					import cde.{Parameters, Field}
 | 
				
			||||||
 | 
					import uncore.devices._
 | 
				
			||||||
 | 
					import junctions.AddrMap
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class MStatus extends Bundle {
 | 
				
			||||||
 | 
					  val debug = Bool() // not truly part of mstatus, but convenient
 | 
				
			||||||
 | 
					  val prv = UInt(width = PRV.SZ) // not truly part of mstatus, but convenient
 | 
				
			||||||
 | 
					  val sd = Bool()
 | 
				
			||||||
 | 
					  val zero3 = UInt(width = 31)
 | 
				
			||||||
 | 
					  val sd_rv32 = Bool()
 | 
				
			||||||
 | 
					  val zero2 = UInt(width = 2)
 | 
				
			||||||
 | 
					  val vm = UInt(width = 5)
 | 
				
			||||||
 | 
					  val zero1 = UInt(width = 4)
 | 
				
			||||||
 | 
					  val mxr = Bool()
 | 
				
			||||||
 | 
					  val pum = Bool()
 | 
				
			||||||
 | 
					  val mprv = Bool()
 | 
				
			||||||
 | 
					  val xs = UInt(width = 2)
 | 
				
			||||||
 | 
					  val fs = UInt(width = 2)
 | 
				
			||||||
 | 
					  val mpp = UInt(width = 2)
 | 
				
			||||||
 | 
					  val hpp = UInt(width = 2)
 | 
				
			||||||
 | 
					  val spp = UInt(width = 1)
 | 
				
			||||||
 | 
					  val mpie = Bool()
 | 
				
			||||||
 | 
					  val hpie = Bool()
 | 
				
			||||||
 | 
					  val spie = Bool()
 | 
				
			||||||
 | 
					  val upie = Bool()
 | 
				
			||||||
 | 
					  val mie = Bool()
 | 
				
			||||||
 | 
					  val hie = Bool()
 | 
				
			||||||
 | 
					  val sie = Bool()
 | 
				
			||||||
 | 
					  val uie = Bool()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class DCSR extends Bundle {
 | 
				
			||||||
 | 
					  val xdebugver = UInt(width = 2)
 | 
				
			||||||
 | 
					  val ndreset = Bool()
 | 
				
			||||||
 | 
					  val fullreset = Bool()
 | 
				
			||||||
 | 
					  val hwbpcount = UInt(width = 12)
 | 
				
			||||||
 | 
					  val ebreakm = Bool()
 | 
				
			||||||
 | 
					  val ebreakh = Bool()
 | 
				
			||||||
 | 
					  val ebreaks = Bool()
 | 
				
			||||||
 | 
					  val ebreaku = Bool()
 | 
				
			||||||
 | 
					  val zero2 = Bool()
 | 
				
			||||||
 | 
					  val stopcycle = Bool()
 | 
				
			||||||
 | 
					  val stoptime = Bool()
 | 
				
			||||||
 | 
					  val cause = UInt(width = 3)
 | 
				
			||||||
 | 
					  val debugint = Bool()
 | 
				
			||||||
 | 
					  val zero1 = Bool()
 | 
				
			||||||
 | 
					  val halt = Bool()
 | 
				
			||||||
 | 
					  val step = Bool()
 | 
				
			||||||
 | 
					  val prv = UInt(width = PRV.SZ)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class MIP extends Bundle {
 | 
				
			||||||
 | 
					  val rocc = Bool()
 | 
				
			||||||
 | 
					  val meip = Bool()
 | 
				
			||||||
 | 
					  val heip = Bool()
 | 
				
			||||||
 | 
					  val seip = Bool()
 | 
				
			||||||
 | 
					  val ueip = Bool()
 | 
				
			||||||
 | 
					  val mtip = Bool()
 | 
				
			||||||
 | 
					  val htip = Bool()
 | 
				
			||||||
 | 
					  val stip = Bool()
 | 
				
			||||||
 | 
					  val utip = Bool()
 | 
				
			||||||
 | 
					  val msip = Bool()
 | 
				
			||||||
 | 
					  val hsip = Bool()
 | 
				
			||||||
 | 
					  val ssip = Bool()
 | 
				
			||||||
 | 
					  val usip = Bool()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class PTBR(implicit p: Parameters) extends CoreBundle()(p) {
 | 
				
			||||||
 | 
					  require(maxPAddrBits - pgIdxBits + asIdBits <= xLen)
 | 
				
			||||||
 | 
					  val asid = UInt(width = asIdBits)
 | 
				
			||||||
 | 
					  val ppn = UInt(width = maxPAddrBits - pgIdxBits)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					object PRV
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  val SZ = 2
 | 
				
			||||||
 | 
					  val U = 0
 | 
				
			||||||
 | 
					  val S = 1
 | 
				
			||||||
 | 
					  val H = 2
 | 
				
			||||||
 | 
					  val M = 3
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					object CSR
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  // commands
 | 
				
			||||||
 | 
					  val SZ = 3
 | 
				
			||||||
 | 
					  val X = BitPat.DC(SZ)
 | 
				
			||||||
 | 
					  val N = UInt(0,SZ)
 | 
				
			||||||
 | 
					  val W = UInt(1,SZ)
 | 
				
			||||||
 | 
					  val S = UInt(2,SZ)
 | 
				
			||||||
 | 
					  val C = UInt(3,SZ)
 | 
				
			||||||
 | 
					  val I = UInt(4,SZ)
 | 
				
			||||||
 | 
					  val R = UInt(5,SZ)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val ADDRSZ = 12
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class CSRFileIO(implicit p: Parameters) extends CoreBundle {
 | 
				
			||||||
 | 
					  val prci = new PRCITileIO().flip
 | 
				
			||||||
 | 
					  val rw = new Bundle {
 | 
				
			||||||
 | 
					    val addr = UInt(INPUT, CSR.ADDRSZ)
 | 
				
			||||||
 | 
					    val cmd = Bits(INPUT, CSR.SZ)
 | 
				
			||||||
 | 
					    val rdata = Bits(OUTPUT, xLen)
 | 
				
			||||||
 | 
					    val wdata = Bits(INPUT, xLen)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val csr_stall = Bool(OUTPUT)
 | 
				
			||||||
 | 
					  val csr_xcpt = Bool(OUTPUT)
 | 
				
			||||||
 | 
					  val eret = Bool(OUTPUT)
 | 
				
			||||||
 | 
					  val singleStep = Bool(OUTPUT)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val status = new MStatus().asOutput
 | 
				
			||||||
 | 
					  val ptbr = new PTBR().asOutput
 | 
				
			||||||
 | 
					  val evec = UInt(OUTPUT, vaddrBitsExtended)
 | 
				
			||||||
 | 
					  val exception = Bool(INPUT)
 | 
				
			||||||
 | 
					  val retire = UInt(INPUT, log2Up(1+retireWidth))
 | 
				
			||||||
 | 
					  val custom_mrw_csrs = Vec(nCustomMrwCsrs, UInt(INPUT, xLen))
 | 
				
			||||||
 | 
					  val cause = UInt(INPUT, xLen)
 | 
				
			||||||
 | 
					  val pc = UInt(INPUT, vaddrBitsExtended)
 | 
				
			||||||
 | 
					  val badaddr = UInt(INPUT, vaddrBitsExtended)
 | 
				
			||||||
 | 
					  val fatc = Bool(OUTPUT)
 | 
				
			||||||
 | 
					  val time = UInt(OUTPUT, xLen)
 | 
				
			||||||
 | 
					  val fcsr_rm = Bits(OUTPUT, FPConstants.RM_SZ)
 | 
				
			||||||
 | 
					  val fcsr_flags = Valid(Bits(width = FPConstants.FLAGS_SZ)).flip
 | 
				
			||||||
 | 
					  val rocc = new RoCCInterface().flip
 | 
				
			||||||
 | 
					  val interrupt = Bool(OUTPUT)
 | 
				
			||||||
 | 
					  val interrupt_cause = UInt(OUTPUT, xLen)
 | 
				
			||||||
 | 
					  val bp = Vec(p(NBreakpoints), new BP).asOutput
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class CSRFile(implicit p: Parameters) extends CoreModule()(p)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  val io = new CSRFileIO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val reset_mstatus = Wire(init=new MStatus().fromBits(0))
 | 
				
			||||||
 | 
					  reset_mstatus.mpp := PRV.M
 | 
				
			||||||
 | 
					  reset_mstatus.prv := PRV.M
 | 
				
			||||||
 | 
					  val reg_mstatus = Reg(init=reset_mstatus)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val reset_dcsr = Wire(init=new DCSR().fromBits(0))
 | 
				
			||||||
 | 
					  reset_dcsr.xdebugver := 1
 | 
				
			||||||
 | 
					  reset_dcsr.prv := PRV.M
 | 
				
			||||||
 | 
					  val reg_dcsr = Reg(init=reset_dcsr)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val (supported_interrupts, delegable_interrupts) = {
 | 
				
			||||||
 | 
					    val sup = Wire(init=new MIP().fromBits(0))
 | 
				
			||||||
 | 
					    sup.ssip := Bool(p(UseVM))
 | 
				
			||||||
 | 
					    sup.msip := true
 | 
				
			||||||
 | 
					    sup.stip := Bool(p(UseVM))
 | 
				
			||||||
 | 
					    sup.mtip := true
 | 
				
			||||||
 | 
					    sup.meip := true
 | 
				
			||||||
 | 
					    sup.seip := Bool(p(UseVM))
 | 
				
			||||||
 | 
					    sup.rocc := usingRoCC
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    val del = Wire(init=sup)
 | 
				
			||||||
 | 
					    del.msip := false
 | 
				
			||||||
 | 
					    del.mtip := false
 | 
				
			||||||
 | 
					    del.meip := false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    (sup.toBits, del.toBits)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  val delegable_exceptions = UInt(Seq(
 | 
				
			||||||
 | 
					    Causes.misaligned_fetch,
 | 
				
			||||||
 | 
					    Causes.fault_fetch,
 | 
				
			||||||
 | 
					    Causes.breakpoint,
 | 
				
			||||||
 | 
					    Causes.fault_load,
 | 
				
			||||||
 | 
					    Causes.fault_store,
 | 
				
			||||||
 | 
					    Causes.user_ecall).map(1 << _).sum)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val exception = io.exception || io.csr_xcpt
 | 
				
			||||||
 | 
					  val reg_debug = Reg(init=Bool(false))
 | 
				
			||||||
 | 
					  val reg_dpc = Reg(UInt(width = vaddrBitsExtended))
 | 
				
			||||||
 | 
					  val reg_dscratch = Reg(UInt(width = xLen))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val reg_singleStepped = Reg(Bool())
 | 
				
			||||||
 | 
					  when (io.retire(0) || exception) { reg_singleStepped := true }
 | 
				
			||||||
 | 
					  when (!io.singleStep) { reg_singleStepped := false }
 | 
				
			||||||
 | 
					  assert(!io.singleStep || io.retire <= UInt(1))
 | 
				
			||||||
 | 
					  assert(!reg_singleStepped || io.retire === UInt(0))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val reg_tdrselect = Reg(new TDRSelect)
 | 
				
			||||||
 | 
					  val reg_bp = Reg(Vec(1 << log2Up(p(NBreakpoints)), new BP))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val reg_mie = Reg(init=UInt(0, xLen))
 | 
				
			||||||
 | 
					  val reg_mideleg = Reg(init=UInt(0, xLen))
 | 
				
			||||||
 | 
					  val reg_medeleg = Reg(init=UInt(0, xLen))
 | 
				
			||||||
 | 
					  val reg_mip = Reg(new MIP)
 | 
				
			||||||
 | 
					  val reg_mepc = Reg(UInt(width = vaddrBitsExtended))
 | 
				
			||||||
 | 
					  val reg_mcause = Reg(Bits(width = xLen))
 | 
				
			||||||
 | 
					  val reg_mbadaddr = Reg(UInt(width = vaddrBitsExtended))
 | 
				
			||||||
 | 
					  val reg_mscratch = Reg(Bits(width = xLen))
 | 
				
			||||||
 | 
					  val reg_mtvec = Reg(init=UInt(p(MtvecInit), paddrBits min xLen))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val reg_sepc = Reg(UInt(width = vaddrBitsExtended))
 | 
				
			||||||
 | 
					  val reg_scause = Reg(Bits(width = xLen))
 | 
				
			||||||
 | 
					  val reg_sbadaddr = Reg(UInt(width = vaddrBitsExtended))
 | 
				
			||||||
 | 
					  val reg_sscratch = Reg(Bits(width = xLen))
 | 
				
			||||||
 | 
					  val reg_stvec = Reg(UInt(width = vaddrBits))
 | 
				
			||||||
 | 
					  val reg_sptbr = Reg(new PTBR)
 | 
				
			||||||
 | 
					  val reg_wfi = Reg(init=Bool(false))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val reg_fflags = Reg(UInt(width = 5))
 | 
				
			||||||
 | 
					  val reg_frm = Reg(UInt(width = 3))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val reg_instret = WideCounter(64, io.retire)
 | 
				
			||||||
 | 
					  val reg_cycle: UInt = if (enableCommitLog) { reg_instret } else { WideCounter(64) }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val mip = Wire(init=reg_mip)
 | 
				
			||||||
 | 
					  mip.rocc := io.rocc.interrupt
 | 
				
			||||||
 | 
					  val read_mip = mip.toBits & supported_interrupts
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val pending_interrupts = read_mip & reg_mie
 | 
				
			||||||
 | 
					  val m_interrupts = Mux(!reg_debug && (reg_mstatus.prv < PRV.M || (reg_mstatus.prv === PRV.M && reg_mstatus.mie)), pending_interrupts & ~reg_mideleg, UInt(0))
 | 
				
			||||||
 | 
					  val s_interrupts = Mux(!reg_debug && (reg_mstatus.prv < PRV.S || (reg_mstatus.prv === PRV.S && reg_mstatus.sie)), pending_interrupts & reg_mideleg, UInt(0))
 | 
				
			||||||
 | 
					  val all_interrupts = m_interrupts | s_interrupts
 | 
				
			||||||
 | 
					  val interruptMSB = BigInt(1) << (xLen-1)
 | 
				
			||||||
 | 
					  val interruptCause = interruptMSB + PriorityEncoder(all_interrupts)
 | 
				
			||||||
 | 
					  io.interrupt := all_interrupts.orR && !io.singleStep || reg_singleStepped
 | 
				
			||||||
 | 
					  io.interrupt_cause := interruptCause
 | 
				
			||||||
 | 
					  io.bp := reg_bp take p(NBreakpoints)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val debugIntCause = reg_mip.getWidth
 | 
				
			||||||
 | 
					  // debug interrupts are only masked by being in debug mode
 | 
				
			||||||
 | 
					  when (Bool(usingDebug) && reg_dcsr.debugint && !reg_debug) {
 | 
				
			||||||
 | 
					    io.interrupt := true
 | 
				
			||||||
 | 
					    io.interrupt_cause := interruptMSB + debugIntCause
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val system_insn = io.rw.cmd === CSR.I
 | 
				
			||||||
 | 
					  val cpu_ren = io.rw.cmd =/= CSR.N && !system_insn
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val isa_string = "IM" +
 | 
				
			||||||
 | 
					    (if (usingVM) "S" else "") +
 | 
				
			||||||
 | 
					    (if (usingUser) "U" else "") +
 | 
				
			||||||
 | 
					    (if (usingAtomics) "A" else "") +
 | 
				
			||||||
 | 
					    (if (usingFPU) "FD" else "") +
 | 
				
			||||||
 | 
					    (if (usingRoCC) "X" else "")
 | 
				
			||||||
 | 
					  val isa = (BigInt(log2Ceil(xLen) - 4) << (xLen-2)) |
 | 
				
			||||||
 | 
					    isa_string.map(x => 1 << (x - 'A')).reduce(_|_)
 | 
				
			||||||
 | 
					  val read_mstatus = io.status.toBits()(xLen-1,0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val read_mapping = collection.mutable.LinkedHashMap[Int,Bits](
 | 
				
			||||||
 | 
					    CSRs.tdrselect -> reg_tdrselect.toBits,
 | 
				
			||||||
 | 
					    CSRs.tdrdata1 -> reg_bp(reg_tdrselect.tdrindex).control.toBits,
 | 
				
			||||||
 | 
					    CSRs.tdrdata2 -> reg_bp(reg_tdrselect.tdrindex).address,
 | 
				
			||||||
 | 
					    CSRs.mimpid -> UInt(0),
 | 
				
			||||||
 | 
					    CSRs.marchid -> UInt(0),
 | 
				
			||||||
 | 
					    CSRs.mvendorid -> UInt(0),
 | 
				
			||||||
 | 
					    CSRs.mcycle -> reg_cycle,
 | 
				
			||||||
 | 
					    CSRs.minstret -> reg_instret,
 | 
				
			||||||
 | 
					    CSRs.mucounteren -> UInt(0),
 | 
				
			||||||
 | 
					    CSRs.mutime_delta -> UInt(0),
 | 
				
			||||||
 | 
					    CSRs.mucycle_delta -> UInt(0),
 | 
				
			||||||
 | 
					    CSRs.muinstret_delta -> UInt(0),
 | 
				
			||||||
 | 
					    CSRs.misa -> UInt(isa),
 | 
				
			||||||
 | 
					    CSRs.mstatus -> read_mstatus,
 | 
				
			||||||
 | 
					    CSRs.mtvec -> reg_mtvec,
 | 
				
			||||||
 | 
					    CSRs.mip -> read_mip,
 | 
				
			||||||
 | 
					    CSRs.mie -> reg_mie,
 | 
				
			||||||
 | 
					    CSRs.mideleg -> reg_mideleg,
 | 
				
			||||||
 | 
					    CSRs.medeleg -> reg_medeleg,
 | 
				
			||||||
 | 
					    CSRs.mscratch -> reg_mscratch,
 | 
				
			||||||
 | 
					    CSRs.mepc -> reg_mepc.sextTo(xLen),
 | 
				
			||||||
 | 
					    CSRs.mbadaddr -> reg_mbadaddr.sextTo(xLen),
 | 
				
			||||||
 | 
					    CSRs.mcause -> reg_mcause,
 | 
				
			||||||
 | 
					    CSRs.mhartid -> io.prci.id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (usingDebug) {
 | 
				
			||||||
 | 
					    read_mapping += CSRs.dcsr -> reg_dcsr.toBits
 | 
				
			||||||
 | 
					    read_mapping += CSRs.dpc -> reg_dpc.toBits
 | 
				
			||||||
 | 
					    read_mapping += CSRs.dscratch -> reg_dscratch.toBits
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (usingFPU) {
 | 
				
			||||||
 | 
					    read_mapping += CSRs.fflags -> reg_fflags
 | 
				
			||||||
 | 
					    read_mapping += CSRs.frm -> reg_frm
 | 
				
			||||||
 | 
					    read_mapping += CSRs.fcsr -> Cat(reg_frm, reg_fflags)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (usingVM) {
 | 
				
			||||||
 | 
					    val read_sie = reg_mie & reg_mideleg
 | 
				
			||||||
 | 
					    val read_sip = read_mip & reg_mideleg
 | 
				
			||||||
 | 
					    val read_sstatus = Wire(init=io.status)
 | 
				
			||||||
 | 
					    read_sstatus.vm := 0
 | 
				
			||||||
 | 
					    read_sstatus.mprv := 0
 | 
				
			||||||
 | 
					    read_sstatus.mpp := 0
 | 
				
			||||||
 | 
					    read_sstatus.hpp := 0
 | 
				
			||||||
 | 
					    read_sstatus.mpie := 0
 | 
				
			||||||
 | 
					    read_sstatus.hpie := 0
 | 
				
			||||||
 | 
					    read_sstatus.mie := 0
 | 
				
			||||||
 | 
					    read_sstatus.hie := 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    read_mapping += CSRs.sstatus -> (read_sstatus.toBits())(xLen-1,0)
 | 
				
			||||||
 | 
					    read_mapping += CSRs.sip -> read_sip.toBits
 | 
				
			||||||
 | 
					    read_mapping += CSRs.sie -> read_sie.toBits
 | 
				
			||||||
 | 
					    read_mapping += CSRs.sscratch -> reg_sscratch
 | 
				
			||||||
 | 
					    read_mapping += CSRs.scause -> reg_scause
 | 
				
			||||||
 | 
					    read_mapping += CSRs.sbadaddr -> reg_sbadaddr.sextTo(xLen)
 | 
				
			||||||
 | 
					    read_mapping += CSRs.sptbr -> reg_sptbr.toBits
 | 
				
			||||||
 | 
					    read_mapping += CSRs.sepc -> reg_sepc.sextTo(xLen)
 | 
				
			||||||
 | 
					    read_mapping += CSRs.stvec -> reg_stvec.sextTo(xLen)
 | 
				
			||||||
 | 
					    read_mapping += CSRs.mscounteren -> UInt(0)
 | 
				
			||||||
 | 
					    read_mapping += CSRs.mstime_delta -> UInt(0)
 | 
				
			||||||
 | 
					    read_mapping += CSRs.mscycle_delta -> UInt(0)
 | 
				
			||||||
 | 
					    read_mapping += CSRs.msinstret_delta -> UInt(0)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (xLen == 32) {
 | 
				
			||||||
 | 
					    read_mapping += CSRs.mcycleh -> (reg_cycle >> 32)
 | 
				
			||||||
 | 
					    read_mapping += CSRs.minstreth -> (reg_instret >> 32)
 | 
				
			||||||
 | 
					    read_mapping += CSRs.mutime_deltah -> UInt(0)
 | 
				
			||||||
 | 
					    read_mapping += CSRs.mucycle_deltah -> UInt(0)
 | 
				
			||||||
 | 
					    read_mapping += CSRs.muinstret_deltah -> UInt(0)
 | 
				
			||||||
 | 
					    if (usingVM) {
 | 
				
			||||||
 | 
					      read_mapping += CSRs.mstime_deltah -> UInt(0)
 | 
				
			||||||
 | 
					      read_mapping += CSRs.mscycle_deltah -> UInt(0)
 | 
				
			||||||
 | 
					      read_mapping += CSRs.msinstret_deltah -> UInt(0)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  for (i <- 0 until nCustomMrwCsrs) {
 | 
				
			||||||
 | 
					    val addr = 0xff0 + i
 | 
				
			||||||
 | 
					    require(addr < (1 << CSR.ADDRSZ))
 | 
				
			||||||
 | 
					    require(!read_mapping.contains(addr), "custom MRW CSR address " + i + " is already in use")
 | 
				
			||||||
 | 
					    read_mapping += addr -> io.custom_mrw_csrs(i)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  for ((addr, i) <- roccCsrs.zipWithIndex) {
 | 
				
			||||||
 | 
					    require(!read_mapping.contains(addr), "RoCC: CSR address " + addr + " is already in use")
 | 
				
			||||||
 | 
					    read_mapping += addr -> io.rocc.csr.rdata(i)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val decoded_addr = read_mapping map { case (k, v) => k -> (io.rw.addr === k) }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val addr_valid = decoded_addr.values.reduce(_||_)
 | 
				
			||||||
 | 
					  val fp_csr =
 | 
				
			||||||
 | 
					    if (usingFPU) decoded_addr(CSRs.fflags) || decoded_addr(CSRs.frm) || decoded_addr(CSRs.fcsr)
 | 
				
			||||||
 | 
					    else Bool(false)
 | 
				
			||||||
 | 
					  val csr_debug = Bool(usingDebug) && io.rw.addr(5)
 | 
				
			||||||
 | 
					  val csr_addr_priv = Cat(io.rw.addr(6,5).andR, io.rw.addr(9,8))
 | 
				
			||||||
 | 
					  val priv_sufficient = Cat(reg_debug, reg_mstatus.prv) >= csr_addr_priv
 | 
				
			||||||
 | 
					  val read_only = io.rw.addr(11,10).andR
 | 
				
			||||||
 | 
					  val cpu_wen = cpu_ren && io.rw.cmd =/= CSR.R && priv_sufficient
 | 
				
			||||||
 | 
					  val wen = cpu_wen && !read_only
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val wdata = (Mux((io.rw.cmd === CSR.S || io.rw.cmd === CSR.C), io.rw.rdata, UInt(0)) |
 | 
				
			||||||
 | 
					               Mux(io.rw.cmd =/= CSR.C, io.rw.wdata, UInt(0))) &
 | 
				
			||||||
 | 
					              ~Mux(io.rw.cmd === CSR.C, io.rw.wdata, UInt(0))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val do_system_insn = priv_sufficient && system_insn
 | 
				
			||||||
 | 
					  val opcode = UInt(1) << io.rw.addr(2,0)
 | 
				
			||||||
 | 
					  val insn_call = do_system_insn && opcode(0)
 | 
				
			||||||
 | 
					  val insn_break = do_system_insn && opcode(1)
 | 
				
			||||||
 | 
					  val insn_ret = do_system_insn && opcode(2)
 | 
				
			||||||
 | 
					  val insn_sfence_vm = do_system_insn && opcode(4)
 | 
				
			||||||
 | 
					  val insn_wfi = do_system_insn && opcode(5)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  io.csr_xcpt := (cpu_wen && read_only) ||
 | 
				
			||||||
 | 
					    (cpu_ren && (!priv_sufficient || !addr_valid || fp_csr && !io.status.fs.orR)) ||
 | 
				
			||||||
 | 
					    (system_insn && !priv_sufficient) ||
 | 
				
			||||||
 | 
					    insn_call || insn_break
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  when (insn_wfi) { reg_wfi := true }
 | 
				
			||||||
 | 
					  when (pending_interrupts.orR) { reg_wfi := false }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val cause =
 | 
				
			||||||
 | 
					    Mux(!io.csr_xcpt, io.cause,
 | 
				
			||||||
 | 
					    Mux(insn_call, reg_mstatus.prv + Causes.user_ecall,
 | 
				
			||||||
 | 
					    Mux[UInt](insn_break, Causes.breakpoint, Causes.illegal_instruction)))
 | 
				
			||||||
 | 
					  val cause_lsbs = cause(log2Up(xLen)-1,0)
 | 
				
			||||||
 | 
					  val causeIsDebugInt = cause(xLen-1) && cause_lsbs === debugIntCause
 | 
				
			||||||
 | 
					  val causeIsDebugBreak = cause === Causes.breakpoint && Cat(reg_dcsr.ebreakm, reg_dcsr.ebreakh, reg_dcsr.ebreaks, reg_dcsr.ebreaku)(reg_mstatus.prv)
 | 
				
			||||||
 | 
					  val trapToDebug = Bool(usingDebug) && (reg_singleStepped || causeIsDebugInt || causeIsDebugBreak || reg_debug)
 | 
				
			||||||
 | 
					  val delegate = Bool(p(UseVM)) && reg_mstatus.prv < PRV.M && Mux(cause(xLen-1), reg_mideleg(cause_lsbs), reg_medeleg(cause_lsbs))
 | 
				
			||||||
 | 
					  val debugTVec = Mux(reg_debug, UInt(0x808), UInt(0x800))
 | 
				
			||||||
 | 
					  val tvec = Mux(trapToDebug, debugTVec, Mux(delegate, reg_stvec.sextTo(vaddrBitsExtended), reg_mtvec))
 | 
				
			||||||
 | 
					  val epc = Mux(csr_debug, reg_dpc, Mux(Bool(p(UseVM)) && !csr_addr_priv(1), reg_sepc, reg_mepc))
 | 
				
			||||||
 | 
					  io.fatc := insn_sfence_vm
 | 
				
			||||||
 | 
					  io.evec := Mux(exception, tvec, epc)
 | 
				
			||||||
 | 
					  io.ptbr := reg_sptbr
 | 
				
			||||||
 | 
					  io.eret := insn_ret
 | 
				
			||||||
 | 
					  io.singleStep := reg_dcsr.step && !reg_debug
 | 
				
			||||||
 | 
					  io.status := reg_mstatus
 | 
				
			||||||
 | 
					  io.status.sd := io.status.fs.andR || io.status.xs.andR
 | 
				
			||||||
 | 
					  io.status.debug := reg_debug
 | 
				
			||||||
 | 
					  if (xLen == 32)
 | 
				
			||||||
 | 
					    io.status.sd_rv32 := io.status.sd
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  when (exception) {
 | 
				
			||||||
 | 
					    val epc = ~(~io.pc | (coreInstBytes-1))
 | 
				
			||||||
 | 
					    val pie = read_mstatus(reg_mstatus.prv)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    when (trapToDebug) {
 | 
				
			||||||
 | 
					      reg_debug := true
 | 
				
			||||||
 | 
					      reg_dpc := epc
 | 
				
			||||||
 | 
					      reg_dcsr.cause := Mux(reg_singleStepped, UInt(4), Mux(causeIsDebugInt, UInt(3), UInt(1)))
 | 
				
			||||||
 | 
					      reg_dcsr.prv := reg_mstatus.prv
 | 
				
			||||||
 | 
					    }.elsewhen (delegate) {
 | 
				
			||||||
 | 
					      reg_sepc := epc
 | 
				
			||||||
 | 
					      reg_scause := cause
 | 
				
			||||||
 | 
					      reg_sbadaddr := io.badaddr
 | 
				
			||||||
 | 
					      reg_mstatus.spie := pie
 | 
				
			||||||
 | 
					      reg_mstatus.spp := reg_mstatus.prv
 | 
				
			||||||
 | 
					      reg_mstatus.sie := false
 | 
				
			||||||
 | 
					      reg_mstatus.prv := PRV.S
 | 
				
			||||||
 | 
					    }.otherwise {
 | 
				
			||||||
 | 
					      reg_mepc := epc
 | 
				
			||||||
 | 
					      reg_mcause := cause
 | 
				
			||||||
 | 
					      reg_mbadaddr := io.badaddr
 | 
				
			||||||
 | 
					      reg_mstatus.mpie := pie
 | 
				
			||||||
 | 
					      reg_mstatus.mpp := reg_mstatus.prv
 | 
				
			||||||
 | 
					      reg_mstatus.mie := false
 | 
				
			||||||
 | 
					      reg_mstatus.prv := PRV.M
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  when (insn_ret) {
 | 
				
			||||||
 | 
					    when (Bool(p(UseVM)) && !csr_addr_priv(1)) {
 | 
				
			||||||
 | 
					      when (reg_mstatus.spp.toBool) { reg_mstatus.sie := reg_mstatus.spie }
 | 
				
			||||||
 | 
					      reg_mstatus.spie := false
 | 
				
			||||||
 | 
					      reg_mstatus.spp := PRV.U
 | 
				
			||||||
 | 
					      reg_mstatus.prv := reg_mstatus.spp
 | 
				
			||||||
 | 
					    }.elsewhen (csr_debug) {
 | 
				
			||||||
 | 
					      reg_mstatus.prv := reg_dcsr.prv
 | 
				
			||||||
 | 
					      reg_debug := false
 | 
				
			||||||
 | 
					    }.otherwise {
 | 
				
			||||||
 | 
					      when (reg_mstatus.mpp(1)) { reg_mstatus.mie := reg_mstatus.mpie }
 | 
				
			||||||
 | 
					      .elsewhen (Bool(usingVM) && reg_mstatus.mpp(0)) { reg_mstatus.sie := reg_mstatus.mpie }
 | 
				
			||||||
 | 
					      reg_mstatus.mpie := false
 | 
				
			||||||
 | 
					      reg_mstatus.mpp := PRV.U
 | 
				
			||||||
 | 
					      reg_mstatus.prv := reg_mstatus.mpp
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  assert(PopCount(insn_ret :: io.exception :: io.csr_xcpt :: Nil) <= 1, "these conditions must be mutually exclusive")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  io.time := reg_cycle
 | 
				
			||||||
 | 
					  io.csr_stall := reg_wfi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  io.rw.rdata := Mux1H(for ((k, v) <- read_mapping) yield decoded_addr(k) -> v)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  io.fcsr_rm := reg_frm
 | 
				
			||||||
 | 
					  when (io.fcsr_flags.valid) {
 | 
				
			||||||
 | 
					    reg_fflags := reg_fflags | io.fcsr_flags.bits
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val supportedModes = Vec((PRV.M +: (if (usingUser) Some(PRV.U) else None) ++: (if (usingVM) Seq(PRV.S) else Nil)).map(UInt(_)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  when (wen) {
 | 
				
			||||||
 | 
					    when (decoded_addr(CSRs.mstatus)) {
 | 
				
			||||||
 | 
					      val new_mstatus = new MStatus().fromBits(wdata)
 | 
				
			||||||
 | 
					      reg_mstatus.mie := new_mstatus.mie
 | 
				
			||||||
 | 
					      reg_mstatus.mpie := new_mstatus.mpie
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (supportedModes.size > 1) {
 | 
				
			||||||
 | 
					        reg_mstatus.mprv := new_mstatus.mprv
 | 
				
			||||||
 | 
					        when (supportedModes contains new_mstatus.mpp) { reg_mstatus.mpp := new_mstatus.mpp }
 | 
				
			||||||
 | 
					        if (supportedModes.size > 2) {
 | 
				
			||||||
 | 
					          reg_mstatus.mxr := new_mstatus.mxr
 | 
				
			||||||
 | 
					          reg_mstatus.pum := new_mstatus.pum
 | 
				
			||||||
 | 
					          reg_mstatus.spp := new_mstatus.spp
 | 
				
			||||||
 | 
					          reg_mstatus.spie := new_mstatus.spie
 | 
				
			||||||
 | 
					          reg_mstatus.sie := new_mstatus.sie
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (usingVM) {
 | 
				
			||||||
 | 
					        require(if (xLen == 32) pgLevels == 2 else pgLevels > 2 && pgLevels < 6)
 | 
				
			||||||
 | 
					        val vm_on = 6 + pgLevels // TODO Sv48 support should imply Sv39 support
 | 
				
			||||||
 | 
					        when (new_mstatus.vm === 0) { reg_mstatus.vm := 0 }
 | 
				
			||||||
 | 
					        when (new_mstatus.vm === vm_on) { reg_mstatus.vm := vm_on }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if (usingVM || usingFPU) reg_mstatus.fs := Fill(2, new_mstatus.fs.orR)
 | 
				
			||||||
 | 
					      if (usingRoCC) reg_mstatus.xs := Fill(2, new_mstatus.xs.orR)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    when (decoded_addr(CSRs.mip)) {
 | 
				
			||||||
 | 
					      val new_mip = new MIP().fromBits(wdata)
 | 
				
			||||||
 | 
					      if (usingVM) {
 | 
				
			||||||
 | 
					        reg_mip.ssip := new_mip.ssip
 | 
				
			||||||
 | 
					        reg_mip.stip := new_mip.stip
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    when (decoded_addr(CSRs.mie))      { reg_mie := wdata & supported_interrupts }
 | 
				
			||||||
 | 
					    when (decoded_addr(CSRs.mepc))     { reg_mepc := ~(~wdata | (coreInstBytes-1)) }
 | 
				
			||||||
 | 
					    when (decoded_addr(CSRs.mscratch)) { reg_mscratch := wdata }
 | 
				
			||||||
 | 
					    if (p(MtvecWritable))
 | 
				
			||||||
 | 
					      when (decoded_addr(CSRs.mtvec))  { reg_mtvec := wdata >> 2 << 2 }
 | 
				
			||||||
 | 
					    when (decoded_addr(CSRs.mcause))   { reg_mcause := wdata & UInt((BigInt(1) << (xLen-1)) + 31) /* only implement 5 LSBs and MSB */ }
 | 
				
			||||||
 | 
					    when (decoded_addr(CSRs.mbadaddr)) { reg_mbadaddr := wdata(vaddrBitsExtended-1,0) }
 | 
				
			||||||
 | 
					    if (usingFPU) {
 | 
				
			||||||
 | 
					      when (decoded_addr(CSRs.fflags)) { reg_fflags := wdata }
 | 
				
			||||||
 | 
					      when (decoded_addr(CSRs.frm))    { reg_frm := wdata }
 | 
				
			||||||
 | 
					      when (decoded_addr(CSRs.fcsr))   { reg_fflags := wdata; reg_frm := wdata >> reg_fflags.getWidth }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (usingDebug) {
 | 
				
			||||||
 | 
					      when (decoded_addr(CSRs.dcsr)) {
 | 
				
			||||||
 | 
					        val new_dcsr = new DCSR().fromBits(wdata)
 | 
				
			||||||
 | 
					        reg_dcsr.halt := new_dcsr.halt
 | 
				
			||||||
 | 
					        reg_dcsr.step := new_dcsr.step
 | 
				
			||||||
 | 
					        reg_dcsr.ebreakm := new_dcsr.ebreakm
 | 
				
			||||||
 | 
					        if (usingVM) reg_dcsr.ebreaks := new_dcsr.ebreaks
 | 
				
			||||||
 | 
					        if (usingUser) reg_dcsr.ebreaku := new_dcsr.ebreaku
 | 
				
			||||||
 | 
					        if (supportedModes.size > 1) reg_dcsr.prv := new_dcsr.prv
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      when (decoded_addr(CSRs.dpc))      { reg_dpc := ~(~wdata | (coreInstBytes-1)) }
 | 
				
			||||||
 | 
					      when (decoded_addr(CSRs.dscratch)) { reg_dscratch := wdata }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (usingVM) {
 | 
				
			||||||
 | 
					      when (decoded_addr(CSRs.sstatus)) {
 | 
				
			||||||
 | 
					        val new_sstatus = new MStatus().fromBits(wdata)
 | 
				
			||||||
 | 
					        reg_mstatus.sie := new_sstatus.sie
 | 
				
			||||||
 | 
					        reg_mstatus.spie := new_sstatus.spie
 | 
				
			||||||
 | 
					        reg_mstatus.spp := new_sstatus.spp
 | 
				
			||||||
 | 
					        reg_mstatus.pum := new_sstatus.pum
 | 
				
			||||||
 | 
					        reg_mstatus.fs := Fill(2, new_sstatus.fs.orR) // even without an FPU
 | 
				
			||||||
 | 
					        if (usingRoCC) reg_mstatus.xs := Fill(2, new_sstatus.xs.orR)
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      when (decoded_addr(CSRs.sip)) {
 | 
				
			||||||
 | 
					        val new_sip = new MIP().fromBits(wdata)
 | 
				
			||||||
 | 
					        reg_mip.ssip := new_sip.ssip
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      when (decoded_addr(CSRs.sie))      { reg_mie := (reg_mie & ~reg_mideleg) | (wdata & reg_mideleg) }
 | 
				
			||||||
 | 
					      when (decoded_addr(CSRs.sscratch)) { reg_sscratch := wdata }
 | 
				
			||||||
 | 
					      when (decoded_addr(CSRs.sptbr))    { reg_sptbr.ppn := wdata(ppnBits-1,0) }
 | 
				
			||||||
 | 
					      when (decoded_addr(CSRs.sepc))     { reg_sepc := ~(~wdata | (coreInstBytes-1)) }
 | 
				
			||||||
 | 
					      when (decoded_addr(CSRs.stvec))    { reg_stvec := wdata >> 2 << 2 }
 | 
				
			||||||
 | 
					      when (decoded_addr(CSRs.scause))   { reg_scause := wdata & UInt((BigInt(1) << (xLen-1)) + 31) /* only implement 5 LSBs and MSB */ }
 | 
				
			||||||
 | 
					      when (decoded_addr(CSRs.sbadaddr)) { reg_sbadaddr := wdata(vaddrBitsExtended-1,0) }
 | 
				
			||||||
 | 
					      when (decoded_addr(CSRs.mideleg))  { reg_mideleg := wdata & delegable_interrupts }
 | 
				
			||||||
 | 
					      when (decoded_addr(CSRs.medeleg))  { reg_medeleg := wdata & delegable_exceptions }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (p(NBreakpoints) > 0) {
 | 
				
			||||||
 | 
					      val newTDR = new TDRSelect().fromBits(wdata)
 | 
				
			||||||
 | 
					      when (decoded_addr(CSRs.tdrselect)) { reg_tdrselect.tdrindex := newTDR.tdrindex }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      when (reg_tdrselect.tdrmode || reg_debug) {
 | 
				
			||||||
 | 
					        when (decoded_addr(CSRs.tdrdata1)) {
 | 
				
			||||||
 | 
					          val newBPC = new BPControl().fromBits(wdata)
 | 
				
			||||||
 | 
					          reg_bp(reg_tdrselect.tdrindex).control := newBPC
 | 
				
			||||||
 | 
					          reg_bp(reg_tdrselect.tdrindex).control.bpmatch := newBPC.bpmatch & 2 /* exact/NAPOT only */
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        when (decoded_addr(CSRs.tdrdata2)) { reg_bp(reg_tdrselect.tdrindex).address := wdata }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  reg_mip := io.prci.interrupts
 | 
				
			||||||
 | 
					  reg_dcsr.debugint := io.prci.interrupts.debug
 | 
				
			||||||
 | 
					  reg_dcsr.hwbpcount := UInt(p(NBreakpoints))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  io.rocc.csr.waddr := io.rw.addr
 | 
				
			||||||
 | 
					  io.rocc.csr.wdata := wdata
 | 
				
			||||||
 | 
					  io.rocc.csr.wen := wen
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (!usingUser) {
 | 
				
			||||||
 | 
					    reg_mstatus.mpp := PRV.M
 | 
				
			||||||
 | 
					    reg_mstatus.prv := PRV.M
 | 
				
			||||||
 | 
					    reg_mstatus.mprv := false
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  reg_sptbr.asid := 0
 | 
				
			||||||
 | 
					  reg_tdrselect.reserved := 0
 | 
				
			||||||
 | 
					  reg_tdrselect.tdrmode := true // TODO support D-mode breakpoint theft
 | 
				
			||||||
 | 
					  if (reg_bp.isEmpty) reg_tdrselect.tdrindex := 0
 | 
				
			||||||
 | 
					  for (bpc <- reg_bp map {_.control}) {
 | 
				
			||||||
 | 
					    bpc.tdrtype := bpc.tdrType
 | 
				
			||||||
 | 
					    bpc.bpamaskmax := bpc.bpaMaskMax
 | 
				
			||||||
 | 
					    bpc.reserved := 0
 | 
				
			||||||
 | 
					    bpc.bpaction := 0
 | 
				
			||||||
 | 
					    bpc.h := false
 | 
				
			||||||
 | 
					    if (!usingVM) bpc.s := false
 | 
				
			||||||
 | 
					    if (!usingUser) bpc.u := false
 | 
				
			||||||
 | 
					    if (!usingVM && !usingUser) bpc.m := true
 | 
				
			||||||
 | 
					    when (reset) {
 | 
				
			||||||
 | 
					      bpc.r := false
 | 
				
			||||||
 | 
					      bpc.w := false
 | 
				
			||||||
 | 
					      bpc.x := false
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  for (bp <- reg_bp drop p(NBreakpoints))
 | 
				
			||||||
 | 
					    bp := new BP().fromBits(0)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										447
									
								
								rocket/src/main/scala/dcache.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										447
									
								
								rocket/src/main/scala/dcache.scala
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,447 @@
 | 
				
			|||||||
 | 
					// See LICENSE for license details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package rocket
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import Chisel._
 | 
				
			||||||
 | 
					import junctions._
 | 
				
			||||||
 | 
					import uncore.tilelink._
 | 
				
			||||||
 | 
					import uncore.agents._
 | 
				
			||||||
 | 
					import uncore.coherence._
 | 
				
			||||||
 | 
					import uncore.util._
 | 
				
			||||||
 | 
					import uncore.constants._
 | 
				
			||||||
 | 
					import cde.{Parameters, Field}
 | 
				
			||||||
 | 
					import Util._
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class DCacheDataReq(implicit p: Parameters) extends L1HellaCacheBundle()(p) {
 | 
				
			||||||
 | 
					  val addr = Bits(width = untagBits)
 | 
				
			||||||
 | 
					  val write = Bool()
 | 
				
			||||||
 | 
					  val wdata = Bits(width = rowBits)
 | 
				
			||||||
 | 
					  val wmask = Bits(width = rowBytes)
 | 
				
			||||||
 | 
					  val way_en = Bits(width = nWays)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class DCacheDataArray(implicit p: Parameters) extends L1HellaCacheModule()(p) {
 | 
				
			||||||
 | 
					  val io = new Bundle {
 | 
				
			||||||
 | 
					    val req = Valid(new DCacheDataReq).flip
 | 
				
			||||||
 | 
					    val resp = Vec(nWays, Bits(OUTPUT, rowBits))
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val addr = io.req.bits.addr >> rowOffBits
 | 
				
			||||||
 | 
					  for (w <- 0 until nWays) {
 | 
				
			||||||
 | 
					    val array = SeqMem(nSets*refillCycles, Vec(rowBytes, Bits(width=8)))
 | 
				
			||||||
 | 
					    val valid = io.req.valid && (Bool(nWays == 1) || io.req.bits.way_en(w))
 | 
				
			||||||
 | 
					    when (valid && io.req.bits.write) {
 | 
				
			||||||
 | 
					      val data = Vec.tabulate(rowBytes)(i => io.req.bits.wdata(8*(i+1)-1, 8*i))
 | 
				
			||||||
 | 
					      array.write(addr, data, io.req.bits.wmask.toBools)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    io.resp(w) := array.read(addr, valid && !io.req.bits.write).toBits
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class DCache(implicit p: Parameters) extends L1HellaCacheModule()(p) {
 | 
				
			||||||
 | 
					  val io = new Bundle {
 | 
				
			||||||
 | 
					    val cpu = (new HellaCacheIO).flip
 | 
				
			||||||
 | 
					    val ptw = new TLBPTWIO()
 | 
				
			||||||
 | 
					    val mem = new ClientTileLinkIO
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val fq = Module(new FinishQueue(1))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  require(rowBits == encRowBits) // no ECC
 | 
				
			||||||
 | 
					  require(refillCyclesPerBeat == 1)
 | 
				
			||||||
 | 
					  require(rowBits >= coreDataBits)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // tags
 | 
				
			||||||
 | 
					  val replacer = p(Replacer)()
 | 
				
			||||||
 | 
					  def onReset = L1Metadata(UInt(0), ClientMetadata.onReset)
 | 
				
			||||||
 | 
					  val meta = Module(new MetadataArray(onReset _))
 | 
				
			||||||
 | 
					  val metaReadArb = Module(new Arbiter(new MetaReadReq, 3))
 | 
				
			||||||
 | 
					  val metaWriteArb = Module(new Arbiter(new L1MetaWriteReq, 3))
 | 
				
			||||||
 | 
					  meta.io.read <> metaReadArb.io.out
 | 
				
			||||||
 | 
					  meta.io.write <> metaWriteArb.io.out
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // data
 | 
				
			||||||
 | 
					  val data = Module(new DCacheDataArray)
 | 
				
			||||||
 | 
					  val dataArb = Module(new Arbiter(new DCacheDataReq, 4))
 | 
				
			||||||
 | 
					  data.io.req <> dataArb.io.out
 | 
				
			||||||
 | 
					  dataArb.io.out.ready := true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val s1_valid = Reg(next=io.cpu.req.fire(), init=Bool(false))
 | 
				
			||||||
 | 
					  val s1_probe = Reg(next=io.mem.probe.fire(), init=Bool(false))
 | 
				
			||||||
 | 
					  val probe_bits = RegEnable(io.mem.probe.bits, io.mem.probe.fire())
 | 
				
			||||||
 | 
					  val s1_nack = Wire(init=Bool(false))
 | 
				
			||||||
 | 
					  val s1_valid_masked = s1_valid && !io.cpu.s1_kill
 | 
				
			||||||
 | 
					  val s1_valid_not_nacked = s1_valid_masked && !s1_nack
 | 
				
			||||||
 | 
					  val s1_req = Reg(io.cpu.req.bits)
 | 
				
			||||||
 | 
					  when (metaReadArb.io.out.valid) {
 | 
				
			||||||
 | 
					    s1_req := io.cpu.req.bits
 | 
				
			||||||
 | 
					    s1_req.addr := Cat(io.cpu.req.bits.addr >> untagBits, metaReadArb.io.out.bits.idx, io.cpu.req.bits.addr(blockOffBits-1,0))
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  val s1_read = isRead(s1_req.cmd)
 | 
				
			||||||
 | 
					  val s1_write = isWrite(s1_req.cmd)
 | 
				
			||||||
 | 
					  val s1_readwrite = s1_read || s1_write
 | 
				
			||||||
 | 
					  val s1_flush_valid = Reg(Bool())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val s_ready :: s_grant_wait :: s_voluntary_writeback :: s_probe_rep_dirty :: s_probe_rep_clean :: s_probe_rep_miss :: s_voluntary_write_meta :: s_probe_write_meta :: Nil = Enum(UInt(), 8)
 | 
				
			||||||
 | 
					  val grant_wait = Reg(init=Bool(false))
 | 
				
			||||||
 | 
					  val release_ack_wait = Reg(init=Bool(false))
 | 
				
			||||||
 | 
					  val release_state = Reg(init=s_ready)
 | 
				
			||||||
 | 
					  val pstore1_valid = Wire(Bool())
 | 
				
			||||||
 | 
					  val pstore2_valid = Reg(Bool())
 | 
				
			||||||
 | 
					  val inWriteback = release_state === s_voluntary_writeback || release_state === s_probe_rep_dirty
 | 
				
			||||||
 | 
					  val releaseWay = Wire(UInt())
 | 
				
			||||||
 | 
					  io.cpu.req.ready := (release_state === s_ready) && !grant_wait && !s1_nack
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // hit initiation path
 | 
				
			||||||
 | 
					  dataArb.io.in(3).valid := io.cpu.req.valid && isRead(io.cpu.req.bits.cmd)
 | 
				
			||||||
 | 
					  dataArb.io.in(3).bits.write := false
 | 
				
			||||||
 | 
					  dataArb.io.in(3).bits.addr := io.cpu.req.bits.addr
 | 
				
			||||||
 | 
					  dataArb.io.in(3).bits.way_en := ~UInt(0, nWays)
 | 
				
			||||||
 | 
					  when (!dataArb.io.in(3).ready && isRead(io.cpu.req.bits.cmd)) { io.cpu.req.ready := false }
 | 
				
			||||||
 | 
					  metaReadArb.io.in(2).valid := io.cpu.req.valid
 | 
				
			||||||
 | 
					  metaReadArb.io.in(2).bits.idx := io.cpu.req.bits.addr(idxMSB, idxLSB)
 | 
				
			||||||
 | 
					  metaReadArb.io.in(2).bits.way_en := ~UInt(0, nWays)
 | 
				
			||||||
 | 
					  when (!metaReadArb.io.in(2).ready) { io.cpu.req.ready := false }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // address translation
 | 
				
			||||||
 | 
					  val tlb = Module(new TLB)
 | 
				
			||||||
 | 
					  io.ptw <> tlb.io.ptw
 | 
				
			||||||
 | 
					  tlb.io.req.valid := s1_valid_masked && s1_readwrite
 | 
				
			||||||
 | 
					  tlb.io.req.bits.passthrough := s1_req.phys
 | 
				
			||||||
 | 
					  tlb.io.req.bits.vpn := s1_req.addr >> pgIdxBits
 | 
				
			||||||
 | 
					  tlb.io.req.bits.instruction := false
 | 
				
			||||||
 | 
					  tlb.io.req.bits.store := s1_write
 | 
				
			||||||
 | 
					  when (!tlb.io.req.ready && !io.cpu.req.bits.phys) { io.cpu.req.ready := false }
 | 
				
			||||||
 | 
					  when (s1_valid && s1_readwrite && tlb.io.resp.miss) { s1_nack := true }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val s1_paddr = Cat(tlb.io.resp.ppn, s1_req.addr(pgIdxBits-1,0))
 | 
				
			||||||
 | 
					  val s1_tag = Mux(s1_probe, probe_bits.addr_block >> idxBits, s1_paddr(paddrBits-1, untagBits))
 | 
				
			||||||
 | 
					  val s1_hit_way = meta.io.resp.map(r => r.coh.isValid() && r.tag === s1_tag).toBits
 | 
				
			||||||
 | 
					  val s1_hit_state = ClientMetadata.onReset.fromBits(
 | 
				
			||||||
 | 
					    meta.io.resp.map(r => Mux(r.tag === s1_tag, r.coh.toBits, UInt(0)))
 | 
				
			||||||
 | 
					    .reduce (_|_))
 | 
				
			||||||
 | 
					  val s1_data_way = Mux(inWriteback, releaseWay, s1_hit_way)
 | 
				
			||||||
 | 
					  val s1_data = Mux1H(s1_data_way, data.io.resp) // retime into s2 if critical
 | 
				
			||||||
 | 
					  val s1_victim_way = Wire(init = replacer.way)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val s2_valid = Reg(next=s1_valid_masked, init=Bool(false))
 | 
				
			||||||
 | 
					  val s2_probe = Reg(next=s1_probe, init=Bool(false))
 | 
				
			||||||
 | 
					  val releaseInFlight = s1_probe || s2_probe || release_state =/= s_ready
 | 
				
			||||||
 | 
					  val s2_valid_masked = s2_valid && Reg(next = !s1_nack)
 | 
				
			||||||
 | 
					  val s2_req = Reg(io.cpu.req.bits)
 | 
				
			||||||
 | 
					  val s2_uncached = Reg(Bool())
 | 
				
			||||||
 | 
					  when (s1_valid_not_nacked || s1_flush_valid) {
 | 
				
			||||||
 | 
					    s2_req := s1_req
 | 
				
			||||||
 | 
					    s2_req.addr := s1_paddr
 | 
				
			||||||
 | 
					    s2_uncached := !tlb.io.resp.cacheable
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  val s2_read = isRead(s2_req.cmd)
 | 
				
			||||||
 | 
					  val s2_write = isWrite(s2_req.cmd)
 | 
				
			||||||
 | 
					  val s2_readwrite = s2_read || s2_write
 | 
				
			||||||
 | 
					  val s2_flush_valid = RegNext(s1_flush_valid)
 | 
				
			||||||
 | 
					  val s2_data = RegEnable(s1_data, s1_valid || inWriteback)
 | 
				
			||||||
 | 
					  val s2_probe_way = RegEnable(s1_hit_way, s1_probe)
 | 
				
			||||||
 | 
					  val s2_probe_state = RegEnable(s1_hit_state, s1_probe)
 | 
				
			||||||
 | 
					  val s2_hit_way = RegEnable(s1_hit_way, s1_valid_not_nacked)
 | 
				
			||||||
 | 
					  val s2_hit_state = RegEnable(s1_hit_state, s1_valid_not_nacked)
 | 
				
			||||||
 | 
					  val s2_hit = s2_hit_state.isHit(s2_req.cmd)
 | 
				
			||||||
 | 
					  val s2_valid_hit = s2_valid_masked && s2_readwrite && s2_hit
 | 
				
			||||||
 | 
					  val s2_valid_miss = s2_valid_masked && s2_readwrite && !s2_hit && !(pstore1_valid || pstore2_valid) && !release_ack_wait
 | 
				
			||||||
 | 
					  val s2_valid_cached_miss = s2_valid_miss && !s2_uncached
 | 
				
			||||||
 | 
					  val s2_victimize = s2_valid_cached_miss || s2_flush_valid
 | 
				
			||||||
 | 
					  val s2_valid_uncached = s2_valid_miss && s2_uncached
 | 
				
			||||||
 | 
					  val s2_victim_way = Mux(s2_hit_state.isValid() && !s2_flush_valid, s2_hit_way, UIntToOH(RegEnable(s1_victim_way, s1_valid_not_nacked || s1_flush_valid)))
 | 
				
			||||||
 | 
					  val s2_victim_tag = RegEnable(meta.io.resp(s1_victim_way).tag, s1_valid_not_nacked || s1_flush_valid)
 | 
				
			||||||
 | 
					  val s2_victim_state = Mux(s2_hit_state.isValid() && !s2_flush_valid, s2_hit_state, RegEnable(meta.io.resp(s1_victim_way).coh, s1_valid_not_nacked || s1_flush_valid))
 | 
				
			||||||
 | 
					  val s2_victim_valid = s2_victim_state.isValid()
 | 
				
			||||||
 | 
					  val s2_victim_dirty = s2_victim_state.requiresVoluntaryWriteback()
 | 
				
			||||||
 | 
					  io.cpu.s2_nack := s2_valid && !s2_valid_hit && !(s2_valid_uncached && io.mem.acquire.ready)
 | 
				
			||||||
 | 
					  when (s2_valid && !s2_valid_hit) { s1_nack := true }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // exceptions
 | 
				
			||||||
 | 
					  val misaligned = new StoreGen(s1_req.typ, s1_req.addr, UInt(0), wordBytes).misaligned
 | 
				
			||||||
 | 
					  io.cpu.xcpt.ma.ld := s1_read && misaligned
 | 
				
			||||||
 | 
					  io.cpu.xcpt.ma.st := s1_write && misaligned
 | 
				
			||||||
 | 
					  io.cpu.xcpt.pf.ld := s1_read && tlb.io.resp.xcpt_ld
 | 
				
			||||||
 | 
					  io.cpu.xcpt.pf.st := s1_write && tlb.io.resp.xcpt_st
 | 
				
			||||||
 | 
					  assert(!(Reg(next=
 | 
				
			||||||
 | 
					    (io.cpu.xcpt.ma.ld || io.cpu.xcpt.ma.st || io.cpu.xcpt.pf.ld || io.cpu.xcpt.pf.st)) &&
 | 
				
			||||||
 | 
					    s2_valid_masked),
 | 
				
			||||||
 | 
					      "DCache exception occurred - cache response not killed.")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // load reservations
 | 
				
			||||||
 | 
					  val s2_lr = Bool(usingAtomics) && s2_req.cmd === M_XLR
 | 
				
			||||||
 | 
					  val s2_sc = Bool(usingAtomics) && s2_req.cmd === M_XSC
 | 
				
			||||||
 | 
					  val lrscCount = Reg(init=UInt(0))
 | 
				
			||||||
 | 
					  val lrscValid = lrscCount > 0
 | 
				
			||||||
 | 
					  val lrscAddr = Reg(UInt())
 | 
				
			||||||
 | 
					  val s2_sc_fail = s2_sc && !(lrscValid && lrscAddr === (s2_req.addr >> blockOffBits))
 | 
				
			||||||
 | 
					  when (s2_valid_hit && s2_lr) {
 | 
				
			||||||
 | 
					    lrscCount := lrscCycles - 1
 | 
				
			||||||
 | 
					    lrscAddr := s2_req.addr >> blockOffBits
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  when (lrscValid) { lrscCount := lrscCount - 1 }
 | 
				
			||||||
 | 
					  when ((s2_valid_hit && s2_sc) || io.cpu.invalidate_lr) { lrscCount := 0 }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // pending store buffer
 | 
				
			||||||
 | 
					  val pstore1_cmd = RegEnable(s1_req.cmd, s1_valid_not_nacked && s1_write)
 | 
				
			||||||
 | 
					  val pstore1_typ = RegEnable(s1_req.typ, s1_valid_not_nacked && s1_write)
 | 
				
			||||||
 | 
					  val pstore1_addr = RegEnable(s1_paddr, s1_valid_not_nacked && s1_write)
 | 
				
			||||||
 | 
					  val pstore1_data = RegEnable(io.cpu.s1_data, s1_valid_not_nacked && s1_write)
 | 
				
			||||||
 | 
					  val pstore1_way = RegEnable(s1_hit_way, s1_valid_not_nacked && s1_write)
 | 
				
			||||||
 | 
					  val pstore1_storegen = new StoreGen(pstore1_typ, pstore1_addr, pstore1_data, wordBytes)
 | 
				
			||||||
 | 
					  val pstore1_storegen_data = Wire(init = pstore1_storegen.data)
 | 
				
			||||||
 | 
					  val pstore1_amo = Bool(usingAtomics) && isRead(pstore1_cmd)
 | 
				
			||||||
 | 
					  val pstore_drain_structural = pstore1_valid && pstore2_valid && ((s1_valid && s1_write) || pstore1_amo)
 | 
				
			||||||
 | 
					  val pstore_drain_opportunistic = !(io.cpu.req.valid && isRead(io.cpu.req.bits.cmd))
 | 
				
			||||||
 | 
					  val pstore_drain_on_miss = releaseInFlight || io.cpu.s2_nack
 | 
				
			||||||
 | 
					  val pstore_drain =
 | 
				
			||||||
 | 
					    Bool(usingAtomics) && pstore_drain_structural ||
 | 
				
			||||||
 | 
					    (((pstore1_valid && !pstore1_amo) || pstore2_valid) && (pstore_drain_opportunistic || pstore_drain_on_miss))
 | 
				
			||||||
 | 
					  pstore1_valid := {
 | 
				
			||||||
 | 
					    val s2_store_valid = s2_valid_hit && s2_write && !s2_sc_fail
 | 
				
			||||||
 | 
					    val pstore1_held = Reg(Bool())
 | 
				
			||||||
 | 
					    assert(!s2_store_valid || !pstore1_held)
 | 
				
			||||||
 | 
					    pstore1_held := (s2_store_valid || pstore1_held) && pstore2_valid && !pstore_drain
 | 
				
			||||||
 | 
					    s2_store_valid || pstore1_held
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  val advance_pstore1 = pstore1_valid && (pstore2_valid === pstore_drain)
 | 
				
			||||||
 | 
					  pstore2_valid := pstore2_valid && !pstore_drain || advance_pstore1
 | 
				
			||||||
 | 
					  val pstore2_addr = RegEnable(pstore1_addr, advance_pstore1)
 | 
				
			||||||
 | 
					  val pstore2_way = RegEnable(pstore1_way, advance_pstore1)
 | 
				
			||||||
 | 
					  val pstore2_storegen_data = RegEnable(pstore1_storegen_data, advance_pstore1)
 | 
				
			||||||
 | 
					  val pstore2_storegen_mask = RegEnable(pstore1_storegen.mask, advance_pstore1)
 | 
				
			||||||
 | 
					  dataArb.io.in(0).valid := pstore_drain
 | 
				
			||||||
 | 
					  dataArb.io.in(0).bits.write := true
 | 
				
			||||||
 | 
					  dataArb.io.in(0).bits.addr := Mux(pstore2_valid, pstore2_addr, pstore1_addr)
 | 
				
			||||||
 | 
					  dataArb.io.in(0).bits.way_en := Mux(pstore2_valid, pstore2_way, pstore1_way)
 | 
				
			||||||
 | 
					  dataArb.io.in(0).bits.wdata := Fill(rowWords, Mux(pstore2_valid, pstore2_storegen_data, pstore1_storegen_data))
 | 
				
			||||||
 | 
					  val pstore_mask_shift = Mux(pstore2_valid, pstore2_addr, pstore1_addr).extract(rowOffBits-1,offsetlsb) << wordOffBits
 | 
				
			||||||
 | 
					  dataArb.io.in(0).bits.wmask := Mux(pstore2_valid, pstore2_storegen_mask, pstore1_storegen.mask) << pstore_mask_shift
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // store->load RAW hazard detection
 | 
				
			||||||
 | 
					  val s1_idx = s1_req.addr(idxMSB, wordOffBits)
 | 
				
			||||||
 | 
					  val s1_raw_hazard = s1_read &&
 | 
				
			||||||
 | 
					    ((pstore1_valid && pstore1_addr(idxMSB, wordOffBits) === s1_idx) ||
 | 
				
			||||||
 | 
					     (pstore2_valid && pstore2_addr(idxMSB, wordOffBits) === s1_idx))
 | 
				
			||||||
 | 
					  when (s1_valid && s1_raw_hazard) { s1_nack := true }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val s2_new_hit_state = s2_hit_state.onHit(s2_req.cmd)
 | 
				
			||||||
 | 
					  metaWriteArb.io.in(0).valid := (s2_valid_hit && s2_hit_state =/= s2_new_hit_state) || (s2_victimize && !s2_victim_dirty)
 | 
				
			||||||
 | 
					  metaWriteArb.io.in(0).bits.way_en := s2_victim_way
 | 
				
			||||||
 | 
					  metaWriteArb.io.in(0).bits.idx := s2_req.addr(idxMSB, idxLSB)
 | 
				
			||||||
 | 
					  metaWriteArb.io.in(0).bits.data.coh := Mux(s2_hit, s2_new_hit_state, ClientMetadata.onReset)
 | 
				
			||||||
 | 
					  metaWriteArb.io.in(0).bits.data.tag := s2_req.addr(paddrBits-1, untagBits)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // acquire
 | 
				
			||||||
 | 
					  val cachedGetMessage = s2_hit_state.makeAcquire(
 | 
				
			||||||
 | 
					    client_xact_id = UInt(0),
 | 
				
			||||||
 | 
					    addr_block = s2_req.addr(paddrBits-1, blockOffBits),
 | 
				
			||||||
 | 
					    op_code = s2_req.cmd)
 | 
				
			||||||
 | 
					  val uncachedGetMessage = Get(
 | 
				
			||||||
 | 
					    client_xact_id = UInt(0),
 | 
				
			||||||
 | 
					    addr_block = s2_req.addr(paddrBits-1, blockOffBits),
 | 
				
			||||||
 | 
					    addr_beat = s2_req.addr(blockOffBits-1, beatOffBits),
 | 
				
			||||||
 | 
					    addr_byte = s2_req.addr(beatOffBits-1, 0),
 | 
				
			||||||
 | 
					    operand_size = s2_req.typ,
 | 
				
			||||||
 | 
					    alloc = Bool(false))
 | 
				
			||||||
 | 
					  val uncachedPutOffset = s2_req.addr.extract(beatOffBits-1, wordOffBits)
 | 
				
			||||||
 | 
					  val uncachedPutMessage = Put(
 | 
				
			||||||
 | 
					    client_xact_id = UInt(0),
 | 
				
			||||||
 | 
					    addr_block = s2_req.addr(paddrBits-1, blockOffBits),
 | 
				
			||||||
 | 
					    addr_beat = s2_req.addr(blockOffBits-1, beatOffBits),
 | 
				
			||||||
 | 
					    data = Fill(beatWords, pstore1_storegen.data),
 | 
				
			||||||
 | 
					    wmask = Some(pstore1_storegen.mask << (uncachedPutOffset << wordOffBits)),
 | 
				
			||||||
 | 
					    alloc = Bool(false))
 | 
				
			||||||
 | 
					  val uncachedPutAtomicMessage = PutAtomic(
 | 
				
			||||||
 | 
					    client_xact_id = UInt(0),
 | 
				
			||||||
 | 
					    addr_block = s2_req.addr(paddrBits-1, blockOffBits),
 | 
				
			||||||
 | 
					    addr_beat = s2_req.addr(blockOffBits-1, beatOffBits),
 | 
				
			||||||
 | 
					    addr_byte = s2_req.addr(beatOffBits-1, 0),
 | 
				
			||||||
 | 
					    atomic_opcode = s2_req.cmd,
 | 
				
			||||||
 | 
					    operand_size = s2_req.typ,
 | 
				
			||||||
 | 
					    data = Fill(beatWords, pstore1_storegen.data))
 | 
				
			||||||
 | 
					  io.mem.acquire.valid := ((s2_valid_cached_miss && !s2_victim_dirty) || s2_valid_uncached) && fq.io.enq.ready
 | 
				
			||||||
 | 
					  io.mem.acquire.bits := cachedGetMessage
 | 
				
			||||||
 | 
					  when (s2_uncached) {
 | 
				
			||||||
 | 
					    assert(!s2_valid_masked || !s2_hit_state.isValid(), "cache hit on uncached access")
 | 
				
			||||||
 | 
					    io.mem.acquire.bits := uncachedGetMessage
 | 
				
			||||||
 | 
					    when (s2_write) {
 | 
				
			||||||
 | 
					      io.mem.acquire.bits := uncachedPutMessage
 | 
				
			||||||
 | 
					      when (pstore1_amo) {
 | 
				
			||||||
 | 
					        io.mem.acquire.bits := uncachedPutAtomicMessage
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  when (io.mem.acquire.fire()) { grant_wait := true }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // grant
 | 
				
			||||||
 | 
					  val grantIsRefill = io.mem.grant.bits.hasMultibeatData()
 | 
				
			||||||
 | 
					  val grantIsVoluntary = io.mem.grant.bits.isVoluntary()
 | 
				
			||||||
 | 
					  val grantIsUncached = !grantIsRefill && !grantIsVoluntary
 | 
				
			||||||
 | 
					  when (io.mem.grant.valid) {
 | 
				
			||||||
 | 
					    assert(grant_wait || grantIsVoluntary && release_ack_wait, "unexpected grant")
 | 
				
			||||||
 | 
					    when (grantIsUncached) { s2_data := io.mem.grant.bits.data }
 | 
				
			||||||
 | 
					    when (grantIsVoluntary) { release_ack_wait := false }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  val (refillCount, refillDone) = Counter(io.mem.grant.fire() && grantIsRefill, refillCycles)
 | 
				
			||||||
 | 
					  val grantDone = refillDone || grantIsUncached
 | 
				
			||||||
 | 
					  when (io.mem.grant.fire() && grantDone) { grant_wait := false }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // data refill
 | 
				
			||||||
 | 
					  dataArb.io.in(1).valid := grantIsRefill && io.mem.grant.valid
 | 
				
			||||||
 | 
					  io.mem.grant.ready := true
 | 
				
			||||||
 | 
					  assert(dataArb.io.in(1).ready || !dataArb.io.in(1).valid)
 | 
				
			||||||
 | 
					  dataArb.io.in(1).bits.write := true
 | 
				
			||||||
 | 
					  dataArb.io.in(1).bits.addr := Cat(s2_req.addr(paddrBits-1, blockOffBits), io.mem.grant.bits.addr_beat) << beatOffBits
 | 
				
			||||||
 | 
					  dataArb.io.in(1).bits.way_en := s2_victim_way
 | 
				
			||||||
 | 
					  dataArb.io.in(1).bits.wdata := io.mem.grant.bits.data
 | 
				
			||||||
 | 
					  dataArb.io.in(1).bits.wmask := ~UInt(0, rowBytes)
 | 
				
			||||||
 | 
					  // tag updates on refill
 | 
				
			||||||
 | 
					  metaWriteArb.io.in(1).valid := refillDone
 | 
				
			||||||
 | 
					  assert(!metaWriteArb.io.in(1).valid || metaWriteArb.io.in(1).ready)
 | 
				
			||||||
 | 
					  metaWriteArb.io.in(1).bits.way_en := s2_victim_way
 | 
				
			||||||
 | 
					  metaWriteArb.io.in(1).bits.idx := s2_req.addr(idxMSB, idxLSB)
 | 
				
			||||||
 | 
					  metaWriteArb.io.in(1).bits.data.coh := s2_hit_state.onGrant(io.mem.grant.bits, s2_req.cmd)
 | 
				
			||||||
 | 
					  metaWriteArb.io.in(1).bits.data.tag := s2_req.addr(paddrBits-1, untagBits)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // finish
 | 
				
			||||||
 | 
					  fq.io.enq.valid := io.mem.grant.fire() && io.mem.grant.bits.requiresAck() && (!grantIsRefill || refillDone)
 | 
				
			||||||
 | 
					  fq.io.enq.bits := io.mem.grant.bits.makeFinish()
 | 
				
			||||||
 | 
					  io.mem.finish <> fq.io.deq
 | 
				
			||||||
 | 
					  when (fq.io.enq.valid) { assert(fq.io.enq.ready) }
 | 
				
			||||||
 | 
					  when (refillDone) { replacer.miss }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // probe
 | 
				
			||||||
 | 
					  val block_probe = releaseInFlight || lrscValid || (s2_valid_hit && s2_lr)
 | 
				
			||||||
 | 
					  metaReadArb.io.in(1).valid := io.mem.probe.valid && !block_probe
 | 
				
			||||||
 | 
					  io.mem.probe.ready := metaReadArb.io.in(1).ready && !block_probe && !s1_valid && (!s2_valid || s2_valid_hit)
 | 
				
			||||||
 | 
					  metaReadArb.io.in(1).bits.idx := io.mem.probe.bits.addr_block
 | 
				
			||||||
 | 
					  metaReadArb.io.in(1).bits.way_en := ~UInt(0, nWays)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // release
 | 
				
			||||||
 | 
					  val (writebackCount, writebackDone) = Counter(io.mem.release.fire() && inWriteback, refillCycles)
 | 
				
			||||||
 | 
					  val releaseDone = writebackDone || (io.mem.release.fire() && !inWriteback)
 | 
				
			||||||
 | 
					  val releaseRejected = io.mem.release.valid && !io.mem.release.ready
 | 
				
			||||||
 | 
					  val s1_release_data_valid = Reg(next = dataArb.io.in(2).fire())
 | 
				
			||||||
 | 
					  val s2_release_data_valid = Reg(next = s1_release_data_valid && !releaseRejected)
 | 
				
			||||||
 | 
					  val releaseDataBeat = Cat(UInt(0), writebackCount) + Mux(releaseRejected, UInt(0), s1_release_data_valid + Cat(UInt(0), s2_release_data_valid))
 | 
				
			||||||
 | 
					  io.mem.release.valid := s2_release_data_valid
 | 
				
			||||||
 | 
					  io.mem.release.bits := ClientMetadata.onReset.makeRelease(probe_bits)
 | 
				
			||||||
 | 
					  val voluntaryReleaseMessage = s2_victim_state.makeVoluntaryWriteback(UInt(0), UInt(0))
 | 
				
			||||||
 | 
					  val voluntaryNewCoh = s2_victim_state.onCacheControl(M_FLUSH)
 | 
				
			||||||
 | 
					  val probeResponseMessage = s2_probe_state.makeRelease(probe_bits)
 | 
				
			||||||
 | 
					  val probeNewCoh = s2_probe_state.onProbe(probe_bits)
 | 
				
			||||||
 | 
					  val newCoh = Wire(init = probeNewCoh)
 | 
				
			||||||
 | 
					  releaseWay := s2_probe_way
 | 
				
			||||||
 | 
					  when (s2_victimize && s2_victim_dirty) {
 | 
				
			||||||
 | 
					    assert(!s2_hit_state.isValid())
 | 
				
			||||||
 | 
					    release_state := s_voluntary_writeback
 | 
				
			||||||
 | 
					    probe_bits.addr_block := Cat(s2_victim_tag, s2_req.addr(idxMSB, idxLSB))
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  when (s2_probe) {
 | 
				
			||||||
 | 
					    when (s2_probe_state.requiresVoluntaryWriteback()) { release_state := s_probe_rep_dirty }
 | 
				
			||||||
 | 
					    .elsewhen (s2_probe_state.isValid()) { release_state := s_probe_rep_clean }
 | 
				
			||||||
 | 
					    .otherwise {
 | 
				
			||||||
 | 
					      io.mem.release.valid := true
 | 
				
			||||||
 | 
					      release_state := s_probe_rep_miss
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  when (releaseDone) { release_state := s_ready }
 | 
				
			||||||
 | 
					  when (release_state === s_probe_rep_miss || release_state === s_probe_rep_clean) {
 | 
				
			||||||
 | 
					    io.mem.release.valid := true
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  when (release_state === s_probe_rep_clean || release_state === s_probe_rep_dirty) {
 | 
				
			||||||
 | 
					    io.mem.release.bits := probeResponseMessage
 | 
				
			||||||
 | 
					    when (releaseDone) { release_state := s_probe_write_meta }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  when (release_state === s_voluntary_writeback || release_state === s_voluntary_write_meta) {
 | 
				
			||||||
 | 
					    io.mem.release.bits := voluntaryReleaseMessage
 | 
				
			||||||
 | 
					    newCoh := voluntaryNewCoh
 | 
				
			||||||
 | 
					    releaseWay := s2_victim_way
 | 
				
			||||||
 | 
					    when (releaseDone) {
 | 
				
			||||||
 | 
					      release_state := s_voluntary_write_meta
 | 
				
			||||||
 | 
					      release_ack_wait := true
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  when (s2_probe && !io.mem.release.fire()) { s1_nack := true }
 | 
				
			||||||
 | 
					  io.mem.release.bits.addr_block := probe_bits.addr_block
 | 
				
			||||||
 | 
					  io.mem.release.bits.addr_beat := writebackCount
 | 
				
			||||||
 | 
					  io.mem.release.bits.data := s2_data
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  dataArb.io.in(2).valid := inWriteback && releaseDataBeat < refillCycles
 | 
				
			||||||
 | 
					  dataArb.io.in(2).bits.write := false
 | 
				
			||||||
 | 
					  dataArb.io.in(2).bits.addr := Cat(io.mem.release.bits.addr_block, releaseDataBeat(log2Up(refillCycles)-1,0)) << rowOffBits
 | 
				
			||||||
 | 
					  dataArb.io.in(2).bits.way_en := ~UInt(0, nWays)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  metaWriteArb.io.in(2).valid := (release_state === s_voluntary_write_meta || release_state === s_probe_write_meta)
 | 
				
			||||||
 | 
					  metaWriteArb.io.in(2).bits.way_en := releaseWay
 | 
				
			||||||
 | 
					  metaWriteArb.io.in(2).bits.idx := io.mem.release.bits.full_addr()(idxMSB, idxLSB)
 | 
				
			||||||
 | 
					  metaWriteArb.io.in(2).bits.data.coh := newCoh
 | 
				
			||||||
 | 
					  metaWriteArb.io.in(2).bits.data.tag := io.mem.release.bits.full_addr()(paddrBits-1, untagBits)
 | 
				
			||||||
 | 
					  when (metaWriteArb.io.in(2).fire()) { release_state := s_ready }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // cached response
 | 
				
			||||||
 | 
					  io.cpu.resp.valid := s2_valid_hit
 | 
				
			||||||
 | 
					  io.cpu.resp.bits := s2_req
 | 
				
			||||||
 | 
					  io.cpu.resp.bits.has_data := s2_read
 | 
				
			||||||
 | 
					  io.cpu.resp.bits.replay := false
 | 
				
			||||||
 | 
					  io.cpu.ordered := !(s1_valid || s2_valid || grant_wait)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // uncached response
 | 
				
			||||||
 | 
					  io.cpu.replay_next := io.mem.grant.valid && grantIsUncached
 | 
				
			||||||
 | 
					  val doUncachedResp = Reg(next = io.cpu.replay_next)
 | 
				
			||||||
 | 
					  when (doUncachedResp) {
 | 
				
			||||||
 | 
					    assert(!s2_valid_hit)
 | 
				
			||||||
 | 
					    io.cpu.resp.valid := true
 | 
				
			||||||
 | 
					    io.cpu.resp.bits.replay := true
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // load data subword mux/sign extension
 | 
				
			||||||
 | 
					  val s2_word_idx = s2_req.addr.extract(log2Up(rowBits/8)-1, log2Up(wordBytes))
 | 
				
			||||||
 | 
					  val s2_data_word = s2_data >> Cat(s2_word_idx, UInt(0, log2Up(coreDataBits)))
 | 
				
			||||||
 | 
					  val loadgen = new LoadGen(s2_req.typ, s2_req.addr, s2_data_word, s2_sc, wordBytes)
 | 
				
			||||||
 | 
					  io.cpu.resp.bits.data := loadgen.data | s2_sc_fail
 | 
				
			||||||
 | 
					  io.cpu.resp.bits.data_word_bypass := loadgen.wordData
 | 
				
			||||||
 | 
					  io.cpu.resp.bits.store_data := pstore1_data
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // AMOs
 | 
				
			||||||
 | 
					  if (usingAtomics) {
 | 
				
			||||||
 | 
					    val amoalu = Module(new AMOALU)
 | 
				
			||||||
 | 
					    amoalu.io.addr := pstore1_addr
 | 
				
			||||||
 | 
					    amoalu.io.cmd := pstore1_cmd
 | 
				
			||||||
 | 
					    amoalu.io.typ := pstore1_typ
 | 
				
			||||||
 | 
					    amoalu.io.lhs := s2_data_word
 | 
				
			||||||
 | 
					    amoalu.io.rhs := pstore1_data
 | 
				
			||||||
 | 
					    pstore1_storegen_data := amoalu.io.out
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    assert(!(s1_valid_masked && s1_read && s1_write), "unsupported D$ operation")
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // flushes
 | 
				
			||||||
 | 
					  val flushed = Reg(init=Bool(true))
 | 
				
			||||||
 | 
					  val flushing = Reg(init=Bool(false))
 | 
				
			||||||
 | 
					  val flushCounter = Counter(nSets * nWays)
 | 
				
			||||||
 | 
					  when (io.mem.acquire.fire()) { flushed := false }
 | 
				
			||||||
 | 
					  when (s2_valid_masked && s2_req.cmd === M_FLUSH_ALL) {
 | 
				
			||||||
 | 
					    io.cpu.s2_nack := !flushed
 | 
				
			||||||
 | 
					    when (!flushed) {
 | 
				
			||||||
 | 
					      flushing := !release_ack_wait
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  s1_flush_valid := metaReadArb.io.in(0).fire() && !s1_flush_valid && !s2_flush_valid && release_state === s_ready && !release_ack_wait
 | 
				
			||||||
 | 
					  metaReadArb.io.in(0).valid := flushing
 | 
				
			||||||
 | 
					  metaReadArb.io.in(0).bits.idx := flushCounter.value
 | 
				
			||||||
 | 
					  metaReadArb.io.in(0).bits.way_en := ~UInt(0, nWays)
 | 
				
			||||||
 | 
					  when (flushing) {
 | 
				
			||||||
 | 
					    s1_victim_way := flushCounter.value >> log2Up(nSets)
 | 
				
			||||||
 | 
					    when (s2_flush_valid) {
 | 
				
			||||||
 | 
					      when (flushCounter.inc()) {
 | 
				
			||||||
 | 
					        flushed := true
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    when (flushed && release_state === s_ready && !release_ack_wait) {
 | 
				
			||||||
 | 
					      flushing := false
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										203
									
								
								rocket/src/main/scala/decode.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										203
									
								
								rocket/src/main/scala/decode.scala
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,203 @@
 | 
				
			|||||||
 | 
					// See LICENSE for license details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package rocket
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import Chisel._
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					object DecodeLogic
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  def term(lit: BitPat) =
 | 
				
			||||||
 | 
					    new Term(lit.value, BigInt(2).pow(lit.getWidth)-(lit.mask+1))
 | 
				
			||||||
 | 
					  def logic(addr: UInt, addrWidth: Int, cache: scala.collection.mutable.Map[Term,Bool], terms: Seq[Term]) = {
 | 
				
			||||||
 | 
					    terms.map { t =>
 | 
				
			||||||
 | 
					      cache.getOrElseUpdate(t, (if (t.mask == 0) addr else addr & Bits(BigInt(2).pow(addrWidth)-(t.mask+1), addrWidth)) === Bits(t.value, addrWidth))
 | 
				
			||||||
 | 
					    }.foldLeft(Bool(false))(_||_)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
						def apply(addr: UInt, default: BitPat, mapping: Iterable[(BitPat, BitPat)]): UInt = {
 | 
				
			||||||
 | 
					    val cache = caches.getOrElseUpdate(addr, collection.mutable.Map[Term,Bool]())
 | 
				
			||||||
 | 
					    val dterm = term(default)
 | 
				
			||||||
 | 
					    val (keys, values) = mapping.unzip
 | 
				
			||||||
 | 
					    val addrWidth = keys.map(_.getWidth).max
 | 
				
			||||||
 | 
					    val terms = keys.toList.map(k => term(k))
 | 
				
			||||||
 | 
					    val termvalues = terms zip values.toList.map(term(_))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (t <- keys.zip(terms).tails; if !t.isEmpty)
 | 
				
			||||||
 | 
					      for (u <- t.tail)
 | 
				
			||||||
 | 
					        assert(!t.head._2.intersects(u._2), "DecodeLogic: keys " + t.head + " and " + u + " overlap")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    (0 until default.getWidth.max(values.map(_.getWidth).max)).map({ case (i: Int) =>
 | 
				
			||||||
 | 
					      val mint = termvalues.filter { case (k,t) => ((t.mask >> i) & 1) == 0 && ((t.value >> i) & 1) == 1 }.map(_._1)
 | 
				
			||||||
 | 
					      val maxt = termvalues.filter { case (k,t) => ((t.mask >> i) & 1) == 0 && ((t.value >> i) & 1) == 0 }.map(_._1)
 | 
				
			||||||
 | 
					      val dc = termvalues.filter { case (k,t) => ((t.mask >> i) & 1) == 1 }.map(_._1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (((dterm.mask >> i) & 1) != 0) {
 | 
				
			||||||
 | 
					        logic(addr, addrWidth, cache, SimplifyDC(mint, maxt, addrWidth)).toBits
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        val defbit = (dterm.value.toInt >> i) & 1
 | 
				
			||||||
 | 
					        val t = if (defbit == 0) mint else maxt
 | 
				
			||||||
 | 
					        val bit = logic(addr, addrWidth, cache, Simplify(t, dc, addrWidth)).toBits
 | 
				
			||||||
 | 
					        if (defbit == 0) bit else ~bit
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }).reverse.reduceRight(Cat(_,_))
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  def apply(addr: UInt, default: Seq[BitPat], mappingIn: Iterable[(BitPat, Seq[BitPat])]): Seq[UInt] = {
 | 
				
			||||||
 | 
					    val mapping = collection.mutable.ArrayBuffer.fill(default.size)(collection.mutable.ArrayBuffer[(BitPat, BitPat)]())
 | 
				
			||||||
 | 
					    for ((key, values) <- mappingIn)
 | 
				
			||||||
 | 
					      for ((value, i) <- values zipWithIndex)
 | 
				
			||||||
 | 
					        mapping(i) += key -> value
 | 
				
			||||||
 | 
					    for ((thisDefault, thisMapping) <- default zip mapping)
 | 
				
			||||||
 | 
					      yield apply(addr, thisDefault, thisMapping)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  def apply(addr: UInt, default: Seq[BitPat], mappingIn: List[(UInt, Seq[BitPat])]): Seq[UInt] =
 | 
				
			||||||
 | 
					    apply(addr, default, mappingIn.map(m => (BitPat(m._1), m._2)).asInstanceOf[Iterable[(BitPat, Seq[BitPat])]])
 | 
				
			||||||
 | 
					  def apply(addr: UInt, trues: Iterable[UInt], falses: Iterable[UInt]): Bool =
 | 
				
			||||||
 | 
					    apply(addr, BitPat.DC(1), trues.map(BitPat(_) -> BitPat("b1")) ++ falses.map(BitPat(_) -> BitPat("b0"))).toBool
 | 
				
			||||||
 | 
					  private val caches = collection.mutable.Map[UInt,collection.mutable.Map[Term,Bool]]()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Term(val value: BigInt, val mask: BigInt = 0)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  var prime = true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def covers(x: Term) = ((value ^ x.value) &~ mask | x.mask &~ mask) == 0
 | 
				
			||||||
 | 
					  def intersects(x: Term) = ((value ^ x.value) &~ mask &~ x.mask) == 0
 | 
				
			||||||
 | 
					  override def equals(that: Any) = that match {
 | 
				
			||||||
 | 
					    case x: Term => x.value == value && x.mask == mask
 | 
				
			||||||
 | 
					    case _ => false
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  override def hashCode = value.toInt
 | 
				
			||||||
 | 
					  def < (that: Term) = value < that.value || value == that.value && mask < that.mask
 | 
				
			||||||
 | 
					  def similar(x: Term) = {
 | 
				
			||||||
 | 
					    val diff = value - x.value
 | 
				
			||||||
 | 
					    mask == x.mask && value > x.value && (diff & diff-1) == 0
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  def merge(x: Term) = {
 | 
				
			||||||
 | 
					    prime = false
 | 
				
			||||||
 | 
					    x.prime = false
 | 
				
			||||||
 | 
					    val bit = value - x.value
 | 
				
			||||||
 | 
					    new Term(value &~ bit, mask | bit)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override def toString = value.toString(16) + "-" + mask.toString(16) + (if (prime) "p" else "")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					object Simplify
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  def getPrimeImplicants(implicants: Seq[Term], bits: Int) = {
 | 
				
			||||||
 | 
					    var prime = List[Term]()
 | 
				
			||||||
 | 
					    implicants.foreach(_.prime = true)
 | 
				
			||||||
 | 
					    val cols = (0 to bits).map(b => implicants.filter(b == _.mask.bitCount))
 | 
				
			||||||
 | 
					    val table = cols.map(c => (0 to bits).map(b => collection.mutable.Set(c.filter(b == _.value.bitCount):_*)))
 | 
				
			||||||
 | 
					    for (i <- 0 to bits) {
 | 
				
			||||||
 | 
					      for (j <- 0 until bits-i)
 | 
				
			||||||
 | 
					        table(i)(j).foreach(a => table(i+1)(j) ++= table(i)(j+1).filter(_.similar(a)).map(_.merge(a)))
 | 
				
			||||||
 | 
					      for (r <- table(i))
 | 
				
			||||||
 | 
					        for (p <- r; if p.prime)
 | 
				
			||||||
 | 
					          prime = p :: prime
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    prime.sortWith(_<_)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  def getEssentialPrimeImplicants(prime: Seq[Term], minterms: Seq[Term]): (Seq[Term],Seq[Term],Seq[Term]) = {
 | 
				
			||||||
 | 
					    for (i <- 0 until prime.size) {
 | 
				
			||||||
 | 
					      val icover = minterms.filter(prime(i) covers _)
 | 
				
			||||||
 | 
					      for (j <- 0 until prime.size) {
 | 
				
			||||||
 | 
					        val jcover = minterms.filter(prime(j) covers _)
 | 
				
			||||||
 | 
					        if (icover.size > jcover.size && jcover.forall(prime(i) covers _))
 | 
				
			||||||
 | 
					          return getEssentialPrimeImplicants(prime.filter(_ != prime(j)), minterms)
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    val essentiallyCovered = minterms.filter(t => prime.count(_ covers t) == 1)
 | 
				
			||||||
 | 
					    val essential = prime.filter(p => essentiallyCovered.exists(p covers _))
 | 
				
			||||||
 | 
					    val nonessential = prime.filterNot(essential contains _)
 | 
				
			||||||
 | 
					    val uncovered = minterms.filterNot(t => essential.exists(_ covers t))
 | 
				
			||||||
 | 
					    if (essential.isEmpty || uncovered.isEmpty)
 | 
				
			||||||
 | 
					      (essential, nonessential, uncovered)
 | 
				
			||||||
 | 
					    else {
 | 
				
			||||||
 | 
					      val (a, b, c) = getEssentialPrimeImplicants(nonessential, uncovered)
 | 
				
			||||||
 | 
					      (essential ++ a, b, c)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  def getCost(cover: Seq[Term], bits: Int) = cover.map(bits - _.mask.bitCount).sum
 | 
				
			||||||
 | 
					  def cheaper(a: List[Term], b: List[Term], bits: Int) = {
 | 
				
			||||||
 | 
					    val ca = getCost(a, bits)
 | 
				
			||||||
 | 
					    val cb = getCost(b, bits)
 | 
				
			||||||
 | 
					    def listLess(a: List[Term], b: List[Term]): Boolean = !b.isEmpty && (a.isEmpty || a.head < b.head || a.head == b.head && listLess(a.tail, b.tail))
 | 
				
			||||||
 | 
					    ca < cb || ca == cb && listLess(a.sortWith(_<_), b.sortWith(_<_))
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  def getCover(implicants: Seq[Term], minterms: Seq[Term], bits: Int) = {
 | 
				
			||||||
 | 
					    if (minterms.nonEmpty) {
 | 
				
			||||||
 | 
					      val cover = minterms.map(m => implicants.filter(_.covers(m)).map(i => collection.mutable.Set(i)))
 | 
				
			||||||
 | 
					      val all = cover.reduceLeft((c0, c1) => c0.map(a => c1.map(_ ++ a)).reduceLeft(_++_))
 | 
				
			||||||
 | 
					      all.map(_.toList).reduceLeft((a, b) => if (cheaper(a, b, bits)) a else b)
 | 
				
			||||||
 | 
					    } else
 | 
				
			||||||
 | 
					      Seq[Term]()
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  def stringify(s: Seq[Term], bits: Int) = s.map(t => (0 until bits).map(i => if ((t.mask & (1 << i)) != 0) "x" else ((t.value >> i) & 1).toString).reduceLeft(_+_).reverse).reduceLeft(_+" + "+_)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def apply(minterms: Seq[Term], dontcares: Seq[Term], bits: Int) = {
 | 
				
			||||||
 | 
					    val prime = getPrimeImplicants(minterms ++ dontcares, bits)
 | 
				
			||||||
 | 
					    minterms.foreach(t => assert(prime.exists(_.covers(t))))
 | 
				
			||||||
 | 
					    val (eprime, prime2, uncovered) = getEssentialPrimeImplicants(prime, minterms)
 | 
				
			||||||
 | 
					    val cover = eprime ++ getCover(prime2, uncovered, bits)
 | 
				
			||||||
 | 
					    minterms.foreach(t => assert(cover.exists(_.covers(t)))) // sanity check
 | 
				
			||||||
 | 
					    cover
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					object SimplifyDC
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  def getImplicitDC(maxterms: Seq[Term], term: Term, bits: Int, above: Boolean): Term = {
 | 
				
			||||||
 | 
					    for (i <- 0 until bits) {
 | 
				
			||||||
 | 
					      var t: Term = null
 | 
				
			||||||
 | 
					      if (above && ((term.value | term.mask) & (BigInt(1) << i)) == 0)
 | 
				
			||||||
 | 
					        t = new Term(term.value | (BigInt(1) << i), term.mask)
 | 
				
			||||||
 | 
					      else if (!above && (term.value & (BigInt(1) << i)) != 0)
 | 
				
			||||||
 | 
					        t = new Term(term.value & ~(BigInt(1) << i), term.mask)
 | 
				
			||||||
 | 
					      if (t != null && !maxterms.exists(_.intersects(t)))
 | 
				
			||||||
 | 
					        return t
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    null
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  def getPrimeImplicants(minterms: Seq[Term], maxterms: Seq[Term], bits: Int) = {
 | 
				
			||||||
 | 
					    var prime = List[Term]()
 | 
				
			||||||
 | 
					    minterms.foreach(_.prime = true)
 | 
				
			||||||
 | 
					    var mint = minterms.map(t => new Term(t.value, t.mask))
 | 
				
			||||||
 | 
					    val cols = (0 to bits).map(b => mint.filter(b == _.mask.bitCount))
 | 
				
			||||||
 | 
					    val table = cols.map(c => (0 to bits).map(b => collection.mutable.Set(c.filter(b == _.value.bitCount):_*)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (i <- 0 to bits) {
 | 
				
			||||||
 | 
					      for (j <- 0 until bits-i) {
 | 
				
			||||||
 | 
					        table(i)(j).foreach(a => table(i+1)(j) ++= table(i)(j+1).filter(_ similar a).map(_ merge a))
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      for (j <- 0 until bits-i) {
 | 
				
			||||||
 | 
					        for (a <- table(i)(j).filter(_.prime)) {
 | 
				
			||||||
 | 
					          val dc = getImplicitDC(maxterms, a, bits, true)
 | 
				
			||||||
 | 
					          if (dc != null)
 | 
				
			||||||
 | 
					            table(i+1)(j) += dc merge a
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        for (a <- table(i)(j+1).filter(_.prime)) {
 | 
				
			||||||
 | 
					          val dc = getImplicitDC(maxterms, a, bits, false)
 | 
				
			||||||
 | 
					          if (dc != null)
 | 
				
			||||||
 | 
					            table(i+1)(j) += a merge dc
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      for (r <- table(i))
 | 
				
			||||||
 | 
					        for (p <- r; if p.prime)
 | 
				
			||||||
 | 
					          prime = p :: prime
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    prime.sortWith(_<_)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def verify(cover: Seq[Term], minterms: Seq[Term], maxterms: Seq[Term]) = {
 | 
				
			||||||
 | 
					    assert(minterms.forall(t => cover.exists(_ covers t)))
 | 
				
			||||||
 | 
					    assert(maxterms.forall(t => !cover.exists(_ intersects t)))
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  def apply(minterms: Seq[Term], maxterms: Seq[Term], bits: Int) = {
 | 
				
			||||||
 | 
					    val prime = getPrimeImplicants(minterms, maxterms, bits)
 | 
				
			||||||
 | 
					    val (eprime, prime2, uncovered) = Simplify.getEssentialPrimeImplicants(prime, minterms)
 | 
				
			||||||
 | 
					    val cover = eprime ++ Simplify.getCover(prime2, uncovered, bits)
 | 
				
			||||||
 | 
					    verify(cover, minterms, maxterms)
 | 
				
			||||||
 | 
					    cover
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										400
									
								
								rocket/src/main/scala/dma.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										400
									
								
								rocket/src/main/scala/dma.scala
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,400 @@
 | 
				
			|||||||
 | 
					package rocket
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import Chisel._
 | 
				
			||||||
 | 
					import uncore.tilelink._
 | 
				
			||||||
 | 
					import uncore.devices._
 | 
				
			||||||
 | 
					import uncore.devices.DmaRequest._
 | 
				
			||||||
 | 
					import uncore.agents._
 | 
				
			||||||
 | 
					import uncore.util._
 | 
				
			||||||
 | 
					import junctions.{ParameterizedBundle, AddrMap}
 | 
				
			||||||
 | 
					import cde.Parameters
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					trait HasClientDmaParameters extends HasCoreParameters with HasDmaParameters {
 | 
				
			||||||
 | 
					  val dmaAddrBits = coreMaxAddrBits
 | 
				
			||||||
 | 
					  val dmaSegmentSizeBits = coreMaxAddrBits
 | 
				
			||||||
 | 
					  val dmaSegmentBits = 24
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					abstract class ClientDmaBundle(implicit val p: Parameters)
 | 
				
			||||||
 | 
					  extends ParameterizedBundle()(p) with HasClientDmaParameters
 | 
				
			||||||
 | 
					abstract class ClientDmaModule(implicit val p: Parameters)
 | 
				
			||||||
 | 
					  extends Module with HasClientDmaParameters
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ClientDmaRequest(implicit p: Parameters) extends ClientDmaBundle()(p) {
 | 
				
			||||||
 | 
					  val cmd = UInt(width = DMA_CMD_SZ)
 | 
				
			||||||
 | 
					  val src_start  = UInt(width = dmaAddrBits)
 | 
				
			||||||
 | 
					  val dst_start  = UInt(width = dmaAddrBits)
 | 
				
			||||||
 | 
					  val src_stride = UInt(width = dmaSegmentSizeBits)
 | 
				
			||||||
 | 
					  val dst_stride = UInt(width = dmaSegmentSizeBits)
 | 
				
			||||||
 | 
					  val segment_size = UInt(width = dmaSegmentSizeBits)
 | 
				
			||||||
 | 
					  val nsegments  = UInt(width = dmaSegmentBits)
 | 
				
			||||||
 | 
					  val word_size  = UInt(width = dmaWordSizeBits)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					object ClientDmaRequest {
 | 
				
			||||||
 | 
					  def apply(cmd: UInt,
 | 
				
			||||||
 | 
					            src_start: UInt,
 | 
				
			||||||
 | 
					            dst_start: UInt,
 | 
				
			||||||
 | 
					            segment_size: UInt,
 | 
				
			||||||
 | 
					            nsegments: UInt = UInt(1),
 | 
				
			||||||
 | 
					            src_stride: UInt = UInt(0),
 | 
				
			||||||
 | 
					            dst_stride: UInt = UInt(0),
 | 
				
			||||||
 | 
					            word_size: UInt = UInt(0))
 | 
				
			||||||
 | 
					      (implicit p: Parameters) = {
 | 
				
			||||||
 | 
					    val req = Wire(new ClientDmaRequest)
 | 
				
			||||||
 | 
					    req.cmd := cmd
 | 
				
			||||||
 | 
					    req.src_start := src_start
 | 
				
			||||||
 | 
					    req.dst_start := dst_start
 | 
				
			||||||
 | 
					    req.src_stride := src_stride
 | 
				
			||||||
 | 
					    req.dst_stride := dst_stride
 | 
				
			||||||
 | 
					    req.segment_size := segment_size
 | 
				
			||||||
 | 
					    req.nsegments := nsegments
 | 
				
			||||||
 | 
					    req.word_size := word_size
 | 
				
			||||||
 | 
					    req
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					object ClientDmaResponse {
 | 
				
			||||||
 | 
					  val pagefault = UInt("b01")
 | 
				
			||||||
 | 
					  val invalid_region = UInt("b10")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def apply(status: UInt = UInt(0))(implicit p: Parameters) = {
 | 
				
			||||||
 | 
					    val resp = Wire(new ClientDmaResponse)
 | 
				
			||||||
 | 
					    resp.status := status
 | 
				
			||||||
 | 
					    resp
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ClientDmaResponse(implicit p: Parameters) extends ClientDmaBundle {
 | 
				
			||||||
 | 
					  val status = UInt(width = dmaStatusBits)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ClientDmaIO(implicit p: Parameters) extends ParameterizedBundle()(p) {
 | 
				
			||||||
 | 
					  val req = Decoupled(new ClientDmaRequest)
 | 
				
			||||||
 | 
					  val resp = Valid(new ClientDmaResponse).flip
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class DmaFrontend(implicit p: Parameters) extends CoreModule()(p)
 | 
				
			||||||
 | 
					    with HasClientDmaParameters with HasTileLinkParameters {
 | 
				
			||||||
 | 
					  val io = new Bundle {
 | 
				
			||||||
 | 
					    val cpu = (new ClientDmaIO).flip
 | 
				
			||||||
 | 
					    val mem = new ClientUncachedTileLinkIO
 | 
				
			||||||
 | 
					    val ptw = new TLBPTWIO
 | 
				
			||||||
 | 
					    val busy = Bool(OUTPUT)
 | 
				
			||||||
 | 
					    val incr_outstanding = Bool(OUTPUT)
 | 
				
			||||||
 | 
					    val host_id = UInt(INPUT, log2Up(nCores))
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val tlb = Module(new DecoupledTLB()(p.alterPartial({
 | 
				
			||||||
 | 
					    case CacheName => "L1D"
 | 
				
			||||||
 | 
					  })))
 | 
				
			||||||
 | 
					  io.ptw <> tlb.io.ptw
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private val pgSize = 1 << pgIdxBits
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val cmd = Reg(UInt(width = DMA_CMD_SZ))
 | 
				
			||||||
 | 
					  val adv_ptr = MuxLookup(cmd, UInt("b11"), Seq(
 | 
				
			||||||
 | 
					    DMA_CMD_PFR -> UInt("b10"),
 | 
				
			||||||
 | 
					    DMA_CMD_PFW -> UInt("b10"),
 | 
				
			||||||
 | 
					    DMA_CMD_SIN -> UInt("b10"),
 | 
				
			||||||
 | 
					    DMA_CMD_SOUT -> UInt("b01")))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val segment_size = Reg(UInt(width = dmaSegmentSizeBits))
 | 
				
			||||||
 | 
					  val bytes_left = Reg(UInt(width = dmaSegmentSizeBits))
 | 
				
			||||||
 | 
					  val segments_left = Reg(UInt(width = dmaSegmentBits))
 | 
				
			||||||
 | 
					  val word_size = Reg(UInt(width = dmaWordSizeBits))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val src_vaddr = Reg(UInt(width = dmaAddrBits))
 | 
				
			||||||
 | 
					  val dst_vaddr = Reg(UInt(width = dmaAddrBits))
 | 
				
			||||||
 | 
					  val src_vpn = src_vaddr(dmaAddrBits - 1, pgIdxBits)
 | 
				
			||||||
 | 
					  val dst_vpn = dst_vaddr(dmaAddrBits - 1, pgIdxBits)
 | 
				
			||||||
 | 
					  val src_idx = src_vaddr(pgIdxBits - 1, 0)
 | 
				
			||||||
 | 
					  val dst_idx = dst_vaddr(pgIdxBits - 1, 0)
 | 
				
			||||||
 | 
					  val src_pglen = UInt(pgSize) - src_idx
 | 
				
			||||||
 | 
					  val dst_pglen = UInt(pgSize) - dst_idx
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val src_stride = Reg(UInt(width = dmaSegmentSizeBits))
 | 
				
			||||||
 | 
					  val dst_stride = Reg(UInt(width = dmaSegmentSizeBits))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val src_ppn = Reg(UInt(width = ppnBits))
 | 
				
			||||||
 | 
					  val dst_ppn = Reg(UInt(width = ppnBits))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val src_paddr = Cat(src_ppn, src_idx)
 | 
				
			||||||
 | 
					  val dst_paddr = Cat(dst_ppn, dst_idx)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val last_src_vpn = Reg(UInt(width = vpnBits))
 | 
				
			||||||
 | 
					  val last_dst_vpn = Reg(UInt(width = vpnBits))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val tx_len = Util.minUInt(src_pglen, dst_pglen, bytes_left)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val dma_busy = Reg(init = UInt(0, tlMaxClientXacts))
 | 
				
			||||||
 | 
					  val dma_xact_id = PriorityEncoder(~dma_busy)
 | 
				
			||||||
 | 
					  val (dma_req_beat, dma_req_done) = Counter(io.mem.acquire.fire(), tlDataBeats)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val (s_idle :: s_translate :: s_dma_req :: s_dma_update ::
 | 
				
			||||||
 | 
					       s_prepare :: s_finish :: Nil) = Enum(Bits(), 6)
 | 
				
			||||||
 | 
					  val state = Reg(init = s_idle)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // lower bit is for src, higher bit is for dst
 | 
				
			||||||
 | 
					  val to_translate = Reg(init = UInt(0, 2))
 | 
				
			||||||
 | 
					  val tlb_sent = Reg(init = UInt(0, 2))
 | 
				
			||||||
 | 
					  val tlb_to_send = to_translate & ~tlb_sent
 | 
				
			||||||
 | 
					  val resp_status = Reg(UInt(width = dmaStatusBits))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def make_acquire(
 | 
				
			||||||
 | 
					      addr_beat: UInt, client_xact_id: UInt, client_id: UInt,
 | 
				
			||||||
 | 
					      cmd: UInt, source: UInt, dest: UInt,
 | 
				
			||||||
 | 
					      length: UInt, size: UInt): Acquire = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    val data_blob = Wire(UInt(width = tlDataBeats * tlDataBits))
 | 
				
			||||||
 | 
					    data_blob := DmaRequest(
 | 
				
			||||||
 | 
					      xact_id = UInt(0),
 | 
				
			||||||
 | 
					      client_id = client_id,
 | 
				
			||||||
 | 
					      cmd = cmd,
 | 
				
			||||||
 | 
					      source = source,
 | 
				
			||||||
 | 
					      dest = dest,
 | 
				
			||||||
 | 
					      length = length,
 | 
				
			||||||
 | 
					      size = size).toBits
 | 
				
			||||||
 | 
					    val data_beats = Vec(tlDataBeats, UInt(width = tlDataBits)).fromBits(data_blob)
 | 
				
			||||||
 | 
					    val base_addr = addrMap("devices:dma").start
 | 
				
			||||||
 | 
					    val addr_block = UInt(base_addr >> (tlBeatAddrBits + tlByteAddrBits))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    PutBlock(
 | 
				
			||||||
 | 
					      client_xact_id = client_xact_id,
 | 
				
			||||||
 | 
					      addr_block = addr_block,
 | 
				
			||||||
 | 
					      addr_beat = addr_beat,
 | 
				
			||||||
 | 
					      data = data_beats(addr_beat),
 | 
				
			||||||
 | 
					      alloc = Bool(false))
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def check_region(cmd: UInt, src: UInt, dst: UInt): Bool = {
 | 
				
			||||||
 | 
					    val src_cacheable = addrMap.isCacheable(src)
 | 
				
			||||||
 | 
					    val dst_cacheable = addrMap.isCacheable(dst)
 | 
				
			||||||
 | 
					    val dst_ok = Mux(cmd === DMA_CMD_SOUT, !dst_cacheable, dst_cacheable)
 | 
				
			||||||
 | 
					    val src_ok = Mux(cmd === DMA_CMD_SIN,  !src_cacheable, Bool(true))
 | 
				
			||||||
 | 
					    dst_ok && src_ok
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  tlb.io.req.valid := tlb_to_send.orR
 | 
				
			||||||
 | 
					  tlb.io.req.bits.vpn := Mux(tlb_to_send(0), src_vpn, dst_vpn)
 | 
				
			||||||
 | 
					  tlb.io.req.bits.passthrough := Bool(false)
 | 
				
			||||||
 | 
					  tlb.io.req.bits.instruction := Bool(false)
 | 
				
			||||||
 | 
					  tlb.io.req.bits.store := !tlb_to_send(0)
 | 
				
			||||||
 | 
					  tlb.io.resp.ready := tlb_sent.orR
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  when (tlb.io.req.fire()) {
 | 
				
			||||||
 | 
					    tlb_sent := tlb_sent | PriorityEncoderOH(tlb_to_send)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  when (tlb.io.resp.fire()) {
 | 
				
			||||||
 | 
					    val recv_choice = PriorityEncoderOH(to_translate)
 | 
				
			||||||
 | 
					    val error = Mux(recv_choice(0),
 | 
				
			||||||
 | 
					      tlb.io.resp.bits.xcpt_ld, tlb.io.resp.bits.xcpt_st)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    when (error) {
 | 
				
			||||||
 | 
					      resp_status := ClientDmaResponse.pagefault
 | 
				
			||||||
 | 
					      state := s_finish
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // getting the src translation
 | 
				
			||||||
 | 
					    when (recv_choice(0)) {
 | 
				
			||||||
 | 
					      src_ppn := tlb.io.resp.bits.ppn
 | 
				
			||||||
 | 
					    } .otherwise {
 | 
				
			||||||
 | 
					      dst_ppn := tlb.io.resp.bits.ppn
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    to_translate := to_translate & ~recv_choice
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  io.cpu.req.ready := state === s_idle
 | 
				
			||||||
 | 
					  io.cpu.resp.valid := state === s_finish
 | 
				
			||||||
 | 
					  io.cpu.resp.bits := ClientDmaResponse(resp_status)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  io.mem.acquire.valid := (state === s_dma_req) && !dma_busy.andR
 | 
				
			||||||
 | 
					  io.mem.acquire.bits := make_acquire(
 | 
				
			||||||
 | 
					    addr_beat = dma_req_beat,
 | 
				
			||||||
 | 
					    client_id = io.host_id,
 | 
				
			||||||
 | 
					    client_xact_id = dma_xact_id,
 | 
				
			||||||
 | 
					    cmd = cmd, source = src_paddr, dest = dst_paddr,
 | 
				
			||||||
 | 
					    length = tx_len, size = word_size)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  io.mem.grant.ready := (state =/= s_dma_req)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  when (io.cpu.req.fire()) {
 | 
				
			||||||
 | 
					    val req = io.cpu.req.bits
 | 
				
			||||||
 | 
					    val is_prefetch = req.cmd(2, 1) === UInt("b01")
 | 
				
			||||||
 | 
					    cmd := req.cmd
 | 
				
			||||||
 | 
					    src_vaddr := req.src_start
 | 
				
			||||||
 | 
					    dst_vaddr := req.dst_start
 | 
				
			||||||
 | 
					    src_stride := req.src_stride
 | 
				
			||||||
 | 
					    dst_stride := req.dst_stride
 | 
				
			||||||
 | 
					    segment_size := req.segment_size
 | 
				
			||||||
 | 
					    segments_left := req.nsegments - UInt(1)
 | 
				
			||||||
 | 
					    bytes_left := req.segment_size
 | 
				
			||||||
 | 
					    word_size := req.word_size
 | 
				
			||||||
 | 
					    to_translate := Mux(is_prefetch, UInt("b10"), UInt("b11"))
 | 
				
			||||||
 | 
					    tlb_sent := UInt(0)
 | 
				
			||||||
 | 
					    state := s_translate
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  when (state === s_translate && !to_translate.orR) {
 | 
				
			||||||
 | 
					    when (check_region(cmd, src_paddr, dst_paddr)) {
 | 
				
			||||||
 | 
					      state := s_dma_req
 | 
				
			||||||
 | 
					    } .otherwise {
 | 
				
			||||||
 | 
					      resp_status := ClientDmaResponse.invalid_region
 | 
				
			||||||
 | 
					      state := s_finish
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def setBusy(set: Bool, xact_id: UInt): UInt =
 | 
				
			||||||
 | 
					    Mux(set, UIntToOH(xact_id), UInt(0))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  dma_busy := (dma_busy |
 | 
				
			||||||
 | 
					                setBusy(dma_req_done, dma_xact_id)) &
 | 
				
			||||||
 | 
					                ~setBusy(io.mem.grant.fire(), io.mem.grant.bits.client_xact_id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  when (dma_req_done) {
 | 
				
			||||||
 | 
					    src_vaddr := src_vaddr + Mux(adv_ptr(0), tx_len, UInt(0))
 | 
				
			||||||
 | 
					    dst_vaddr := dst_vaddr + Mux(adv_ptr(1), tx_len, UInt(0))
 | 
				
			||||||
 | 
					    bytes_left := bytes_left - tx_len
 | 
				
			||||||
 | 
					    state := s_dma_update
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  when (state === s_dma_update) {
 | 
				
			||||||
 | 
					    when (bytes_left === UInt(0)) {
 | 
				
			||||||
 | 
					      when (segments_left === UInt(0)) {
 | 
				
			||||||
 | 
					        resp_status := UInt(0)
 | 
				
			||||||
 | 
					        state := s_finish
 | 
				
			||||||
 | 
					      } .otherwise {
 | 
				
			||||||
 | 
					        last_src_vpn := src_vpn
 | 
				
			||||||
 | 
					        last_dst_vpn := dst_vpn
 | 
				
			||||||
 | 
					        src_vaddr := src_vaddr + src_stride
 | 
				
			||||||
 | 
					        dst_vaddr := dst_vaddr + dst_stride
 | 
				
			||||||
 | 
					        bytes_left := segment_size
 | 
				
			||||||
 | 
					        segments_left := segments_left - UInt(1)
 | 
				
			||||||
 | 
					        state := s_prepare
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    } .otherwise {
 | 
				
			||||||
 | 
					      to_translate := adv_ptr & Cat(dst_idx === UInt(0), src_idx === UInt(0))
 | 
				
			||||||
 | 
					      tlb_sent := UInt(0)
 | 
				
			||||||
 | 
					      state := s_translate
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  when (state === s_prepare) {
 | 
				
			||||||
 | 
					    to_translate := adv_ptr & Cat(
 | 
				
			||||||
 | 
					      dst_vpn =/= last_dst_vpn,
 | 
				
			||||||
 | 
					      src_vpn =/= last_src_vpn)
 | 
				
			||||||
 | 
					    tlb_sent := UInt(0)
 | 
				
			||||||
 | 
					    state := s_translate
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  when (state === s_finish) { state := s_idle }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  io.busy := (state =/= s_idle) || dma_busy.orR
 | 
				
			||||||
 | 
					  io.incr_outstanding := dma_req_done
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					object DmaCtrlRegNumbers {
 | 
				
			||||||
 | 
					  val SRC_STRIDE = 0
 | 
				
			||||||
 | 
					  val DST_STRIDE = 1
 | 
				
			||||||
 | 
					  val SEGMENT_SIZE = 2
 | 
				
			||||||
 | 
					  val NSEGMENTS = 3
 | 
				
			||||||
 | 
					  val WORD_SIZE = 4
 | 
				
			||||||
 | 
					  val RESP_STATUS = 5
 | 
				
			||||||
 | 
					  val OUTSTANDING = 6
 | 
				
			||||||
 | 
					  val NCSRS = 7
 | 
				
			||||||
 | 
					  val CSR_BASE = 0x800
 | 
				
			||||||
 | 
					  val CSR_END  = CSR_BASE + NCSRS
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					import DmaCtrlRegNumbers._
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class DmaCtrlRegFile(implicit val p: Parameters) extends Module
 | 
				
			||||||
 | 
					    with HasClientDmaParameters with HasTileLinkParameters {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private val nWriteRegs = 5
 | 
				
			||||||
 | 
					  private val nRegs = nWriteRegs + 2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val io = new Bundle {
 | 
				
			||||||
 | 
					    val wen = Bool(INPUT)
 | 
				
			||||||
 | 
					    val waddr = UInt(INPUT, log2Up(nRegs))
 | 
				
			||||||
 | 
					    val wdata = UInt(INPUT, dmaSegmentSizeBits)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    val src_stride = UInt(OUTPUT, dmaSegmentSizeBits)
 | 
				
			||||||
 | 
					    val dst_stride = UInt(OUTPUT, dmaSegmentSizeBits)
 | 
				
			||||||
 | 
					    val segment_size = UInt(OUTPUT, dmaSegmentSizeBits)
 | 
				
			||||||
 | 
					    val nsegments  = UInt(OUTPUT, dmaSegmentBits)
 | 
				
			||||||
 | 
					    val word_size = UInt(OUTPUT, dmaWordSizeBits)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    val incr_outstanding = Bool(INPUT)
 | 
				
			||||||
 | 
					    val xact_outstanding = Bool(OUTPUT)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val regs = Reg(Vec(nWriteRegs, UInt(width = dmaSegmentSizeBits)))
 | 
				
			||||||
 | 
					  val waddr = io.waddr(log2Up(NCSRS) - 1, 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  io.src_stride := regs(SRC_STRIDE)
 | 
				
			||||||
 | 
					  io.dst_stride := regs(DST_STRIDE)
 | 
				
			||||||
 | 
					  io.segment_size := regs(SEGMENT_SIZE)
 | 
				
			||||||
 | 
					  io.nsegments := regs(NSEGMENTS)
 | 
				
			||||||
 | 
					  io.word_size := regs(WORD_SIZE)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  when (io.wen && waddr < UInt(nWriteRegs)) {
 | 
				
			||||||
 | 
					    regs.write(waddr, io.wdata)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val outstanding_cnt = TwoWayCounter(
 | 
				
			||||||
 | 
					    io.incr_outstanding,
 | 
				
			||||||
 | 
					    io.wen && io.waddr === UInt(OUTSTANDING),
 | 
				
			||||||
 | 
					    tlMaxClientXacts)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  io.xact_outstanding := outstanding_cnt > UInt(0)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class DmaController(implicit p: Parameters) extends RoCC()(p)
 | 
				
			||||||
 | 
					    with HasClientDmaParameters {
 | 
				
			||||||
 | 
					  io.mem.req.valid := Bool(false)
 | 
				
			||||||
 | 
					  io.resp.valid := Bool(false)
 | 
				
			||||||
 | 
					  io.interrupt := Bool(false)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val cmd = Queue(io.cmd)
 | 
				
			||||||
 | 
					  val inst = cmd.bits.inst
 | 
				
			||||||
 | 
					  val is_transfer = inst.funct < UInt(8)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val reg_status = Reg(UInt(width = dmaStatusBits))
 | 
				
			||||||
 | 
					  val crfile = Module(new DmaCtrlRegFile)
 | 
				
			||||||
 | 
					  crfile.io.waddr := io.csr.waddr
 | 
				
			||||||
 | 
					  crfile.io.wdata := io.csr.wdata
 | 
				
			||||||
 | 
					  crfile.io.wen := io.csr.wen
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  io.csr.rdata(SRC_STRIDE) := crfile.io.src_stride
 | 
				
			||||||
 | 
					  io.csr.rdata(DST_STRIDE) := crfile.io.dst_stride
 | 
				
			||||||
 | 
					  io.csr.rdata(SEGMENT_SIZE) := crfile.io.segment_size
 | 
				
			||||||
 | 
					  io.csr.rdata(NSEGMENTS) := crfile.io.nsegments
 | 
				
			||||||
 | 
					  io.csr.rdata(WORD_SIZE) := crfile.io.word_size
 | 
				
			||||||
 | 
					  io.csr.rdata(RESP_STATUS) := reg_status
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val frontend = Module(new DmaFrontend)
 | 
				
			||||||
 | 
					  io.ptw(0) <> frontend.io.ptw
 | 
				
			||||||
 | 
					  io.autl <> frontend.io.mem
 | 
				
			||||||
 | 
					  crfile.io.incr_outstanding := frontend.io.incr_outstanding
 | 
				
			||||||
 | 
					  frontend.io.host_id := io.host_id
 | 
				
			||||||
 | 
					  frontend.io.cpu.req.valid := cmd.valid && is_transfer
 | 
				
			||||||
 | 
					  frontend.io.cpu.req.bits := ClientDmaRequest(
 | 
				
			||||||
 | 
					    cmd = cmd.bits.inst.funct,
 | 
				
			||||||
 | 
					    src_start = cmd.bits.rs2,
 | 
				
			||||||
 | 
					    dst_start = cmd.bits.rs1,
 | 
				
			||||||
 | 
					    src_stride = crfile.io.src_stride,
 | 
				
			||||||
 | 
					    dst_stride = crfile.io.dst_stride,
 | 
				
			||||||
 | 
					    segment_size = crfile.io.segment_size,
 | 
				
			||||||
 | 
					    nsegments = crfile.io.nsegments,
 | 
				
			||||||
 | 
					    word_size = crfile.io.word_size)
 | 
				
			||||||
 | 
					  cmd.ready := is_transfer && frontend.io.cpu.req.ready
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  when (frontend.io.cpu.resp.valid) {
 | 
				
			||||||
 | 
					    reg_status := frontend.io.cpu.resp.bits.status
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  io.busy := cmd.valid || frontend.io.busy || crfile.io.xact_outstanding
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										96
									
								
								rocket/src/main/scala/dpath_alu.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								rocket/src/main/scala/dpath_alu.scala
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,96 @@
 | 
				
			|||||||
 | 
					// See LICENSE for license details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package rocket
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import Chisel._
 | 
				
			||||||
 | 
					import cde.{Parameters, Field}
 | 
				
			||||||
 | 
					import Instructions._
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					object ALU
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  val SZ_ALU_FN = 4
 | 
				
			||||||
 | 
					  val FN_X    = BitPat("b????")
 | 
				
			||||||
 | 
					  val FN_ADD  = UInt(0)
 | 
				
			||||||
 | 
					  val FN_SL   = UInt(1)
 | 
				
			||||||
 | 
					  val FN_SEQ  = UInt(2)
 | 
				
			||||||
 | 
					  val FN_SNE  = UInt(3)
 | 
				
			||||||
 | 
					  val FN_XOR  = UInt(4)
 | 
				
			||||||
 | 
					  val FN_SR   = UInt(5)
 | 
				
			||||||
 | 
					  val FN_OR   = UInt(6)
 | 
				
			||||||
 | 
					  val FN_AND  = UInt(7)
 | 
				
			||||||
 | 
					  val FN_SUB  = UInt(10)
 | 
				
			||||||
 | 
					  val FN_SRA  = UInt(11)
 | 
				
			||||||
 | 
					  val FN_SLT  = UInt(12)
 | 
				
			||||||
 | 
					  val FN_SGE  = UInt(13)
 | 
				
			||||||
 | 
					  val FN_SLTU = UInt(14)
 | 
				
			||||||
 | 
					  val FN_SGEU = UInt(15)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val FN_DIV  = FN_XOR
 | 
				
			||||||
 | 
					  val FN_DIVU = FN_SR
 | 
				
			||||||
 | 
					  val FN_REM  = FN_OR
 | 
				
			||||||
 | 
					  val FN_REMU = FN_AND
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val FN_MUL    = FN_ADD
 | 
				
			||||||
 | 
					  val FN_MULH   = FN_SL
 | 
				
			||||||
 | 
					  val FN_MULHSU = FN_SLT
 | 
				
			||||||
 | 
					  val FN_MULHU  = FN_SLTU
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def isMulFN(fn: UInt, cmp: UInt) = fn(1,0) === cmp(1,0)
 | 
				
			||||||
 | 
					  def isSub(cmd: UInt) = cmd(3)
 | 
				
			||||||
 | 
					  def isCmp(cmd: UInt) = cmd === FN_SEQ || cmd === FN_SNE || cmd >= FN_SLT
 | 
				
			||||||
 | 
					  def cmpUnsigned(cmd: UInt) = cmd(1)
 | 
				
			||||||
 | 
					  def cmpInverted(cmd: UInt) = cmd(0)
 | 
				
			||||||
 | 
					  def cmpEq(cmd: UInt) = !cmd(3)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					import ALU._
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ALU(implicit p: Parameters) extends CoreModule()(p) {
 | 
				
			||||||
 | 
					  val io = new Bundle {
 | 
				
			||||||
 | 
					    val dw = Bits(INPUT, SZ_DW)
 | 
				
			||||||
 | 
					    val fn = Bits(INPUT, SZ_ALU_FN)
 | 
				
			||||||
 | 
					    val in2 = UInt(INPUT, xLen)
 | 
				
			||||||
 | 
					    val in1 = UInt(INPUT, xLen)
 | 
				
			||||||
 | 
					    val out = UInt(OUTPUT, xLen)
 | 
				
			||||||
 | 
					    val adder_out = UInt(OUTPUT, xLen)
 | 
				
			||||||
 | 
					    val cmp_out = Bool(OUTPUT)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // ADD, SUB
 | 
				
			||||||
 | 
					  val in2_inv = Mux(isSub(io.fn), ~io.in2, io.in2)
 | 
				
			||||||
 | 
					  val in1_xor_in2 = io.in1 ^ in2_inv
 | 
				
			||||||
 | 
					  io.adder_out := io.in1 + in2_inv + isSub(io.fn)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // SLT, SLTU
 | 
				
			||||||
 | 
					  io.cmp_out := cmpInverted(io.fn) ^
 | 
				
			||||||
 | 
					    Mux(cmpEq(io.fn), in1_xor_in2 === UInt(0),
 | 
				
			||||||
 | 
					    Mux(io.in1(xLen-1) === io.in2(xLen-1), io.adder_out(xLen-1),
 | 
				
			||||||
 | 
					    Mux(cmpUnsigned(io.fn), io.in2(xLen-1), io.in1(xLen-1))))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // SLL, SRL, SRA
 | 
				
			||||||
 | 
					  val (shamt, shin_r) =
 | 
				
			||||||
 | 
					    if (xLen == 32) (io.in2(4,0), io.in1)
 | 
				
			||||||
 | 
					    else {
 | 
				
			||||||
 | 
					      require(xLen == 64)
 | 
				
			||||||
 | 
					      val shin_hi_32 = Fill(32, isSub(io.fn) && io.in1(31))
 | 
				
			||||||
 | 
					      val shin_hi = Mux(io.dw === DW_64, io.in1(63,32), shin_hi_32)
 | 
				
			||||||
 | 
					      val shamt = Cat(io.in2(5) & (io.dw === DW_64), io.in2(4,0))
 | 
				
			||||||
 | 
					      (shamt, Cat(shin_hi, io.in1(31,0)))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  val shin = Mux(io.fn === FN_SR  || io.fn === FN_SRA, shin_r, Reverse(shin_r))
 | 
				
			||||||
 | 
					  val shout_r = (Cat(isSub(io.fn) & shin(xLen-1), shin).toSInt >> shamt)(xLen-1,0)
 | 
				
			||||||
 | 
					  val shout_l = Reverse(shout_r)
 | 
				
			||||||
 | 
					  val shout = Mux(io.fn === FN_SR || io.fn === FN_SRA, shout_r, UInt(0)) |
 | 
				
			||||||
 | 
					              Mux(io.fn === FN_SL,                     shout_l, UInt(0))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // AND, OR, XOR
 | 
				
			||||||
 | 
					  val logic = Mux(io.fn === FN_XOR || io.fn === FN_OR, in1_xor_in2, UInt(0)) |
 | 
				
			||||||
 | 
					              Mux(io.fn === FN_OR || io.fn === FN_AND, io.in1 & io.in2, UInt(0))
 | 
				
			||||||
 | 
					  val shift_logic = (isCmp(io.fn) && io.cmp_out) | logic | shout
 | 
				
			||||||
 | 
					  val out = Mux(io.fn === FN_ADD || io.fn === FN_SUB, io.adder_out, shift_logic)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  io.out := out
 | 
				
			||||||
 | 
					  if (xLen > 32) {
 | 
				
			||||||
 | 
					    require(xLen == 64)
 | 
				
			||||||
 | 
					    when (io.dw === DW_32) { io.out := Cat(Fill(32, out(31)), out(31,0)) }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										641
									
								
								rocket/src/main/scala/fpu.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										641
									
								
								rocket/src/main/scala/fpu.scala
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,641 @@
 | 
				
			|||||||
 | 
					// See LICENSE for license details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package rocket
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import Chisel._
 | 
				
			||||||
 | 
					import Instructions._
 | 
				
			||||||
 | 
					import Util._
 | 
				
			||||||
 | 
					import FPConstants._
 | 
				
			||||||
 | 
					import uncore.constants.MemoryOpConstants._
 | 
				
			||||||
 | 
					import cde.{Parameters, Field}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					case object SFMALatency extends Field[Int]
 | 
				
			||||||
 | 
					case object DFMALatency extends Field[Int]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					object FPConstants
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  val FCMD_ADD =    BitPat("b0??00")
 | 
				
			||||||
 | 
					  val FCMD_SUB =    BitPat("b0??01")
 | 
				
			||||||
 | 
					  val FCMD_MUL =    BitPat("b0??10")
 | 
				
			||||||
 | 
					  val FCMD_MADD =   BitPat("b1??00")
 | 
				
			||||||
 | 
					  val FCMD_MSUB =   BitPat("b1??01")
 | 
				
			||||||
 | 
					  val FCMD_NMSUB =  BitPat("b1??10")
 | 
				
			||||||
 | 
					  val FCMD_NMADD =  BitPat("b1??11")
 | 
				
			||||||
 | 
					  val FCMD_DIV =    BitPat("b?0011")
 | 
				
			||||||
 | 
					  val FCMD_SQRT =   BitPat("b?1011")
 | 
				
			||||||
 | 
					  val FCMD_SGNJ =   BitPat("b??1?0")
 | 
				
			||||||
 | 
					  val FCMD_MINMAX = BitPat("b?01?1")
 | 
				
			||||||
 | 
					  val FCMD_CVT_FF = BitPat("b??0??")
 | 
				
			||||||
 | 
					  val FCMD_CVT_IF = BitPat("b?10??")
 | 
				
			||||||
 | 
					  val FCMD_CMP =    BitPat("b?01??")
 | 
				
			||||||
 | 
					  val FCMD_MV_XF =  BitPat("b?11??")
 | 
				
			||||||
 | 
					  val FCMD_CVT_FI = BitPat("b??0??")
 | 
				
			||||||
 | 
					  val FCMD_MV_FX =  BitPat("b??1??")
 | 
				
			||||||
 | 
					  val FCMD_X =      BitPat("b?????")
 | 
				
			||||||
 | 
					  val FCMD_WIDTH = 5
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val RM_SZ = 3
 | 
				
			||||||
 | 
					  val FLAGS_SZ = 5
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class FPUCtrlSigs extends Bundle
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  val cmd = Bits(width = FCMD_WIDTH)
 | 
				
			||||||
 | 
					  val ldst = Bool()
 | 
				
			||||||
 | 
					  val wen = Bool()
 | 
				
			||||||
 | 
					  val ren1 = Bool()
 | 
				
			||||||
 | 
					  val ren2 = Bool()
 | 
				
			||||||
 | 
					  val ren3 = Bool()
 | 
				
			||||||
 | 
					  val swap12 = Bool()
 | 
				
			||||||
 | 
					  val swap23 = Bool()
 | 
				
			||||||
 | 
					  val single = Bool()
 | 
				
			||||||
 | 
					  val fromint = Bool()
 | 
				
			||||||
 | 
					  val toint = Bool()
 | 
				
			||||||
 | 
					  val fastpipe = Bool()
 | 
				
			||||||
 | 
					  val fma = Bool()
 | 
				
			||||||
 | 
					  val div = Bool()
 | 
				
			||||||
 | 
					  val sqrt = Bool()
 | 
				
			||||||
 | 
					  val round = Bool()
 | 
				
			||||||
 | 
					  val wflags = Bool()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class FPUDecoder extends Module
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  val io = new Bundle {
 | 
				
			||||||
 | 
					    val inst = Bits(INPUT, 32)
 | 
				
			||||||
 | 
					    val sigs = new FPUCtrlSigs().asOutput
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val decoder = DecodeLogic(io.inst,
 | 
				
			||||||
 | 
					    List                  (FCMD_X,      X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X),
 | 
				
			||||||
 | 
					    Array(FLW      -> List(FCMD_X,      Y,Y,N,N,N,X,X,Y,N,N,N,N,N,N,N,N),
 | 
				
			||||||
 | 
					          FLD      -> List(FCMD_X,      Y,Y,N,N,N,X,X,N,N,N,N,N,N,N,N,N),
 | 
				
			||||||
 | 
					          FSW      -> List(FCMD_MV_XF,  Y,N,N,Y,N,Y,X,Y,N,Y,N,N,N,N,N,N),
 | 
				
			||||||
 | 
					          FSD      -> List(FCMD_MV_XF,  Y,N,N,Y,N,Y,X,N,N,Y,N,N,N,N,N,N),
 | 
				
			||||||
 | 
					          FMV_S_X  -> List(FCMD_MV_FX,  N,Y,N,N,N,X,X,Y,Y,N,N,N,N,N,Y,N),
 | 
				
			||||||
 | 
					          FMV_D_X  -> List(FCMD_MV_FX,  N,Y,N,N,N,X,X,N,Y,N,N,N,N,N,Y,N),
 | 
				
			||||||
 | 
					          FCVT_S_W -> List(FCMD_CVT_FI, N,Y,N,N,N,X,X,Y,Y,N,N,N,N,N,Y,Y),
 | 
				
			||||||
 | 
					          FCVT_S_WU-> List(FCMD_CVT_FI, N,Y,N,N,N,X,X,Y,Y,N,N,N,N,N,Y,Y),
 | 
				
			||||||
 | 
					          FCVT_S_L -> List(FCMD_CVT_FI, N,Y,N,N,N,X,X,Y,Y,N,N,N,N,N,Y,Y),
 | 
				
			||||||
 | 
					          FCVT_S_LU-> List(FCMD_CVT_FI, N,Y,N,N,N,X,X,Y,Y,N,N,N,N,N,Y,Y),
 | 
				
			||||||
 | 
					          FCVT_D_W -> List(FCMD_CVT_FI, N,Y,N,N,N,X,X,N,Y,N,N,N,N,N,Y,Y),
 | 
				
			||||||
 | 
					          FCVT_D_WU-> List(FCMD_CVT_FI, N,Y,N,N,N,X,X,N,Y,N,N,N,N,N,Y,Y),
 | 
				
			||||||
 | 
					          FCVT_D_L -> List(FCMD_CVT_FI, N,Y,N,N,N,X,X,N,Y,N,N,N,N,N,Y,Y),
 | 
				
			||||||
 | 
					          FCVT_D_LU-> List(FCMD_CVT_FI, N,Y,N,N,N,X,X,N,Y,N,N,N,N,N,Y,Y),
 | 
				
			||||||
 | 
					          FMV_X_S  -> List(FCMD_MV_XF,  N,N,Y,N,N,N,X,Y,N,Y,N,N,N,N,Y,N),
 | 
				
			||||||
 | 
					          FMV_X_D  -> List(FCMD_MV_XF,  N,N,Y,N,N,N,X,N,N,Y,N,N,N,N,Y,N),
 | 
				
			||||||
 | 
					          FCLASS_S -> List(FCMD_MV_XF,  N,N,Y,N,N,N,X,Y,N,Y,N,N,N,N,Y,N),
 | 
				
			||||||
 | 
					          FCLASS_D -> List(FCMD_MV_XF,  N,N,Y,N,N,N,X,N,N,Y,N,N,N,N,Y,N),
 | 
				
			||||||
 | 
					          FCVT_W_S -> List(FCMD_CVT_IF, N,N,Y,N,N,N,X,Y,N,Y,N,N,N,N,Y,Y),
 | 
				
			||||||
 | 
					          FCVT_WU_S-> List(FCMD_CVT_IF, N,N,Y,N,N,N,X,Y,N,Y,N,N,N,N,Y,Y),
 | 
				
			||||||
 | 
					          FCVT_L_S -> List(FCMD_CVT_IF, N,N,Y,N,N,N,X,Y,N,Y,N,N,N,N,Y,Y),
 | 
				
			||||||
 | 
					          FCVT_LU_S-> List(FCMD_CVT_IF, N,N,Y,N,N,N,X,Y,N,Y,N,N,N,N,Y,Y),
 | 
				
			||||||
 | 
					          FCVT_W_D -> List(FCMD_CVT_IF, N,N,Y,N,N,N,X,N,N,Y,N,N,N,N,Y,Y),
 | 
				
			||||||
 | 
					          FCVT_WU_D-> List(FCMD_CVT_IF, N,N,Y,N,N,N,X,N,N,Y,N,N,N,N,Y,Y),
 | 
				
			||||||
 | 
					          FCVT_L_D -> List(FCMD_CVT_IF, N,N,Y,N,N,N,X,N,N,Y,N,N,N,N,Y,Y),
 | 
				
			||||||
 | 
					          FCVT_LU_D-> List(FCMD_CVT_IF, N,N,Y,N,N,N,X,N,N,Y,N,N,N,N,Y,Y),
 | 
				
			||||||
 | 
					          FCVT_S_D -> List(FCMD_CVT_FF, N,Y,Y,N,N,N,X,Y,N,N,Y,N,N,N,Y,Y),
 | 
				
			||||||
 | 
					          FCVT_D_S -> List(FCMD_CVT_FF, N,Y,Y,N,N,N,X,N,N,N,Y,N,N,N,Y,Y),
 | 
				
			||||||
 | 
					          FEQ_S    -> List(FCMD_CMP,    N,N,Y,Y,N,N,N,Y,N,Y,N,N,N,N,N,Y),
 | 
				
			||||||
 | 
					          FLT_S    -> List(FCMD_CMP,    N,N,Y,Y,N,N,N,Y,N,Y,N,N,N,N,N,Y),
 | 
				
			||||||
 | 
					          FLE_S    -> List(FCMD_CMP,    N,N,Y,Y,N,N,N,Y,N,Y,N,N,N,N,N,Y),
 | 
				
			||||||
 | 
					          FEQ_D    -> List(FCMD_CMP,    N,N,Y,Y,N,N,N,N,N,Y,N,N,N,N,N,Y),
 | 
				
			||||||
 | 
					          FLT_D    -> List(FCMD_CMP,    N,N,Y,Y,N,N,N,N,N,Y,N,N,N,N,N,Y),
 | 
				
			||||||
 | 
					          FLE_D    -> List(FCMD_CMP,    N,N,Y,Y,N,N,N,N,N,Y,N,N,N,N,N,Y),
 | 
				
			||||||
 | 
					          FSGNJ_S  -> List(FCMD_SGNJ,   N,Y,Y,Y,N,N,N,Y,N,N,Y,N,N,N,N,N),
 | 
				
			||||||
 | 
					          FSGNJN_S -> List(FCMD_SGNJ,   N,Y,Y,Y,N,N,N,Y,N,N,Y,N,N,N,N,N),
 | 
				
			||||||
 | 
					          FSGNJX_S -> List(FCMD_SGNJ,   N,Y,Y,Y,N,N,N,Y,N,N,Y,N,N,N,N,N),
 | 
				
			||||||
 | 
					          FSGNJ_D  -> List(FCMD_SGNJ,   N,Y,Y,Y,N,N,N,N,N,N,Y,N,N,N,N,N),
 | 
				
			||||||
 | 
					          FSGNJN_D -> List(FCMD_SGNJ,   N,Y,Y,Y,N,N,N,N,N,N,Y,N,N,N,N,N),
 | 
				
			||||||
 | 
					          FSGNJX_D -> List(FCMD_SGNJ,   N,Y,Y,Y,N,N,N,N,N,N,Y,N,N,N,N,N),
 | 
				
			||||||
 | 
					          FMIN_S   -> List(FCMD_MINMAX, N,Y,Y,Y,N,N,N,Y,N,N,Y,N,N,N,N,Y),
 | 
				
			||||||
 | 
					          FMAX_S   -> List(FCMD_MINMAX, N,Y,Y,Y,N,N,N,Y,N,N,Y,N,N,N,N,Y),
 | 
				
			||||||
 | 
					          FMIN_D   -> List(FCMD_MINMAX, N,Y,Y,Y,N,N,N,N,N,N,Y,N,N,N,N,Y),
 | 
				
			||||||
 | 
					          FMAX_D   -> List(FCMD_MINMAX, N,Y,Y,Y,N,N,N,N,N,N,Y,N,N,N,N,Y),
 | 
				
			||||||
 | 
					          FADD_S   -> List(FCMD_ADD,    N,Y,Y,Y,N,N,Y,Y,N,N,N,Y,N,N,Y,Y),
 | 
				
			||||||
 | 
					          FSUB_S   -> List(FCMD_SUB,    N,Y,Y,Y,N,N,Y,Y,N,N,N,Y,N,N,Y,Y),
 | 
				
			||||||
 | 
					          FMUL_S   -> List(FCMD_MUL,    N,Y,Y,Y,N,N,N,Y,N,N,N,Y,N,N,Y,Y),
 | 
				
			||||||
 | 
					          FADD_D   -> List(FCMD_ADD,    N,Y,Y,Y,N,N,Y,N,N,N,N,Y,N,N,Y,Y),
 | 
				
			||||||
 | 
					          FSUB_D   -> List(FCMD_SUB,    N,Y,Y,Y,N,N,Y,N,N,N,N,Y,N,N,Y,Y),
 | 
				
			||||||
 | 
					          FMUL_D   -> List(FCMD_MUL,    N,Y,Y,Y,N,N,N,N,N,N,N,Y,N,N,Y,Y),
 | 
				
			||||||
 | 
					          FMADD_S  -> List(FCMD_MADD,   N,Y,Y,Y,Y,N,N,Y,N,N,N,Y,N,N,Y,Y),
 | 
				
			||||||
 | 
					          FMSUB_S  -> List(FCMD_MSUB,   N,Y,Y,Y,Y,N,N,Y,N,N,N,Y,N,N,Y,Y),
 | 
				
			||||||
 | 
					          FNMADD_S -> List(FCMD_NMADD,  N,Y,Y,Y,Y,N,N,Y,N,N,N,Y,N,N,Y,Y),
 | 
				
			||||||
 | 
					          FNMSUB_S -> List(FCMD_NMSUB,  N,Y,Y,Y,Y,N,N,Y,N,N,N,Y,N,N,Y,Y),
 | 
				
			||||||
 | 
					          FMADD_D  -> List(FCMD_MADD,   N,Y,Y,Y,Y,N,N,N,N,N,N,Y,N,N,Y,Y),
 | 
				
			||||||
 | 
					          FMSUB_D  -> List(FCMD_MSUB,   N,Y,Y,Y,Y,N,N,N,N,N,N,Y,N,N,Y,Y),
 | 
				
			||||||
 | 
					          FNMADD_D -> List(FCMD_NMADD,  N,Y,Y,Y,Y,N,N,N,N,N,N,Y,N,N,Y,Y),
 | 
				
			||||||
 | 
					          FNMSUB_D -> List(FCMD_NMSUB,  N,Y,Y,Y,Y,N,N,N,N,N,N,Y,N,N,Y,Y),
 | 
				
			||||||
 | 
					          FDIV_S   -> List(FCMD_DIV,    N,Y,Y,Y,N,N,N,Y,N,N,N,N,Y,N,Y,Y),
 | 
				
			||||||
 | 
					          FSQRT_S  -> List(FCMD_SQRT,   N,Y,Y,N,N,Y,X,Y,N,N,N,N,N,Y,Y,Y),
 | 
				
			||||||
 | 
					          FDIV_D   -> List(FCMD_DIV,    N,Y,Y,Y,N,N,N,N,N,N,N,N,Y,N,Y,Y),
 | 
				
			||||||
 | 
					          FSQRT_D  -> List(FCMD_SQRT,   N,Y,Y,N,N,Y,X,N,N,N,N,N,N,Y,Y,Y)
 | 
				
			||||||
 | 
					          ))
 | 
				
			||||||
 | 
					  val s = io.sigs
 | 
				
			||||||
 | 
					  val sigs = Seq(s.cmd, s.ldst, s.wen, s.ren1, s.ren2, s.ren3, s.swap12,
 | 
				
			||||||
 | 
					                 s.swap23, s.single, s.fromint, s.toint, s.fastpipe, s.fma,
 | 
				
			||||||
 | 
					                 s.div, s.sqrt, s.round, s.wflags)
 | 
				
			||||||
 | 
					  sigs zip decoder map {case(s,d) => s := d}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class FPUIO(implicit p: Parameters) extends CoreBundle {
 | 
				
			||||||
 | 
					  val inst = Bits(INPUT, 32)
 | 
				
			||||||
 | 
					  val fromint_data = Bits(INPUT, xLen)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val fcsr_rm = Bits(INPUT, FPConstants.RM_SZ)
 | 
				
			||||||
 | 
					  val fcsr_flags = Valid(Bits(width = FPConstants.FLAGS_SZ))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val store_data = Bits(OUTPUT, 64)
 | 
				
			||||||
 | 
					  val toint_data = Bits(OUTPUT, xLen)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val dmem_resp_val = Bool(INPUT)
 | 
				
			||||||
 | 
					  val dmem_resp_type = Bits(INPUT, 3)
 | 
				
			||||||
 | 
					  val dmem_resp_tag = UInt(INPUT, 5)
 | 
				
			||||||
 | 
					  val dmem_resp_data = Bits(INPUT, 64)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val valid = Bool(INPUT)
 | 
				
			||||||
 | 
					  val fcsr_rdy = Bool(OUTPUT)
 | 
				
			||||||
 | 
					  val nack_mem = Bool(OUTPUT)
 | 
				
			||||||
 | 
					  val illegal_rm = Bool(OUTPUT)
 | 
				
			||||||
 | 
					  val killx = Bool(INPUT)
 | 
				
			||||||
 | 
					  val killm = Bool(INPUT)
 | 
				
			||||||
 | 
					  val dec = new FPUCtrlSigs().asOutput
 | 
				
			||||||
 | 
					  val sboard_set = Bool(OUTPUT)
 | 
				
			||||||
 | 
					  val sboard_clr = Bool(OUTPUT)
 | 
				
			||||||
 | 
					  val sboard_clra = UInt(OUTPUT, 5)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val cp_req = Decoupled(new FPInput()).flip //cp doesn't pay attn to kill sigs
 | 
				
			||||||
 | 
					  val cp_resp = Decoupled(new FPResult())
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class FPResult extends Bundle
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  val data = Bits(width = 65)
 | 
				
			||||||
 | 
					  val exc = Bits(width = 5)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class FPInput extends FPUCtrlSigs {
 | 
				
			||||||
 | 
					  val rm = Bits(width = 3)
 | 
				
			||||||
 | 
					  val typ = Bits(width = 2)
 | 
				
			||||||
 | 
					  val in1 = Bits(width = 65)
 | 
				
			||||||
 | 
					  val in2 = Bits(width = 65)
 | 
				
			||||||
 | 
					  val in3 = Bits(width = 65)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					object ClassifyRecFN {
 | 
				
			||||||
 | 
					  def apply(expWidth: Int, sigWidth: Int, in: UInt) = {
 | 
				
			||||||
 | 
					    val sign = in(sigWidth + expWidth)
 | 
				
			||||||
 | 
					    val exp = in(sigWidth + expWidth - 1, sigWidth - 1)
 | 
				
			||||||
 | 
					    val sig = in(sigWidth - 2, 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    val code        = exp(expWidth,expWidth-2)
 | 
				
			||||||
 | 
					    val codeHi      = code(2, 1)
 | 
				
			||||||
 | 
					    val isSpecial   = codeHi === UInt(3)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    val isHighSubnormalIn = exp(expWidth-2, 0) < UInt(2)
 | 
				
			||||||
 | 
					    val isSubnormal = code === UInt(1) || codeHi === UInt(1) && isHighSubnormalIn
 | 
				
			||||||
 | 
					    val isNormal = codeHi === UInt(1) && !isHighSubnormalIn || codeHi === UInt(2)
 | 
				
			||||||
 | 
					    val isZero = code === UInt(0)
 | 
				
			||||||
 | 
					    val isInf = isSpecial && !exp(expWidth-2)
 | 
				
			||||||
 | 
					    val isNaN = code.andR
 | 
				
			||||||
 | 
					    val isSNaN = isNaN && !sig(sigWidth-2)
 | 
				
			||||||
 | 
					    val isQNaN = isNaN && sig(sigWidth-2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Cat(isQNaN, isSNaN, isInf && !sign, isNormal && !sign,
 | 
				
			||||||
 | 
					        isSubnormal && !sign, isZero && !sign, isZero && sign,
 | 
				
			||||||
 | 
					        isSubnormal && sign, isNormal && sign, isInf && sign)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class FPToInt extends Module
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  val io = new Bundle {
 | 
				
			||||||
 | 
					    val in = Valid(new FPInput).flip
 | 
				
			||||||
 | 
					    val as_double = new FPInput().asOutput
 | 
				
			||||||
 | 
					    val out = Valid(new Bundle {
 | 
				
			||||||
 | 
					      val lt = Bool()
 | 
				
			||||||
 | 
					      val store = Bits(width = 64)
 | 
				
			||||||
 | 
					      val toint = Bits(width = 64)
 | 
				
			||||||
 | 
					      val exc = Bits(width = 5)
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val in = Reg(new FPInput)
 | 
				
			||||||
 | 
					  val valid = Reg(next=io.in.valid)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def upconvert(x: UInt) = {
 | 
				
			||||||
 | 
					    val s2d = Module(new hardfloat.RecFNToRecFN(8, 24, 11, 53))
 | 
				
			||||||
 | 
					    s2d.io.in := x
 | 
				
			||||||
 | 
					    s2d.io.roundingMode := UInt(0)
 | 
				
			||||||
 | 
					    s2d.io.out
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val in1_upconvert = upconvert(io.in.bits.in1)
 | 
				
			||||||
 | 
					  val in2_upconvert = upconvert(io.in.bits.in2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  when (io.in.valid) {
 | 
				
			||||||
 | 
					    in := io.in.bits
 | 
				
			||||||
 | 
					    when (io.in.bits.single && !io.in.bits.ldst && io.in.bits.cmd =/= FCMD_MV_XF) {
 | 
				
			||||||
 | 
					      in.in1 := in1_upconvert
 | 
				
			||||||
 | 
					      in.in2 := in2_upconvert
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val unrec_s = hardfloat.fNFromRecFN(8, 24, in.in1)
 | 
				
			||||||
 | 
					  val unrec_d = hardfloat.fNFromRecFN(11, 53, in.in1)
 | 
				
			||||||
 | 
					  val unrec_out = Mux(in.single, Cat(Fill(32, unrec_s(31)), unrec_s), unrec_d)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val classify_s = ClassifyRecFN(8, 24, in.in1)
 | 
				
			||||||
 | 
					  val classify_d = ClassifyRecFN(11, 53, in.in1)
 | 
				
			||||||
 | 
					  val classify_out = Mux(in.single, classify_s, classify_d)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val dcmp = Module(new hardfloat.CompareRecFN(11, 53))
 | 
				
			||||||
 | 
					  dcmp.io.a := in.in1
 | 
				
			||||||
 | 
					  dcmp.io.b := in.in2
 | 
				
			||||||
 | 
					  dcmp.io.signaling := Bool(true)
 | 
				
			||||||
 | 
					  val dcmp_out = (~in.rm & Cat(dcmp.io.lt, dcmp.io.eq)).orR
 | 
				
			||||||
 | 
					  val dcmp_exc = dcmp.io.exceptionFlags
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val d2l = Module(new hardfloat.RecFNToIN(11, 53, 64))
 | 
				
			||||||
 | 
					  val d2w = Module(new hardfloat.RecFNToIN(11, 53, 32))
 | 
				
			||||||
 | 
					  d2l.io.in := in.in1
 | 
				
			||||||
 | 
					  d2l.io.roundingMode := in.rm
 | 
				
			||||||
 | 
					  d2l.io.signedOut := ~in.typ(0)
 | 
				
			||||||
 | 
					  d2w.io.in := in.in1
 | 
				
			||||||
 | 
					  d2w.io.roundingMode := in.rm
 | 
				
			||||||
 | 
					  d2w.io.signedOut := ~in.typ(0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  io.out.bits.toint := Mux(in.rm(0), classify_out, unrec_out)
 | 
				
			||||||
 | 
					  io.out.bits.store := unrec_out
 | 
				
			||||||
 | 
					  io.out.bits.exc := Bits(0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  when (in.cmd === FCMD_CMP) {
 | 
				
			||||||
 | 
					    io.out.bits.toint := dcmp_out
 | 
				
			||||||
 | 
					    io.out.bits.exc := dcmp_exc
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  when (in.cmd === FCMD_CVT_IF) {
 | 
				
			||||||
 | 
					    io.out.bits.toint := Mux(in.typ(1), d2l.io.out.toSInt, d2w.io.out.toSInt).toUInt
 | 
				
			||||||
 | 
					    val dflags = Mux(in.typ(1), d2l.io.intExceptionFlags, d2w.io.intExceptionFlags)
 | 
				
			||||||
 | 
					    io.out.bits.exc := Cat(dflags(2, 1).orR, UInt(0, 3), dflags(0))
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  io.out.valid := valid
 | 
				
			||||||
 | 
					  io.out.bits.lt := dcmp.io.lt
 | 
				
			||||||
 | 
					  io.as_double := in
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class IntToFP(val latency: Int) extends Module
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  val io = new Bundle {
 | 
				
			||||||
 | 
					    val in = Valid(new FPInput).flip
 | 
				
			||||||
 | 
					    val out = Valid(new FPResult)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val in = Pipe(io.in)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val mux = Wire(new FPResult)
 | 
				
			||||||
 | 
					  mux.exc := Bits(0)
 | 
				
			||||||
 | 
					  mux.data := hardfloat.recFNFromFN(11, 53, in.bits.in1)
 | 
				
			||||||
 | 
					  when (in.bits.single) {
 | 
				
			||||||
 | 
					    mux.data := Cat(SInt(-1, 32), hardfloat.recFNFromFN(8, 24, in.bits.in1))
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val longValue =
 | 
				
			||||||
 | 
					    Mux(in.bits.typ(1), in.bits.in1.toSInt,
 | 
				
			||||||
 | 
					    Mux(in.bits.typ(0), in.bits.in1(31,0).zext, in.bits.in1(31,0).toSInt))
 | 
				
			||||||
 | 
					  val l2s = Module(new hardfloat.INToRecFN(64, 8, 24))
 | 
				
			||||||
 | 
					  l2s.io.signedIn := ~in.bits.typ(0)
 | 
				
			||||||
 | 
					  l2s.io.in := longValue.toUInt
 | 
				
			||||||
 | 
					  l2s.io.roundingMode := in.bits.rm
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val l2d = Module(new hardfloat.INToRecFN(64, 11, 53))
 | 
				
			||||||
 | 
					  l2d.io.signedIn := ~in.bits.typ(0)
 | 
				
			||||||
 | 
					  l2d.io.in := longValue.toUInt
 | 
				
			||||||
 | 
					  l2d.io.roundingMode := in.bits.rm
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  when (in.bits.cmd === FCMD_CVT_FI) {
 | 
				
			||||||
 | 
					    when (in.bits.single) {
 | 
				
			||||||
 | 
					      mux.data := Cat(SInt(-1, 32), l2s.io.out)
 | 
				
			||||||
 | 
					      mux.exc := l2s.io.exceptionFlags
 | 
				
			||||||
 | 
					    }.otherwise {
 | 
				
			||||||
 | 
					      mux.data := l2d.io.out
 | 
				
			||||||
 | 
					      mux.exc := l2d.io.exceptionFlags
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  io.out <> Pipe(in.valid, mux, latency-1)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class FPToFP(val latency: Int) extends Module
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  val io = new Bundle {
 | 
				
			||||||
 | 
					    val in = Valid(new FPInput).flip
 | 
				
			||||||
 | 
					    val out = Valid(new FPResult)
 | 
				
			||||||
 | 
					    val lt = Bool(INPUT) // from FPToInt
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val in = Pipe(io.in)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // fp->fp units
 | 
				
			||||||
 | 
					  val isSgnj = in.bits.cmd === FCMD_SGNJ
 | 
				
			||||||
 | 
					  def fsgnjSign(in1: Bits, in2: Bits, pos: Int, en: Bool, rm: Bits) =
 | 
				
			||||||
 | 
					    Mux(rm(1) || !en, in1(pos), rm(0)) ^ (en && in2(pos))
 | 
				
			||||||
 | 
					  val sign_s = fsgnjSign(in.bits.in1, in.bits.in2, 32, in.bits.single && isSgnj, in.bits.rm)
 | 
				
			||||||
 | 
					  val sign_d = fsgnjSign(in.bits.in1, in.bits.in2, 64, !in.bits.single && isSgnj, in.bits.rm)
 | 
				
			||||||
 | 
					  val fsgnj = Cat(sign_d, in.bits.in1(63,33), sign_s, in.bits.in1(31,0))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val s2d = Module(new hardfloat.RecFNToRecFN(8, 24, 11, 53))
 | 
				
			||||||
 | 
					  val d2s = Module(new hardfloat.RecFNToRecFN(11, 53, 8, 24))
 | 
				
			||||||
 | 
					  s2d.io.in := in.bits.in1
 | 
				
			||||||
 | 
					  s2d.io.roundingMode := in.bits.rm
 | 
				
			||||||
 | 
					  d2s.io.in := in.bits.in1
 | 
				
			||||||
 | 
					  d2s.io.roundingMode := in.bits.rm
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val isnan1 = Mux(in.bits.single, in.bits.in1(31,29).andR, in.bits.in1(63,61).andR)
 | 
				
			||||||
 | 
					  val isnan2 = Mux(in.bits.single, in.bits.in2(31,29).andR, in.bits.in2(63,61).andR)
 | 
				
			||||||
 | 
					  val issnan1 = isnan1 && ~Mux(in.bits.single, in.bits.in1(22), in.bits.in1(51))
 | 
				
			||||||
 | 
					  val issnan2 = isnan2 && ~Mux(in.bits.single, in.bits.in2(22), in.bits.in2(51))
 | 
				
			||||||
 | 
					  val minmax_exc = Cat(issnan1 || issnan2, Bits(0,4))
 | 
				
			||||||
 | 
					  val isMax = in.bits.rm(0)
 | 
				
			||||||
 | 
					  val isLHS = isnan2 || isMax =/= io.lt && !isnan1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val mux = Wire(new FPResult)
 | 
				
			||||||
 | 
					  mux.exc := minmax_exc
 | 
				
			||||||
 | 
					  mux.data := in.bits.in2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  when (isSgnj) { mux.exc := UInt(0) }
 | 
				
			||||||
 | 
					  when (isSgnj || isLHS) { mux.data := fsgnj }
 | 
				
			||||||
 | 
					  when (in.bits.cmd === FCMD_CVT_FF) {
 | 
				
			||||||
 | 
					    when (in.bits.single) {
 | 
				
			||||||
 | 
					      mux.data := Cat(SInt(-1, 32), d2s.io.out)
 | 
				
			||||||
 | 
					      mux.exc := d2s.io.exceptionFlags
 | 
				
			||||||
 | 
					    }.otherwise {
 | 
				
			||||||
 | 
					      mux.data := s2d.io.out
 | 
				
			||||||
 | 
					      mux.exc := s2d.io.exceptionFlags
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  io.out <> Pipe(in.valid, mux, latency-1)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class FPUFMAPipe(val latency: Int, expWidth: Int, sigWidth: Int) extends Module
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  val io = new Bundle {
 | 
				
			||||||
 | 
					    val in = Valid(new FPInput).flip
 | 
				
			||||||
 | 
					    val out = Valid(new FPResult)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val width = sigWidth + expWidth
 | 
				
			||||||
 | 
					  val one = UInt(1) << (width-1)
 | 
				
			||||||
 | 
					  val zero = (io.in.bits.in1(width) ^ io.in.bits.in2(width)) << width
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val valid = Reg(next=io.in.valid)
 | 
				
			||||||
 | 
					  val in = Reg(new FPInput)
 | 
				
			||||||
 | 
					  when (io.in.valid) {
 | 
				
			||||||
 | 
					    in := io.in.bits
 | 
				
			||||||
 | 
					    val cmd_fma = io.in.bits.ren3
 | 
				
			||||||
 | 
					    val cmd_addsub = io.in.bits.swap23
 | 
				
			||||||
 | 
					    in.cmd := Cat(io.in.bits.cmd(1) & (cmd_fma || cmd_addsub), io.in.bits.cmd(0))
 | 
				
			||||||
 | 
					    when (cmd_addsub) { in.in2 := one }
 | 
				
			||||||
 | 
					    unless (cmd_fma || cmd_addsub) { in.in3 := zero }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val fma = Module(new hardfloat.MulAddRecFN(expWidth, sigWidth))
 | 
				
			||||||
 | 
					  fma.io.op := in.cmd
 | 
				
			||||||
 | 
					  fma.io.roundingMode := in.rm
 | 
				
			||||||
 | 
					  fma.io.a := in.in1
 | 
				
			||||||
 | 
					  fma.io.b := in.in2
 | 
				
			||||||
 | 
					  fma.io.c := in.in3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val res = Wire(new FPResult)
 | 
				
			||||||
 | 
					  res.data := Cat(SInt(-1, 32), fma.io.out)
 | 
				
			||||||
 | 
					  res.exc := fma.io.exceptionFlags
 | 
				
			||||||
 | 
					  io.out := Pipe(valid, res, latency-1)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class FPU(implicit p: Parameters) extends CoreModule()(p) {
 | 
				
			||||||
 | 
					  require(xLen == 64, "RV32 Rocket FP support missing")
 | 
				
			||||||
 | 
					  val io = new FPUIO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val ex_reg_valid = Reg(next=io.valid, init=Bool(false))
 | 
				
			||||||
 | 
					  val req_valid = ex_reg_valid || io.cp_req.valid
 | 
				
			||||||
 | 
					  val ex_reg_inst = RegEnable(io.inst, io.valid)
 | 
				
			||||||
 | 
					  val ex_cp_valid = io.cp_req.valid && !ex_reg_valid
 | 
				
			||||||
 | 
					  val mem_reg_valid = Reg(next=ex_reg_valid && !io.killx || ex_cp_valid, init=Bool(false))
 | 
				
			||||||
 | 
					  val mem_reg_inst = RegEnable(ex_reg_inst, ex_reg_valid)
 | 
				
			||||||
 | 
					  val mem_cp_valid = Reg(next=ex_cp_valid, init=Bool(false))
 | 
				
			||||||
 | 
					  val killm = (io.killm || io.nack_mem) && !mem_cp_valid
 | 
				
			||||||
 | 
					  val wb_reg_valid = Reg(next=mem_reg_valid && (!killm || mem_cp_valid), init=Bool(false))
 | 
				
			||||||
 | 
					  val wb_cp_valid = Reg(next=mem_cp_valid, init=Bool(false))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val fp_decoder = Module(new FPUDecoder)
 | 
				
			||||||
 | 
					  fp_decoder.io.inst := io.inst
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val cp_ctrl = Wire(new FPUCtrlSigs)
 | 
				
			||||||
 | 
					  cp_ctrl <> io.cp_req.bits
 | 
				
			||||||
 | 
					  io.cp_resp.valid := Bool(false)
 | 
				
			||||||
 | 
					  io.cp_resp.bits.data := UInt(0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val id_ctrl = fp_decoder.io.sigs
 | 
				
			||||||
 | 
					  val ex_ctrl = Mux(ex_reg_valid, RegEnable(id_ctrl, io.valid), cp_ctrl)
 | 
				
			||||||
 | 
					  val mem_ctrl = RegEnable(ex_ctrl, req_valid)
 | 
				
			||||||
 | 
					  val wb_ctrl = RegEnable(mem_ctrl, mem_reg_valid)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // load response
 | 
				
			||||||
 | 
					  val load_wb = Reg(next=io.dmem_resp_val)
 | 
				
			||||||
 | 
					  val load_wb_single = RegEnable(io.dmem_resp_type === MT_W || io.dmem_resp_type === MT_WU, io.dmem_resp_val)
 | 
				
			||||||
 | 
					  val load_wb_data = RegEnable(io.dmem_resp_data, io.dmem_resp_val)
 | 
				
			||||||
 | 
					  val load_wb_tag = RegEnable(io.dmem_resp_tag, io.dmem_resp_val)
 | 
				
			||||||
 | 
					  val rec_s = hardfloat.recFNFromFN(8, 24, load_wb_data)
 | 
				
			||||||
 | 
					  val rec_d = hardfloat.recFNFromFN(11, 53, load_wb_data)
 | 
				
			||||||
 | 
					  val load_wb_data_recoded = Mux(load_wb_single, Cat(SInt(-1, 32), rec_s), rec_d)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // regfile
 | 
				
			||||||
 | 
					  val regfile = Mem(32, Bits(width = 65))
 | 
				
			||||||
 | 
					  when (load_wb) {
 | 
				
			||||||
 | 
					    regfile(load_wb_tag) := load_wb_data_recoded
 | 
				
			||||||
 | 
					    if (enableCommitLog) {
 | 
				
			||||||
 | 
					      printf ("f%d p%d 0x%x\n", load_wb_tag, load_wb_tag + UInt(32),
 | 
				
			||||||
 | 
					        Mux(load_wb_single, load_wb_data(31,0), load_wb_data))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val ex_ra1::ex_ra2::ex_ra3::Nil = List.fill(3)(Reg(UInt()))
 | 
				
			||||||
 | 
					  when (io.valid) {
 | 
				
			||||||
 | 
					    when (id_ctrl.ren1) {
 | 
				
			||||||
 | 
					      when (!id_ctrl.swap12) { ex_ra1 := io.inst(19,15) }
 | 
				
			||||||
 | 
					      when (id_ctrl.swap12) { ex_ra2 := io.inst(19,15) }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    when (id_ctrl.ren2) {
 | 
				
			||||||
 | 
					      when (id_ctrl.swap12) { ex_ra1 := io.inst(24,20) }
 | 
				
			||||||
 | 
					      when (id_ctrl.swap23) { ex_ra3 := io.inst(24,20) }
 | 
				
			||||||
 | 
					      when (!id_ctrl.swap12 && !id_ctrl.swap23) { ex_ra2 := io.inst(24,20) }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    when (id_ctrl.ren3) { ex_ra3 := io.inst(31,27) }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  val ex_rs1::ex_rs2::ex_rs3::Nil = Seq(ex_ra1, ex_ra2, ex_ra3).map(regfile(_))
 | 
				
			||||||
 | 
					  val ex_rm = Mux(ex_reg_inst(14,12) === Bits(7), io.fcsr_rm, ex_reg_inst(14,12))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val cp_rs1 = io.cp_req.bits.in1
 | 
				
			||||||
 | 
					  val cp_rs2 = Mux(io.cp_req.bits.swap23, io.cp_req.bits.in3, io.cp_req.bits.in2)
 | 
				
			||||||
 | 
					  val cp_rs3 = Mux(io.cp_req.bits.swap23, io.cp_req.bits.in2, io.cp_req.bits.in3)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val req = Wire(new FPInput)
 | 
				
			||||||
 | 
					  req := ex_ctrl
 | 
				
			||||||
 | 
					  req.rm := Mux(ex_reg_valid, ex_rm, io.cp_req.bits.rm)
 | 
				
			||||||
 | 
					  req.in1 := Mux(ex_reg_valid, ex_rs1, cp_rs1)
 | 
				
			||||||
 | 
					  req.in2 := Mux(ex_reg_valid, ex_rs2, cp_rs2)
 | 
				
			||||||
 | 
					  req.in3 := Mux(ex_reg_valid, ex_rs3, cp_rs3)
 | 
				
			||||||
 | 
					  req.typ := Mux(ex_reg_valid, ex_reg_inst(21,20), io.cp_req.bits.typ)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val sfma = Module(new FPUFMAPipe(p(SFMALatency), 8, 24))
 | 
				
			||||||
 | 
					  sfma.io.in.valid := req_valid && ex_ctrl.fma && ex_ctrl.single
 | 
				
			||||||
 | 
					  sfma.io.in.bits := req
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val dfma = Module(new FPUFMAPipe(p(DFMALatency), 11, 53))
 | 
				
			||||||
 | 
					  dfma.io.in.valid := req_valid && ex_ctrl.fma && !ex_ctrl.single
 | 
				
			||||||
 | 
					  dfma.io.in.bits := req
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val fpiu = Module(new FPToInt)
 | 
				
			||||||
 | 
					  fpiu.io.in.valid := req_valid && (ex_ctrl.toint || ex_ctrl.div || ex_ctrl.sqrt || ex_ctrl.cmd === FCMD_MINMAX)
 | 
				
			||||||
 | 
					  fpiu.io.in.bits := req
 | 
				
			||||||
 | 
					  io.store_data := fpiu.io.out.bits.store
 | 
				
			||||||
 | 
					  io.toint_data := fpiu.io.out.bits.toint
 | 
				
			||||||
 | 
					  when(fpiu.io.out.valid && mem_cp_valid && mem_ctrl.toint){
 | 
				
			||||||
 | 
					    io.cp_resp.bits.data := fpiu.io.out.bits.toint
 | 
				
			||||||
 | 
					    io.cp_resp.valid := Bool(true)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val ifpu = Module(new IntToFP(3))
 | 
				
			||||||
 | 
					  ifpu.io.in.valid := req_valid && ex_ctrl.fromint
 | 
				
			||||||
 | 
					  ifpu.io.in.bits := req
 | 
				
			||||||
 | 
					  ifpu.io.in.bits.in1 := Mux(ex_reg_valid, io.fromint_data, cp_rs1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val fpmu = Module(new FPToFP(2))
 | 
				
			||||||
 | 
					  fpmu.io.in.valid := req_valid && ex_ctrl.fastpipe
 | 
				
			||||||
 | 
					  fpmu.io.in.bits := req
 | 
				
			||||||
 | 
					  fpmu.io.lt := fpiu.io.out.bits.lt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val divSqrt_wen = Reg(next=Bool(false))
 | 
				
			||||||
 | 
					  val divSqrt_inReady = Wire(init=Bool(false))
 | 
				
			||||||
 | 
					  val divSqrt_waddr = Reg(Bits())
 | 
				
			||||||
 | 
					  val divSqrt_wdata = Wire(Bits())
 | 
				
			||||||
 | 
					  val divSqrt_flags = Wire(Bits())
 | 
				
			||||||
 | 
					  val divSqrt_in_flight = Reg(init=Bool(false))
 | 
				
			||||||
 | 
					  val divSqrt_killed = Reg(Bool())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // writeback arbitration
 | 
				
			||||||
 | 
					  case class Pipe(p: Module, lat: Int, cond: (FPUCtrlSigs) => Bool, res: FPResult)
 | 
				
			||||||
 | 
					  val pipes = List(
 | 
				
			||||||
 | 
					    Pipe(fpmu, fpmu.latency, (c: FPUCtrlSigs) => c.fastpipe, fpmu.io.out.bits),
 | 
				
			||||||
 | 
					    Pipe(ifpu, ifpu.latency, (c: FPUCtrlSigs) => c.fromint, ifpu.io.out.bits),
 | 
				
			||||||
 | 
					    Pipe(sfma, sfma.latency, (c: FPUCtrlSigs) => c.fma && c.single, sfma.io.out.bits),
 | 
				
			||||||
 | 
					    Pipe(dfma, dfma.latency, (c: FPUCtrlSigs) => c.fma && !c.single, dfma.io.out.bits))
 | 
				
			||||||
 | 
					  def latencyMask(c: FPUCtrlSigs, offset: Int) = {
 | 
				
			||||||
 | 
					    require(pipes.forall(_.lat >= offset))
 | 
				
			||||||
 | 
					    pipes.map(p => Mux(p.cond(c), UInt(1 << p.lat-offset), UInt(0))).reduce(_|_)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  def pipeid(c: FPUCtrlSigs) = pipes.zipWithIndex.map(p => Mux(p._1.cond(c), UInt(p._2), UInt(0))).reduce(_|_)
 | 
				
			||||||
 | 
					  val maxLatency = pipes.map(_.lat).max
 | 
				
			||||||
 | 
					  val memLatencyMask = latencyMask(mem_ctrl, 2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val wen = Reg(init=Bits(0, maxLatency-1))
 | 
				
			||||||
 | 
					  val winfo = Reg(Vec(maxLatency-1, Bits()))
 | 
				
			||||||
 | 
					  val mem_wen = mem_reg_valid && (mem_ctrl.fma || mem_ctrl.fastpipe || mem_ctrl.fromint)
 | 
				
			||||||
 | 
					  val write_port_busy = RegEnable(mem_wen && (memLatencyMask & latencyMask(ex_ctrl, 1)).orR || (wen & latencyMask(ex_ctrl, 0)).orR, req_valid)
 | 
				
			||||||
 | 
					  val mem_winfo = Cat(mem_cp_valid, pipeid(mem_ctrl), mem_ctrl.single, mem_reg_inst(11,7)) //single only used for debugging
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  for (i <- 0 until maxLatency-2) {
 | 
				
			||||||
 | 
					    when (wen(i+1)) { winfo(i) := winfo(i+1) }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  wen := wen >> 1
 | 
				
			||||||
 | 
					  when (mem_wen) {
 | 
				
			||||||
 | 
					    when (!killm) {
 | 
				
			||||||
 | 
					      wen := wen >> 1 | memLatencyMask
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    for (i <- 0 until maxLatency-1) {
 | 
				
			||||||
 | 
					      when (!write_port_busy && memLatencyMask(i)) {
 | 
				
			||||||
 | 
					        winfo(i) := mem_winfo
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val waddr = Mux(divSqrt_wen, divSqrt_waddr, winfo(0)(4,0).toUInt)
 | 
				
			||||||
 | 
					  val wsrc = (winfo(0) >> 6)(log2Up(pipes.size) - 1,0)
 | 
				
			||||||
 | 
					  val wcp = winfo(0)(6+log2Up(pipes.size))
 | 
				
			||||||
 | 
					  val wdata = Mux(divSqrt_wen, divSqrt_wdata, (pipes.map(_.res.data): Seq[UInt])(wsrc))
 | 
				
			||||||
 | 
					  val wexc = (pipes.map(_.res.exc): Seq[UInt])(wsrc)
 | 
				
			||||||
 | 
					  when ((!wcp && wen(0)) || divSqrt_wen) {
 | 
				
			||||||
 | 
					    regfile(waddr) := wdata
 | 
				
			||||||
 | 
					    if (enableCommitLog) {
 | 
				
			||||||
 | 
					      val wdata_unrec_s = hardfloat.fNFromRecFN(8, 24, wdata(64,0))
 | 
				
			||||||
 | 
					      val wdata_unrec_d = hardfloat.fNFromRecFN(11, 53, wdata(64,0))
 | 
				
			||||||
 | 
					      val wb_single = (winfo(0) >> 5)(0)
 | 
				
			||||||
 | 
					      printf ("f%d p%d 0x%x\n", waddr, waddr+ UInt(32),
 | 
				
			||||||
 | 
					        Mux(wb_single, Cat(UInt(0,32), wdata_unrec_s), wdata_unrec_d))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  when (wcp && wen(0)) {
 | 
				
			||||||
 | 
					    io.cp_resp.bits.data := wdata
 | 
				
			||||||
 | 
					    io.cp_resp.valid := Bool(true)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  io.cp_req.ready := !ex_reg_valid
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val wb_toint_valid = wb_reg_valid && wb_ctrl.toint
 | 
				
			||||||
 | 
					  val wb_toint_exc = RegEnable(fpiu.io.out.bits.exc, mem_ctrl.toint)
 | 
				
			||||||
 | 
					  io.fcsr_flags.valid := wb_toint_valid || divSqrt_wen || wen(0)
 | 
				
			||||||
 | 
					  io.fcsr_flags.bits :=
 | 
				
			||||||
 | 
					    Mux(wb_toint_valid, wb_toint_exc, UInt(0)) |
 | 
				
			||||||
 | 
					    Mux(divSqrt_wen, divSqrt_flags, UInt(0)) |
 | 
				
			||||||
 | 
					    Mux(wen(0), wexc, UInt(0))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val units_busy = mem_reg_valid && (mem_ctrl.div || mem_ctrl.sqrt) && (!divSqrt_inReady || wen.orR) // || mem_reg_valid && mem_ctrl.fma && Reg(next=Mux(ex_ctrl.single, io.sfma.valid, io.dfma.valid))
 | 
				
			||||||
 | 
					  io.fcsr_rdy := !(ex_reg_valid && ex_ctrl.wflags || mem_reg_valid && mem_ctrl.wflags || wb_reg_valid && wb_ctrl.toint || wen.orR || divSqrt_in_flight)
 | 
				
			||||||
 | 
					  io.nack_mem := units_busy || write_port_busy || divSqrt_in_flight
 | 
				
			||||||
 | 
					  io.dec <> fp_decoder.io.sigs
 | 
				
			||||||
 | 
					  def useScoreboard(f: ((Pipe, Int)) => Bool) = pipes.zipWithIndex.filter(_._1.lat > 3).map(x => f(x)).fold(Bool(false))(_||_)
 | 
				
			||||||
 | 
					  io.sboard_set := wb_reg_valid && !wb_cp_valid && Reg(next=useScoreboard(_._1.cond(mem_ctrl)) || mem_ctrl.div || mem_ctrl.sqrt)
 | 
				
			||||||
 | 
					  io.sboard_clr := !wb_cp_valid && (divSqrt_wen || (wen(0) && useScoreboard(x => wsrc === UInt(x._2))))
 | 
				
			||||||
 | 
					  io.sboard_clra := waddr
 | 
				
			||||||
 | 
					  // we don't currently support round-max-magnitude (rm=4)
 | 
				
			||||||
 | 
					  io.illegal_rm := ex_rm(2) && ex_ctrl.round
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  divSqrt_wdata := 0
 | 
				
			||||||
 | 
					  divSqrt_flags := 0
 | 
				
			||||||
 | 
					  if (p(FDivSqrt)) {
 | 
				
			||||||
 | 
					    val divSqrt_single = Reg(Bool())
 | 
				
			||||||
 | 
					    val divSqrt_rm = Reg(Bits())
 | 
				
			||||||
 | 
					    val divSqrt_flags_double = Reg(Bits())
 | 
				
			||||||
 | 
					    val divSqrt_wdata_double = Reg(Bits())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    val divSqrt = Module(new hardfloat.DivSqrtRecF64)
 | 
				
			||||||
 | 
					    divSqrt_inReady := Mux(divSqrt.io.sqrtOp, divSqrt.io.inReady_sqrt, divSqrt.io.inReady_div)
 | 
				
			||||||
 | 
					    val divSqrt_outValid = divSqrt.io.outValid_div || divSqrt.io.outValid_sqrt
 | 
				
			||||||
 | 
					    divSqrt.io.inValid := mem_reg_valid && (mem_ctrl.div || mem_ctrl.sqrt) && !divSqrt_in_flight
 | 
				
			||||||
 | 
					    divSqrt.io.sqrtOp := mem_ctrl.sqrt
 | 
				
			||||||
 | 
					    divSqrt.io.a := fpiu.io.as_double.in1
 | 
				
			||||||
 | 
					    divSqrt.io.b := fpiu.io.as_double.in2
 | 
				
			||||||
 | 
					    divSqrt.io.roundingMode := fpiu.io.as_double.rm
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    when (divSqrt.io.inValid && divSqrt_inReady) {
 | 
				
			||||||
 | 
					      divSqrt_in_flight := true
 | 
				
			||||||
 | 
					      divSqrt_killed := killm
 | 
				
			||||||
 | 
					      divSqrt_single := mem_ctrl.single
 | 
				
			||||||
 | 
					      divSqrt_waddr := mem_reg_inst(11,7)
 | 
				
			||||||
 | 
					      divSqrt_rm := divSqrt.io.roundingMode
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    when (divSqrt_outValid) {
 | 
				
			||||||
 | 
					      divSqrt_wen := !divSqrt_killed
 | 
				
			||||||
 | 
					      divSqrt_wdata_double := divSqrt.io.out
 | 
				
			||||||
 | 
					      divSqrt_in_flight := false
 | 
				
			||||||
 | 
					      divSqrt_flags_double := divSqrt.io.exceptionFlags
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    val divSqrt_toSingle = Module(new hardfloat.RecFNToRecFN(11, 53, 8, 24))
 | 
				
			||||||
 | 
					    divSqrt_toSingle.io.in := divSqrt_wdata_double
 | 
				
			||||||
 | 
					    divSqrt_toSingle.io.roundingMode := divSqrt_rm
 | 
				
			||||||
 | 
					    divSqrt_wdata := Mux(divSqrt_single, divSqrt_toSingle.io.out, divSqrt_wdata_double)
 | 
				
			||||||
 | 
					    divSqrt_flags := divSqrt_flags_double | Mux(divSqrt_single, divSqrt_toSingle.io.exceptionFlags, Bits(0))
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										130
									
								
								rocket/src/main/scala/frontend.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										130
									
								
								rocket/src/main/scala/frontend.scala
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,130 @@
 | 
				
			|||||||
 | 
					package rocket
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import Chisel._
 | 
				
			||||||
 | 
					import uncore.tilelink._
 | 
				
			||||||
 | 
					import Util._
 | 
				
			||||||
 | 
					import cde.{Parameters, Field}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class FrontendReq(implicit p: Parameters) extends CoreBundle()(p) {
 | 
				
			||||||
 | 
					  val pc = UInt(width = vaddrBitsExtended)
 | 
				
			||||||
 | 
					  val speculative = Bool()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class FrontendResp(implicit p: Parameters) extends CoreBundle()(p) {
 | 
				
			||||||
 | 
					  val pc = UInt(width = vaddrBitsExtended)  // ID stage PC
 | 
				
			||||||
 | 
					  val data = Vec(fetchWidth, Bits(width = coreInstBits))
 | 
				
			||||||
 | 
					  val mask = Bits(width = fetchWidth)
 | 
				
			||||||
 | 
					  val xcpt_if = Bool()
 | 
				
			||||||
 | 
					  val replay = Bool()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class FrontendIO(implicit p: Parameters) extends CoreBundle()(p) {
 | 
				
			||||||
 | 
					  val req = Valid(new FrontendReq)
 | 
				
			||||||
 | 
					  val resp = Decoupled(new FrontendResp).flip
 | 
				
			||||||
 | 
					  val btb_resp = Valid(new BTBResp).flip
 | 
				
			||||||
 | 
					  val btb_update = Valid(new BTBUpdate)
 | 
				
			||||||
 | 
					  val bht_update = Valid(new BHTUpdate)
 | 
				
			||||||
 | 
					  val ras_update = Valid(new RASUpdate)
 | 
				
			||||||
 | 
					  val flush_icache = Bool(OUTPUT)
 | 
				
			||||||
 | 
					  val flush_tlb = Bool(OUTPUT)
 | 
				
			||||||
 | 
					  val npc = UInt(INPUT, width = vaddrBitsExtended)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Frontend(implicit p: Parameters) extends CoreModule()(p) with HasL1CacheParameters {
 | 
				
			||||||
 | 
					  val io = new Bundle {
 | 
				
			||||||
 | 
					    val cpu = new FrontendIO().flip
 | 
				
			||||||
 | 
					    val ptw = new TLBPTWIO()
 | 
				
			||||||
 | 
					    val mem = new ClientUncachedTileLinkIO
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val icache = Module(new ICache(latency = 2))
 | 
				
			||||||
 | 
					  val tlb = Module(new TLB)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val s1_pc_ = Reg(UInt(width=vaddrBitsExtended))
 | 
				
			||||||
 | 
					  val s1_pc = ~(~s1_pc_ | (coreInstBytes-1)) // discard PC LSBS (this propagates down the pipeline)
 | 
				
			||||||
 | 
					  val s1_speculative = Reg(Bool())
 | 
				
			||||||
 | 
					  val s1_same_block = Reg(Bool())
 | 
				
			||||||
 | 
					  val s2_valid = Reg(init=Bool(true))
 | 
				
			||||||
 | 
					  val s2_pc = Reg(init=UInt(p(ResetVector)))
 | 
				
			||||||
 | 
					  val s2_btb_resp_valid = Reg(init=Bool(false))
 | 
				
			||||||
 | 
					  val s2_btb_resp_bits = Reg(new BTBResp)
 | 
				
			||||||
 | 
					  val s2_xcpt_if = Reg(init=Bool(false))
 | 
				
			||||||
 | 
					  val s2_speculative = Reg(init=Bool(false))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val ntpc = ~(~s1_pc | (coreInstBytes*fetchWidth-1)) + UInt(coreInstBytes*fetchWidth)
 | 
				
			||||||
 | 
					  val predicted_npc = Wire(init = ntpc)
 | 
				
			||||||
 | 
					  val icmiss = s2_valid && !icache.io.resp.valid
 | 
				
			||||||
 | 
					  val npc = Mux(icmiss, s2_pc, predicted_npc).toUInt
 | 
				
			||||||
 | 
					  val s0_same_block = Wire(init = !icmiss && !io.cpu.req.valid && ((ntpc & rowBytes) === (s1_pc & rowBytes)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val stall = io.cpu.resp.valid && !io.cpu.resp.ready
 | 
				
			||||||
 | 
					  when (!stall) {
 | 
				
			||||||
 | 
					    s1_same_block := s0_same_block && !tlb.io.resp.miss
 | 
				
			||||||
 | 
					    s1_pc_ := npc
 | 
				
			||||||
 | 
					    s1_speculative := Mux(icmiss, s2_speculative, true)
 | 
				
			||||||
 | 
					    s2_valid := !icmiss
 | 
				
			||||||
 | 
					    when (!icmiss) {
 | 
				
			||||||
 | 
					      s2_pc := s1_pc
 | 
				
			||||||
 | 
					      s2_speculative := s1_speculative && !tlb.io.resp.cacheable
 | 
				
			||||||
 | 
					      s2_xcpt_if := tlb.io.resp.xcpt_if
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  when (io.cpu.req.valid) {
 | 
				
			||||||
 | 
					    s1_same_block := Bool(false)
 | 
				
			||||||
 | 
					    s1_pc_ := io.cpu.req.bits.pc
 | 
				
			||||||
 | 
					    s1_speculative := io.cpu.req.bits.speculative
 | 
				
			||||||
 | 
					    s2_valid := Bool(false)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (p(BtbKey).nEntries > 0) {
 | 
				
			||||||
 | 
					    val btb = Module(new BTB)
 | 
				
			||||||
 | 
					    btb.io.req.valid := false
 | 
				
			||||||
 | 
					    btb.io.req.bits.addr := s1_pc
 | 
				
			||||||
 | 
					    btb.io.btb_update := io.cpu.btb_update
 | 
				
			||||||
 | 
					    btb.io.bht_update := io.cpu.bht_update
 | 
				
			||||||
 | 
					    btb.io.ras_update := io.cpu.ras_update
 | 
				
			||||||
 | 
					    when (!stall && !icmiss) {
 | 
				
			||||||
 | 
					      btb.io.req.valid := true
 | 
				
			||||||
 | 
					      s2_btb_resp_valid := btb.io.resp.valid
 | 
				
			||||||
 | 
					      s2_btb_resp_bits := btb.io.resp.bits
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    when (btb.io.resp.bits.taken) {
 | 
				
			||||||
 | 
					      predicted_npc := btb.io.resp.bits.target.sextTo(vaddrBitsExtended)
 | 
				
			||||||
 | 
					      s0_same_block := Bool(false)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  io.ptw <> tlb.io.ptw
 | 
				
			||||||
 | 
					  tlb.io.req.valid := !stall && !icmiss
 | 
				
			||||||
 | 
					  tlb.io.req.bits.vpn := s1_pc >> pgIdxBits
 | 
				
			||||||
 | 
					  tlb.io.req.bits.passthrough := Bool(false)
 | 
				
			||||||
 | 
					  tlb.io.req.bits.instruction := Bool(true)
 | 
				
			||||||
 | 
					  tlb.io.req.bits.store := Bool(false)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  io.mem <> icache.io.mem
 | 
				
			||||||
 | 
					  icache.io.req.valid := !stall && !s0_same_block
 | 
				
			||||||
 | 
					  icache.io.req.bits.addr := io.cpu.npc
 | 
				
			||||||
 | 
					  icache.io.invalidate := io.cpu.flush_icache
 | 
				
			||||||
 | 
					  icache.io.s1_ppn := tlb.io.resp.ppn
 | 
				
			||||||
 | 
					  icache.io.s1_kill := io.cpu.req.valid || tlb.io.resp.miss || tlb.io.resp.xcpt_if || icmiss || io.cpu.flush_tlb
 | 
				
			||||||
 | 
					  icache.io.s2_kill := s2_speculative
 | 
				
			||||||
 | 
					  icache.io.resp.ready := !stall && !s1_same_block
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  io.cpu.resp.valid := s2_valid && (icache.io.resp.valid || s2_speculative || s2_xcpt_if)
 | 
				
			||||||
 | 
					  io.cpu.resp.bits.pc := s2_pc
 | 
				
			||||||
 | 
					  io.cpu.npc := Mux(io.cpu.req.valid, io.cpu.req.bits.pc, npc)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  require(fetchWidth * coreInstBytes <= rowBytes)
 | 
				
			||||||
 | 
					  val fetch_data = icache.io.resp.bits.datablock >> (s2_pc.extract(log2Up(rowBytes)-1,log2Up(fetchWidth*coreInstBytes)) << log2Up(fetchWidth*coreInstBits))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  for (i <- 0 until fetchWidth) {
 | 
				
			||||||
 | 
					    io.cpu.resp.bits.data(i) := fetch_data(i*coreInstBits+coreInstBits-1, i*coreInstBits)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  io.cpu.resp.bits.mask := UInt((1 << fetchWidth)-1) << s2_pc.extract(log2Up(fetchWidth)+log2Up(coreInstBytes)-1, log2Up(coreInstBytes))
 | 
				
			||||||
 | 
					  io.cpu.resp.bits.xcpt_if := s2_xcpt_if
 | 
				
			||||||
 | 
					  io.cpu.resp.bits.replay := s2_speculative && !icache.io.resp.valid && !s2_xcpt_if
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  io.cpu.btb_resp.valid := s2_btb_resp_valid
 | 
				
			||||||
 | 
					  io.cpu.btb_resp.bits := s2_btb_resp_bits
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										157
									
								
								rocket/src/main/scala/icache.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										157
									
								
								rocket/src/main/scala/icache.scala
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,157 @@
 | 
				
			|||||||
 | 
					package rocket
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import Chisel._
 | 
				
			||||||
 | 
					import uncore.agents._
 | 
				
			||||||
 | 
					import uncore.tilelink._
 | 
				
			||||||
 | 
					import uncore.util._
 | 
				
			||||||
 | 
					import Util._
 | 
				
			||||||
 | 
					import cde.{Parameters, Field}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					trait HasL1CacheParameters extends HasCacheParameters with HasCoreParameters {
 | 
				
			||||||
 | 
					  val outerDataBeats = p(TLKey(p(TLId))).dataBeats
 | 
				
			||||||
 | 
					  val outerDataBits = p(TLKey(p(TLId))).dataBitsPerBeat
 | 
				
			||||||
 | 
					  val refillCyclesPerBeat = outerDataBits/rowBits
 | 
				
			||||||
 | 
					  val refillCycles = refillCyclesPerBeat*outerDataBeats
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ICacheReq(implicit p: Parameters) extends CoreBundle()(p) with HasL1CacheParameters {
 | 
				
			||||||
 | 
					  val addr = UInt(width = vaddrBits)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ICacheResp(implicit p: Parameters) extends CoreBundle()(p) with HasL1CacheParameters {
 | 
				
			||||||
 | 
					  val data = Bits(width = coreInstBits)
 | 
				
			||||||
 | 
					  val datablock = Bits(width = rowBits)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ICache(latency: Int)(implicit p: Parameters) extends CoreModule()(p) with HasL1CacheParameters {
 | 
				
			||||||
 | 
					  val io = new Bundle {
 | 
				
			||||||
 | 
					    val req = Valid(new ICacheReq).flip
 | 
				
			||||||
 | 
					    val s1_ppn = UInt(INPUT, ppnBits) // delayed one cycle w.r.t. req
 | 
				
			||||||
 | 
					    val s1_kill = Bool(INPUT) // delayed one cycle w.r.t. req
 | 
				
			||||||
 | 
					    val s2_kill = Bool(INPUT) // delayed two cycles; prevents I$ miss emission
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    val resp = Decoupled(new ICacheResp)
 | 
				
			||||||
 | 
					    val invalidate = Bool(INPUT)
 | 
				
			||||||
 | 
					    val mem = new ClientUncachedTileLinkIO
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  require(isPow2(nSets) && isPow2(nWays))
 | 
				
			||||||
 | 
					  require(isPow2(coreInstBytes))
 | 
				
			||||||
 | 
					  require(!usingVM || pgIdxBits >= untagBits)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val s_ready :: s_request :: s_refill_wait :: s_refill :: Nil = Enum(UInt(), 4)
 | 
				
			||||||
 | 
					  val state = Reg(init=s_ready)
 | 
				
			||||||
 | 
					  val invalidated = Reg(Bool())
 | 
				
			||||||
 | 
					  val stall = !io.resp.ready
 | 
				
			||||||
 | 
					  val rdy = Wire(Bool())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val refill_addr = Reg(UInt(width = paddrBits))
 | 
				
			||||||
 | 
					  val s1_any_tag_hit = Wire(Bool())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val s1_valid = Reg(init=Bool(false))
 | 
				
			||||||
 | 
					  val s1_vaddr = Reg(UInt())
 | 
				
			||||||
 | 
					  val s1_paddr = Cat(io.s1_ppn, s1_vaddr(pgIdxBits-1,0)).toUInt
 | 
				
			||||||
 | 
					  val s1_tag = s1_paddr(tagBits+untagBits-1,untagBits)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val s0_valid = io.req.valid || s1_valid && stall
 | 
				
			||||||
 | 
					  val s0_vaddr = Mux(s1_valid && stall, s1_vaddr, io.req.bits.addr)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  s1_valid := io.req.valid && rdy || s1_valid && stall && !io.s1_kill
 | 
				
			||||||
 | 
					  when (io.req.valid && rdy) {
 | 
				
			||||||
 | 
					    s1_vaddr := io.req.bits.addr
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val out_valid = s1_valid && !io.s1_kill && state === s_ready
 | 
				
			||||||
 | 
					  val s1_idx = s1_vaddr(untagBits-1,blockOffBits)
 | 
				
			||||||
 | 
					  val s1_hit = out_valid && s1_any_tag_hit
 | 
				
			||||||
 | 
					  val s1_miss = out_valid && !s1_any_tag_hit
 | 
				
			||||||
 | 
					  rdy := state === s_ready && !s1_miss
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  when (s1_miss && state === s_ready) {
 | 
				
			||||||
 | 
					    refill_addr := s1_paddr
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  val refill_tag = refill_addr(tagBits+untagBits-1,untagBits)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val narrow_grant = FlowThroughSerializer(io.mem.grant, refillCyclesPerBeat)
 | 
				
			||||||
 | 
					  val (refill_cnt, refill_wrap) = Counter(narrow_grant.fire(), refillCycles)
 | 
				
			||||||
 | 
					  val refill_done = state === s_refill && refill_wrap
 | 
				
			||||||
 | 
					  narrow_grant.ready := Bool(true)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val repl_way = if (isDM) UInt(0) else LFSR16(s1_miss)(log2Up(nWays)-1,0)
 | 
				
			||||||
 | 
					  val entagbits = code.width(tagBits)
 | 
				
			||||||
 | 
					  val tag_array = SeqMem(nSets, Vec(nWays, Bits(width = entagbits)))
 | 
				
			||||||
 | 
					  val tag_rdata = tag_array.read(s0_vaddr(untagBits-1,blockOffBits), !refill_done && s0_valid)
 | 
				
			||||||
 | 
					  when (refill_done) {
 | 
				
			||||||
 | 
					    val tag = code.encode(refill_tag).toUInt
 | 
				
			||||||
 | 
					    tag_array.write(s1_idx, Vec.fill(nWays)(tag), Vec.tabulate(nWays)(repl_way === _))
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val vb_array = Reg(init=Bits(0, nSets*nWays))
 | 
				
			||||||
 | 
					  when (refill_done && !invalidated) {
 | 
				
			||||||
 | 
					    vb_array := vb_array.bitSet(Cat(repl_way, s1_idx), Bool(true))
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  when (io.invalidate) {
 | 
				
			||||||
 | 
					    vb_array := Bits(0)
 | 
				
			||||||
 | 
					    invalidated := Bool(true)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  val s1_disparity = Wire(Vec(nWays, Bool()))
 | 
				
			||||||
 | 
					  for (i <- 0 until nWays)
 | 
				
			||||||
 | 
					    when (s1_valid && s1_disparity(i)) { vb_array := vb_array.bitSet(Cat(UInt(i), s1_idx), Bool(false)) }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val s1_tag_match = Wire(Vec(nWays, Bool()))
 | 
				
			||||||
 | 
					  val s1_tag_hit = Wire(Vec(nWays, Bool()))
 | 
				
			||||||
 | 
					  val s1_dout = Wire(Vec(nWays, Bits(width = rowBits)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  for (i <- 0 until nWays) {
 | 
				
			||||||
 | 
					    val s1_vb = !io.invalidate && vb_array(Cat(UInt(i), s1_vaddr(untagBits-1,blockOffBits))).toBool
 | 
				
			||||||
 | 
					    val tag_out = tag_rdata(i)
 | 
				
			||||||
 | 
					    val s1_tag_disparity = code.decode(tag_out).error
 | 
				
			||||||
 | 
					    s1_tag_match(i) := tag_out(tagBits-1,0) === s1_tag
 | 
				
			||||||
 | 
					    s1_tag_hit(i) := s1_vb && s1_tag_match(i)
 | 
				
			||||||
 | 
					    s1_disparity(i) := s1_vb && (s1_tag_disparity || code.decode(s1_dout(i)).error)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  s1_any_tag_hit := s1_tag_hit.reduceLeft(_||_) && !s1_disparity.reduceLeft(_||_)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  for (i <- 0 until nWays) {
 | 
				
			||||||
 | 
					    val data_array = SeqMem(nSets * refillCycles, Bits(width = code.width(rowBits)))
 | 
				
			||||||
 | 
					    val wen = narrow_grant.valid && repl_way === UInt(i)
 | 
				
			||||||
 | 
					    when (wen) {
 | 
				
			||||||
 | 
					      val e_d = code.encode(narrow_grant.bits.data).toUInt
 | 
				
			||||||
 | 
					      data_array.write((s1_idx << log2Ceil(refillCycles)) | refill_cnt, e_d)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    val s0_raddr = s0_vaddr(untagBits-1,blockOffBits-log2Ceil(refillCycles))
 | 
				
			||||||
 | 
					    s1_dout(i) := data_array.read(s0_raddr, !wen && s0_valid)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // output signals
 | 
				
			||||||
 | 
					  latency match {
 | 
				
			||||||
 | 
					    case 1 =>
 | 
				
			||||||
 | 
					      io.resp.bits.datablock := Mux1H(s1_tag_hit, s1_dout)
 | 
				
			||||||
 | 
					      io.resp.valid := s1_hit
 | 
				
			||||||
 | 
					    case 2 =>
 | 
				
			||||||
 | 
					      val s2_hit = RegEnable(s1_hit, !stall)
 | 
				
			||||||
 | 
					      val s2_tag_hit = RegEnable(s1_tag_hit, !stall)
 | 
				
			||||||
 | 
					      val s2_dout = RegEnable(s1_dout, !stall)
 | 
				
			||||||
 | 
					      io.resp.bits.datablock := Mux1H(s2_tag_hit, s2_dout)
 | 
				
			||||||
 | 
					      io.resp.valid := s2_hit
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  io.mem.acquire.valid := state === s_request && !io.s2_kill
 | 
				
			||||||
 | 
					  io.mem.acquire.bits := GetBlock(addr_block = refill_addr >> blockOffBits)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // control state machine
 | 
				
			||||||
 | 
					  switch (state) {
 | 
				
			||||||
 | 
					    is (s_ready) {
 | 
				
			||||||
 | 
					      when (s1_miss) { state := s_request }
 | 
				
			||||||
 | 
					      invalidated := Bool(false)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    is (s_request) {
 | 
				
			||||||
 | 
					      when (io.mem.acquire.ready) { state := s_refill_wait }
 | 
				
			||||||
 | 
					      when (io.s2_kill) { state := s_ready }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    is (s_refill_wait) {
 | 
				
			||||||
 | 
					      when (io.mem.grant.valid) { state := s_refill }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    is (s_refill) {
 | 
				
			||||||
 | 
					      when (refill_done) { state := s_ready }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										319
									
								
								rocket/src/main/scala/idecode.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										319
									
								
								rocket/src/main/scala/idecode.scala
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,319 @@
 | 
				
			|||||||
 | 
					// See LICENSE for license details
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package rocket
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import Chisel._
 | 
				
			||||||
 | 
					import Instructions._
 | 
				
			||||||
 | 
					import uncore.constants.MemoryOpConstants._
 | 
				
			||||||
 | 
					import ALU._
 | 
				
			||||||
 | 
					import cde.Parameters
 | 
				
			||||||
 | 
					import Util._
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					abstract trait DecodeConstants extends HasCoreParameters
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  val table: Array[(BitPat, List[BitPat])]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class IntCtrlSigs extends Bundle {
 | 
				
			||||||
 | 
					  val legal = Bool()
 | 
				
			||||||
 | 
					  val fp = Bool()
 | 
				
			||||||
 | 
					  val rocc = Bool()
 | 
				
			||||||
 | 
					  val branch = Bool()
 | 
				
			||||||
 | 
					  val jal = Bool()
 | 
				
			||||||
 | 
					  val jalr = Bool()
 | 
				
			||||||
 | 
					  val rxs2 = Bool()
 | 
				
			||||||
 | 
					  val rxs1 = Bool()
 | 
				
			||||||
 | 
					  val sel_alu2 = Bits(width = A2_X.getWidth)
 | 
				
			||||||
 | 
					  val sel_alu1 = Bits(width = A1_X.getWidth)
 | 
				
			||||||
 | 
					  val sel_imm = Bits(width = IMM_X.getWidth)
 | 
				
			||||||
 | 
					  val alu_dw = Bool()
 | 
				
			||||||
 | 
					  val alu_fn = Bits(width = FN_X.getWidth)
 | 
				
			||||||
 | 
					  val mem = Bool()
 | 
				
			||||||
 | 
					  val mem_cmd = Bits(width = M_SZ)
 | 
				
			||||||
 | 
					  val mem_type = Bits(width = MT_SZ)
 | 
				
			||||||
 | 
					  val rfs1 = Bool()
 | 
				
			||||||
 | 
					  val rfs2 = Bool()
 | 
				
			||||||
 | 
					  val rfs3 = Bool()
 | 
				
			||||||
 | 
					  val wfd = Bool()
 | 
				
			||||||
 | 
					  val div = Bool()
 | 
				
			||||||
 | 
					  val wxd = Bool()
 | 
				
			||||||
 | 
					  val csr = Bits(width = CSR.SZ)
 | 
				
			||||||
 | 
					  val fence_i = Bool()
 | 
				
			||||||
 | 
					  val fence = Bool()
 | 
				
			||||||
 | 
					  val amo = Bool()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def default: List[BitPat] =
 | 
				
			||||||
 | 
					                //           jal                                                                 renf1             fence.i
 | 
				
			||||||
 | 
					                //   val     | jalr                                                              | renf2           |
 | 
				
			||||||
 | 
					                //   | fp_val| | renx2                                                           | | renf3         |
 | 
				
			||||||
 | 
					                //   | | rocc| | | renx1     s_alu1                          mem_val             | | | wfd         | 
 | 
				
			||||||
 | 
					                //   | | | br| | | | s_alu2  |       imm    dw     alu       | mem_cmd   mem_type| | | | div       | 
 | 
				
			||||||
 | 
					                //   | | | | | | | | |       |       |      |      |         | |           |     | | | | | wxd     | fence
 | 
				
			||||||
 | 
					                //   | | | | | | | | |       |       |      |      |         | |           |     | | | | | | csr   | | amo
 | 
				
			||||||
 | 
					                //   | | | | | | | | |       |       |      |      |         | |           |     | | | | | | |     | | |
 | 
				
			||||||
 | 
					                List(N,X,X,X,X,X,X,X,A2_X,   A1_X,   IMM_X, DW_X,  FN_X,     N,M_X,        MT_X, X,X,X,X,X,X,CSR.X,X,X,X)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def decode(inst: UInt, table: Iterable[(BitPat, List[BitPat])]) = {
 | 
				
			||||||
 | 
					    val decoder = DecodeLogic(inst, default, table)
 | 
				
			||||||
 | 
					    val sigs = Seq(legal, fp, rocc, branch, jal, jalr, rxs2, rxs1, sel_alu2,
 | 
				
			||||||
 | 
					                   sel_alu1, sel_imm, alu_dw, alu_fn, mem, mem_cmd, mem_type,
 | 
				
			||||||
 | 
					                   rfs1, rfs2, rfs3, wfd, div, wxd, csr, fence_i, fence, amo)
 | 
				
			||||||
 | 
					    sigs zip decoder map {case(s,d) => s := d}
 | 
				
			||||||
 | 
					    this
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class IDecode(implicit val p: Parameters) extends DecodeConstants
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  val table: Array[(BitPat, List[BitPat])] = Array(
 | 
				
			||||||
 | 
					    BNE->       List(Y,N,N,Y,N,N,Y,Y,A2_RS2, A1_RS1, IMM_SB,DW_X,  FN_SNE,   N,M_X,        MT_X, N,N,N,N,N,N,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    BEQ->       List(Y,N,N,Y,N,N,Y,Y,A2_RS2, A1_RS1, IMM_SB,DW_X,  FN_SEQ,   N,M_X,        MT_X, N,N,N,N,N,N,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    BLT->       List(Y,N,N,Y,N,N,Y,Y,A2_RS2, A1_RS1, IMM_SB,DW_X,  FN_SLT,   N,M_X,        MT_X, N,N,N,N,N,N,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    BLTU->      List(Y,N,N,Y,N,N,Y,Y,A2_RS2, A1_RS1, IMM_SB,DW_X,  FN_SLTU,  N,M_X,        MT_X, N,N,N,N,N,N,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    BGE->       List(Y,N,N,Y,N,N,Y,Y,A2_RS2, A1_RS1, IMM_SB,DW_X,  FN_SGE,   N,M_X,        MT_X, N,N,N,N,N,N,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    BGEU->      List(Y,N,N,Y,N,N,Y,Y,A2_RS2, A1_RS1, IMM_SB,DW_X,  FN_SGEU,  N,M_X,        MT_X, N,N,N,N,N,N,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    JAL->       List(Y,N,N,N,Y,N,N,N,A2_FOUR,A1_PC,  IMM_UJ,DW_XPR,FN_ADD,   N,M_X,        MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    JALR->      List(Y,N,N,N,N,Y,N,Y,A2_IMM, A1_RS1, IMM_I, DW_XPR,FN_ADD,   N,M_X,        MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    AUIPC->     List(Y,N,N,N,N,N,N,N,A2_IMM, A1_PC,  IMM_U, DW_XPR,FN_ADD,   N,M_X,        MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    LB->        List(Y,N,N,N,N,N,N,Y,A2_IMM, A1_RS1, IMM_I, DW_XPR,FN_ADD,   Y,M_XRD,      MT_B, N,N,N,N,N,Y,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    LH->        List(Y,N,N,N,N,N,N,Y,A2_IMM, A1_RS1, IMM_I, DW_XPR,FN_ADD,   Y,M_XRD,      MT_H, N,N,N,N,N,Y,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    LW->        List(Y,N,N,N,N,N,N,Y,A2_IMM, A1_RS1, IMM_I, DW_XPR,FN_ADD,   Y,M_XRD,      MT_W, N,N,N,N,N,Y,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    LBU->       List(Y,N,N,N,N,N,N,Y,A2_IMM, A1_RS1, IMM_I, DW_XPR,FN_ADD,   Y,M_XRD,      MT_BU,N,N,N,N,N,Y,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    LHU->       List(Y,N,N,N,N,N,N,Y,A2_IMM, A1_RS1, IMM_I, DW_XPR,FN_ADD,   Y,M_XRD,      MT_HU,N,N,N,N,N,Y,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    SB->        List(Y,N,N,N,N,N,Y,Y,A2_IMM, A1_RS1, IMM_S, DW_XPR,FN_ADD,   Y,M_XWR,      MT_B, N,N,N,N,N,N,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    SH->        List(Y,N,N,N,N,N,Y,Y,A2_IMM, A1_RS1, IMM_S, DW_XPR,FN_ADD,   Y,M_XWR,      MT_H, N,N,N,N,N,N,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    SW->        List(Y,N,N,N,N,N,Y,Y,A2_IMM, A1_RS1, IMM_S, DW_XPR,FN_ADD,   Y,M_XWR,      MT_W, N,N,N,N,N,N,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    LUI->       List(Y,N,N,N,N,N,N,N,A2_IMM, A1_ZERO,IMM_U, DW_XPR,FN_ADD,   N,M_X,        MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    ADDI->      List(Y,N,N,N,N,N,N,Y,A2_IMM, A1_RS1, IMM_I, DW_XPR,FN_ADD,   N,M_X,        MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    SLTI ->     List(Y,N,N,N,N,N,N,Y,A2_IMM, A1_RS1, IMM_I, DW_XPR,FN_SLT,   N,M_X,        MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    SLTIU->     List(Y,N,N,N,N,N,N,Y,A2_IMM, A1_RS1, IMM_I, DW_XPR,FN_SLTU,  N,M_X,        MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    ANDI->      List(Y,N,N,N,N,N,N,Y,A2_IMM, A1_RS1, IMM_I, DW_XPR,FN_AND,   N,M_X,        MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    ORI->       List(Y,N,N,N,N,N,N,Y,A2_IMM, A1_RS1, IMM_I, DW_XPR,FN_OR,    N,M_X,        MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    XORI->      List(Y,N,N,N,N,N,N,Y,A2_IMM, A1_RS1, IMM_I, DW_XPR,FN_XOR,   N,M_X,        MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    SLLI->      List(Y,N,N,N,N,N,N,Y,A2_IMM, A1_RS1, IMM_I, DW_XPR,FN_SL,    N,M_X,        MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    SRLI->      List(Y,N,N,N,N,N,N,Y,A2_IMM, A1_RS1, IMM_I, DW_XPR,FN_SR,    N,M_X,        MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    SRAI->      List(Y,N,N,N,N,N,N,Y,A2_IMM, A1_RS1, IMM_I, DW_XPR,FN_SRA,   N,M_X,        MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    ADD->       List(Y,N,N,N,N,N,Y,Y,A2_RS2, A1_RS1, IMM_X, DW_XPR,FN_ADD,   N,M_X,        MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    SUB->       List(Y,N,N,N,N,N,Y,Y,A2_RS2, A1_RS1, IMM_X, DW_XPR,FN_SUB,   N,M_X,        MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    SLT->       List(Y,N,N,N,N,N,Y,Y,A2_RS2, A1_RS1, IMM_X, DW_XPR,FN_SLT,   N,M_X,        MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    SLTU->      List(Y,N,N,N,N,N,Y,Y,A2_RS2, A1_RS1, IMM_X, DW_XPR,FN_SLTU,  N,M_X,        MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    AND->       List(Y,N,N,N,N,N,Y,Y,A2_RS2, A1_RS1, IMM_X, DW_XPR,FN_AND,   N,M_X,        MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    OR->        List(Y,N,N,N,N,N,Y,Y,A2_RS2, A1_RS1, IMM_X, DW_XPR,FN_OR,    N,M_X,        MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    XOR->       List(Y,N,N,N,N,N,Y,Y,A2_RS2, A1_RS1, IMM_X, DW_XPR,FN_XOR,   N,M_X,        MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    SLL->       List(Y,N,N,N,N,N,Y,Y,A2_RS2, A1_RS1, IMM_X, DW_XPR,FN_SL,    N,M_X,        MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    SRL->       List(Y,N,N,N,N,N,Y,Y,A2_RS2, A1_RS1, IMM_X, DW_XPR,FN_SR,    N,M_X,        MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    SRA->       List(Y,N,N,N,N,N,Y,Y,A2_RS2, A1_RS1, IMM_X, DW_XPR,FN_SRA,   N,M_X,        MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    FENCE->     List(Y,N,N,N,N,N,N,N,A2_X,   A1_X,   IMM_X, DW_X,  FN_X,     N,M_X,        MT_X, N,N,N,N,N,N,CSR.N,N,Y,N),
 | 
				
			||||||
 | 
					    FENCE_I->   List(Y,N,N,N,N,N,N,N,A2_X,   A1_X,   IMM_X, DW_X,  FN_X,     Y,M_FLUSH_ALL,MT_X, N,N,N,N,N,N,CSR.N,Y,N,N),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    SCALL->     List(Y,N,N,N,N,N,N,X,A2_X,   A1_X,   IMM_X, DW_X,  FN_X,     N,M_X,        MT_X, N,N,N,N,N,N,CSR.I,N,N,N),
 | 
				
			||||||
 | 
					    SBREAK->    List(Y,N,N,N,N,N,N,X,A2_X,   A1_X,   IMM_X, DW_X,  FN_X,     N,M_X,        MT_X, N,N,N,N,N,N,CSR.I,N,N,N),
 | 
				
			||||||
 | 
					    MRET->      List(Y,N,N,N,N,N,N,X,A2_X,   A1_X,   IMM_X, DW_X,  FN_X,     N,M_X,        MT_X, N,N,N,N,N,N,CSR.I,N,N,N),
 | 
				
			||||||
 | 
					    WFI->       List(Y,N,N,N,N,N,N,X,A2_X,   A1_X,   IMM_X, DW_X,  FN_X,     N,M_X,        MT_X, N,N,N,N,N,N,CSR.I,N,N,N),
 | 
				
			||||||
 | 
					    CSRRW->     List(Y,N,N,N,N,N,N,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD,   N,M_X,        MT_X, N,N,N,N,N,Y,CSR.W,N,N,N),
 | 
				
			||||||
 | 
					    CSRRS->     List(Y,N,N,N,N,N,N,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD,   N,M_X,        MT_X, N,N,N,N,N,Y,CSR.S,N,N,N),
 | 
				
			||||||
 | 
					    CSRRC->     List(Y,N,N,N,N,N,N,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD,   N,M_X,        MT_X, N,N,N,N,N,Y,CSR.C,N,N,N),
 | 
				
			||||||
 | 
					    CSRRWI->    List(Y,N,N,N,N,N,N,N,A2_IMM, A1_ZERO,IMM_Z, DW_XPR,FN_ADD,   N,M_X,        MT_X, N,N,N,N,N,Y,CSR.W,N,N,N),
 | 
				
			||||||
 | 
					    CSRRSI->    List(Y,N,N,N,N,N,N,N,A2_IMM, A1_ZERO,IMM_Z, DW_XPR,FN_ADD,   N,M_X,        MT_X, N,N,N,N,N,Y,CSR.S,N,N,N),
 | 
				
			||||||
 | 
					    CSRRCI->    List(Y,N,N,N,N,N,N,N,A2_IMM, A1_ZERO,IMM_Z, DW_XPR,FN_ADD,   N,M_X,        MT_X, N,N,N,N,N,Y,CSR.C,N,N,N))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SDecode(implicit val p: Parameters) extends DecodeConstants
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  val table: Array[(BitPat, List[BitPat])] = Array(
 | 
				
			||||||
 | 
					    SFENCE_VM-> List(Y,N,N,N,N,N,N,X,A2_X,   A1_X,   IMM_X, DW_X,  FN_X,     N,M_X,        MT_X, N,N,N,N,N,N,CSR.I,N,N,N),
 | 
				
			||||||
 | 
					    SRET->      List(Y,N,N,N,N,N,N,X,A2_X,   A1_X,   IMM_X, DW_X,  FN_X,     N,M_X,        MT_X, N,N,N,N,N,N,CSR.I,N,N,N))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class DebugDecode(implicit val p: Parameters) extends DecodeConstants
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  val table: Array[(BitPat, List[BitPat])] = Array(
 | 
				
			||||||
 | 
					    DRET->      List(Y,N,N,N,N,N,N,X,A2_X,   A1_X,   IMM_X, DW_X,  FN_X,     N,M_X,        MT_X, N,N,N,N,N,N,CSR.I,N,N,N))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class I64Decode(implicit val p: Parameters) extends DecodeConstants
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  val table: Array[(BitPat, List[BitPat])] = Array(
 | 
				
			||||||
 | 
					    LD->        List(Y,N,N,N,N,N,N,Y,A2_IMM, A1_RS1, IMM_I, DW_XPR,FN_ADD,   Y,M_XRD,      MT_D, N,N,N,N,N,Y,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    LWU->       List(Y,N,N,N,N,N,N,Y,A2_IMM, A1_RS1, IMM_I, DW_XPR,FN_ADD,   Y,M_XRD,      MT_WU,N,N,N,N,N,Y,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    SD->        List(Y,N,N,N,N,N,Y,Y,A2_IMM, A1_RS1, IMM_S, DW_XPR,FN_ADD,   Y,M_XWR,      MT_D, N,N,N,N,N,N,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ADDIW->     List(Y,N,N,N,N,N,N,Y,A2_IMM, A1_RS1, IMM_I, DW_32,FN_ADD,    N,M_X,        MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    SLLIW->     List(Y,N,N,N,N,N,N,Y,A2_IMM, A1_RS1, IMM_I, DW_32,FN_SL,     N,M_X,        MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    SRLIW->     List(Y,N,N,N,N,N,N,Y,A2_IMM, A1_RS1, IMM_I, DW_32,FN_SR,     N,M_X,        MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    SRAIW->     List(Y,N,N,N,N,N,N,Y,A2_IMM, A1_RS1, IMM_I, DW_32,FN_SRA,    N,M_X,        MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    ADDW->      List(Y,N,N,N,N,N,Y,Y,A2_RS2, A1_RS1, IMM_X, DW_32,FN_ADD,    N,M_X,        MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    SUBW->      List(Y,N,N,N,N,N,Y,Y,A2_RS2, A1_RS1, IMM_X, DW_32,FN_SUB,    N,M_X,        MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    SLLW->      List(Y,N,N,N,N,N,Y,Y,A2_RS2, A1_RS1, IMM_X, DW_32,FN_SL,     N,M_X,        MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    SRLW->      List(Y,N,N,N,N,N,Y,Y,A2_RS2, A1_RS1, IMM_X, DW_32,FN_SR,     N,M_X,        MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    SRAW->      List(Y,N,N,N,N,N,Y,Y,A2_RS2, A1_RS1, IMM_X, DW_32,FN_SRA,    N,M_X,        MT_X, N,N,N,N,N,Y,CSR.N,N,N,N))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class MDecode(implicit val p: Parameters) extends DecodeConstants
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  val table: Array[(BitPat, List[BitPat])] = Array(
 | 
				
			||||||
 | 
					    MUL->       List(Y,N,N,N,N,N,Y,Y,A2_RS2, A1_RS1, IMM_X, DW_XPR,FN_MUL,   N,M_X,        MT_X, N,N,N,N,Y,Y,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    MULH->      List(Y,N,N,N,N,N,Y,Y,A2_RS2, A1_RS1, IMM_X, DW_XPR,FN_MULH,  N,M_X,        MT_X, N,N,N,N,Y,Y,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    MULHU->     List(Y,N,N,N,N,N,Y,Y,A2_RS2, A1_RS1, IMM_X, DW_XPR,FN_MULHU, N,M_X,        MT_X, N,N,N,N,Y,Y,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    MULHSU->    List(Y,N,N,N,N,N,Y,Y,A2_RS2, A1_RS1, IMM_X, DW_XPR,FN_MULHSU,N,M_X,        MT_X, N,N,N,N,Y,Y,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    DIV->       List(Y,N,N,N,N,N,Y,Y,A2_RS2, A1_RS1, IMM_X, DW_XPR,FN_DIV,   N,M_X,        MT_X, N,N,N,N,Y,Y,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    DIVU->      List(Y,N,N,N,N,N,Y,Y,A2_RS2, A1_RS1, IMM_X, DW_XPR,FN_DIVU,  N,M_X,        MT_X, N,N,N,N,Y,Y,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    REM->       List(Y,N,N,N,N,N,Y,Y,A2_RS2, A1_RS1, IMM_X, DW_XPR,FN_REM,   N,M_X,        MT_X, N,N,N,N,Y,Y,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    REMU->      List(Y,N,N,N,N,N,Y,Y,A2_RS2, A1_RS1, IMM_X, DW_XPR,FN_REMU,  N,M_X,        MT_X, N,N,N,N,Y,Y,CSR.N,N,N,N))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class M64Decode(implicit val p: Parameters) extends DecodeConstants
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  val table: Array[(BitPat, List[BitPat])] = Array(
 | 
				
			||||||
 | 
					    MULW->      List(Y,N,N,N,N,N,Y,Y,A2_RS2, A1_RS1, IMM_X, DW_32, FN_MUL,   N,M_X,        MT_X, N,N,N,N,Y,Y,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    DIVW->      List(Y,N,N,N,N,N,Y,Y,A2_RS2, A1_RS1, IMM_X, DW_32, FN_DIV,   N,M_X,        MT_X, N,N,N,N,Y,Y,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    DIVUW->     List(Y,N,N,N,N,N,Y,Y,A2_RS2, A1_RS1, IMM_X, DW_32, FN_DIVU,  N,M_X,        MT_X, N,N,N,N,Y,Y,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    REMW->      List(Y,N,N,N,N,N,Y,Y,A2_RS2, A1_RS1, IMM_X, DW_32, FN_REM,   N,M_X,        MT_X, N,N,N,N,Y,Y,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    REMUW->     List(Y,N,N,N,N,N,Y,Y,A2_RS2, A1_RS1, IMM_X, DW_32, FN_REMU,  N,M_X,        MT_X, N,N,N,N,Y,Y,CSR.N,N,N,N))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ADecode(implicit val p: Parameters) extends DecodeConstants
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  val table: Array[(BitPat, List[BitPat])] = Array(
 | 
				
			||||||
 | 
					    AMOADD_W->  List(Y,N,N,N,N,N,Y,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD,   Y,M_XA_ADD,   MT_W, N,N,N,N,N,Y,CSR.N,N,N,Y),
 | 
				
			||||||
 | 
					    AMOXOR_W->  List(Y,N,N,N,N,N,Y,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD,   Y,M_XA_XOR,   MT_W, N,N,N,N,N,Y,CSR.N,N,N,Y),
 | 
				
			||||||
 | 
					    AMOSWAP_W-> List(Y,N,N,N,N,N,Y,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD,   Y,M_XA_SWAP,  MT_W, N,N,N,N,N,Y,CSR.N,N,N,Y),
 | 
				
			||||||
 | 
					    AMOAND_W->  List(Y,N,N,N,N,N,Y,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD,   Y,M_XA_AND,   MT_W, N,N,N,N,N,Y,CSR.N,N,N,Y),
 | 
				
			||||||
 | 
					    AMOOR_W->   List(Y,N,N,N,N,N,Y,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD,   Y,M_XA_OR,    MT_W, N,N,N,N,N,Y,CSR.N,N,N,Y),
 | 
				
			||||||
 | 
					    AMOMIN_W->  List(Y,N,N,N,N,N,Y,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD,   Y,M_XA_MIN,   MT_W, N,N,N,N,N,Y,CSR.N,N,N,Y),
 | 
				
			||||||
 | 
					    AMOMINU_W-> List(Y,N,N,N,N,N,Y,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD,   Y,M_XA_MINU,  MT_W, N,N,N,N,N,Y,CSR.N,N,N,Y),
 | 
				
			||||||
 | 
					    AMOMAX_W->  List(Y,N,N,N,N,N,Y,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD,   Y,M_XA_MAX,   MT_W, N,N,N,N,N,Y,CSR.N,N,N,Y),
 | 
				
			||||||
 | 
					    AMOMAXU_W-> List(Y,N,N,N,N,N,Y,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD,   Y,M_XA_MAXU,  MT_W, N,N,N,N,N,Y,CSR.N,N,N,Y),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    LR_W->      List(Y,N,N,N,N,N,Y,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD,   Y,M_XLR,      MT_W, N,N,N,N,N,Y,CSR.N,N,N,Y),
 | 
				
			||||||
 | 
					    SC_W->      List(Y,N,N,N,N,N,Y,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD,   Y,M_XSC,      MT_W, N,N,N,N,N,Y,CSR.N,N,N,Y))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class A64Decode(implicit val p: Parameters) extends DecodeConstants
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  val table: Array[(BitPat, List[BitPat])] = Array(
 | 
				
			||||||
 | 
					    AMOADD_D->  List(Y,N,N,N,N,N,Y,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD,   Y,M_XA_ADD,   MT_D, N,N,N,N,N,Y,CSR.N,N,N,Y),
 | 
				
			||||||
 | 
					    AMOSWAP_D-> List(Y,N,N,N,N,N,Y,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD,   Y,M_XA_SWAP,  MT_D, N,N,N,N,N,Y,CSR.N,N,N,Y),
 | 
				
			||||||
 | 
					    AMOXOR_D->  List(Y,N,N,N,N,N,Y,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD,   Y,M_XA_XOR,   MT_D, N,N,N,N,N,Y,CSR.N,N,N,Y),
 | 
				
			||||||
 | 
					    AMOAND_D->  List(Y,N,N,N,N,N,Y,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD,   Y,M_XA_AND,   MT_D, N,N,N,N,N,Y,CSR.N,N,N,Y),
 | 
				
			||||||
 | 
					    AMOOR_D->   List(Y,N,N,N,N,N,Y,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD,   Y,M_XA_OR,    MT_D, N,N,N,N,N,Y,CSR.N,N,N,Y),
 | 
				
			||||||
 | 
					    AMOMIN_D->  List(Y,N,N,N,N,N,Y,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD,   Y,M_XA_MIN,   MT_D, N,N,N,N,N,Y,CSR.N,N,N,Y),
 | 
				
			||||||
 | 
					    AMOMINU_D-> List(Y,N,N,N,N,N,Y,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD,   Y,M_XA_MINU,  MT_D, N,N,N,N,N,Y,CSR.N,N,N,Y),
 | 
				
			||||||
 | 
					    AMOMAX_D->  List(Y,N,N,N,N,N,Y,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD,   Y,M_XA_MAX,   MT_D, N,N,N,N,N,Y,CSR.N,N,N,Y),
 | 
				
			||||||
 | 
					    AMOMAXU_D-> List(Y,N,N,N,N,N,Y,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD,   Y,M_XA_MAXU,  MT_D, N,N,N,N,N,Y,CSR.N,N,N,Y),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    LR_D->      List(Y,N,N,N,N,N,Y,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD,   Y,M_XLR,      MT_D, N,N,N,N,N,Y,CSR.N,N,N,Y),
 | 
				
			||||||
 | 
					    SC_D->      List(Y,N,N,N,N,N,Y,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD,   Y,M_XSC,      MT_D, N,N,N,N,N,Y,CSR.N,N,N,Y))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class FDecode(implicit val p: Parameters) extends DecodeConstants
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  val table: Array[(BitPat, List[BitPat])] = Array(
 | 
				
			||||||
 | 
					    FCVT_S_D->  List(Y,Y,N,N,N,N,N,N,A2_X,   A1_X,   IMM_X, DW_X,  FN_X,     N,M_X,        MT_X, Y,N,N,Y,N,N,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    FCVT_D_S->  List(Y,Y,N,N,N,N,N,N,A2_X,   A1_X,   IMM_X, DW_X,  FN_X,     N,M_X,        MT_X, Y,N,N,Y,N,N,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    FSGNJ_S->   List(Y,Y,N,N,N,N,N,N,A2_X,   A1_X,   IMM_X, DW_X,  FN_X,     N,M_X,        MT_X, Y,Y,N,Y,N,N,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    FSGNJ_D->   List(Y,Y,N,N,N,N,N,N,A2_X,   A1_X,   IMM_X, DW_X,  FN_X,     N,M_X,        MT_X, Y,Y,N,Y,N,N,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    FSGNJX_S->  List(Y,Y,N,N,N,N,N,N,A2_X,   A1_X,   IMM_X, DW_X,  FN_X,     N,M_X,        MT_X, Y,Y,N,Y,N,N,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    FSGNJX_D->  List(Y,Y,N,N,N,N,N,N,A2_X,   A1_X,   IMM_X, DW_X,  FN_X,     N,M_X,        MT_X, Y,Y,N,Y,N,N,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    FSGNJN_S->  List(Y,Y,N,N,N,N,N,N,A2_X,   A1_X,   IMM_X, DW_X,  FN_X,     N,M_X,        MT_X, Y,Y,N,Y,N,N,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    FSGNJN_D->  List(Y,Y,N,N,N,N,N,N,A2_X,   A1_X,   IMM_X, DW_X,  FN_X,     N,M_X,        MT_X, Y,Y,N,Y,N,N,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    FMIN_S->    List(Y,Y,N,N,N,N,N,N,A2_X,   A1_X,   IMM_X, DW_X,  FN_X,     N,M_X,        MT_X, Y,Y,N,Y,N,N,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    FMIN_D->    List(Y,Y,N,N,N,N,N,N,A2_X,   A1_X,   IMM_X, DW_X,  FN_X,     N,M_X,        MT_X, Y,Y,N,Y,N,N,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    FMAX_S->    List(Y,Y,N,N,N,N,N,N,A2_X,   A1_X,   IMM_X, DW_X,  FN_X,     N,M_X,        MT_X, Y,Y,N,Y,N,N,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    FMAX_D->    List(Y,Y,N,N,N,N,N,N,A2_X,   A1_X,   IMM_X, DW_X,  FN_X,     N,M_X,        MT_X, Y,Y,N,Y,N,N,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    FADD_S->    List(Y,Y,N,N,N,N,N,N,A2_X,   A1_X,   IMM_X, DW_X,  FN_X,     N,M_X,        MT_X, Y,Y,N,Y,N,N,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    FADD_D->    List(Y,Y,N,N,N,N,N,N,A2_X,   A1_X,   IMM_X, DW_X,  FN_X,     N,M_X,        MT_X, Y,Y,N,Y,N,N,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    FSUB_S->    List(Y,Y,N,N,N,N,N,N,A2_X,   A1_X,   IMM_X, DW_X,  FN_X,     N,M_X,        MT_X, Y,Y,N,Y,N,N,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    FSUB_D->    List(Y,Y,N,N,N,N,N,N,A2_X,   A1_X,   IMM_X, DW_X,  FN_X,     N,M_X,        MT_X, Y,Y,N,Y,N,N,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    FMUL_S->    List(Y,Y,N,N,N,N,N,N,A2_X,   A1_X,   IMM_X, DW_X,  FN_X,     N,M_X,        MT_X, Y,Y,N,Y,N,N,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    FMUL_D->    List(Y,Y,N,N,N,N,N,N,A2_X,   A1_X,   IMM_X, DW_X,  FN_X,     N,M_X,        MT_X, Y,Y,N,Y,N,N,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    FMADD_S->   List(Y,Y,N,N,N,N,N,N,A2_X,   A1_X,   IMM_X, DW_X,  FN_X,     N,M_X,        MT_X, Y,Y,Y,Y,N,N,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    FMADD_D->   List(Y,Y,N,N,N,N,N,N,A2_X,   A1_X,   IMM_X, DW_X,  FN_X,     N,M_X,        MT_X, Y,Y,Y,Y,N,N,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    FMSUB_S->   List(Y,Y,N,N,N,N,N,N,A2_X,   A1_X,   IMM_X, DW_X,  FN_X,     N,M_X,        MT_X, Y,Y,Y,Y,N,N,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    FMSUB_D->   List(Y,Y,N,N,N,N,N,N,A2_X,   A1_X,   IMM_X, DW_X,  FN_X,     N,M_X,        MT_X, Y,Y,Y,Y,N,N,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    FNMADD_S->  List(Y,Y,N,N,N,N,N,N,A2_X,   A1_X,   IMM_X, DW_X,  FN_X,     N,M_X,        MT_X, Y,Y,Y,Y,N,N,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    FNMADD_D->  List(Y,Y,N,N,N,N,N,N,A2_X,   A1_X,   IMM_X, DW_X,  FN_X,     N,M_X,        MT_X, Y,Y,Y,Y,N,N,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    FNMSUB_S->  List(Y,Y,N,N,N,N,N,N,A2_X,   A1_X,   IMM_X, DW_X,  FN_X,     N,M_X,        MT_X, Y,Y,Y,Y,N,N,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    FNMSUB_D->  List(Y,Y,N,N,N,N,N,N,A2_X,   A1_X,   IMM_X, DW_X,  FN_X,     N,M_X,        MT_X, Y,Y,Y,Y,N,N,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    FCLASS_S->  List(Y,Y,N,N,N,N,N,N,A2_X,   A1_X,   IMM_X, DW_X,  FN_X,     N,M_X,        MT_X, Y,N,N,N,N,Y,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    FCLASS_D->  List(Y,Y,N,N,N,N,N,N,A2_X,   A1_X,   IMM_X, DW_X,  FN_X,     N,M_X,        MT_X, Y,N,N,N,N,Y,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    FMV_X_S->   List(Y,Y,N,N,N,N,N,N,A2_X,   A1_X,   IMM_X, DW_X,  FN_X,     N,M_X,        MT_X, Y,N,N,N,N,Y,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    FCVT_W_S->  List(Y,Y,N,N,N,N,N,N,A2_X,   A1_X,   IMM_X, DW_X,  FN_X,     N,M_X,        MT_X, Y,N,N,N,N,Y,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    FCVT_W_D->  List(Y,Y,N,N,N,N,N,N,A2_X,   A1_X,   IMM_X, DW_X,  FN_X,     N,M_X,        MT_X, Y,N,N,N,N,Y,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    FCVT_WU_S-> List(Y,Y,N,N,N,N,N,N,A2_X,   A1_X,   IMM_X, DW_X,  FN_X,     N,M_X,        MT_X, Y,N,N,N,N,Y,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    FCVT_WU_D-> List(Y,Y,N,N,N,N,N,N,A2_X,   A1_X,   IMM_X, DW_X,  FN_X,     N,M_X,        MT_X, Y,N,N,N,N,Y,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    FEQ_S->     List(Y,Y,N,N,N,N,N,N,A2_X,   A1_X,   IMM_X, DW_X,  FN_X,     N,M_X,        MT_X, Y,Y,N,N,N,Y,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    FEQ_D->     List(Y,Y,N,N,N,N,N,N,A2_X,   A1_X,   IMM_X, DW_X,  FN_X,     N,M_X,        MT_X, Y,Y,N,N,N,Y,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    FLT_S->     List(Y,Y,N,N,N,N,N,N,A2_X,   A1_X,   IMM_X, DW_X,  FN_X,     N,M_X,        MT_X, Y,Y,N,N,N,Y,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    FLT_D->     List(Y,Y,N,N,N,N,N,N,A2_X,   A1_X,   IMM_X, DW_X,  FN_X,     N,M_X,        MT_X, Y,Y,N,N,N,Y,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    FLE_S->     List(Y,Y,N,N,N,N,N,N,A2_X,   A1_X,   IMM_X, DW_X,  FN_X,     N,M_X,        MT_X, Y,Y,N,N,N,Y,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    FLE_D->     List(Y,Y,N,N,N,N,N,N,A2_X,   A1_X,   IMM_X, DW_X,  FN_X,     N,M_X,        MT_X, Y,Y,N,N,N,Y,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    FMV_S_X->   List(Y,Y,N,N,N,N,N,Y,A2_X,   A1_RS1, IMM_X, DW_X,  FN_X,     N,M_X,        MT_X, N,N,N,Y,N,N,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    FCVT_S_W->  List(Y,Y,N,N,N,N,N,Y,A2_X,   A1_RS1, IMM_X, DW_X,  FN_X,     N,M_X,        MT_X, N,N,N,Y,N,N,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    FCVT_D_W->  List(Y,Y,N,N,N,N,N,Y,A2_X,   A1_RS1, IMM_X, DW_X,  FN_X,     N,M_X,        MT_X, N,N,N,Y,N,N,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    FCVT_S_WU-> List(Y,Y,N,N,N,N,N,Y,A2_X,   A1_RS1, IMM_X, DW_X,  FN_X,     N,M_X,        MT_X, N,N,N,Y,N,N,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    FCVT_D_WU-> List(Y,Y,N,N,N,N,N,Y,A2_X,   A1_RS1, IMM_X, DW_X,  FN_X,     N,M_X,        MT_X, N,N,N,Y,N,N,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    FLW->       List(Y,Y,N,N,N,N,N,Y,A2_IMM, A1_RS1, IMM_I, DW_XPR,FN_ADD,   Y,M_XRD,      MT_W, N,N,N,Y,N,N,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    FLD->       List(Y,Y,N,N,N,N,N,Y,A2_IMM, A1_RS1, IMM_I, DW_XPR,FN_ADD,   Y,M_XRD,      MT_D, N,N,N,Y,N,N,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    FSW->       List(Y,Y,N,N,N,N,N,Y,A2_IMM, A1_RS1, IMM_S, DW_XPR,FN_ADD,   Y,M_XWR,      MT_W, N,Y,N,N,N,N,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    FSD->       List(Y,Y,N,N,N,N,N,Y,A2_IMM, A1_RS1, IMM_S, DW_XPR,FN_ADD,   Y,M_XWR,      MT_D, N,Y,N,N,N,N,CSR.N,N,N,N))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class F64Decode(implicit val p: Parameters) extends DecodeConstants
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  val table: Array[(BitPat, List[BitPat])] = Array(
 | 
				
			||||||
 | 
					    FMV_X_D->   List(Y,Y,N,N,N,N,N,N,A2_X,   A1_X,   IMM_X, DW_X,  FN_X,     N,M_X,        MT_X, Y,N,N,N,N,Y,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    FCVT_L_S->  List(Y,Y,N,N,N,N,N,N,A2_X,   A1_X,   IMM_X, DW_X,  FN_X,     N,M_X,        MT_X, Y,N,N,N,N,Y,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    FCVT_L_D->  List(Y,Y,N,N,N,N,N,N,A2_X,   A1_X,   IMM_X, DW_X,  FN_X,     N,M_X,        MT_X, Y,N,N,N,N,Y,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    FCVT_LU_S-> List(Y,Y,N,N,N,N,N,N,A2_X,   A1_X,   IMM_X, DW_X,  FN_X,     N,M_X,        MT_X, Y,N,N,N,N,Y,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    FCVT_LU_D-> List(Y,Y,N,N,N,N,N,N,A2_X,   A1_X,   IMM_X, DW_X,  FN_X,     N,M_X,        MT_X, Y,N,N,N,N,Y,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    FMV_D_X->   List(Y,Y,N,N,N,N,N,Y,A2_X,   A1_RS1, IMM_X, DW_X,  FN_X,     N,M_X,        MT_X, N,N,N,Y,N,N,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    FCVT_S_L->  List(Y,Y,N,N,N,N,N,Y,A2_X,   A1_RS1, IMM_X, DW_X,  FN_X,     N,M_X,        MT_X, N,N,N,Y,N,N,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    FCVT_D_L->  List(Y,Y,N,N,N,N,N,Y,A2_X,   A1_RS1, IMM_X, DW_X,  FN_X,     N,M_X,        MT_X, N,N,N,Y,N,N,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    FCVT_S_LU-> List(Y,Y,N,N,N,N,N,Y,A2_X,   A1_RS1, IMM_X, DW_X,  FN_X,     N,M_X,        MT_X, N,N,N,Y,N,N,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    FCVT_D_LU-> List(Y,Y,N,N,N,N,N,Y,A2_X,   A1_RS1, IMM_X, DW_X,  FN_X,     N,M_X,        MT_X, N,N,N,Y,N,N,CSR.N,N,N,N))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class FDivSqrtDecode(implicit val p: Parameters) extends DecodeConstants
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  val table: Array[(BitPat, List[BitPat])] = Array(
 | 
				
			||||||
 | 
					    FDIV_S->    List(Y,Y,N,N,N,N,N,N,A2_X,   A1_X,   IMM_X, DW_X,  FN_X,     N,M_X,        MT_X, Y,Y,N,Y,N,N,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    FDIV_D->    List(Y,Y,N,N,N,N,N,N,A2_X,   A1_X,   IMM_X, DW_X,  FN_X,     N,M_X,        MT_X, Y,Y,N,Y,N,N,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    FSQRT_S->   List(Y,Y,N,N,N,N,N,N,A2_X,   A1_X,   IMM_X, DW_X,  FN_X,     N,M_X,        MT_X, Y,Y,N,Y,N,N,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    FSQRT_D->   List(Y,Y,N,N,N,N,N,N,A2_X,   A1_X,   IMM_X, DW_X,  FN_X,     N,M_X,        MT_X, Y,Y,N,Y,N,N,CSR.N,N,N,N))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class RoCCDecode(implicit val p: Parameters) extends DecodeConstants
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  val table: Array[(BitPat, List[BitPat])] = Array(
 | 
				
			||||||
 | 
					    CUSTOM0->           List(Y,N,Y,N,N,N,N,N,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD,   N,M_X,        MT_X, N,N,N,N,N,N,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    CUSTOM0_RS1->       List(Y,N,Y,N,N,N,N,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD,   N,M_X,        MT_X, N,N,N,N,N,N,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    CUSTOM0_RS1_RS2->   List(Y,N,Y,N,N,N,Y,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD,   N,M_X,        MT_X, N,N,N,N,N,N,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    CUSTOM0_RD->        List(Y,N,Y,N,N,N,N,N,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD,   N,M_X,        MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    CUSTOM0_RD_RS1->    List(Y,N,Y,N,N,N,N,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD,   N,M_X,        MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    CUSTOM0_RD_RS1_RS2->List(Y,N,Y,N,N,N,Y,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD,   N,M_X,        MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    CUSTOM1->           List(Y,N,Y,N,N,N,N,N,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD,   N,M_X,        MT_X, N,N,N,N,N,N,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    CUSTOM1_RS1->       List(Y,N,Y,N,N,N,N,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD,   N,M_X,        MT_X, N,N,N,N,N,N,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    CUSTOM1_RS1_RS2->   List(Y,N,Y,N,N,N,Y,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD,   N,M_X,        MT_X, N,N,N,N,N,N,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    CUSTOM1_RD->        List(Y,N,Y,N,N,N,N,N,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD,   N,M_X,        MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    CUSTOM1_RD_RS1->    List(Y,N,Y,N,N,N,N,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD,   N,M_X,        MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    CUSTOM1_RD_RS1_RS2->List(Y,N,Y,N,N,N,Y,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD,   N,M_X,        MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    CUSTOM2->           List(Y,N,Y,N,N,N,N,N,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD,   N,M_X,        MT_X, N,N,N,N,N,N,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    CUSTOM2_RS1->       List(Y,N,Y,N,N,N,N,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD,   N,M_X,        MT_X, N,N,N,N,N,N,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    CUSTOM2_RS1_RS2->   List(Y,N,Y,N,N,N,Y,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD,   N,M_X,        MT_X, N,N,N,N,N,N,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    CUSTOM2_RD->        List(Y,N,Y,N,N,N,N,N,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD,   N,M_X,        MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    CUSTOM2_RD_RS1->    List(Y,N,Y,N,N,N,N,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD,   N,M_X,        MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    CUSTOM2_RD_RS1_RS2->List(Y,N,Y,N,N,N,Y,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD,   N,M_X,        MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    CUSTOM3->           List(Y,N,Y,N,N,N,N,N,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD,   N,M_X,        MT_X, N,N,N,N,N,N,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    CUSTOM3_RS1->       List(Y,N,Y,N,N,N,N,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD,   N,M_X,        MT_X, N,N,N,N,N,N,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    CUSTOM3_RS1_RS2->   List(Y,N,Y,N,N,N,Y,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD,   N,M_X,        MT_X, N,N,N,N,N,N,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    CUSTOM3_RD->        List(Y,N,Y,N,N,N,N,N,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD,   N,M_X,        MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    CUSTOM3_RD_RS1->    List(Y,N,Y,N,N,N,N,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD,   N,M_X,        MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
 | 
				
			||||||
 | 
					    CUSTOM3_RD_RS1_RS2->List(Y,N,Y,N,N,N,Y,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD,   N,M_X,        MT_X, N,N,N,N,N,Y,CSR.N,N,N,N))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										383
									
								
								rocket/src/main/scala/instructions.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										383
									
								
								rocket/src/main/scala/instructions.scala
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,383 @@
 | 
				
			|||||||
 | 
					// See LICENSE for license details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package rocket
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import Chisel._
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Automatically generated by parse-opcodes */
 | 
				
			||||||
 | 
					object Instructions {
 | 
				
			||||||
 | 
					  def BEQ                = BitPat("b?????????????????000?????1100011")
 | 
				
			||||||
 | 
					  def BNE                = BitPat("b?????????????????001?????1100011")
 | 
				
			||||||
 | 
					  def BLT                = BitPat("b?????????????????100?????1100011")
 | 
				
			||||||
 | 
					  def BGE                = BitPat("b?????????????????101?????1100011")
 | 
				
			||||||
 | 
					  def BLTU               = BitPat("b?????????????????110?????1100011")
 | 
				
			||||||
 | 
					  def BGEU               = BitPat("b?????????????????111?????1100011")
 | 
				
			||||||
 | 
					  def JALR               = BitPat("b?????????????????000?????1100111")
 | 
				
			||||||
 | 
					  def JAL                = BitPat("b?????????????????????????1101111")
 | 
				
			||||||
 | 
					  def LUI                = BitPat("b?????????????????????????0110111")
 | 
				
			||||||
 | 
					  def AUIPC              = BitPat("b?????????????????????????0010111")
 | 
				
			||||||
 | 
					  def ADDI               = BitPat("b?????????????????000?????0010011")
 | 
				
			||||||
 | 
					  def SLLI               = BitPat("b000000???????????001?????0010011")
 | 
				
			||||||
 | 
					  def SLTI               = BitPat("b?????????????????010?????0010011")
 | 
				
			||||||
 | 
					  def SLTIU              = BitPat("b?????????????????011?????0010011")
 | 
				
			||||||
 | 
					  def XORI               = BitPat("b?????????????????100?????0010011")
 | 
				
			||||||
 | 
					  def SRLI               = BitPat("b000000???????????101?????0010011")
 | 
				
			||||||
 | 
					  def SRAI               = BitPat("b010000???????????101?????0010011")
 | 
				
			||||||
 | 
					  def ORI                = BitPat("b?????????????????110?????0010011")
 | 
				
			||||||
 | 
					  def ANDI               = BitPat("b?????????????????111?????0010011")
 | 
				
			||||||
 | 
					  def ADD                = BitPat("b0000000??????????000?????0110011")
 | 
				
			||||||
 | 
					  def SUB                = BitPat("b0100000??????????000?????0110011")
 | 
				
			||||||
 | 
					  def SLL                = BitPat("b0000000??????????001?????0110011")
 | 
				
			||||||
 | 
					  def SLT                = BitPat("b0000000??????????010?????0110011")
 | 
				
			||||||
 | 
					  def SLTU               = BitPat("b0000000??????????011?????0110011")
 | 
				
			||||||
 | 
					  def XOR                = BitPat("b0000000??????????100?????0110011")
 | 
				
			||||||
 | 
					  def SRL                = BitPat("b0000000??????????101?????0110011")
 | 
				
			||||||
 | 
					  def SRA                = BitPat("b0100000??????????101?????0110011")
 | 
				
			||||||
 | 
					  def OR                 = BitPat("b0000000??????????110?????0110011")
 | 
				
			||||||
 | 
					  def AND                = BitPat("b0000000??????????111?????0110011")
 | 
				
			||||||
 | 
					  def ADDIW              = BitPat("b?????????????????000?????0011011")
 | 
				
			||||||
 | 
					  def SLLIW              = BitPat("b0000000??????????001?????0011011")
 | 
				
			||||||
 | 
					  def SRLIW              = BitPat("b0000000??????????101?????0011011")
 | 
				
			||||||
 | 
					  def SRAIW              = BitPat("b0100000??????????101?????0011011")
 | 
				
			||||||
 | 
					  def ADDW               = BitPat("b0000000??????????000?????0111011")
 | 
				
			||||||
 | 
					  def SUBW               = BitPat("b0100000??????????000?????0111011")
 | 
				
			||||||
 | 
					  def SLLW               = BitPat("b0000000??????????001?????0111011")
 | 
				
			||||||
 | 
					  def SRLW               = BitPat("b0000000??????????101?????0111011")
 | 
				
			||||||
 | 
					  def SRAW               = BitPat("b0100000??????????101?????0111011")
 | 
				
			||||||
 | 
					  def LB                 = BitPat("b?????????????????000?????0000011")
 | 
				
			||||||
 | 
					  def LH                 = BitPat("b?????????????????001?????0000011")
 | 
				
			||||||
 | 
					  def LW                 = BitPat("b?????????????????010?????0000011")
 | 
				
			||||||
 | 
					  def LD                 = BitPat("b?????????????????011?????0000011")
 | 
				
			||||||
 | 
					  def LBU                = BitPat("b?????????????????100?????0000011")
 | 
				
			||||||
 | 
					  def LHU                = BitPat("b?????????????????101?????0000011")
 | 
				
			||||||
 | 
					  def LWU                = BitPat("b?????????????????110?????0000011")
 | 
				
			||||||
 | 
					  def SB                 = BitPat("b?????????????????000?????0100011")
 | 
				
			||||||
 | 
					  def SH                 = BitPat("b?????????????????001?????0100011")
 | 
				
			||||||
 | 
					  def SW                 = BitPat("b?????????????????010?????0100011")
 | 
				
			||||||
 | 
					  def SD                 = BitPat("b?????????????????011?????0100011")
 | 
				
			||||||
 | 
					  def FENCE              = BitPat("b?????????????????000?????0001111")
 | 
				
			||||||
 | 
					  def FENCE_I            = BitPat("b?????????????????001?????0001111")
 | 
				
			||||||
 | 
					  def MUL                = BitPat("b0000001??????????000?????0110011")
 | 
				
			||||||
 | 
					  def MULH               = BitPat("b0000001??????????001?????0110011")
 | 
				
			||||||
 | 
					  def MULHSU             = BitPat("b0000001??????????010?????0110011")
 | 
				
			||||||
 | 
					  def MULHU              = BitPat("b0000001??????????011?????0110011")
 | 
				
			||||||
 | 
					  def DIV                = BitPat("b0000001??????????100?????0110011")
 | 
				
			||||||
 | 
					  def DIVU               = BitPat("b0000001??????????101?????0110011")
 | 
				
			||||||
 | 
					  def REM                = BitPat("b0000001??????????110?????0110011")
 | 
				
			||||||
 | 
					  def REMU               = BitPat("b0000001??????????111?????0110011")
 | 
				
			||||||
 | 
					  def MULW               = BitPat("b0000001??????????000?????0111011")
 | 
				
			||||||
 | 
					  def DIVW               = BitPat("b0000001??????????100?????0111011")
 | 
				
			||||||
 | 
					  def DIVUW              = BitPat("b0000001??????????101?????0111011")
 | 
				
			||||||
 | 
					  def REMW               = BitPat("b0000001??????????110?????0111011")
 | 
				
			||||||
 | 
					  def REMUW              = BitPat("b0000001??????????111?????0111011")
 | 
				
			||||||
 | 
					  def AMOADD_W           = BitPat("b00000????????????010?????0101111")
 | 
				
			||||||
 | 
					  def AMOXOR_W           = BitPat("b00100????????????010?????0101111")
 | 
				
			||||||
 | 
					  def AMOOR_W            = BitPat("b01000????????????010?????0101111")
 | 
				
			||||||
 | 
					  def AMOAND_W           = BitPat("b01100????????????010?????0101111")
 | 
				
			||||||
 | 
					  def AMOMIN_W           = BitPat("b10000????????????010?????0101111")
 | 
				
			||||||
 | 
					  def AMOMAX_W           = BitPat("b10100????????????010?????0101111")
 | 
				
			||||||
 | 
					  def AMOMINU_W          = BitPat("b11000????????????010?????0101111")
 | 
				
			||||||
 | 
					  def AMOMAXU_W          = BitPat("b11100????????????010?????0101111")
 | 
				
			||||||
 | 
					  def AMOSWAP_W          = BitPat("b00001????????????010?????0101111")
 | 
				
			||||||
 | 
					  def LR_W               = BitPat("b00010??00000?????010?????0101111")
 | 
				
			||||||
 | 
					  def SC_W               = BitPat("b00011????????????010?????0101111")
 | 
				
			||||||
 | 
					  def AMOADD_D           = BitPat("b00000????????????011?????0101111")
 | 
				
			||||||
 | 
					  def AMOXOR_D           = BitPat("b00100????????????011?????0101111")
 | 
				
			||||||
 | 
					  def AMOOR_D            = BitPat("b01000????????????011?????0101111")
 | 
				
			||||||
 | 
					  def AMOAND_D           = BitPat("b01100????????????011?????0101111")
 | 
				
			||||||
 | 
					  def AMOMIN_D           = BitPat("b10000????????????011?????0101111")
 | 
				
			||||||
 | 
					  def AMOMAX_D           = BitPat("b10100????????????011?????0101111")
 | 
				
			||||||
 | 
					  def AMOMINU_D          = BitPat("b11000????????????011?????0101111")
 | 
				
			||||||
 | 
					  def AMOMAXU_D          = BitPat("b11100????????????011?????0101111")
 | 
				
			||||||
 | 
					  def AMOSWAP_D          = BitPat("b00001????????????011?????0101111")
 | 
				
			||||||
 | 
					  def LR_D               = BitPat("b00010??00000?????011?????0101111")
 | 
				
			||||||
 | 
					  def SC_D               = BitPat("b00011????????????011?????0101111")
 | 
				
			||||||
 | 
					  def ECALL              = BitPat("b00000000000000000000000001110011")
 | 
				
			||||||
 | 
					  def EBREAK             = BitPat("b00000000000100000000000001110011")
 | 
				
			||||||
 | 
					  def URET               = BitPat("b00000000001000000000000001110011")
 | 
				
			||||||
 | 
					  def SRET               = BitPat("b00010000001000000000000001110011")
 | 
				
			||||||
 | 
					  def HRET               = BitPat("b00100000001000000000000001110011")
 | 
				
			||||||
 | 
					  def MRET               = BitPat("b00110000001000000000000001110011")
 | 
				
			||||||
 | 
					  def DRET               = BitPat("b01111011001000000000000001110011")
 | 
				
			||||||
 | 
					  def SFENCE_VM          = BitPat("b000100000100?????000000001110011")
 | 
				
			||||||
 | 
					  def WFI                = BitPat("b00010000010100000000000001110011")
 | 
				
			||||||
 | 
					  def CSRRW              = BitPat("b?????????????????001?????1110011")
 | 
				
			||||||
 | 
					  def CSRRS              = BitPat("b?????????????????010?????1110011")
 | 
				
			||||||
 | 
					  def CSRRC              = BitPat("b?????????????????011?????1110011")
 | 
				
			||||||
 | 
					  def CSRRWI             = BitPat("b?????????????????101?????1110011")
 | 
				
			||||||
 | 
					  def CSRRSI             = BitPat("b?????????????????110?????1110011")
 | 
				
			||||||
 | 
					  def CSRRCI             = BitPat("b?????????????????111?????1110011")
 | 
				
			||||||
 | 
					  def FADD_S             = BitPat("b0000000??????????????????1010011")
 | 
				
			||||||
 | 
					  def FSUB_S             = BitPat("b0000100??????????????????1010011")
 | 
				
			||||||
 | 
					  def FMUL_S             = BitPat("b0001000??????????????????1010011")
 | 
				
			||||||
 | 
					  def FDIV_S             = BitPat("b0001100??????????????????1010011")
 | 
				
			||||||
 | 
					  def FSGNJ_S            = BitPat("b0010000??????????000?????1010011")
 | 
				
			||||||
 | 
					  def FSGNJN_S           = BitPat("b0010000??????????001?????1010011")
 | 
				
			||||||
 | 
					  def FSGNJX_S           = BitPat("b0010000??????????010?????1010011")
 | 
				
			||||||
 | 
					  def FMIN_S             = BitPat("b0010100??????????000?????1010011")
 | 
				
			||||||
 | 
					  def FMAX_S             = BitPat("b0010100??????????001?????1010011")
 | 
				
			||||||
 | 
					  def FSQRT_S            = BitPat("b010110000000?????????????1010011")
 | 
				
			||||||
 | 
					  def FADD_D             = BitPat("b0000001??????????????????1010011")
 | 
				
			||||||
 | 
					  def FSUB_D             = BitPat("b0000101??????????????????1010011")
 | 
				
			||||||
 | 
					  def FMUL_D             = BitPat("b0001001??????????????????1010011")
 | 
				
			||||||
 | 
					  def FDIV_D             = BitPat("b0001101??????????????????1010011")
 | 
				
			||||||
 | 
					  def FSGNJ_D            = BitPat("b0010001??????????000?????1010011")
 | 
				
			||||||
 | 
					  def FSGNJN_D           = BitPat("b0010001??????????001?????1010011")
 | 
				
			||||||
 | 
					  def FSGNJX_D           = BitPat("b0010001??????????010?????1010011")
 | 
				
			||||||
 | 
					  def FMIN_D             = BitPat("b0010101??????????000?????1010011")
 | 
				
			||||||
 | 
					  def FMAX_D             = BitPat("b0010101??????????001?????1010011")
 | 
				
			||||||
 | 
					  def FCVT_S_D           = BitPat("b010000000001?????????????1010011")
 | 
				
			||||||
 | 
					  def FCVT_D_S           = BitPat("b010000100000?????????????1010011")
 | 
				
			||||||
 | 
					  def FSQRT_D            = BitPat("b010110100000?????????????1010011")
 | 
				
			||||||
 | 
					  def FLE_S              = BitPat("b1010000??????????000?????1010011")
 | 
				
			||||||
 | 
					  def FLT_S              = BitPat("b1010000??????????001?????1010011")
 | 
				
			||||||
 | 
					  def FEQ_S              = BitPat("b1010000??????????010?????1010011")
 | 
				
			||||||
 | 
					  def FLE_D              = BitPat("b1010001??????????000?????1010011")
 | 
				
			||||||
 | 
					  def FLT_D              = BitPat("b1010001??????????001?????1010011")
 | 
				
			||||||
 | 
					  def FEQ_D              = BitPat("b1010001??????????010?????1010011")
 | 
				
			||||||
 | 
					  def FCVT_W_S           = BitPat("b110000000000?????????????1010011")
 | 
				
			||||||
 | 
					  def FCVT_WU_S          = BitPat("b110000000001?????????????1010011")
 | 
				
			||||||
 | 
					  def FCVT_L_S           = BitPat("b110000000010?????????????1010011")
 | 
				
			||||||
 | 
					  def FCVT_LU_S          = BitPat("b110000000011?????????????1010011")
 | 
				
			||||||
 | 
					  def FMV_X_S            = BitPat("b111000000000?????000?????1010011")
 | 
				
			||||||
 | 
					  def FCLASS_S           = BitPat("b111000000000?????001?????1010011")
 | 
				
			||||||
 | 
					  def FCVT_W_D           = BitPat("b110000100000?????????????1010011")
 | 
				
			||||||
 | 
					  def FCVT_WU_D          = BitPat("b110000100001?????????????1010011")
 | 
				
			||||||
 | 
					  def FCVT_L_D           = BitPat("b110000100010?????????????1010011")
 | 
				
			||||||
 | 
					  def FCVT_LU_D          = BitPat("b110000100011?????????????1010011")
 | 
				
			||||||
 | 
					  def FMV_X_D            = BitPat("b111000100000?????000?????1010011")
 | 
				
			||||||
 | 
					  def FCLASS_D           = BitPat("b111000100000?????001?????1010011")
 | 
				
			||||||
 | 
					  def FCVT_S_W           = BitPat("b110100000000?????????????1010011")
 | 
				
			||||||
 | 
					  def FCVT_S_WU          = BitPat("b110100000001?????????????1010011")
 | 
				
			||||||
 | 
					  def FCVT_S_L           = BitPat("b110100000010?????????????1010011")
 | 
				
			||||||
 | 
					  def FCVT_S_LU          = BitPat("b110100000011?????????????1010011")
 | 
				
			||||||
 | 
					  def FMV_S_X            = BitPat("b111100000000?????000?????1010011")
 | 
				
			||||||
 | 
					  def FCVT_D_W           = BitPat("b110100100000?????????????1010011")
 | 
				
			||||||
 | 
					  def FCVT_D_WU          = BitPat("b110100100001?????????????1010011")
 | 
				
			||||||
 | 
					  def FCVT_D_L           = BitPat("b110100100010?????????????1010011")
 | 
				
			||||||
 | 
					  def FCVT_D_LU          = BitPat("b110100100011?????????????1010011")
 | 
				
			||||||
 | 
					  def FMV_D_X            = BitPat("b111100100000?????000?????1010011")
 | 
				
			||||||
 | 
					  def FLW                = BitPat("b?????????????????010?????0000111")
 | 
				
			||||||
 | 
					  def FLD                = BitPat("b?????????????????011?????0000111")
 | 
				
			||||||
 | 
					  def FSW                = BitPat("b?????????????????010?????0100111")
 | 
				
			||||||
 | 
					  def FSD                = BitPat("b?????????????????011?????0100111")
 | 
				
			||||||
 | 
					  def FMADD_S            = BitPat("b?????00??????????????????1000011")
 | 
				
			||||||
 | 
					  def FMSUB_S            = BitPat("b?????00??????????????????1000111")
 | 
				
			||||||
 | 
					  def FNMSUB_S           = BitPat("b?????00??????????????????1001011")
 | 
				
			||||||
 | 
					  def FNMADD_S           = BitPat("b?????00??????????????????1001111")
 | 
				
			||||||
 | 
					  def FMADD_D            = BitPat("b?????01??????????????????1000011")
 | 
				
			||||||
 | 
					  def FMSUB_D            = BitPat("b?????01??????????????????1000111")
 | 
				
			||||||
 | 
					  def FNMSUB_D           = BitPat("b?????01??????????????????1001011")
 | 
				
			||||||
 | 
					  def FNMADD_D           = BitPat("b?????01??????????????????1001111")
 | 
				
			||||||
 | 
					  def CUSTOM0            = BitPat("b?????????????????000?????0001011")
 | 
				
			||||||
 | 
					  def CUSTOM0_RS1        = BitPat("b?????????????????010?????0001011")
 | 
				
			||||||
 | 
					  def CUSTOM0_RS1_RS2    = BitPat("b?????????????????011?????0001011")
 | 
				
			||||||
 | 
					  def CUSTOM0_RD         = BitPat("b?????????????????100?????0001011")
 | 
				
			||||||
 | 
					  def CUSTOM0_RD_RS1     = BitPat("b?????????????????110?????0001011")
 | 
				
			||||||
 | 
					  def CUSTOM0_RD_RS1_RS2 = BitPat("b?????????????????111?????0001011")
 | 
				
			||||||
 | 
					  def CUSTOM1            = BitPat("b?????????????????000?????0101011")
 | 
				
			||||||
 | 
					  def CUSTOM1_RS1        = BitPat("b?????????????????010?????0101011")
 | 
				
			||||||
 | 
					  def CUSTOM1_RS1_RS2    = BitPat("b?????????????????011?????0101011")
 | 
				
			||||||
 | 
					  def CUSTOM1_RD         = BitPat("b?????????????????100?????0101011")
 | 
				
			||||||
 | 
					  def CUSTOM1_RD_RS1     = BitPat("b?????????????????110?????0101011")
 | 
				
			||||||
 | 
					  def CUSTOM1_RD_RS1_RS2 = BitPat("b?????????????????111?????0101011")
 | 
				
			||||||
 | 
					  def CUSTOM2            = BitPat("b?????????????????000?????1011011")
 | 
				
			||||||
 | 
					  def CUSTOM2_RS1        = BitPat("b?????????????????010?????1011011")
 | 
				
			||||||
 | 
					  def CUSTOM2_RS1_RS2    = BitPat("b?????????????????011?????1011011")
 | 
				
			||||||
 | 
					  def CUSTOM2_RD         = BitPat("b?????????????????100?????1011011")
 | 
				
			||||||
 | 
					  def CUSTOM2_RD_RS1     = BitPat("b?????????????????110?????1011011")
 | 
				
			||||||
 | 
					  def CUSTOM2_RD_RS1_RS2 = BitPat("b?????????????????111?????1011011")
 | 
				
			||||||
 | 
					  def CUSTOM3            = BitPat("b?????????????????000?????1111011")
 | 
				
			||||||
 | 
					  def CUSTOM3_RS1        = BitPat("b?????????????????010?????1111011")
 | 
				
			||||||
 | 
					  def CUSTOM3_RS1_RS2    = BitPat("b?????????????????011?????1111011")
 | 
				
			||||||
 | 
					  def CUSTOM3_RD         = BitPat("b?????????????????100?????1111011")
 | 
				
			||||||
 | 
					  def CUSTOM3_RD_RS1     = BitPat("b?????????????????110?????1111011")
 | 
				
			||||||
 | 
					  def CUSTOM3_RD_RS1_RS2 = BitPat("b?????????????????111?????1111011")
 | 
				
			||||||
 | 
					  def SLLI_RV32          = BitPat("b0000000??????????001?????0010011")
 | 
				
			||||||
 | 
					  def SRLI_RV32          = BitPat("b0000000??????????101?????0010011")
 | 
				
			||||||
 | 
					  def SRAI_RV32          = BitPat("b0100000??????????101?????0010011")
 | 
				
			||||||
 | 
					  def FRFLAGS            = BitPat("b00000000000100000010?????1110011")
 | 
				
			||||||
 | 
					  def FSFLAGS            = BitPat("b000000000001?????001?????1110011")
 | 
				
			||||||
 | 
					  def FSFLAGSI           = BitPat("b000000000001?????101?????1110011")
 | 
				
			||||||
 | 
					  def FRRM               = BitPat("b00000000001000000010?????1110011")
 | 
				
			||||||
 | 
					  def FSRM               = BitPat("b000000000010?????001?????1110011")
 | 
				
			||||||
 | 
					  def FSRMI              = BitPat("b000000000010?????101?????1110011")
 | 
				
			||||||
 | 
					  def FSCSR              = BitPat("b000000000011?????001?????1110011")
 | 
				
			||||||
 | 
					  def FRCSR              = BitPat("b00000000001100000010?????1110011")
 | 
				
			||||||
 | 
					  def RDCYCLE            = BitPat("b11000000000000000010?????1110011")
 | 
				
			||||||
 | 
					  def RDTIME             = BitPat("b11000000000100000010?????1110011")
 | 
				
			||||||
 | 
					  def RDINSTRET          = BitPat("b11000000001000000010?????1110011")
 | 
				
			||||||
 | 
					  def RDCYCLEH           = BitPat("b11001000000000000010?????1110011")
 | 
				
			||||||
 | 
					  def RDTIMEH            = BitPat("b11001000000100000010?????1110011")
 | 
				
			||||||
 | 
					  def RDINSTRETH         = BitPat("b11001000001000000010?????1110011")
 | 
				
			||||||
 | 
					  def SCALL              = BitPat("b00000000000000000000000001110011")
 | 
				
			||||||
 | 
					  def SBREAK             = BitPat("b00000000000100000000000001110011")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					object Causes {
 | 
				
			||||||
 | 
					  val misaligned_fetch = 0x0
 | 
				
			||||||
 | 
					  val fault_fetch = 0x1
 | 
				
			||||||
 | 
					  val illegal_instruction = 0x2
 | 
				
			||||||
 | 
					  val breakpoint = 0x3
 | 
				
			||||||
 | 
					  val misaligned_load = 0x4
 | 
				
			||||||
 | 
					  val fault_load = 0x5
 | 
				
			||||||
 | 
					  val misaligned_store = 0x6
 | 
				
			||||||
 | 
					  val fault_store = 0x7
 | 
				
			||||||
 | 
					  val user_ecall = 0x8
 | 
				
			||||||
 | 
					  val supervisor_ecall = 0x9
 | 
				
			||||||
 | 
					  val hypervisor_ecall = 0xa
 | 
				
			||||||
 | 
					  val machine_ecall = 0xb
 | 
				
			||||||
 | 
					  val all = {
 | 
				
			||||||
 | 
					    val res = collection.mutable.ArrayBuffer[Int]()
 | 
				
			||||||
 | 
					    res += misaligned_fetch
 | 
				
			||||||
 | 
					    res += fault_fetch
 | 
				
			||||||
 | 
					    res += illegal_instruction
 | 
				
			||||||
 | 
					    res += breakpoint
 | 
				
			||||||
 | 
					    res += misaligned_load
 | 
				
			||||||
 | 
					    res += fault_load
 | 
				
			||||||
 | 
					    res += misaligned_store
 | 
				
			||||||
 | 
					    res += fault_store
 | 
				
			||||||
 | 
					    res += user_ecall
 | 
				
			||||||
 | 
					    res += supervisor_ecall
 | 
				
			||||||
 | 
					    res += hypervisor_ecall
 | 
				
			||||||
 | 
					    res += machine_ecall
 | 
				
			||||||
 | 
					    res.toArray
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					object CSRs {
 | 
				
			||||||
 | 
					  val fflags = 0x1
 | 
				
			||||||
 | 
					  val frm = 0x2
 | 
				
			||||||
 | 
					  val fcsr = 0x3
 | 
				
			||||||
 | 
					  val cycle = 0xc00
 | 
				
			||||||
 | 
					  val time = 0xc01
 | 
				
			||||||
 | 
					  val instret = 0xc02
 | 
				
			||||||
 | 
					  val sstatus = 0x100
 | 
				
			||||||
 | 
					  val sie = 0x104
 | 
				
			||||||
 | 
					  val stvec = 0x105
 | 
				
			||||||
 | 
					  val sscratch = 0x140
 | 
				
			||||||
 | 
					  val sepc = 0x141
 | 
				
			||||||
 | 
					  val scause = 0x142
 | 
				
			||||||
 | 
					  val sbadaddr = 0x143
 | 
				
			||||||
 | 
					  val sip = 0x144
 | 
				
			||||||
 | 
					  val sptbr = 0x180
 | 
				
			||||||
 | 
					  val scycle = 0xd00
 | 
				
			||||||
 | 
					  val stime = 0xd01
 | 
				
			||||||
 | 
					  val sinstret = 0xd02
 | 
				
			||||||
 | 
					  val mstatus = 0x300
 | 
				
			||||||
 | 
					  val medeleg = 0x302
 | 
				
			||||||
 | 
					  val mideleg = 0x303
 | 
				
			||||||
 | 
					  val mie = 0x304
 | 
				
			||||||
 | 
					  val mtvec = 0x305
 | 
				
			||||||
 | 
					  val mscratch = 0x340
 | 
				
			||||||
 | 
					  val mepc = 0x341
 | 
				
			||||||
 | 
					  val mcause = 0x342
 | 
				
			||||||
 | 
					  val mbadaddr = 0x343
 | 
				
			||||||
 | 
					  val mip = 0x344
 | 
				
			||||||
 | 
					  val mucounteren = 0x310
 | 
				
			||||||
 | 
					  val mscounteren = 0x311
 | 
				
			||||||
 | 
					  val mucycle_delta = 0x700
 | 
				
			||||||
 | 
					  val mutime_delta = 0x701
 | 
				
			||||||
 | 
					  val muinstret_delta = 0x702
 | 
				
			||||||
 | 
					  val mscycle_delta = 0x704
 | 
				
			||||||
 | 
					  val mstime_delta = 0x705
 | 
				
			||||||
 | 
					  val msinstret_delta = 0x706
 | 
				
			||||||
 | 
					  val tdrselect = 0x7a0
 | 
				
			||||||
 | 
					  val tdrdata1 = 0x7a1
 | 
				
			||||||
 | 
					  val tdrdata2 = 0x7a2
 | 
				
			||||||
 | 
					  val tdrdata3 = 0x7a3
 | 
				
			||||||
 | 
					  val dcsr = 0x7b0
 | 
				
			||||||
 | 
					  val dpc = 0x7b1
 | 
				
			||||||
 | 
					  val dscratch = 0x7b2
 | 
				
			||||||
 | 
					  val mcycle = 0xf00
 | 
				
			||||||
 | 
					  val mtime = 0xf01
 | 
				
			||||||
 | 
					  val minstret = 0xf02
 | 
				
			||||||
 | 
					  val misa = 0xf10
 | 
				
			||||||
 | 
					  val mvendorid = 0xf11
 | 
				
			||||||
 | 
					  val marchid = 0xf12
 | 
				
			||||||
 | 
					  val mimpid = 0xf13
 | 
				
			||||||
 | 
					  val mhartid = 0xf14
 | 
				
			||||||
 | 
					  val mreset = 0x7c2
 | 
				
			||||||
 | 
					  val cycleh = 0xc80
 | 
				
			||||||
 | 
					  val timeh = 0xc81
 | 
				
			||||||
 | 
					  val instreth = 0xc82
 | 
				
			||||||
 | 
					  val mucycle_deltah = 0x780
 | 
				
			||||||
 | 
					  val mutime_deltah = 0x781
 | 
				
			||||||
 | 
					  val muinstret_deltah = 0x782
 | 
				
			||||||
 | 
					  val mscycle_deltah = 0x784
 | 
				
			||||||
 | 
					  val mstime_deltah = 0x785
 | 
				
			||||||
 | 
					  val msinstret_deltah = 0x786
 | 
				
			||||||
 | 
					  val mcycleh = 0xf80
 | 
				
			||||||
 | 
					  val mtimeh = 0xf81
 | 
				
			||||||
 | 
					  val minstreth = 0xf82
 | 
				
			||||||
 | 
					  val all = {
 | 
				
			||||||
 | 
					    val res = collection.mutable.ArrayBuffer[Int]()
 | 
				
			||||||
 | 
					    res += fflags
 | 
				
			||||||
 | 
					    res += frm
 | 
				
			||||||
 | 
					    res += fcsr
 | 
				
			||||||
 | 
					    res += cycle
 | 
				
			||||||
 | 
					    res += time
 | 
				
			||||||
 | 
					    res += instret
 | 
				
			||||||
 | 
					    res += sstatus
 | 
				
			||||||
 | 
					    res += sie
 | 
				
			||||||
 | 
					    res += stvec
 | 
				
			||||||
 | 
					    res += sscratch
 | 
				
			||||||
 | 
					    res += sepc
 | 
				
			||||||
 | 
					    res += scause
 | 
				
			||||||
 | 
					    res += sbadaddr
 | 
				
			||||||
 | 
					    res += sip
 | 
				
			||||||
 | 
					    res += sptbr
 | 
				
			||||||
 | 
					    res += scycle
 | 
				
			||||||
 | 
					    res += stime
 | 
				
			||||||
 | 
					    res += sinstret
 | 
				
			||||||
 | 
					    res += mstatus
 | 
				
			||||||
 | 
					    res += medeleg
 | 
				
			||||||
 | 
					    res += mideleg
 | 
				
			||||||
 | 
					    res += mie
 | 
				
			||||||
 | 
					    res += mtvec
 | 
				
			||||||
 | 
					    res += mscratch
 | 
				
			||||||
 | 
					    res += mepc
 | 
				
			||||||
 | 
					    res += mcause
 | 
				
			||||||
 | 
					    res += mbadaddr
 | 
				
			||||||
 | 
					    res += mip
 | 
				
			||||||
 | 
					    res += mucounteren
 | 
				
			||||||
 | 
					    res += mscounteren
 | 
				
			||||||
 | 
					    res += mucycle_delta
 | 
				
			||||||
 | 
					    res += mutime_delta
 | 
				
			||||||
 | 
					    res += muinstret_delta
 | 
				
			||||||
 | 
					    res += mscycle_delta
 | 
				
			||||||
 | 
					    res += mstime_delta
 | 
				
			||||||
 | 
					    res += msinstret_delta
 | 
				
			||||||
 | 
					    res += tdrselect
 | 
				
			||||||
 | 
					    res += tdrdata1
 | 
				
			||||||
 | 
					    res += tdrdata2
 | 
				
			||||||
 | 
					    res += tdrdata3
 | 
				
			||||||
 | 
					    res += dcsr
 | 
				
			||||||
 | 
					    res += dpc
 | 
				
			||||||
 | 
					    res += dscratch
 | 
				
			||||||
 | 
					    res += mcycle
 | 
				
			||||||
 | 
					    res += mtime
 | 
				
			||||||
 | 
					    res += minstret
 | 
				
			||||||
 | 
					    res += misa
 | 
				
			||||||
 | 
					    res += mvendorid
 | 
				
			||||||
 | 
					    res += marchid
 | 
				
			||||||
 | 
					    res += mimpid
 | 
				
			||||||
 | 
					    res += mhartid
 | 
				
			||||||
 | 
					    res += mreset
 | 
				
			||||||
 | 
					    res.toArray
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  val all32 = {
 | 
				
			||||||
 | 
					    val res = collection.mutable.ArrayBuffer(all:_*)
 | 
				
			||||||
 | 
					    res += cycleh
 | 
				
			||||||
 | 
					    res += timeh
 | 
				
			||||||
 | 
					    res += instreth
 | 
				
			||||||
 | 
					    res += mucycle_deltah
 | 
				
			||||||
 | 
					    res += mutime_deltah
 | 
				
			||||||
 | 
					    res += muinstret_deltah
 | 
				
			||||||
 | 
					    res += mscycle_deltah
 | 
				
			||||||
 | 
					    res += mstime_deltah
 | 
				
			||||||
 | 
					    res += msinstret_deltah
 | 
				
			||||||
 | 
					    res += mcycleh
 | 
				
			||||||
 | 
					    res += mtimeh
 | 
				
			||||||
 | 
					    res += minstreth
 | 
				
			||||||
 | 
					    res.toArray
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										152
									
								
								rocket/src/main/scala/multiplier.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										152
									
								
								rocket/src/main/scala/multiplier.scala
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,152 @@
 | 
				
			|||||||
 | 
					// See LICENSE for license details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package rocket
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import Chisel._
 | 
				
			||||||
 | 
					import ALU._
 | 
				
			||||||
 | 
					import Util._
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class MultiplierReq(dataBits: Int, tagBits: Int) extends Bundle {
 | 
				
			||||||
 | 
					  val fn = Bits(width = SZ_ALU_FN)
 | 
				
			||||||
 | 
					  val dw = Bits(width = SZ_DW)
 | 
				
			||||||
 | 
					  val in1 = Bits(width = dataBits)
 | 
				
			||||||
 | 
					  val in2 = Bits(width = dataBits)
 | 
				
			||||||
 | 
					  val tag = UInt(width = tagBits)
 | 
				
			||||||
 | 
					  override def cloneType = new MultiplierReq(dataBits, tagBits).asInstanceOf[this.type]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class MultiplierResp(dataBits: Int, tagBits: Int) extends Bundle {
 | 
				
			||||||
 | 
					  val data = Bits(width = dataBits)
 | 
				
			||||||
 | 
					  val tag = UInt(width = tagBits)
 | 
				
			||||||
 | 
					  override def cloneType = new MultiplierResp(dataBits, tagBits).asInstanceOf[this.type]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class MultiplierIO(dataBits: Int, tagBits: Int) extends Bundle {
 | 
				
			||||||
 | 
					  val req = Decoupled(new MultiplierReq(dataBits, tagBits)).flip
 | 
				
			||||||
 | 
					  val kill = Bool(INPUT)
 | 
				
			||||||
 | 
					  val resp = Decoupled(new MultiplierResp(dataBits, tagBits))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class MulDiv(
 | 
				
			||||||
 | 
					    width: Int,
 | 
				
			||||||
 | 
					    nXpr: Int = 32,
 | 
				
			||||||
 | 
					    unroll: Int = 1,
 | 
				
			||||||
 | 
					    earlyOut: Boolean = false) extends Module {
 | 
				
			||||||
 | 
					  val io = new MultiplierIO(width, log2Up(nXpr))
 | 
				
			||||||
 | 
					  val w = io.req.bits.in1.getWidth
 | 
				
			||||||
 | 
					  val mulw = (w+unroll-1)/unroll*unroll
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					  val s_ready :: s_neg_inputs :: s_busy :: s_move_rem :: s_neg_output :: s_done :: Nil = Enum(UInt(), 6)
 | 
				
			||||||
 | 
					  val state = Reg(init=s_ready)
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					  val req = Reg(io.req.bits)
 | 
				
			||||||
 | 
					  val count = Reg(UInt(width = log2Up(w+1)))
 | 
				
			||||||
 | 
					  val neg_out = Reg(Bool())
 | 
				
			||||||
 | 
					  val isMul = Reg(Bool())
 | 
				
			||||||
 | 
					  val isHi = Reg(Bool())
 | 
				
			||||||
 | 
					  val divisor = Reg(Bits(width = w+1)) // div only needs w bits
 | 
				
			||||||
 | 
					  val remainder = Reg(Bits(width = 2*mulw+2)) // div only needs 2*w+1 bits
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val cmdMul :: cmdHi :: lhsSigned :: rhsSigned :: Nil =
 | 
				
			||||||
 | 
					    DecodeLogic(io.req.bits.fn, List(X, X, X, X), List(
 | 
				
			||||||
 | 
					                   FN_DIV    -> List(N, N, Y, Y),
 | 
				
			||||||
 | 
					                   FN_REM    -> List(N, Y, Y, Y),
 | 
				
			||||||
 | 
					                   FN_DIVU   -> List(N, N, N, N),
 | 
				
			||||||
 | 
					                   FN_REMU   -> List(N, Y, N, N),
 | 
				
			||||||
 | 
					                   FN_MUL    -> List(Y, N, X, X),
 | 
				
			||||||
 | 
					                   FN_MULH   -> List(Y, Y, Y, Y),
 | 
				
			||||||
 | 
					                   FN_MULHU  -> List(Y, Y, N, N),
 | 
				
			||||||
 | 
					                   FN_MULHSU -> List(Y, Y, Y, N))).map(_ toBool)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  require(w == 32 || w == 64)
 | 
				
			||||||
 | 
					  def halfWidth(req: MultiplierReq) = Bool(w > 32) && req.dw === DW_32
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def sext(x: Bits, halfW: Bool, signed: Bool) = {
 | 
				
			||||||
 | 
					    val sign = signed && Mux(halfW, x(w/2-1), x(w-1))
 | 
				
			||||||
 | 
					    val hi = Mux(halfW, Fill(w/2, sign), x(w-1,w/2))
 | 
				
			||||||
 | 
					    (Cat(hi, x(w/2-1,0)), sign)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  val (lhs_in, lhs_sign) = sext(io.req.bits.in1, halfWidth(io.req.bits), lhsSigned)
 | 
				
			||||||
 | 
					  val (rhs_in, rhs_sign) = sext(io.req.bits.in2, halfWidth(io.req.bits), rhsSigned)
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  val subtractor = remainder(2*w,w) - divisor(w,0)
 | 
				
			||||||
 | 
					  val less = subtractor(w)
 | 
				
			||||||
 | 
					  val negated_remainder = -remainder(w-1,0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  when (state === s_neg_inputs) {
 | 
				
			||||||
 | 
					    when (remainder(w-1) || isMul) {
 | 
				
			||||||
 | 
					      remainder := negated_remainder
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    when (divisor(w-1) || isMul) {
 | 
				
			||||||
 | 
					      divisor := subtractor
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    state := s_busy
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  when (state === s_neg_output) {
 | 
				
			||||||
 | 
					    remainder := negated_remainder
 | 
				
			||||||
 | 
					    state := s_done
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  when (state === s_move_rem) {
 | 
				
			||||||
 | 
					    remainder := remainder(2*w, w+1)
 | 
				
			||||||
 | 
					    state := Mux(neg_out, s_neg_output, s_done)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  when (state === s_busy && isMul) {
 | 
				
			||||||
 | 
					    val mulReg = Cat(remainder(2*mulw+1,w+1),remainder(w-1,0))
 | 
				
			||||||
 | 
					    val mplier = mulReg(mulw-1,0)
 | 
				
			||||||
 | 
					    val accum = mulReg(2*mulw,mulw).toSInt
 | 
				
			||||||
 | 
					    val mpcand = divisor.toSInt
 | 
				
			||||||
 | 
					    val prod = mplier(unroll-1,0) * mpcand + accum
 | 
				
			||||||
 | 
					    val nextMulReg = Cat(prod, mplier(mulw-1,unroll)).toUInt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    val eOutMask = (SInt(BigInt(-1) << mulw) >> (count * unroll)(log2Up(mulw)-1,0))(mulw-1,0)
 | 
				
			||||||
 | 
					    val eOut = Bool(earlyOut) && count =/= mulw/unroll-1 && count =/= 0 &&
 | 
				
			||||||
 | 
					      !isHi && (mplier & ~eOutMask) === UInt(0)
 | 
				
			||||||
 | 
					    val eOutRes = (mulReg >> (mulw - count * unroll)(log2Up(mulw)-1,0))
 | 
				
			||||||
 | 
					    val nextMulReg1 = Cat(nextMulReg(2*mulw,mulw), Mux(eOut, eOutRes, nextMulReg)(mulw-1,0))
 | 
				
			||||||
 | 
					    remainder := Cat(nextMulReg1 >> w, Bool(false), nextMulReg1(w-1,0))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    count := count + 1
 | 
				
			||||||
 | 
					    when (eOut || count === mulw/unroll-1) {
 | 
				
			||||||
 | 
					      state := Mux(isHi, s_move_rem, s_done)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  when (state === s_busy && !isMul) {
 | 
				
			||||||
 | 
					    when (count === w) {
 | 
				
			||||||
 | 
					      state := Mux(isHi, s_move_rem, Mux(neg_out, s_neg_output, s_done))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    count := count + 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    remainder := Cat(Mux(less, remainder(2*w-1,w), subtractor(w-1,0)), remainder(w-1,0), !less)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    val divisorMSB = Log2(divisor(w-1,0), w)
 | 
				
			||||||
 | 
					    val dividendMSB = Log2(remainder(w-1,0), w)
 | 
				
			||||||
 | 
					    val eOutPos = UInt(w-1) + divisorMSB - dividendMSB
 | 
				
			||||||
 | 
					    val eOutZero = divisorMSB > dividendMSB
 | 
				
			||||||
 | 
					    val eOut = count === 0 && less /* not divby0 */ && (eOutPos > 0 || eOutZero)
 | 
				
			||||||
 | 
					    when (Bool(earlyOut) && eOut) {
 | 
				
			||||||
 | 
					      val shift = Mux(eOutZero, UInt(w-1), eOutPos(log2Up(w)-1,0))
 | 
				
			||||||
 | 
					      remainder := remainder(w-1,0) << shift
 | 
				
			||||||
 | 
					      count := shift
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    when (count === 0 && !less /* divby0 */ && !isHi) { neg_out := false }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  when (io.resp.fire() || io.kill) {
 | 
				
			||||||
 | 
					    state := s_ready
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  when (io.req.fire()) {
 | 
				
			||||||
 | 
					    state := Mux(lhs_sign || rhs_sign && !cmdMul, s_neg_inputs, s_busy)
 | 
				
			||||||
 | 
					    isMul := cmdMul
 | 
				
			||||||
 | 
					    isHi := cmdHi
 | 
				
			||||||
 | 
					    count := 0
 | 
				
			||||||
 | 
					    neg_out := !cmdMul && Mux(cmdHi, lhs_sign, lhs_sign =/= rhs_sign)
 | 
				
			||||||
 | 
					    divisor := Cat(rhs_sign, rhs_in)
 | 
				
			||||||
 | 
					    remainder := lhs_in
 | 
				
			||||||
 | 
					    req := io.req.bits
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  io.resp.bits := req
 | 
				
			||||||
 | 
					  io.resp.bits.data := Mux(halfWidth(req), Cat(Fill(w/2, remainder(w/2-1)), remainder(w/2-1,0)), remainder(w-1,0))
 | 
				
			||||||
 | 
					  io.resp.valid := state === s_done
 | 
				
			||||||
 | 
					  io.req.ready := state === s_ready
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										1247
									
								
								rocket/src/main/scala/nbdcache.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1247
									
								
								rocket/src/main/scala/nbdcache.scala
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										4
									
								
								rocket/src/main/scala/package.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								rocket/src/main/scala/package.scala
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,4 @@
 | 
				
			|||||||
 | 
					// See LICENSE for license details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package object rocket extends 
 | 
				
			||||||
 | 
					  rocket.constants.ScalarOpConstants
 | 
				
			||||||
							
								
								
									
										203
									
								
								rocket/src/main/scala/ptw.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										203
									
								
								rocket/src/main/scala/ptw.scala
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,203 @@
 | 
				
			|||||||
 | 
					// See LICENSE for license details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package rocket
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import Chisel._
 | 
				
			||||||
 | 
					import uncore.agents._
 | 
				
			||||||
 | 
					import uncore.constants._
 | 
				
			||||||
 | 
					import Util._
 | 
				
			||||||
 | 
					import cde.{Parameters, Field}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class PTWReq(implicit p: Parameters) extends CoreBundle()(p) {
 | 
				
			||||||
 | 
					  val prv = Bits(width = 2)
 | 
				
			||||||
 | 
					  val pum = Bool()
 | 
				
			||||||
 | 
					  val mxr = Bool()
 | 
				
			||||||
 | 
					  val addr = UInt(width = vpnBits)
 | 
				
			||||||
 | 
					  val store = Bool()
 | 
				
			||||||
 | 
					  val fetch = Bool()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class PTWResp(implicit p: Parameters) extends CoreBundle()(p) {
 | 
				
			||||||
 | 
					  val pte = new PTE
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class TLBPTWIO(implicit p: Parameters) extends CoreBundle()(p) {
 | 
				
			||||||
 | 
					  val req = Decoupled(new PTWReq)
 | 
				
			||||||
 | 
					  val resp = Valid(new PTWResp).flip
 | 
				
			||||||
 | 
					  val ptbr = new PTBR().asInput
 | 
				
			||||||
 | 
					  val invalidate = Bool(INPUT)
 | 
				
			||||||
 | 
					  val status = new MStatus().asInput
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class DatapathPTWIO(implicit p: Parameters) extends CoreBundle()(p) {
 | 
				
			||||||
 | 
					  val ptbr = new PTBR().asInput
 | 
				
			||||||
 | 
					  val invalidate = Bool(INPUT)
 | 
				
			||||||
 | 
					  val status = new MStatus().asInput
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class PTE(implicit p: Parameters) extends CoreBundle()(p) {
 | 
				
			||||||
 | 
					  val reserved_for_hardware = Bits(width = 16)
 | 
				
			||||||
 | 
					  val ppn = UInt(width = 38)
 | 
				
			||||||
 | 
					  val reserved_for_software = Bits(width = 2)
 | 
				
			||||||
 | 
					  val d = Bool()
 | 
				
			||||||
 | 
					  val a = Bool()
 | 
				
			||||||
 | 
					  val g = Bool()
 | 
				
			||||||
 | 
					  val u = Bool()
 | 
				
			||||||
 | 
					  val x = Bool()
 | 
				
			||||||
 | 
					  val w = Bool()
 | 
				
			||||||
 | 
					  val r = Bool()
 | 
				
			||||||
 | 
					  val v = Bool()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def table(dummy: Int = 0) = v && !r && !w && !x
 | 
				
			||||||
 | 
					  def leaf(dummy: Int = 0) = v && (r || (x && !w))
 | 
				
			||||||
 | 
					  def ur(dummy: Int = 0) = sr() && u
 | 
				
			||||||
 | 
					  def uw(dummy: Int = 0) = sw() && u
 | 
				
			||||||
 | 
					  def ux(dummy: Int = 0) = sx() && u
 | 
				
			||||||
 | 
					  def sr(dummy: Int = 0) = leaf() && r
 | 
				
			||||||
 | 
					  def sw(dummy: Int = 0) = leaf() && w
 | 
				
			||||||
 | 
					  def sx(dummy: Int = 0) = leaf() && x
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def access_ok(req: PTWReq) = {
 | 
				
			||||||
 | 
					    val perm_ok = Mux(req.fetch, x, Mux(req.store, w, r || (x && req.mxr)))
 | 
				
			||||||
 | 
					    val priv_ok = Mux(u, !req.pum, req.prv(0))
 | 
				
			||||||
 | 
					    leaf() && priv_ok && perm_ok
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class PTW(n: Int)(implicit p: Parameters) extends CoreModule()(p) {
 | 
				
			||||||
 | 
					  val io = new Bundle {
 | 
				
			||||||
 | 
					    val requestor = Vec(n, new TLBPTWIO).flip
 | 
				
			||||||
 | 
					    val mem = new HellaCacheIO
 | 
				
			||||||
 | 
					    val dpath = new DatapathPTWIO
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  require(usingAtomics, "PTW requires atomic memory operations")
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  val s_ready :: s_req :: s_wait :: s_set_dirty :: s_wait_dirty :: s_done :: Nil = Enum(UInt(), 6)
 | 
				
			||||||
 | 
					  val state = Reg(init=s_ready)
 | 
				
			||||||
 | 
					  val count = Reg(UInt(width = log2Up(pgLevels)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val r_req = Reg(new PTWReq)
 | 
				
			||||||
 | 
					  val r_req_dest = Reg(Bits())
 | 
				
			||||||
 | 
					  val r_pte = Reg(new PTE)
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  val vpn_idxs = (0 until pgLevels).map(i => (r_req.addr >> (pgLevels-i-1)*pgLevelBits)(pgLevelBits-1,0))
 | 
				
			||||||
 | 
					  val vpn_idx = vpn_idxs(count)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val arb = Module(new RRArbiter(new PTWReq, n))
 | 
				
			||||||
 | 
					  arb.io.in <> io.requestor.map(_.req)
 | 
				
			||||||
 | 
					  arb.io.out.ready := state === s_ready
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val pte = new PTE().fromBits(io.mem.resp.bits.data)
 | 
				
			||||||
 | 
					  val pte_addr = Cat(r_pte.ppn, vpn_idx).toUInt << log2Up(xLen/8)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  when (arb.io.out.fire()) {
 | 
				
			||||||
 | 
					    r_req := arb.io.out.bits
 | 
				
			||||||
 | 
					    r_req_dest := arb.io.chosen
 | 
				
			||||||
 | 
					    r_pte.ppn := io.dpath.ptbr.ppn
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val (pte_cache_hit, pte_cache_data) = {
 | 
				
			||||||
 | 
					    val size = 1 << log2Up(pgLevels * 2)
 | 
				
			||||||
 | 
					    val plru = new PseudoLRU(size)
 | 
				
			||||||
 | 
					    val valid = Reg(init = UInt(0, size))
 | 
				
			||||||
 | 
					    val tags = Reg(Vec(size, UInt(width = paddrBits)))
 | 
				
			||||||
 | 
					    val data = Reg(Vec(size, UInt(width = ppnBits)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    val hits = tags.map(_ === pte_addr).toBits & valid
 | 
				
			||||||
 | 
					    val hit = hits.orR
 | 
				
			||||||
 | 
					    when (io.mem.resp.valid && pte.table() && !hit) {
 | 
				
			||||||
 | 
					      val r = Mux(valid.andR, plru.replace, PriorityEncoder(~valid))
 | 
				
			||||||
 | 
					      valid := valid | UIntToOH(r)
 | 
				
			||||||
 | 
					      tags(r) := pte_addr
 | 
				
			||||||
 | 
					      data(r) := pte.ppn
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    when (hit && state === s_req) { plru.access(OHToUInt(hits)) }
 | 
				
			||||||
 | 
					    when (io.dpath.invalidate) { valid := 0 }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    (hit, Mux1H(hits, data))
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val set_dirty_bit = pte.access_ok(r_req) && (!pte.a || (r_req.store && !pte.d))
 | 
				
			||||||
 | 
					  when (io.mem.resp.valid && state === s_wait && !set_dirty_bit) {
 | 
				
			||||||
 | 
					    r_pte := pte
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val pte_wdata = Wire(init=new PTE().fromBits(0))
 | 
				
			||||||
 | 
					  pte_wdata.a := true
 | 
				
			||||||
 | 
					  pte_wdata.d := r_req.store
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  io.mem.req.valid     := state === s_req || state === s_set_dirty
 | 
				
			||||||
 | 
					  io.mem.req.bits.phys := Bool(true)
 | 
				
			||||||
 | 
					  io.mem.req.bits.cmd  := Mux(state === s_set_dirty, M_XA_OR, M_XRD)
 | 
				
			||||||
 | 
					  io.mem.req.bits.typ  := MT_D
 | 
				
			||||||
 | 
					  io.mem.req.bits.addr := pte_addr
 | 
				
			||||||
 | 
					  io.mem.s1_data := pte_wdata.toBits
 | 
				
			||||||
 | 
					  io.mem.s1_kill := Bool(false)
 | 
				
			||||||
 | 
					  io.mem.invalidate_lr := Bool(false)
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  val r_resp_ppn = io.mem.req.bits.addr >> pgIdxBits
 | 
				
			||||||
 | 
					  val resp_ppns = (0 until pgLevels-1).map(i => Cat(r_resp_ppn >> pgLevelBits*(pgLevels-i-1), r_req.addr(pgLevelBits*(pgLevels-i-1)-1,0))) :+ r_resp_ppn
 | 
				
			||||||
 | 
					  val resp_ppn = resp_ppns(count)
 | 
				
			||||||
 | 
					  val resp_val = state === s_done
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  for (i <- 0 until io.requestor.size) {
 | 
				
			||||||
 | 
					    io.requestor(i).resp.valid := resp_val && (r_req_dest === i)
 | 
				
			||||||
 | 
					    io.requestor(i).resp.bits.pte := r_pte
 | 
				
			||||||
 | 
					    io.requestor(i).resp.bits.pte.ppn := resp_ppn
 | 
				
			||||||
 | 
					    io.requestor(i).ptbr := io.dpath.ptbr
 | 
				
			||||||
 | 
					    io.requestor(i).invalidate := io.dpath.invalidate
 | 
				
			||||||
 | 
					    io.requestor(i).status := io.dpath.status
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // control state machine
 | 
				
			||||||
 | 
					  switch (state) {
 | 
				
			||||||
 | 
					    is (s_ready) {
 | 
				
			||||||
 | 
					      when (arb.io.out.valid) {
 | 
				
			||||||
 | 
					        state := s_req
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      count := UInt(0)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    is (s_req) {
 | 
				
			||||||
 | 
					      when (pte_cache_hit && count < pgLevels-1) {
 | 
				
			||||||
 | 
					        io.mem.req.valid := false
 | 
				
			||||||
 | 
					        state := s_req
 | 
				
			||||||
 | 
					        count := count + 1
 | 
				
			||||||
 | 
					        r_pte.ppn := pte_cache_data
 | 
				
			||||||
 | 
					      }.elsewhen (io.mem.req.ready) {
 | 
				
			||||||
 | 
					        state := s_wait
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    is (s_wait) {
 | 
				
			||||||
 | 
					      when (io.mem.s2_nack) {
 | 
				
			||||||
 | 
					        state := s_req
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      when (io.mem.resp.valid) {
 | 
				
			||||||
 | 
					        state := s_done
 | 
				
			||||||
 | 
					        when (set_dirty_bit) {
 | 
				
			||||||
 | 
					          state := s_set_dirty
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        when (pte.table() && count < pgLevels-1) {
 | 
				
			||||||
 | 
					          state := s_req
 | 
				
			||||||
 | 
					          count := count + 1
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    is (s_set_dirty) {
 | 
				
			||||||
 | 
					      when (io.mem.req.ready) {
 | 
				
			||||||
 | 
					        state := s_wait_dirty
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    is (s_wait_dirty) {
 | 
				
			||||||
 | 
					      when (io.mem.s2_nack) {
 | 
				
			||||||
 | 
					        state := s_set_dirty
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      when (io.mem.resp.valid) {
 | 
				
			||||||
 | 
					        state := s_req
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    is (s_done) {
 | 
				
			||||||
 | 
					      state := s_ready
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										303
									
								
								rocket/src/main/scala/rocc.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										303
									
								
								rocket/src/main/scala/rocc.scala
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,303 @@
 | 
				
			|||||||
 | 
					// See LICENSE for license details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package rocket
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import Chisel._
 | 
				
			||||||
 | 
					import uncore.tilelink._
 | 
				
			||||||
 | 
					import uncore.constants._
 | 
				
			||||||
 | 
					import uncore.agents.CacheName
 | 
				
			||||||
 | 
					import Util._
 | 
				
			||||||
 | 
					import cde.{Parameters, Field}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					case object RoccMaxTaggedMemXacts extends Field[Int]
 | 
				
			||||||
 | 
					case object RoccNMemChannels extends Field[Int]
 | 
				
			||||||
 | 
					case object RoccNPTWPorts extends Field[Int]
 | 
				
			||||||
 | 
					case object RoccNCSRs extends Field[Int]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class RoCCCSRs(implicit p: Parameters) extends CoreBundle()(p) {
 | 
				
			||||||
 | 
					  val rdata = Vec(nRoccCsrs, UInt(INPUT, xLen))
 | 
				
			||||||
 | 
					  val waddr = UInt(OUTPUT, CSR.ADDRSZ)
 | 
				
			||||||
 | 
					  val wdata = UInt(OUTPUT, xLen)
 | 
				
			||||||
 | 
					  val wen = Bool(OUTPUT)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class RoCCInstruction extends Bundle
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  val funct = Bits(width = 7)
 | 
				
			||||||
 | 
					  val rs2 = Bits(width = 5)
 | 
				
			||||||
 | 
					  val rs1 = Bits(width = 5)
 | 
				
			||||||
 | 
					  val xd = Bool()
 | 
				
			||||||
 | 
					  val xs1 = Bool()
 | 
				
			||||||
 | 
					  val xs2 = Bool()
 | 
				
			||||||
 | 
					  val rd = Bits(width = 5)
 | 
				
			||||||
 | 
					  val opcode = Bits(width = 7)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class RoCCCommand(implicit p: Parameters) extends CoreBundle()(p) {
 | 
				
			||||||
 | 
					  val inst = new RoCCInstruction
 | 
				
			||||||
 | 
					  val rs1 = Bits(width = xLen)
 | 
				
			||||||
 | 
					  val rs2 = Bits(width = xLen)
 | 
				
			||||||
 | 
					  val status = new MStatus
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class RoCCResponse(implicit p: Parameters) extends CoreBundle()(p) {
 | 
				
			||||||
 | 
					  val rd = Bits(width = 5)
 | 
				
			||||||
 | 
					  val data = Bits(width = xLen)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class RoCCInterface(implicit p: Parameters) extends CoreBundle()(p) {
 | 
				
			||||||
 | 
					  val cmd = Decoupled(new RoCCCommand).flip
 | 
				
			||||||
 | 
					  val resp = Decoupled(new RoCCResponse)
 | 
				
			||||||
 | 
					  val mem = new HellaCacheIO()(p.alterPartial({ case CacheName => "L1D" }))
 | 
				
			||||||
 | 
					  val busy = Bool(OUTPUT)
 | 
				
			||||||
 | 
					  val interrupt = Bool(OUTPUT)
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  // These should be handled differently, eventually
 | 
				
			||||||
 | 
					  val autl = new ClientUncachedTileLinkIO
 | 
				
			||||||
 | 
					  val utl = Vec(p(RoccNMemChannels), new ClientUncachedTileLinkIO)
 | 
				
			||||||
 | 
					  val ptw = Vec(p(RoccNPTWPorts), new TLBPTWIO)
 | 
				
			||||||
 | 
					  val fpu_req = Decoupled(new FPInput)
 | 
				
			||||||
 | 
					  val fpu_resp = Decoupled(new FPResult).flip
 | 
				
			||||||
 | 
					  val exception = Bool(INPUT)
 | 
				
			||||||
 | 
					  val csr = (new RoCCCSRs).flip
 | 
				
			||||||
 | 
					  val host_id = UInt(INPUT, log2Up(nCores))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override def cloneType = new RoCCInterface().asInstanceOf[this.type]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					abstract class RoCC(implicit p: Parameters) extends CoreModule()(p) {
 | 
				
			||||||
 | 
					  val io = new RoCCInterface
 | 
				
			||||||
 | 
					  io.mem.req.bits.phys := Bool(true) // don't perform address translation
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class AccumulatorExample(n: Int = 4)(implicit p: Parameters) extends RoCC()(p) {
 | 
				
			||||||
 | 
					  val regfile = Mem(n, UInt(width = xLen))
 | 
				
			||||||
 | 
					  val busy = Reg(init = Vec.fill(n){Bool(false)})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val cmd = Queue(io.cmd)
 | 
				
			||||||
 | 
					  val funct = cmd.bits.inst.funct
 | 
				
			||||||
 | 
					  val addr = cmd.bits.rs2(log2Up(n)-1,0)
 | 
				
			||||||
 | 
					  val doWrite = funct === UInt(0)
 | 
				
			||||||
 | 
					  val doRead = funct === UInt(1)
 | 
				
			||||||
 | 
					  val doLoad = funct === UInt(2)
 | 
				
			||||||
 | 
					  val doAccum = funct === UInt(3)
 | 
				
			||||||
 | 
					  val memRespTag = io.mem.resp.bits.tag(log2Up(n)-1,0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // datapath
 | 
				
			||||||
 | 
					  val addend = cmd.bits.rs1
 | 
				
			||||||
 | 
					  val accum = regfile(addr)
 | 
				
			||||||
 | 
					  val wdata = Mux(doWrite, addend, accum + addend)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  when (cmd.fire() && (doWrite || doAccum)) {
 | 
				
			||||||
 | 
					    regfile(addr) := wdata
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  when (io.mem.resp.valid) {
 | 
				
			||||||
 | 
					    regfile(memRespTag) := io.mem.resp.bits.data
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // control
 | 
				
			||||||
 | 
					  when (io.mem.req.fire()) {
 | 
				
			||||||
 | 
					    busy(addr) := Bool(true)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  when (io.mem.resp.valid) {
 | 
				
			||||||
 | 
					    busy(memRespTag) := Bool(false)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val doResp = cmd.bits.inst.xd
 | 
				
			||||||
 | 
					  val stallReg = busy(addr)
 | 
				
			||||||
 | 
					  val stallLoad = doLoad && !io.mem.req.ready
 | 
				
			||||||
 | 
					  val stallResp = doResp && !io.resp.ready
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  cmd.ready := !stallReg && !stallLoad && !stallResp
 | 
				
			||||||
 | 
					    // command resolved if no stalls AND not issuing a load that will need a request
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // PROC RESPONSE INTERFACE
 | 
				
			||||||
 | 
					  io.resp.valid := cmd.valid && doResp && !stallReg && !stallLoad
 | 
				
			||||||
 | 
					    // valid response if valid command, need a response, and no stalls
 | 
				
			||||||
 | 
					  io.resp.bits.rd := cmd.bits.inst.rd
 | 
				
			||||||
 | 
					    // Must respond with the appropriate tag or undefined behavior
 | 
				
			||||||
 | 
					  io.resp.bits.data := accum
 | 
				
			||||||
 | 
					    // Semantics is to always send out prior accumulator register value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  io.busy := cmd.valid || busy.reduce(_||_)
 | 
				
			||||||
 | 
					    // Be busy when have pending memory requests or committed possibility of pending requests
 | 
				
			||||||
 | 
					  io.interrupt := Bool(false)
 | 
				
			||||||
 | 
					    // Set this true to trigger an interrupt on the processor (please refer to supervisor documentation)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // MEMORY REQUEST INTERFACE
 | 
				
			||||||
 | 
					  io.mem.req.valid := cmd.valid && doLoad && !stallReg && !stallResp
 | 
				
			||||||
 | 
					  io.mem.req.bits.addr := addend
 | 
				
			||||||
 | 
					  io.mem.req.bits.tag := addr
 | 
				
			||||||
 | 
					  io.mem.req.bits.cmd := M_XRD // perform a load (M_XWR for stores)
 | 
				
			||||||
 | 
					  io.mem.req.bits.typ := MT_D // D = 8 bytes, W = 4, H = 2, B = 1
 | 
				
			||||||
 | 
					  io.mem.req.bits.data := Bits(0) // we're not performing any stores...
 | 
				
			||||||
 | 
					  io.mem.invalidate_lr := false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  io.autl.acquire.valid := false
 | 
				
			||||||
 | 
					  io.autl.grant.ready := false
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class TranslatorExample(implicit p: Parameters) extends RoCC()(p) {
 | 
				
			||||||
 | 
					  val req_addr = Reg(UInt(width = coreMaxAddrBits))
 | 
				
			||||||
 | 
					  val req_rd = Reg(io.resp.bits.rd)
 | 
				
			||||||
 | 
					  val req_offset = req_addr(pgIdxBits - 1, 0)
 | 
				
			||||||
 | 
					  val req_vpn = req_addr(coreMaxAddrBits - 1, pgIdxBits)
 | 
				
			||||||
 | 
					  val pte = Reg(new PTE)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val s_idle :: s_ptw_req :: s_ptw_resp :: s_resp :: Nil = Enum(Bits(), 4)
 | 
				
			||||||
 | 
					  val state = Reg(init = s_idle)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  io.cmd.ready := (state === s_idle)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  when (io.cmd.fire()) {
 | 
				
			||||||
 | 
					    req_rd := io.cmd.bits.inst.rd
 | 
				
			||||||
 | 
					    req_addr := io.cmd.bits.rs1
 | 
				
			||||||
 | 
					    state := s_ptw_req
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private val ptw = io.ptw(0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  when (ptw.req.fire()) { state := s_ptw_resp }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  when (state === s_ptw_resp && ptw.resp.valid) {
 | 
				
			||||||
 | 
					    pte := ptw.resp.bits.pte
 | 
				
			||||||
 | 
					    state := s_resp
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  when (io.resp.fire()) { state := s_idle }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ptw.req.valid := (state === s_ptw_req)
 | 
				
			||||||
 | 
					  ptw.req.bits.addr := req_vpn
 | 
				
			||||||
 | 
					  ptw.req.bits.store := Bool(false)
 | 
				
			||||||
 | 
					  ptw.req.bits.fetch := Bool(false)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  io.resp.valid := (state === s_resp)
 | 
				
			||||||
 | 
					  io.resp.bits.rd := req_rd
 | 
				
			||||||
 | 
					  io.resp.bits.data := Mux(pte.leaf(), Cat(pte.ppn, req_offset), ~UInt(0, xLen))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  io.busy := (state =/= s_idle)
 | 
				
			||||||
 | 
					  io.interrupt := Bool(false)
 | 
				
			||||||
 | 
					  io.mem.req.valid := Bool(false)
 | 
				
			||||||
 | 
					  io.mem.invalidate_lr := Bool(false)
 | 
				
			||||||
 | 
					  io.autl.acquire.valid := Bool(false)
 | 
				
			||||||
 | 
					  io.autl.grant.ready := Bool(false)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class CharacterCountExample(implicit p: Parameters) extends RoCC()(p)
 | 
				
			||||||
 | 
					    with HasTileLinkParameters {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private val blockOffset = tlBeatAddrBits + tlByteAddrBits
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val needle = Reg(UInt(width = 8))
 | 
				
			||||||
 | 
					  val addr = Reg(UInt(width = coreMaxAddrBits))
 | 
				
			||||||
 | 
					  val count = Reg(UInt(width = xLen))
 | 
				
			||||||
 | 
					  val resp_rd = Reg(io.resp.bits.rd)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val addr_block = addr(coreMaxAddrBits - 1, blockOffset)
 | 
				
			||||||
 | 
					  val offset = addr(blockOffset - 1, 0)
 | 
				
			||||||
 | 
					  val next_addr = (addr_block + UInt(1)) << UInt(blockOffset)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val s_idle :: s_acq :: s_gnt :: s_check :: s_resp :: Nil = Enum(Bits(), 5)
 | 
				
			||||||
 | 
					  val state = Reg(init = s_idle)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val gnt = io.autl.grant.bits
 | 
				
			||||||
 | 
					  val recv_data = Reg(UInt(width = tlDataBits))
 | 
				
			||||||
 | 
					  val recv_beat = Reg(UInt(width = tlBeatAddrBits))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val data_bytes = Vec.tabulate(tlDataBytes) { i => recv_data(8 * (i + 1) - 1, 8 * i) }
 | 
				
			||||||
 | 
					  val zero_match = data_bytes.map(_ === UInt(0))
 | 
				
			||||||
 | 
					  val needle_match = data_bytes.map(_ === needle)
 | 
				
			||||||
 | 
					  val first_zero = PriorityEncoder(zero_match)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val chars_found = PopCount(needle_match.zipWithIndex.map {
 | 
				
			||||||
 | 
					    case (matches, i) =>
 | 
				
			||||||
 | 
					      val idx = Cat(recv_beat, UInt(i, tlByteAddrBits))
 | 
				
			||||||
 | 
					      matches && idx >= offset && UInt(i) <= first_zero
 | 
				
			||||||
 | 
					  })
 | 
				
			||||||
 | 
					  val zero_found = zero_match.reduce(_ || _)
 | 
				
			||||||
 | 
					  val finished = Reg(Bool())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  io.cmd.ready := (state === s_idle)
 | 
				
			||||||
 | 
					  io.resp.valid := (state === s_resp)
 | 
				
			||||||
 | 
					  io.resp.bits.rd := resp_rd
 | 
				
			||||||
 | 
					  io.resp.bits.data := count
 | 
				
			||||||
 | 
					  io.autl.acquire.valid := (state === s_acq)
 | 
				
			||||||
 | 
					  io.autl.acquire.bits := GetBlock(addr_block = addr_block)
 | 
				
			||||||
 | 
					  io.autl.grant.ready := (state === s_gnt)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  when (io.cmd.fire()) {
 | 
				
			||||||
 | 
					    addr := io.cmd.bits.rs1
 | 
				
			||||||
 | 
					    needle := io.cmd.bits.rs2
 | 
				
			||||||
 | 
					    resp_rd := io.cmd.bits.inst.rd
 | 
				
			||||||
 | 
					    count := UInt(0)
 | 
				
			||||||
 | 
					    finished := Bool(false)
 | 
				
			||||||
 | 
					    state := s_acq
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  when (io.autl.acquire.fire()) { state := s_gnt }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  when (io.autl.grant.fire()) {
 | 
				
			||||||
 | 
					    recv_beat := gnt.addr_beat
 | 
				
			||||||
 | 
					    recv_data := gnt.data
 | 
				
			||||||
 | 
					    state := s_check
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  when (state === s_check) {
 | 
				
			||||||
 | 
					    when (!finished) {
 | 
				
			||||||
 | 
					      count := count + chars_found
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    when (zero_found) { finished := Bool(true) }
 | 
				
			||||||
 | 
					    when (recv_beat === UInt(tlDataBeats - 1)) {
 | 
				
			||||||
 | 
					      addr := next_addr
 | 
				
			||||||
 | 
					      state := Mux(zero_found || finished, s_resp, s_acq)
 | 
				
			||||||
 | 
					    } .otherwise {
 | 
				
			||||||
 | 
					      state := s_gnt
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  when (io.resp.fire()) { state := s_idle }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  io.busy := (state =/= s_idle)
 | 
				
			||||||
 | 
					  io.interrupt := Bool(false)
 | 
				
			||||||
 | 
					  io.mem.req.valid := Bool(false)
 | 
				
			||||||
 | 
					  io.mem.invalidate_lr := Bool(false)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class OpcodeSet(val opcodes: Seq[UInt]) {
 | 
				
			||||||
 | 
					  def |(set: OpcodeSet) =
 | 
				
			||||||
 | 
					    new OpcodeSet(this.opcodes ++ set.opcodes)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def matches(oc: UInt) = opcodes.map(_ === oc).reduce(_ || _)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					object OpcodeSet {
 | 
				
			||||||
 | 
					  val custom0 = new OpcodeSet(Seq(Bits("b0001011")))
 | 
				
			||||||
 | 
					  val custom1 = new OpcodeSet(Seq(Bits("b0101011")))
 | 
				
			||||||
 | 
					  val custom2 = new OpcodeSet(Seq(Bits("b1011011")))
 | 
				
			||||||
 | 
					  val custom3 = new OpcodeSet(Seq(Bits("b1111011")))
 | 
				
			||||||
 | 
					  val all = custom0 | custom1 | custom2 | custom3
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class RoccCommandRouter(opcodes: Seq[OpcodeSet])(implicit p: Parameters)
 | 
				
			||||||
 | 
					    extends CoreModule()(p) {
 | 
				
			||||||
 | 
					  val io = new Bundle {
 | 
				
			||||||
 | 
					    val in = Decoupled(new RoCCCommand).flip
 | 
				
			||||||
 | 
					    val out = Vec(opcodes.size, Decoupled(new RoCCCommand))
 | 
				
			||||||
 | 
					    val busy = Bool(OUTPUT)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val cmd = Queue(io.in)
 | 
				
			||||||
 | 
					  val cmdReadys = io.out.zip(opcodes).map { case (out, opcode) =>
 | 
				
			||||||
 | 
					    val me = opcode.matches(cmd.bits.inst.opcode)
 | 
				
			||||||
 | 
					    out.valid := cmd.valid && me
 | 
				
			||||||
 | 
					    out.bits := cmd.bits
 | 
				
			||||||
 | 
					    out.ready && me
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  cmd.ready := cmdReadys.reduce(_ || _)
 | 
				
			||||||
 | 
					  io.busy := cmd.valid
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  assert(PopCount(cmdReadys) <= UInt(1),
 | 
				
			||||||
 | 
					    "Custom opcode matched for more than one accelerator")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										679
									
								
								rocket/src/main/scala/rocket.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										679
									
								
								rocket/src/main/scala/rocket.scala
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,679 @@
 | 
				
			|||||||
 | 
					// See LICENSE for license details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package rocket
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import Chisel._
 | 
				
			||||||
 | 
					import junctions._
 | 
				
			||||||
 | 
					import uncore.devices._
 | 
				
			||||||
 | 
					import uncore.agents.CacheName
 | 
				
			||||||
 | 
					import uncore.constants._
 | 
				
			||||||
 | 
					import Util._
 | 
				
			||||||
 | 
					import cde.{Parameters, Field}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					case object UseFPU extends Field[Boolean]
 | 
				
			||||||
 | 
					case object FDivSqrt extends Field[Boolean]
 | 
				
			||||||
 | 
					case object XLen extends Field[Int]
 | 
				
			||||||
 | 
					case object FetchWidth extends Field[Int]
 | 
				
			||||||
 | 
					case object RetireWidth extends Field[Int]
 | 
				
			||||||
 | 
					case object UseVM extends Field[Boolean]
 | 
				
			||||||
 | 
					case object UseUser extends Field[Boolean]
 | 
				
			||||||
 | 
					case object UseDebug extends Field[Boolean]
 | 
				
			||||||
 | 
					case object UseAtomics extends Field[Boolean]
 | 
				
			||||||
 | 
					case object UsePerfCounters extends Field[Boolean]
 | 
				
			||||||
 | 
					case object FastLoadWord extends Field[Boolean]
 | 
				
			||||||
 | 
					case object FastLoadByte extends Field[Boolean]
 | 
				
			||||||
 | 
					case object MulUnroll extends Field[Int]
 | 
				
			||||||
 | 
					case object DivEarlyOut extends Field[Boolean]
 | 
				
			||||||
 | 
					case object CoreInstBits extends Field[Int]
 | 
				
			||||||
 | 
					case object CoreDataBits extends Field[Int]
 | 
				
			||||||
 | 
					case object CoreDCacheReqTagBits extends Field[Int]
 | 
				
			||||||
 | 
					case object NCustomMRWCSRs extends Field[Int]
 | 
				
			||||||
 | 
					case object MtvecWritable extends Field[Boolean]
 | 
				
			||||||
 | 
					case object MtvecInit extends Field[BigInt]
 | 
				
			||||||
 | 
					case object ResetVector extends Field[BigInt]
 | 
				
			||||||
 | 
					case object NBreakpoints extends Field[Int]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					trait HasCoreParameters extends HasAddrMapParameters {
 | 
				
			||||||
 | 
					  implicit val p: Parameters
 | 
				
			||||||
 | 
					  val xLen = p(XLen)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val usingVM = p(UseVM)
 | 
				
			||||||
 | 
					  val usingUser = p(UseUser)
 | 
				
			||||||
 | 
					  val usingDebug = p(UseDebug)
 | 
				
			||||||
 | 
					  val usingFPU = p(UseFPU)
 | 
				
			||||||
 | 
					  val usingAtomics = p(UseAtomics)
 | 
				
			||||||
 | 
					  val usingFDivSqrt = p(FDivSqrt)
 | 
				
			||||||
 | 
					  val usingRoCC = !p(BuildRoCC).isEmpty
 | 
				
			||||||
 | 
					  val mulUnroll = p(MulUnroll)
 | 
				
			||||||
 | 
					  val divEarlyOut = p(DivEarlyOut)
 | 
				
			||||||
 | 
					  val fastLoadWord = p(FastLoadWord)
 | 
				
			||||||
 | 
					  val fastLoadByte = p(FastLoadByte)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val retireWidth = p(RetireWidth)
 | 
				
			||||||
 | 
					  val fetchWidth = p(FetchWidth)
 | 
				
			||||||
 | 
					  val coreInstBits = p(CoreInstBits)
 | 
				
			||||||
 | 
					  val coreInstBytes = coreInstBits/8
 | 
				
			||||||
 | 
					  val coreDataBits = xLen
 | 
				
			||||||
 | 
					  val coreDataBytes = coreDataBits/8
 | 
				
			||||||
 | 
					  val coreDCacheReqTagBits = 7 + (2 + (if(!usingRoCC) 0 else 1))
 | 
				
			||||||
 | 
					  val vpnBitsExtended = vpnBits + (vaddrBits < xLen).toInt
 | 
				
			||||||
 | 
					  val vaddrBitsExtended = vpnBitsExtended + pgIdxBits
 | 
				
			||||||
 | 
					  val coreMaxAddrBits = paddrBits max vaddrBitsExtended
 | 
				
			||||||
 | 
					  val nCustomMrwCsrs = p(NCustomMRWCSRs)
 | 
				
			||||||
 | 
					  val roccCsrs = if (p(BuildRoCC).isEmpty) Nil
 | 
				
			||||||
 | 
					    else p(BuildRoCC).flatMap(_.csrs)
 | 
				
			||||||
 | 
					  val nRoccCsrs = p(RoccNCSRs)
 | 
				
			||||||
 | 
					  val nCores = p(NTiles)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Print out log of committed instructions and their writeback values.
 | 
				
			||||||
 | 
					  // Requires post-processing due to out-of-order writebacks.
 | 
				
			||||||
 | 
					  val enableCommitLog = false
 | 
				
			||||||
 | 
					  val usingPerfCounters = p(UsePerfCounters)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val maxPAddrBits = xLen match {
 | 
				
			||||||
 | 
					    case 32 => 34
 | 
				
			||||||
 | 
					    case 64 => 50
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  require(paddrBits < maxPAddrBits)
 | 
				
			||||||
 | 
					  require(!fastLoadByte || fastLoadWord)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					abstract class CoreModule(implicit val p: Parameters) extends Module
 | 
				
			||||||
 | 
					  with HasCoreParameters
 | 
				
			||||||
 | 
					abstract class CoreBundle(implicit val p: Parameters) extends ParameterizedBundle()(p)
 | 
				
			||||||
 | 
					  with HasCoreParameters
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class RegFile(n: Int, w: Int, zero: Boolean = false) {
 | 
				
			||||||
 | 
					  private val rf = Mem(n, UInt(width = w))
 | 
				
			||||||
 | 
					  private def access(addr: UInt) = rf(~addr(log2Up(n)-1,0))
 | 
				
			||||||
 | 
					  private val reads = collection.mutable.ArrayBuffer[(UInt,UInt)]()
 | 
				
			||||||
 | 
					  private var canRead = true
 | 
				
			||||||
 | 
					  def read(addr: UInt) = {
 | 
				
			||||||
 | 
					    require(canRead)
 | 
				
			||||||
 | 
					    reads += addr -> Wire(UInt())
 | 
				
			||||||
 | 
					    reads.last._2 := Mux(Bool(zero) && addr === UInt(0), UInt(0), access(addr))
 | 
				
			||||||
 | 
					    reads.last._2
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  def write(addr: UInt, data: UInt) = {
 | 
				
			||||||
 | 
					    canRead = false
 | 
				
			||||||
 | 
					    when (addr =/= UInt(0)) {
 | 
				
			||||||
 | 
					      access(addr) := data
 | 
				
			||||||
 | 
					      for ((raddr, rdata) <- reads)
 | 
				
			||||||
 | 
					        when (addr === raddr) { rdata := data }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					object ImmGen {
 | 
				
			||||||
 | 
					  def apply(sel: UInt, inst: UInt) = {
 | 
				
			||||||
 | 
					    val sign = Mux(sel === IMM_Z, SInt(0), inst(31).toSInt)
 | 
				
			||||||
 | 
					    val b30_20 = Mux(sel === IMM_U, inst(30,20).toSInt, sign)
 | 
				
			||||||
 | 
					    val b19_12 = Mux(sel =/= IMM_U && sel =/= IMM_UJ, sign, inst(19,12).toSInt)
 | 
				
			||||||
 | 
					    val b11 = Mux(sel === IMM_U || sel === IMM_Z, SInt(0),
 | 
				
			||||||
 | 
					              Mux(sel === IMM_UJ, inst(20).toSInt,
 | 
				
			||||||
 | 
					              Mux(sel === IMM_SB, inst(7).toSInt, sign)))
 | 
				
			||||||
 | 
					    val b10_5 = Mux(sel === IMM_U || sel === IMM_Z, Bits(0), inst(30,25))
 | 
				
			||||||
 | 
					    val b4_1 = Mux(sel === IMM_U, Bits(0),
 | 
				
			||||||
 | 
					               Mux(sel === IMM_S || sel === IMM_SB, inst(11,8),
 | 
				
			||||||
 | 
					               Mux(sel === IMM_Z, inst(19,16), inst(24,21))))
 | 
				
			||||||
 | 
					    val b0 = Mux(sel === IMM_S, inst(7),
 | 
				
			||||||
 | 
					             Mux(sel === IMM_I, inst(20),
 | 
				
			||||||
 | 
					             Mux(sel === IMM_Z, inst(15), Bits(0))))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Cat(sign, b30_20, b19_12, b11, b10_5, b4_1, b0).toSInt
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Rocket(implicit p: Parameters) extends CoreModule()(p) {
 | 
				
			||||||
 | 
					  val io = new Bundle {
 | 
				
			||||||
 | 
					    val prci = new PRCITileIO().flip
 | 
				
			||||||
 | 
					    val imem  = new FrontendIO()(p.alterPartial({case CacheName => "L1I" }))
 | 
				
			||||||
 | 
					    val dmem = new HellaCacheIO()(p.alterPartial({ case CacheName => "L1D" }))
 | 
				
			||||||
 | 
					    val ptw = new DatapathPTWIO().flip
 | 
				
			||||||
 | 
					    val fpu = new FPUIO().flip
 | 
				
			||||||
 | 
					    val rocc = new RoCCInterface().flip
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val decode_table = {
 | 
				
			||||||
 | 
					    (if (true) new MDecode +: (if (xLen > 32) Seq(new M64Decode) else Nil) else Nil) ++:
 | 
				
			||||||
 | 
					    (if (usingAtomics) new ADecode +: (if (xLen > 32) Seq(new A64Decode) else Nil) else Nil) ++:
 | 
				
			||||||
 | 
					    (if (usingFPU) new FDecode +: (if (xLen > 32) Seq(new F64Decode) else Nil) else Nil) ++:
 | 
				
			||||||
 | 
					    (if (usingFPU && usingFDivSqrt) Some(new FDivSqrtDecode) else None) ++:
 | 
				
			||||||
 | 
					    (if (usingRoCC) Some(new RoCCDecode) else None) ++:
 | 
				
			||||||
 | 
					    (if (xLen > 32) Some(new I64Decode) else None) ++:
 | 
				
			||||||
 | 
					    (if (usingVM) Some(new SDecode) else None) ++:
 | 
				
			||||||
 | 
					    (if (usingDebug) Some(new DebugDecode) else None) ++:
 | 
				
			||||||
 | 
					    Seq(new IDecode)
 | 
				
			||||||
 | 
					  } flatMap(_.table)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val ex_ctrl = Reg(new IntCtrlSigs)
 | 
				
			||||||
 | 
					  val mem_ctrl = Reg(new IntCtrlSigs)
 | 
				
			||||||
 | 
					  val wb_ctrl = Reg(new IntCtrlSigs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val ex_reg_xcpt_interrupt  = Reg(Bool())
 | 
				
			||||||
 | 
					  val ex_reg_valid           = Reg(Bool())
 | 
				
			||||||
 | 
					  val ex_reg_btb_hit         = Reg(Bool())
 | 
				
			||||||
 | 
					  val ex_reg_btb_resp        = Reg(io.imem.btb_resp.bits)
 | 
				
			||||||
 | 
					  val ex_reg_xcpt            = Reg(Bool())
 | 
				
			||||||
 | 
					  val ex_reg_flush_pipe      = Reg(Bool())
 | 
				
			||||||
 | 
					  val ex_reg_load_use        = Reg(Bool())
 | 
				
			||||||
 | 
					  val ex_reg_cause           = Reg(UInt())
 | 
				
			||||||
 | 
					  val ex_reg_replay = Reg(Bool())
 | 
				
			||||||
 | 
					  val ex_reg_pc = Reg(UInt())
 | 
				
			||||||
 | 
					  val ex_reg_inst = Reg(Bits())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val mem_reg_xcpt_interrupt  = Reg(Bool())
 | 
				
			||||||
 | 
					  val mem_reg_valid           = Reg(Bool())
 | 
				
			||||||
 | 
					  val mem_reg_btb_hit         = Reg(Bool())
 | 
				
			||||||
 | 
					  val mem_reg_btb_resp        = Reg(io.imem.btb_resp.bits)
 | 
				
			||||||
 | 
					  val mem_reg_xcpt            = Reg(Bool())
 | 
				
			||||||
 | 
					  val mem_reg_replay          = Reg(Bool())
 | 
				
			||||||
 | 
					  val mem_reg_flush_pipe      = Reg(Bool())
 | 
				
			||||||
 | 
					  val mem_reg_cause           = Reg(UInt())
 | 
				
			||||||
 | 
					  val mem_reg_slow_bypass     = Reg(Bool())
 | 
				
			||||||
 | 
					  val mem_reg_load            = Reg(Bool())
 | 
				
			||||||
 | 
					  val mem_reg_store           = Reg(Bool())
 | 
				
			||||||
 | 
					  val mem_reg_pc = Reg(UInt())
 | 
				
			||||||
 | 
					  val mem_reg_inst = Reg(Bits())
 | 
				
			||||||
 | 
					  val mem_reg_wdata = Reg(Bits())
 | 
				
			||||||
 | 
					  val mem_reg_rs2 = Reg(Bits())
 | 
				
			||||||
 | 
					  val take_pc_mem = Wire(Bool())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val wb_reg_valid           = Reg(Bool())
 | 
				
			||||||
 | 
					  val wb_reg_xcpt            = Reg(Bool())
 | 
				
			||||||
 | 
					  val wb_reg_mem_xcpt        = Reg(Bool())
 | 
				
			||||||
 | 
					  val wb_reg_replay          = Reg(Bool())
 | 
				
			||||||
 | 
					  val wb_reg_cause           = Reg(UInt())
 | 
				
			||||||
 | 
					  val wb_reg_pc = Reg(UInt())
 | 
				
			||||||
 | 
					  val wb_reg_inst = Reg(Bits())
 | 
				
			||||||
 | 
					  val wb_reg_wdata = Reg(Bits())
 | 
				
			||||||
 | 
					  val wb_reg_rs2 = Reg(Bits())
 | 
				
			||||||
 | 
					  val take_pc_wb = Wire(Bool())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val take_pc_mem_wb = take_pc_wb || take_pc_mem
 | 
				
			||||||
 | 
					  val take_pc = take_pc_mem_wb
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // decode stage
 | 
				
			||||||
 | 
					  val id_pc = io.imem.resp.bits.pc
 | 
				
			||||||
 | 
					  val id_inst = io.imem.resp.bits.data(0).toBits; require(fetchWidth == 1)
 | 
				
			||||||
 | 
					  val id_ctrl = Wire(new IntCtrlSigs()).decode(id_inst, decode_table)
 | 
				
			||||||
 | 
					  val id_raddr3 = id_inst(31,27)
 | 
				
			||||||
 | 
					  val id_raddr2 = id_inst(24,20)
 | 
				
			||||||
 | 
					  val id_raddr1 = id_inst(19,15)
 | 
				
			||||||
 | 
					  val id_waddr  = id_inst(11,7)
 | 
				
			||||||
 | 
					  val id_load_use = Wire(Bool())
 | 
				
			||||||
 | 
					  val id_reg_fence = Reg(init=Bool(false))
 | 
				
			||||||
 | 
					  val id_ren = IndexedSeq(id_ctrl.rxs1, id_ctrl.rxs2)
 | 
				
			||||||
 | 
					  val id_raddr = IndexedSeq(id_raddr1, id_raddr2)
 | 
				
			||||||
 | 
					  val rf = new RegFile(31, xLen)
 | 
				
			||||||
 | 
					  val id_rs = id_raddr.map(rf.read _)
 | 
				
			||||||
 | 
					  val ctrl_killd = Wire(Bool())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val csr = Module(new CSRFile)
 | 
				
			||||||
 | 
					  val id_csr_en = id_ctrl.csr =/= CSR.N
 | 
				
			||||||
 | 
					  val id_system_insn = id_ctrl.csr === CSR.I
 | 
				
			||||||
 | 
					  val id_csr_ren = (id_ctrl.csr === CSR.S || id_ctrl.csr === CSR.C) && id_raddr1 === UInt(0)
 | 
				
			||||||
 | 
					  val id_csr = Mux(id_csr_ren, CSR.R, id_ctrl.csr)
 | 
				
			||||||
 | 
					  val id_csr_addr = id_inst(31,20)
 | 
				
			||||||
 | 
					  // this is overly conservative
 | 
				
			||||||
 | 
					  val safe_csrs = CSRs.sscratch :: CSRs.sepc :: CSRs.mscratch :: CSRs.mepc :: CSRs.mcause :: CSRs.mbadaddr :: Nil
 | 
				
			||||||
 | 
					  val legal_csrs = collection.mutable.LinkedHashSet(CSRs.all:_*)
 | 
				
			||||||
 | 
					  val id_csr_flush = id_system_insn || (id_csr_en && !id_csr_ren && !DecodeLogic(id_csr_addr, safe_csrs.map(UInt(_)), (legal_csrs -- safe_csrs).toList.map(UInt(_))))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val id_illegal_insn = !id_ctrl.legal ||
 | 
				
			||||||
 | 
					    id_ctrl.fp && !csr.io.status.fs.orR ||
 | 
				
			||||||
 | 
					    id_ctrl.rocc && !csr.io.status.xs.orR
 | 
				
			||||||
 | 
					  // stall decode for fences (now, for AMO.aq; later, for AMO.rl and FENCE)
 | 
				
			||||||
 | 
					  val id_amo_aq = id_inst(26)
 | 
				
			||||||
 | 
					  val id_amo_rl = id_inst(25)
 | 
				
			||||||
 | 
					  val id_fence_next = id_ctrl.fence || id_ctrl.amo && id_amo_rl
 | 
				
			||||||
 | 
					  val id_mem_busy = !io.dmem.ordered || io.dmem.req.valid
 | 
				
			||||||
 | 
					  val id_rocc_busy = Bool(usingRoCC) &&
 | 
				
			||||||
 | 
					    (io.rocc.busy || ex_reg_valid && ex_ctrl.rocc ||
 | 
				
			||||||
 | 
					     mem_reg_valid && mem_ctrl.rocc || wb_reg_valid && wb_ctrl.rocc)
 | 
				
			||||||
 | 
					  id_reg_fence := id_fence_next || id_reg_fence && id_mem_busy
 | 
				
			||||||
 | 
					  val id_do_fence = id_rocc_busy && id_ctrl.fence ||
 | 
				
			||||||
 | 
					    id_mem_busy && (id_ctrl.amo && id_amo_aq || id_ctrl.fence_i || id_reg_fence && (id_ctrl.mem || id_ctrl.rocc) || id_csr_en)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val bpu = Module(new BreakpointUnit)
 | 
				
			||||||
 | 
					  bpu.io.status := csr.io.status
 | 
				
			||||||
 | 
					  bpu.io.bp := csr.io.bp
 | 
				
			||||||
 | 
					  bpu.io.pc := id_pc
 | 
				
			||||||
 | 
					  bpu.io.ea := mem_reg_wdata
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val (id_xcpt, id_cause) = checkExceptions(List(
 | 
				
			||||||
 | 
					    (csr.io.interrupt,          csr.io.interrupt_cause),
 | 
				
			||||||
 | 
					    (bpu.io.xcpt_if,            UInt(Causes.breakpoint)),
 | 
				
			||||||
 | 
					    (io.imem.resp.bits.xcpt_if, UInt(Causes.fault_fetch)),
 | 
				
			||||||
 | 
					    (id_illegal_insn,           UInt(Causes.illegal_instruction))))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val dcache_bypass_data =
 | 
				
			||||||
 | 
					    if (fastLoadByte) io.dmem.resp.bits.data
 | 
				
			||||||
 | 
					    else if (fastLoadWord) io.dmem.resp.bits.data_word_bypass
 | 
				
			||||||
 | 
					    else wb_reg_wdata
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // detect bypass opportunities
 | 
				
			||||||
 | 
					  val ex_waddr = ex_reg_inst(11,7)
 | 
				
			||||||
 | 
					  val mem_waddr = mem_reg_inst(11,7)
 | 
				
			||||||
 | 
					  val wb_waddr = wb_reg_inst(11,7)
 | 
				
			||||||
 | 
					  val bypass_sources = IndexedSeq(
 | 
				
			||||||
 | 
					    (Bool(true), UInt(0), UInt(0)), // treat reading x0 as a bypass
 | 
				
			||||||
 | 
					    (ex_reg_valid && ex_ctrl.wxd, ex_waddr, mem_reg_wdata),
 | 
				
			||||||
 | 
					    (mem_reg_valid && mem_ctrl.wxd && !mem_ctrl.mem, mem_waddr, wb_reg_wdata),
 | 
				
			||||||
 | 
					    (mem_reg_valid && mem_ctrl.wxd, mem_waddr, dcache_bypass_data))
 | 
				
			||||||
 | 
					  val id_bypass_src = id_raddr.map(raddr => bypass_sources.map(s => s._1 && s._2 === raddr))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // execute stage
 | 
				
			||||||
 | 
					  val bypass_mux = Vec(bypass_sources.map(_._3))
 | 
				
			||||||
 | 
					  val ex_reg_rs_bypass = Reg(Vec(id_raddr.size, Bool()))
 | 
				
			||||||
 | 
					  val ex_reg_rs_lsb = Reg(Vec(id_raddr.size, UInt()))
 | 
				
			||||||
 | 
					  val ex_reg_rs_msb = Reg(Vec(id_raddr.size, UInt()))
 | 
				
			||||||
 | 
					  val ex_rs = for (i <- 0 until id_raddr.size)
 | 
				
			||||||
 | 
					    yield Mux(ex_reg_rs_bypass(i), bypass_mux(ex_reg_rs_lsb(i)), Cat(ex_reg_rs_msb(i), ex_reg_rs_lsb(i)))
 | 
				
			||||||
 | 
					  val ex_imm = ImmGen(ex_ctrl.sel_imm, ex_reg_inst)
 | 
				
			||||||
 | 
					  val ex_op1 = MuxLookup(ex_ctrl.sel_alu1, SInt(0), Seq(
 | 
				
			||||||
 | 
					    A1_RS1 -> ex_rs(0).toSInt,
 | 
				
			||||||
 | 
					    A1_PC -> ex_reg_pc.toSInt))
 | 
				
			||||||
 | 
					  val ex_op2 = MuxLookup(ex_ctrl.sel_alu2, SInt(0), Seq(
 | 
				
			||||||
 | 
					    A2_RS2 -> ex_rs(1).toSInt,
 | 
				
			||||||
 | 
					    A2_IMM -> ex_imm,
 | 
				
			||||||
 | 
					    A2_FOUR -> SInt(4)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val alu = Module(new ALU)
 | 
				
			||||||
 | 
					  alu.io.dw := ex_ctrl.alu_dw
 | 
				
			||||||
 | 
					  alu.io.fn := ex_ctrl.alu_fn
 | 
				
			||||||
 | 
					  alu.io.in2 := ex_op2.toUInt
 | 
				
			||||||
 | 
					  alu.io.in1 := ex_op1.toUInt
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  // multiplier and divider
 | 
				
			||||||
 | 
					  val div = Module(new MulDiv(width = xLen,
 | 
				
			||||||
 | 
					                              unroll = mulUnroll,
 | 
				
			||||||
 | 
					                              earlyOut = divEarlyOut))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  div.io.req.valid := ex_reg_valid && ex_ctrl.div
 | 
				
			||||||
 | 
					  div.io.req.bits.dw := ex_ctrl.alu_dw
 | 
				
			||||||
 | 
					  div.io.req.bits.fn := ex_ctrl.alu_fn
 | 
				
			||||||
 | 
					  div.io.req.bits.in1 := ex_rs(0)
 | 
				
			||||||
 | 
					  div.io.req.bits.in2 := ex_rs(1)
 | 
				
			||||||
 | 
					  div.io.req.bits.tag := ex_waddr
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ex_reg_valid := !ctrl_killd
 | 
				
			||||||
 | 
					  ex_reg_replay := !take_pc && io.imem.resp.valid && io.imem.resp.bits.replay
 | 
				
			||||||
 | 
					  ex_reg_xcpt := !ctrl_killd && id_xcpt
 | 
				
			||||||
 | 
					  ex_reg_xcpt_interrupt := !take_pc && io.imem.resp.valid && csr.io.interrupt
 | 
				
			||||||
 | 
					  when (id_xcpt) { ex_reg_cause := id_cause }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  when (!ctrl_killd) {
 | 
				
			||||||
 | 
					    ex_ctrl := id_ctrl
 | 
				
			||||||
 | 
					    ex_ctrl.csr := id_csr
 | 
				
			||||||
 | 
					    ex_reg_btb_hit := io.imem.btb_resp.valid
 | 
				
			||||||
 | 
					    when (io.imem.btb_resp.valid) { ex_reg_btb_resp := io.imem.btb_resp.bits }
 | 
				
			||||||
 | 
					    ex_reg_flush_pipe := id_ctrl.fence_i || id_csr_flush || csr.io.singleStep
 | 
				
			||||||
 | 
					    ex_reg_load_use := id_load_use
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    when (id_ctrl.jalr && csr.io.status.debug) {
 | 
				
			||||||
 | 
					      ex_reg_flush_pipe := true
 | 
				
			||||||
 | 
					      ex_ctrl.fence_i := true
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (i <- 0 until id_raddr.size) {
 | 
				
			||||||
 | 
					      val do_bypass = id_bypass_src(i).reduce(_||_)
 | 
				
			||||||
 | 
					      val bypass_src = PriorityEncoder(id_bypass_src(i))
 | 
				
			||||||
 | 
					      ex_reg_rs_bypass(i) := do_bypass
 | 
				
			||||||
 | 
					      ex_reg_rs_lsb(i) := bypass_src
 | 
				
			||||||
 | 
					      when (id_ren(i) && !do_bypass) {
 | 
				
			||||||
 | 
					        ex_reg_rs_lsb(i) := id_rs(i)(bypass_src.getWidth-1,0)
 | 
				
			||||||
 | 
					        ex_reg_rs_msb(i) := id_rs(i) >> bypass_src.getWidth
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  when (!ctrl_killd || csr.io.interrupt || io.imem.resp.bits.replay) {
 | 
				
			||||||
 | 
					    ex_reg_inst := id_inst
 | 
				
			||||||
 | 
					    ex_reg_pc := id_pc
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // replay inst in ex stage?
 | 
				
			||||||
 | 
					  val ex_pc_valid = ex_reg_valid || ex_reg_replay || ex_reg_xcpt_interrupt
 | 
				
			||||||
 | 
					  val wb_dcache_miss = wb_ctrl.mem && !io.dmem.resp.valid
 | 
				
			||||||
 | 
					  val replay_ex_structural = ex_ctrl.mem && !io.dmem.req.ready ||
 | 
				
			||||||
 | 
					                             ex_ctrl.div && !div.io.req.ready
 | 
				
			||||||
 | 
					  val replay_ex_load_use = wb_dcache_miss && ex_reg_load_use
 | 
				
			||||||
 | 
					  val replay_ex = ex_reg_replay || (ex_reg_valid && (replay_ex_structural || replay_ex_load_use))
 | 
				
			||||||
 | 
					  val ctrl_killx = take_pc_mem_wb || replay_ex || !ex_reg_valid
 | 
				
			||||||
 | 
					  // detect 2-cycle load-use delay for LB/LH/SC
 | 
				
			||||||
 | 
					  val ex_slow_bypass = ex_ctrl.mem_cmd === M_XSC || Vec(MT_B, MT_BU, MT_H, MT_HU).contains(ex_ctrl.mem_type)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val (ex_xcpt, ex_cause) = checkExceptions(List(
 | 
				
			||||||
 | 
					    (ex_reg_xcpt_interrupt || ex_reg_xcpt, ex_reg_cause),
 | 
				
			||||||
 | 
					    (ex_ctrl.fp && io.fpu.illegal_rm,      UInt(Causes.illegal_instruction))))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // memory stage
 | 
				
			||||||
 | 
					  val mem_br_taken = mem_reg_wdata(0)
 | 
				
			||||||
 | 
					  val mem_br_target = mem_reg_pc.toSInt +
 | 
				
			||||||
 | 
					    Mux(mem_ctrl.branch && mem_br_taken, ImmGen(IMM_SB, mem_reg_inst),
 | 
				
			||||||
 | 
					    Mux(mem_ctrl.jal, ImmGen(IMM_UJ, mem_reg_inst), SInt(4)))
 | 
				
			||||||
 | 
					  val mem_int_wdata = Mux(mem_ctrl.jalr, mem_br_target, mem_reg_wdata.toSInt).toUInt
 | 
				
			||||||
 | 
					  val mem_npc = (Mux(mem_ctrl.jalr, encodeVirtualAddress(mem_reg_wdata, mem_reg_wdata).toSInt, mem_br_target) & SInt(-2)).toUInt
 | 
				
			||||||
 | 
					  val mem_wrong_npc = Mux(ex_pc_valid, mem_npc =/= ex_reg_pc, Mux(io.imem.resp.valid, mem_npc =/= id_pc, Bool(true)))
 | 
				
			||||||
 | 
					  val mem_npc_misaligned = mem_npc(1)
 | 
				
			||||||
 | 
					  val mem_cfi = mem_ctrl.branch || mem_ctrl.jalr || mem_ctrl.jal
 | 
				
			||||||
 | 
					  val mem_cfi_taken = (mem_ctrl.branch && mem_br_taken) || mem_ctrl.jalr || mem_ctrl.jal
 | 
				
			||||||
 | 
					  val mem_misprediction =
 | 
				
			||||||
 | 
					    if (p(BtbKey).nEntries == 0) mem_cfi_taken
 | 
				
			||||||
 | 
					    else mem_wrong_npc
 | 
				
			||||||
 | 
					  val want_take_pc_mem = mem_reg_valid && (mem_misprediction || mem_reg_flush_pipe)
 | 
				
			||||||
 | 
					  take_pc_mem := want_take_pc_mem && !mem_npc_misaligned
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  mem_reg_valid := !ctrl_killx
 | 
				
			||||||
 | 
					  mem_reg_replay := !take_pc_mem_wb && replay_ex
 | 
				
			||||||
 | 
					  mem_reg_xcpt := !ctrl_killx && ex_xcpt
 | 
				
			||||||
 | 
					  mem_reg_xcpt_interrupt := !take_pc_mem_wb && ex_reg_xcpt_interrupt
 | 
				
			||||||
 | 
					  when (ex_xcpt) { mem_reg_cause := ex_cause }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  when (ex_pc_valid) {
 | 
				
			||||||
 | 
					    mem_ctrl := ex_ctrl
 | 
				
			||||||
 | 
					    mem_reg_load := ex_ctrl.mem && isRead(ex_ctrl.mem_cmd)
 | 
				
			||||||
 | 
					    mem_reg_store := ex_ctrl.mem && isWrite(ex_ctrl.mem_cmd)
 | 
				
			||||||
 | 
					    mem_reg_btb_hit := ex_reg_btb_hit
 | 
				
			||||||
 | 
					    when (ex_reg_btb_hit) { mem_reg_btb_resp := ex_reg_btb_resp }
 | 
				
			||||||
 | 
					    mem_reg_flush_pipe := ex_reg_flush_pipe
 | 
				
			||||||
 | 
					    mem_reg_slow_bypass := ex_slow_bypass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mem_reg_inst := ex_reg_inst
 | 
				
			||||||
 | 
					    mem_reg_pc := ex_reg_pc
 | 
				
			||||||
 | 
					    mem_reg_wdata := alu.io.out
 | 
				
			||||||
 | 
					    when (ex_ctrl.rxs2 && (ex_ctrl.mem || ex_ctrl.rocc)) {
 | 
				
			||||||
 | 
					      mem_reg_rs2 := ex_rs(1)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val (mem_new_xcpt, mem_new_cause) = checkExceptions(List(
 | 
				
			||||||
 | 
					    (mem_reg_load && bpu.io.xcpt_ld,         UInt(Causes.breakpoint)),
 | 
				
			||||||
 | 
					    (mem_reg_store && bpu.io.xcpt_st,        UInt(Causes.breakpoint)),
 | 
				
			||||||
 | 
					    (want_take_pc_mem && mem_npc_misaligned, UInt(Causes.misaligned_fetch)),
 | 
				
			||||||
 | 
					    (mem_ctrl.mem && io.dmem.xcpt.ma.st,     UInt(Causes.misaligned_store)),
 | 
				
			||||||
 | 
					    (mem_ctrl.mem && io.dmem.xcpt.ma.ld,     UInt(Causes.misaligned_load)),
 | 
				
			||||||
 | 
					    (mem_ctrl.mem && io.dmem.xcpt.pf.st,     UInt(Causes.fault_store)),
 | 
				
			||||||
 | 
					    (mem_ctrl.mem && io.dmem.xcpt.pf.ld,     UInt(Causes.fault_load))))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val (mem_xcpt, mem_cause) = checkExceptions(List(
 | 
				
			||||||
 | 
					    (mem_reg_xcpt_interrupt || mem_reg_xcpt, mem_reg_cause),
 | 
				
			||||||
 | 
					    (mem_reg_valid && mem_new_xcpt,          mem_new_cause)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val dcache_kill_mem = mem_reg_valid && mem_ctrl.wxd && io.dmem.replay_next // structural hazard on writeback port
 | 
				
			||||||
 | 
					  val fpu_kill_mem = mem_reg_valid && mem_ctrl.fp && io.fpu.nack_mem
 | 
				
			||||||
 | 
					  val replay_mem  = dcache_kill_mem || mem_reg_replay || fpu_kill_mem
 | 
				
			||||||
 | 
					  val killm_common = dcache_kill_mem || take_pc_wb || mem_reg_xcpt || !mem_reg_valid
 | 
				
			||||||
 | 
					  div.io.kill := killm_common && Reg(next = div.io.req.fire())
 | 
				
			||||||
 | 
					  val ctrl_killm = killm_common || mem_xcpt || fpu_kill_mem
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // writeback stage
 | 
				
			||||||
 | 
					  wb_reg_valid := !ctrl_killm
 | 
				
			||||||
 | 
					  wb_reg_replay := replay_mem && !take_pc_wb
 | 
				
			||||||
 | 
					  wb_reg_xcpt := mem_xcpt && !take_pc_wb
 | 
				
			||||||
 | 
					  wb_reg_mem_xcpt := mem_reg_valid && mem_new_xcpt && !(mem_reg_xcpt_interrupt || mem_reg_xcpt)
 | 
				
			||||||
 | 
					  when (mem_xcpt) { wb_reg_cause := mem_cause }
 | 
				
			||||||
 | 
					  when (mem_reg_valid || mem_reg_replay || mem_reg_xcpt_interrupt) {
 | 
				
			||||||
 | 
					    wb_ctrl := mem_ctrl
 | 
				
			||||||
 | 
					    wb_reg_wdata := Mux(mem_ctrl.fp && mem_ctrl.wxd, io.fpu.toint_data, mem_int_wdata)
 | 
				
			||||||
 | 
					    when (mem_ctrl.rocc) {
 | 
				
			||||||
 | 
					      wb_reg_rs2 := mem_reg_rs2
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    wb_reg_inst := mem_reg_inst
 | 
				
			||||||
 | 
					    wb_reg_pc := mem_reg_pc
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val wb_set_sboard = wb_ctrl.div || wb_dcache_miss || wb_ctrl.rocc
 | 
				
			||||||
 | 
					  val replay_wb_common = io.dmem.s2_nack || wb_reg_replay
 | 
				
			||||||
 | 
					  val replay_wb_rocc = wb_reg_valid && wb_ctrl.rocc && !io.rocc.cmd.ready
 | 
				
			||||||
 | 
					  val replay_wb = replay_wb_common || replay_wb_rocc
 | 
				
			||||||
 | 
					  val wb_xcpt = wb_reg_xcpt || csr.io.csr_xcpt
 | 
				
			||||||
 | 
					  take_pc_wb := replay_wb || wb_xcpt || csr.io.eret
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // writeback arbitration
 | 
				
			||||||
 | 
					  val dmem_resp_xpu = !io.dmem.resp.bits.tag(0).toBool
 | 
				
			||||||
 | 
					  val dmem_resp_fpu =  io.dmem.resp.bits.tag(0).toBool
 | 
				
			||||||
 | 
					  val dmem_resp_waddr = io.dmem.resp.bits.tag >> 1
 | 
				
			||||||
 | 
					  val dmem_resp_valid = io.dmem.resp.valid && io.dmem.resp.bits.has_data
 | 
				
			||||||
 | 
					  val dmem_resp_replay = dmem_resp_valid && io.dmem.resp.bits.replay
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  div.io.resp.ready := !(wb_reg_valid && wb_ctrl.wxd)
 | 
				
			||||||
 | 
					  val ll_wdata = Wire(init = div.io.resp.bits.data)
 | 
				
			||||||
 | 
					  val ll_waddr = Wire(init = div.io.resp.bits.tag)
 | 
				
			||||||
 | 
					  val ll_wen = Wire(init = div.io.resp.fire())
 | 
				
			||||||
 | 
					  if (usingRoCC) {
 | 
				
			||||||
 | 
					    io.rocc.resp.ready := !(wb_reg_valid && wb_ctrl.wxd)
 | 
				
			||||||
 | 
					    when (io.rocc.resp.fire()) {
 | 
				
			||||||
 | 
					      div.io.resp.ready := Bool(false)
 | 
				
			||||||
 | 
					      ll_wdata := io.rocc.resp.bits.data
 | 
				
			||||||
 | 
					      ll_waddr := io.rocc.resp.bits.rd
 | 
				
			||||||
 | 
					      ll_wen := Bool(true)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  when (dmem_resp_replay && dmem_resp_xpu) {
 | 
				
			||||||
 | 
					    div.io.resp.ready := Bool(false)
 | 
				
			||||||
 | 
					    if (usingRoCC)
 | 
				
			||||||
 | 
					      io.rocc.resp.ready := Bool(false)
 | 
				
			||||||
 | 
					    ll_waddr := dmem_resp_waddr
 | 
				
			||||||
 | 
					    ll_wen := Bool(true)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val wb_valid = wb_reg_valid && !replay_wb && !wb_xcpt
 | 
				
			||||||
 | 
					  val wb_wen = wb_valid && wb_ctrl.wxd
 | 
				
			||||||
 | 
					  val rf_wen = wb_wen || ll_wen 
 | 
				
			||||||
 | 
					  val rf_waddr = Mux(ll_wen, ll_waddr, wb_waddr)
 | 
				
			||||||
 | 
					  val rf_wdata = Mux(dmem_resp_valid && dmem_resp_xpu, io.dmem.resp.bits.data,
 | 
				
			||||||
 | 
					                 Mux(ll_wen, ll_wdata,
 | 
				
			||||||
 | 
					                 Mux(wb_ctrl.csr =/= CSR.N, csr.io.rw.rdata,
 | 
				
			||||||
 | 
					                 wb_reg_wdata)))
 | 
				
			||||||
 | 
					  when (rf_wen) { rf.write(rf_waddr, rf_wdata) }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // hook up control/status regfile
 | 
				
			||||||
 | 
					  csr.io.exception := wb_reg_xcpt
 | 
				
			||||||
 | 
					  csr.io.cause := wb_reg_cause
 | 
				
			||||||
 | 
					  csr.io.retire := wb_valid
 | 
				
			||||||
 | 
					  csr.io.prci <> io.prci
 | 
				
			||||||
 | 
					  io.fpu.fcsr_rm := csr.io.fcsr_rm
 | 
				
			||||||
 | 
					  csr.io.fcsr_flags := io.fpu.fcsr_flags
 | 
				
			||||||
 | 
					  io.rocc.csr <> csr.io.rocc.csr
 | 
				
			||||||
 | 
					  csr.io.rocc.interrupt <> io.rocc.interrupt
 | 
				
			||||||
 | 
					  csr.io.pc := wb_reg_pc
 | 
				
			||||||
 | 
					  csr.io.badaddr := Mux(wb_reg_mem_xcpt, encodeVirtualAddress(wb_reg_wdata, wb_reg_wdata), wb_reg_pc)
 | 
				
			||||||
 | 
					  io.ptw.ptbr := csr.io.ptbr
 | 
				
			||||||
 | 
					  io.ptw.invalidate := csr.io.fatc
 | 
				
			||||||
 | 
					  io.ptw.status := csr.io.status
 | 
				
			||||||
 | 
					  csr.io.rw.addr := wb_reg_inst(31,20)
 | 
				
			||||||
 | 
					  csr.io.rw.cmd := Mux(wb_reg_valid, wb_ctrl.csr, CSR.N)
 | 
				
			||||||
 | 
					  csr.io.rw.wdata := wb_reg_wdata
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val hazard_targets = Seq((id_ctrl.rxs1 && id_raddr1 =/= UInt(0), id_raddr1),
 | 
				
			||||||
 | 
					                           (id_ctrl.rxs2 && id_raddr2 =/= UInt(0), id_raddr2),
 | 
				
			||||||
 | 
					                           (id_ctrl.wxd  && id_waddr  =/= UInt(0), id_waddr))
 | 
				
			||||||
 | 
					  val fp_hazard_targets = Seq((io.fpu.dec.ren1, id_raddr1),
 | 
				
			||||||
 | 
					                              (io.fpu.dec.ren2, id_raddr2),
 | 
				
			||||||
 | 
					                              (io.fpu.dec.ren3, id_raddr3),
 | 
				
			||||||
 | 
					                              (io.fpu.dec.wen, id_waddr))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val sboard = new Scoreboard(32)
 | 
				
			||||||
 | 
					  sboard.clear(ll_wen, ll_waddr)
 | 
				
			||||||
 | 
					  val id_sboard_hazard = checkHazards(hazard_targets, sboard.read _)
 | 
				
			||||||
 | 
					  sboard.set(wb_set_sboard && wb_wen, wb_waddr)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // stall for RAW/WAW hazards on CSRs, loads, AMOs, and mul/div in execute stage.
 | 
				
			||||||
 | 
					  val ex_cannot_bypass = ex_ctrl.csr =/= CSR.N || ex_ctrl.jalr || ex_ctrl.mem || ex_ctrl.div || ex_ctrl.fp || ex_ctrl.rocc
 | 
				
			||||||
 | 
					  val data_hazard_ex = ex_ctrl.wxd && checkHazards(hazard_targets, _ === ex_waddr)
 | 
				
			||||||
 | 
					  val fp_data_hazard_ex = ex_ctrl.wfd && checkHazards(fp_hazard_targets, _ === ex_waddr)
 | 
				
			||||||
 | 
					  val id_ex_hazard = ex_reg_valid && (data_hazard_ex && ex_cannot_bypass || fp_data_hazard_ex)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // stall for RAW/WAW hazards on CSRs, LB/LH, and mul/div in memory stage.
 | 
				
			||||||
 | 
					  val mem_mem_cmd_bh =
 | 
				
			||||||
 | 
					    if (fastLoadWord) Bool(!fastLoadByte) && mem_reg_slow_bypass
 | 
				
			||||||
 | 
					    else Bool(true)
 | 
				
			||||||
 | 
					  val mem_cannot_bypass = mem_ctrl.csr =/= CSR.N || mem_ctrl.mem && mem_mem_cmd_bh || mem_ctrl.div || mem_ctrl.fp || mem_ctrl.rocc
 | 
				
			||||||
 | 
					  val data_hazard_mem = mem_ctrl.wxd && checkHazards(hazard_targets, _ === mem_waddr)
 | 
				
			||||||
 | 
					  val fp_data_hazard_mem = mem_ctrl.wfd && checkHazards(fp_hazard_targets, _ === mem_waddr)
 | 
				
			||||||
 | 
					  val id_mem_hazard = mem_reg_valid && (data_hazard_mem && mem_cannot_bypass || fp_data_hazard_mem)
 | 
				
			||||||
 | 
					  id_load_use := mem_reg_valid && data_hazard_mem && mem_ctrl.mem
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // stall for RAW/WAW hazards on load/AMO misses and mul/div in writeback.
 | 
				
			||||||
 | 
					  val data_hazard_wb = wb_ctrl.wxd && checkHazards(hazard_targets, _ === wb_waddr)
 | 
				
			||||||
 | 
					  val fp_data_hazard_wb = wb_ctrl.wfd && checkHazards(fp_hazard_targets, _ === wb_waddr)
 | 
				
			||||||
 | 
					  val id_wb_hazard = wb_reg_valid && (data_hazard_wb && wb_set_sboard || fp_data_hazard_wb)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val id_stall_fpu = if (usingFPU) {
 | 
				
			||||||
 | 
					    val fp_sboard = new Scoreboard(32)
 | 
				
			||||||
 | 
					    fp_sboard.set((wb_dcache_miss && wb_ctrl.wfd || io.fpu.sboard_set) && wb_valid, wb_waddr)
 | 
				
			||||||
 | 
					    fp_sboard.clear(dmem_resp_replay && dmem_resp_fpu, dmem_resp_waddr)
 | 
				
			||||||
 | 
					    fp_sboard.clear(io.fpu.sboard_clr, io.fpu.sboard_clra)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    id_csr_en && !io.fpu.fcsr_rdy || checkHazards(fp_hazard_targets, fp_sboard.read _)
 | 
				
			||||||
 | 
					  } else Bool(false)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val dcache_blocked = Reg(Bool())
 | 
				
			||||||
 | 
					  dcache_blocked := !io.dmem.req.ready && (io.dmem.req.valid || dcache_blocked)
 | 
				
			||||||
 | 
					  val rocc_blocked = Reg(Bool())
 | 
				
			||||||
 | 
					  rocc_blocked := !wb_reg_xcpt && !io.rocc.cmd.ready && (io.rocc.cmd.valid || rocc_blocked)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val ctrl_stalld =
 | 
				
			||||||
 | 
					    id_ex_hazard || id_mem_hazard || id_wb_hazard || id_sboard_hazard ||
 | 
				
			||||||
 | 
					    id_ctrl.fp && id_stall_fpu ||
 | 
				
			||||||
 | 
					    id_ctrl.mem && dcache_blocked || // reduce activity during D$ misses
 | 
				
			||||||
 | 
					    id_ctrl.rocc && rocc_blocked || // reduce activity while RoCC is busy
 | 
				
			||||||
 | 
					    id_do_fence ||
 | 
				
			||||||
 | 
					    csr.io.csr_stall
 | 
				
			||||||
 | 
					  ctrl_killd := !io.imem.resp.valid || io.imem.resp.bits.replay || take_pc || ctrl_stalld || csr.io.interrupt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  io.imem.req.valid := take_pc
 | 
				
			||||||
 | 
					  io.imem.req.bits.speculative := !take_pc_wb
 | 
				
			||||||
 | 
					  io.imem.req.bits.pc :=
 | 
				
			||||||
 | 
					    Mux(wb_xcpt || csr.io.eret, csr.io.evec,     // exception or [m|s]ret
 | 
				
			||||||
 | 
					    Mux(replay_wb,              wb_reg_pc,       // replay
 | 
				
			||||||
 | 
					                                mem_npc)).toUInt // mispredicted branch
 | 
				
			||||||
 | 
					  io.imem.flush_icache := wb_reg_valid && wb_ctrl.fence_i && !io.dmem.s2_nack
 | 
				
			||||||
 | 
					  io.imem.flush_tlb := csr.io.fatc
 | 
				
			||||||
 | 
					  io.imem.resp.ready := !ctrl_stalld || csr.io.interrupt || take_pc_mem
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  io.imem.btb_update.valid := mem_reg_valid && !mem_npc_misaligned && mem_wrong_npc && mem_cfi_taken && !take_pc_wb
 | 
				
			||||||
 | 
					  io.imem.btb_update.bits.isJump := mem_ctrl.jal || mem_ctrl.jalr
 | 
				
			||||||
 | 
					  io.imem.btb_update.bits.isReturn := mem_ctrl.jalr && mem_reg_inst(19,15) === BitPat("b00??1")
 | 
				
			||||||
 | 
					  io.imem.btb_update.bits.pc := mem_reg_pc
 | 
				
			||||||
 | 
					  io.imem.btb_update.bits.target := io.imem.req.bits.pc
 | 
				
			||||||
 | 
					  io.imem.btb_update.bits.br_pc := mem_reg_pc
 | 
				
			||||||
 | 
					  io.imem.btb_update.bits.prediction.valid := mem_reg_btb_hit
 | 
				
			||||||
 | 
					  io.imem.btb_update.bits.prediction.bits := mem_reg_btb_resp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  io.imem.bht_update.valid := mem_reg_valid && mem_ctrl.branch && !take_pc_wb
 | 
				
			||||||
 | 
					  io.imem.bht_update.bits.pc := mem_reg_pc
 | 
				
			||||||
 | 
					  io.imem.bht_update.bits.taken := mem_br_taken
 | 
				
			||||||
 | 
					  io.imem.bht_update.bits.mispredict := mem_wrong_npc
 | 
				
			||||||
 | 
					  io.imem.bht_update.bits.prediction := io.imem.btb_update.bits.prediction
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  io.imem.ras_update.valid := mem_reg_valid && io.imem.btb_update.bits.isJump && !mem_npc_misaligned && !take_pc_wb
 | 
				
			||||||
 | 
					  io.imem.ras_update.bits.returnAddr := mem_int_wdata
 | 
				
			||||||
 | 
					  io.imem.ras_update.bits.isCall := mem_ctrl.wxd && mem_waddr(0)
 | 
				
			||||||
 | 
					  io.imem.ras_update.bits.isReturn := io.imem.btb_update.bits.isReturn
 | 
				
			||||||
 | 
					  io.imem.ras_update.bits.prediction := io.imem.btb_update.bits.prediction
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  io.fpu.valid := !ctrl_killd && id_ctrl.fp
 | 
				
			||||||
 | 
					  io.fpu.killx := ctrl_killx
 | 
				
			||||||
 | 
					  io.fpu.killm := killm_common
 | 
				
			||||||
 | 
					  io.fpu.inst := id_inst
 | 
				
			||||||
 | 
					  io.fpu.fromint_data := ex_rs(0)
 | 
				
			||||||
 | 
					  io.fpu.dmem_resp_val := dmem_resp_valid && dmem_resp_fpu
 | 
				
			||||||
 | 
					  io.fpu.dmem_resp_data := io.dmem.resp.bits.data_word_bypass
 | 
				
			||||||
 | 
					  io.fpu.dmem_resp_type := io.dmem.resp.bits.typ
 | 
				
			||||||
 | 
					  io.fpu.dmem_resp_tag := dmem_resp_waddr
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  io.dmem.req.valid     := ex_reg_valid && ex_ctrl.mem
 | 
				
			||||||
 | 
					  val ex_dcache_tag = Cat(ex_waddr, ex_ctrl.fp)
 | 
				
			||||||
 | 
					  require(coreDCacheReqTagBits >= ex_dcache_tag.getWidth)
 | 
				
			||||||
 | 
					  io.dmem.req.bits.tag  := ex_dcache_tag
 | 
				
			||||||
 | 
					  io.dmem.req.bits.cmd  := ex_ctrl.mem_cmd
 | 
				
			||||||
 | 
					  io.dmem.req.bits.typ  := ex_ctrl.mem_type
 | 
				
			||||||
 | 
					  io.dmem.req.bits.phys := Bool(false)
 | 
				
			||||||
 | 
					  io.dmem.req.bits.addr := encodeVirtualAddress(ex_rs(0), alu.io.adder_out)
 | 
				
			||||||
 | 
					  io.dmem.s1_kill := killm_common || mem_xcpt
 | 
				
			||||||
 | 
					  io.dmem.s1_data := Mux(mem_ctrl.fp, io.fpu.store_data, mem_reg_rs2)
 | 
				
			||||||
 | 
					  io.dmem.invalidate_lr := wb_xcpt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  io.rocc.cmd.valid := wb_reg_valid && wb_ctrl.rocc && !replay_wb_common
 | 
				
			||||||
 | 
					  io.rocc.exception := wb_xcpt && csr.io.status.xs.orR
 | 
				
			||||||
 | 
					  io.rocc.cmd.bits.status := csr.io.status
 | 
				
			||||||
 | 
					  io.rocc.cmd.bits.inst := new RoCCInstruction().fromBits(wb_reg_inst)
 | 
				
			||||||
 | 
					  io.rocc.cmd.bits.rs1 := wb_reg_wdata
 | 
				
			||||||
 | 
					  io.rocc.cmd.bits.rs2 := wb_reg_rs2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (enableCommitLog) {
 | 
				
			||||||
 | 
					    val pc = Wire(SInt(width=xLen))
 | 
				
			||||||
 | 
					    pc := wb_reg_pc
 | 
				
			||||||
 | 
					    val inst = wb_reg_inst
 | 
				
			||||||
 | 
					    val rd = RegNext(RegNext(RegNext(id_waddr)))
 | 
				
			||||||
 | 
					    val wfd = wb_ctrl.wfd
 | 
				
			||||||
 | 
					    val wxd = wb_ctrl.wxd
 | 
				
			||||||
 | 
					    val has_data = wb_wen && !wb_set_sboard
 | 
				
			||||||
 | 
					    val priv = csr.io.status.prv
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    when (wb_valid) {
 | 
				
			||||||
 | 
					      when (wfd) {
 | 
				
			||||||
 | 
					        printf ("%d 0x%x (0x%x) f%d p%d 0xXXXXXXXXXXXXXXXX\n", priv, pc, inst, rd, rd+UInt(32))
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      .elsewhen (wxd && rd =/= UInt(0) && has_data) {
 | 
				
			||||||
 | 
					        printf ("%d 0x%x (0x%x) x%d 0x%x\n", priv, pc, inst, rd, rf_wdata)
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      .elsewhen (wxd && rd =/= UInt(0) && !has_data) {
 | 
				
			||||||
 | 
					        printf ("%d 0x%x (0x%x) x%d p%d 0xXXXXXXXXXXXXXXXX\n", priv, pc, inst, rd, rd)
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      .otherwise {
 | 
				
			||||||
 | 
					        printf ("%d 0x%x (0x%x)\n", priv, pc, inst)
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    when (ll_wen && rf_waddr =/= UInt(0)) {
 | 
				
			||||||
 | 
					      printf ("x%d p%d 0x%x\n", rf_waddr, rf_waddr, rf_wdata)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  else {
 | 
				
			||||||
 | 
					    printf("C%d: %d [%d] pc=[%x] W[r%d=%x][%d] R[r%d=%x] R[r%d=%x] inst=[%x] DASM(%x)\n",
 | 
				
			||||||
 | 
					         io.prci.id, csr.io.time(31,0), wb_valid, wb_reg_pc,
 | 
				
			||||||
 | 
					         Mux(rf_wen, rf_waddr, UInt(0)), rf_wdata, rf_wen,
 | 
				
			||||||
 | 
					         wb_reg_inst(19,15), Reg(next=Reg(next=ex_rs(0))),
 | 
				
			||||||
 | 
					         wb_reg_inst(24,20), Reg(next=Reg(next=ex_rs(1))),
 | 
				
			||||||
 | 
					         wb_reg_inst, wb_reg_inst)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def checkExceptions(x: Seq[(Bool, UInt)]) =
 | 
				
			||||||
 | 
					    (x.map(_._1).reduce(_||_), PriorityMux(x))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def checkHazards(targets: Seq[(Bool, UInt)], cond: UInt => Bool) =
 | 
				
			||||||
 | 
					    targets.map(h => h._1 && cond(h._2)).reduce(_||_)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def encodeVirtualAddress(a0: UInt, ea: UInt) = if (vaddrBitsExtended == vaddrBits) ea else {
 | 
				
			||||||
 | 
					    // efficient means to compress 64-bit VA into vaddrBits+1 bits
 | 
				
			||||||
 | 
					    // (VA is bad if VA(vaddrBits) != VA(vaddrBits-1))
 | 
				
			||||||
 | 
					    val a = a0 >> vaddrBits-1
 | 
				
			||||||
 | 
					    val e = ea(vaddrBits,vaddrBits-1).toSInt
 | 
				
			||||||
 | 
					    val msb =
 | 
				
			||||||
 | 
					      Mux(a === UInt(0) || a === UInt(1), e =/= SInt(0),
 | 
				
			||||||
 | 
					      Mux(a.toSInt === SInt(-1) || a.toSInt === SInt(-2), e === SInt(-1), e(0)))
 | 
				
			||||||
 | 
					    Cat(msb, ea(vaddrBits-1,0))
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  class Scoreboard(n: Int)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    def set(en: Bool, addr: UInt): Unit = update(en, _next | mask(en, addr))
 | 
				
			||||||
 | 
					    def clear(en: Bool, addr: UInt): Unit = update(en, _next & ~mask(en, addr))
 | 
				
			||||||
 | 
					    def read(addr: UInt): Bool = r(addr)
 | 
				
			||||||
 | 
					    def readBypassed(addr: UInt): Bool = _next(addr)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private val r = Reg(init=Bits(0, n))
 | 
				
			||||||
 | 
					    private var _next = r
 | 
				
			||||||
 | 
					    private var ens = Bool(false)
 | 
				
			||||||
 | 
					    private def mask(en: Bool, addr: UInt) = Mux(en, UInt(1) << addr, UInt(0))
 | 
				
			||||||
 | 
					    private def update(en: Bool, update: UInt) = {
 | 
				
			||||||
 | 
					      _next = update
 | 
				
			||||||
 | 
					      ens = ens || en
 | 
				
			||||||
 | 
					      when (ens) { r := _next }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										151
									
								
								rocket/src/main/scala/tile.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										151
									
								
								rocket/src/main/scala/tile.scala
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,151 @@
 | 
				
			|||||||
 | 
					// See LICENSE for license details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package rocket
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import Chisel._
 | 
				
			||||||
 | 
					import uncore.tilelink._
 | 
				
			||||||
 | 
					import uncore.agents._
 | 
				
			||||||
 | 
					import uncore.devices._
 | 
				
			||||||
 | 
					import Util._
 | 
				
			||||||
 | 
					import cde.{Parameters, Field}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					case object CoreName extends Field[String]
 | 
				
			||||||
 | 
					case object BuildRoCC extends Field[Seq[RoccParameters]]
 | 
				
			||||||
 | 
					case object NCachedTileLinkPorts extends Field[Int]
 | 
				
			||||||
 | 
					case object NUncachedTileLinkPorts extends Field[Int]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					case class RoccParameters(
 | 
				
			||||||
 | 
					  opcodes: OpcodeSet,
 | 
				
			||||||
 | 
					  generator: Parameters => RoCC,
 | 
				
			||||||
 | 
					  nMemChannels: Int = 0,
 | 
				
			||||||
 | 
					  nPTWPorts : Int = 0,
 | 
				
			||||||
 | 
					  csrs: Seq[Int] = Nil,
 | 
				
			||||||
 | 
					  useFPU: Boolean = false)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					abstract class Tile(clockSignal: Clock = null, resetSignal: Bool = null)
 | 
				
			||||||
 | 
					    (implicit p: Parameters) extends Module(Option(clockSignal), Option(resetSignal)) {
 | 
				
			||||||
 | 
					  val nCachedTileLinkPorts = p(NCachedTileLinkPorts)
 | 
				
			||||||
 | 
					  val nUncachedTileLinkPorts = p(NUncachedTileLinkPorts)
 | 
				
			||||||
 | 
					  val dcacheParams = p.alterPartial({ case CacheName => "L1D" })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val io = new Bundle {
 | 
				
			||||||
 | 
					    val cached = Vec(nCachedTileLinkPorts, new ClientTileLinkIO)
 | 
				
			||||||
 | 
					    val uncached = Vec(nUncachedTileLinkPorts, new ClientUncachedTileLinkIO)
 | 
				
			||||||
 | 
					    val prci = new PRCITileIO().flip
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class RocketTile(clockSignal: Clock = null, resetSignal: Bool = null)
 | 
				
			||||||
 | 
					    (implicit p: Parameters) extends Tile(clockSignal, resetSignal)(p) {
 | 
				
			||||||
 | 
					  val buildRocc = p(BuildRoCC)
 | 
				
			||||||
 | 
					  val usingRocc = !buildRocc.isEmpty
 | 
				
			||||||
 | 
					  val nRocc = buildRocc.size
 | 
				
			||||||
 | 
					  val nFPUPorts = buildRocc.filter(_.useFPU).size
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val core = Module(new Rocket()(p.alterPartial({ case CoreName => "Rocket" })))
 | 
				
			||||||
 | 
					  val icache = Module(new Frontend()(p.alterPartial({
 | 
				
			||||||
 | 
					    case CacheName => "L1I"
 | 
				
			||||||
 | 
					    case CoreName => "Rocket" })))
 | 
				
			||||||
 | 
					  val dcache =
 | 
				
			||||||
 | 
					    if (p(NMSHRs) == 0) Module(new DCache()(dcacheParams)).io
 | 
				
			||||||
 | 
					    else Module(new HellaCache()(dcacheParams)).io
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val ptwPorts = collection.mutable.ArrayBuffer(icache.io.ptw, dcache.ptw)
 | 
				
			||||||
 | 
					  val dcPorts = collection.mutable.ArrayBuffer(core.io.dmem)
 | 
				
			||||||
 | 
					  val uncachedArbPorts = collection.mutable.ArrayBuffer(icache.io.mem)
 | 
				
			||||||
 | 
					  val uncachedPorts = collection.mutable.ArrayBuffer[ClientUncachedTileLinkIO]()
 | 
				
			||||||
 | 
					  val cachedPorts = collection.mutable.ArrayBuffer(dcache.mem)
 | 
				
			||||||
 | 
					  core.io.prci <> io.prci
 | 
				
			||||||
 | 
					  icache.io.cpu <> core.io.imem
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val fpuOpt = if (p(UseFPU)) Some(Module(new FPU)) else None
 | 
				
			||||||
 | 
					  fpuOpt.foreach(fpu => core.io.fpu <> fpu.io)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (usingRocc) {
 | 
				
			||||||
 | 
					    val respArb = Module(new RRArbiter(new RoCCResponse, nRocc))
 | 
				
			||||||
 | 
					    core.io.rocc.resp <> respArb.io.out
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    val roccOpcodes = buildRocc.map(_.opcodes)
 | 
				
			||||||
 | 
					    val cmdRouter = Module(new RoccCommandRouter(roccOpcodes))
 | 
				
			||||||
 | 
					    cmdRouter.io.in <> core.io.rocc.cmd
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    val roccs = buildRocc.zipWithIndex.map { case (accelParams, i) =>
 | 
				
			||||||
 | 
					      val rocc = accelParams.generator(p.alterPartial({
 | 
				
			||||||
 | 
					        case RoccNMemChannels => accelParams.nMemChannels
 | 
				
			||||||
 | 
					        case RoccNPTWPorts => accelParams.nPTWPorts
 | 
				
			||||||
 | 
					        case RoccNCSRs => accelParams.csrs.size
 | 
				
			||||||
 | 
					      }))
 | 
				
			||||||
 | 
					      val dcIF = Module(new SimpleHellaCacheIF()(dcacheParams))
 | 
				
			||||||
 | 
					      rocc.io.cmd <> cmdRouter.io.out(i)
 | 
				
			||||||
 | 
					      rocc.io.exception := core.io.rocc.exception
 | 
				
			||||||
 | 
					      rocc.io.host_id := io.prci.id
 | 
				
			||||||
 | 
					      dcIF.io.requestor <> rocc.io.mem
 | 
				
			||||||
 | 
					      dcPorts += dcIF.io.cache
 | 
				
			||||||
 | 
					      uncachedArbPorts += rocc.io.autl
 | 
				
			||||||
 | 
					      rocc
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (nFPUPorts > 0) {
 | 
				
			||||||
 | 
					      fpuOpt.foreach { fpu =>
 | 
				
			||||||
 | 
					        val fpArb = Module(new InOrderArbiter(new FPInput, new FPResult, nFPUPorts))
 | 
				
			||||||
 | 
					        val fp_roccs = roccs.zip(buildRocc)
 | 
				
			||||||
 | 
					          .filter { case (_, params) => params.useFPU }
 | 
				
			||||||
 | 
					          .map { case (rocc, _) => rocc.io }
 | 
				
			||||||
 | 
					        fpArb.io.in_req <> fp_roccs.map(_.fpu_req)
 | 
				
			||||||
 | 
					        fp_roccs.zip(fpArb.io.in_resp).foreach {
 | 
				
			||||||
 | 
					          case (rocc, fpu_resp) => rocc.fpu_resp <> fpu_resp
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        fpu.io.cp_req <> fpArb.io.out_req
 | 
				
			||||||
 | 
					        fpArb.io.out_resp <> fpu.io.cp_resp
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    core.io.rocc.busy := cmdRouter.io.busy || roccs.map(_.io.busy).reduce(_ || _)
 | 
				
			||||||
 | 
					    core.io.rocc.interrupt := roccs.map(_.io.interrupt).reduce(_ || _)
 | 
				
			||||||
 | 
					    respArb.io.in <> roccs.map(rocc => Queue(rocc.io.resp))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (p(RoccNCSRs) > 0) {
 | 
				
			||||||
 | 
					      core.io.rocc.csr.rdata <> roccs.flatMap(_.io.csr.rdata)
 | 
				
			||||||
 | 
					      for ((rocc, accelParams) <- roccs.zip(buildRocc)) {
 | 
				
			||||||
 | 
					        rocc.io.csr.waddr := core.io.rocc.csr.waddr
 | 
				
			||||||
 | 
					        rocc.io.csr.wdata := core.io.rocc.csr.wdata
 | 
				
			||||||
 | 
					        rocc.io.csr.wen := core.io.rocc.csr.wen &&
 | 
				
			||||||
 | 
					          accelParams.csrs
 | 
				
			||||||
 | 
					            .map(core.io.rocc.csr.waddr === UInt(_))
 | 
				
			||||||
 | 
					            .reduce((a, b) => a || b)
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ptwPorts ++= roccs.flatMap(_.io.ptw)
 | 
				
			||||||
 | 
					    uncachedPorts ++= roccs.flatMap(_.io.utl)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val uncachedArb = Module(new ClientUncachedTileLinkIOArbiter(uncachedArbPorts.size))
 | 
				
			||||||
 | 
					  uncachedArb.io.in <> uncachedArbPorts
 | 
				
			||||||
 | 
					  uncachedArb.io.out +=: uncachedPorts
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Connect the caches and RoCC to the outer memory system
 | 
				
			||||||
 | 
					  io.uncached <> uncachedPorts
 | 
				
			||||||
 | 
					  io.cached <> cachedPorts
 | 
				
			||||||
 | 
					  // TODO remove nCached/nUncachedTileLinkPorts parameters and these assertions
 | 
				
			||||||
 | 
					  require(uncachedPorts.size == nUncachedTileLinkPorts)
 | 
				
			||||||
 | 
					  require(cachedPorts.size == nCachedTileLinkPorts)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (p(UseVM)) {
 | 
				
			||||||
 | 
					    val ptw = Module(new PTW(ptwPorts.size)(dcacheParams))
 | 
				
			||||||
 | 
					    ptw.io.requestor <> ptwPorts
 | 
				
			||||||
 | 
					    ptw.io.mem +=: dcPorts
 | 
				
			||||||
 | 
					    core.io.ptw <> ptw.io.dpath
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val dcArb = Module(new HellaCacheArbiter(dcPorts.size)(dcacheParams))
 | 
				
			||||||
 | 
					  dcArb.io.requestor <> dcPorts
 | 
				
			||||||
 | 
					  dcache.cpu <> dcArb.io.mem
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (!usingRocc || nFPUPorts == 0) {
 | 
				
			||||||
 | 
					    fpuOpt.foreach { fpu =>
 | 
				
			||||||
 | 
					      fpu.io.cp_req.valid := Bool(false)
 | 
				
			||||||
 | 
					      fpu.io.cp_resp.ready := Bool(false)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										176
									
								
								rocket/src/main/scala/tlb.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										176
									
								
								rocket/src/main/scala/tlb.scala
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,176 @@
 | 
				
			|||||||
 | 
					// See LICENSE for license details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package rocket
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import Chisel._
 | 
				
			||||||
 | 
					import Util._
 | 
				
			||||||
 | 
					import junctions._
 | 
				
			||||||
 | 
					import scala.math._
 | 
				
			||||||
 | 
					import cde.{Parameters, Field}
 | 
				
			||||||
 | 
					import uncore.agents.PseudoLRU
 | 
				
			||||||
 | 
					import uncore.coherence._
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					case object NTLBEntries extends Field[Int]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					trait HasTLBParameters extends HasCoreParameters {
 | 
				
			||||||
 | 
					  val entries = p(NTLBEntries)
 | 
				
			||||||
 | 
					  val camAddrBits = log2Ceil(entries)
 | 
				
			||||||
 | 
					  val camTagBits = asIdBits + vpnBits
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class TLBReq(implicit p: Parameters) extends CoreBundle()(p) {
 | 
				
			||||||
 | 
					  val vpn = UInt(width = vpnBitsExtended)
 | 
				
			||||||
 | 
					  val passthrough = Bool()
 | 
				
			||||||
 | 
					  val instruction = Bool()
 | 
				
			||||||
 | 
					  val store = Bool()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class TLBResp(implicit p: Parameters) extends CoreBundle()(p) {
 | 
				
			||||||
 | 
					  // lookup responses
 | 
				
			||||||
 | 
					  val miss = Bool(OUTPUT)
 | 
				
			||||||
 | 
					  val ppn = UInt(OUTPUT, ppnBits)
 | 
				
			||||||
 | 
					  val xcpt_ld = Bool(OUTPUT)
 | 
				
			||||||
 | 
					  val xcpt_st = Bool(OUTPUT)
 | 
				
			||||||
 | 
					  val xcpt_if = Bool(OUTPUT)
 | 
				
			||||||
 | 
					  val cacheable = Bool(OUTPUT)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class TLB(implicit val p: Parameters) extends Module with HasTLBParameters {
 | 
				
			||||||
 | 
					  val io = new Bundle {
 | 
				
			||||||
 | 
					    val req = Decoupled(new TLBReq).flip
 | 
				
			||||||
 | 
					    val resp = new TLBResp
 | 
				
			||||||
 | 
					    val ptw = new TLBPTWIO
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val valid = Reg(init = UInt(0, entries))
 | 
				
			||||||
 | 
					  val ppns = Reg(Vec(entries, io.ptw.resp.bits.pte.ppn))
 | 
				
			||||||
 | 
					  val tags = Reg(Vec(entries, UInt(width = asIdBits + vpnBits)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val s_ready :: s_request :: s_wait :: s_wait_invalidate :: Nil = Enum(UInt(), 4)
 | 
				
			||||||
 | 
					  val state = Reg(init=s_ready)
 | 
				
			||||||
 | 
					  val r_refill_tag = Reg(UInt(width = asIdBits + vpnBits))
 | 
				
			||||||
 | 
					  val r_refill_waddr = Reg(UInt(width = log2Ceil(entries)))
 | 
				
			||||||
 | 
					  val r_req = Reg(new TLBReq)
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  val lookup_tag = Cat(io.ptw.ptbr.asid, io.req.bits.vpn(vpnBits-1,0)).toUInt
 | 
				
			||||||
 | 
					  val hitsVec = (0 until entries).map(i => valid(i) && tags(i) === lookup_tag)
 | 
				
			||||||
 | 
					  val hits = hitsVec.toBits
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  // permission bit arrays
 | 
				
			||||||
 | 
					  val pte_array = Reg(new PTE)
 | 
				
			||||||
 | 
					  val u_array = Reg(UInt(width = entries)) // user permission
 | 
				
			||||||
 | 
					  val sw_array = Reg(UInt(width = entries)) // write permission
 | 
				
			||||||
 | 
					  val sx_array = Reg(UInt(width = entries)) // execute permission
 | 
				
			||||||
 | 
					  val sr_array = Reg(UInt(width = entries)) // read permission
 | 
				
			||||||
 | 
					  val dirty_array = Reg(UInt(width = entries)) // PTE dirty bit
 | 
				
			||||||
 | 
					  when (io.ptw.resp.valid) {
 | 
				
			||||||
 | 
					    val pte = io.ptw.resp.bits.pte
 | 
				
			||||||
 | 
					    ppns(r_refill_waddr) := pte.ppn
 | 
				
			||||||
 | 
					    tags(r_refill_waddr) := r_refill_tag
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    val mask = UIntToOH(r_refill_waddr)
 | 
				
			||||||
 | 
					    valid := valid | mask
 | 
				
			||||||
 | 
					    u_array := Mux(pte.u, u_array | mask, u_array & ~mask)
 | 
				
			||||||
 | 
					    sr_array := Mux(pte.sr(), sr_array | mask, sr_array & ~mask)
 | 
				
			||||||
 | 
					    sw_array := Mux(pte.sw(), sw_array | mask, sw_array & ~mask)
 | 
				
			||||||
 | 
					    sx_array := Mux(pte.sx(), sx_array | mask, sx_array & ~mask)
 | 
				
			||||||
 | 
					    dirty_array := Mux(pte.d, dirty_array | mask, dirty_array & ~mask)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					  // high if there are any unused (invalid) entries in the TLB
 | 
				
			||||||
 | 
					  val plru = new PseudoLRU(entries)
 | 
				
			||||||
 | 
					  val repl_waddr = Mux(!valid.andR, PriorityEncoder(~valid), plru.replace)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val do_mprv = io.ptw.status.mprv && !io.req.bits.instruction
 | 
				
			||||||
 | 
					  val priv = Mux(do_mprv, io.ptw.status.mpp, io.ptw.status.prv)
 | 
				
			||||||
 | 
					  val priv_s = priv === PRV.S
 | 
				
			||||||
 | 
					  val priv_uses_vm = priv <= PRV.S && !io.ptw.status.debug
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val priv_ok = Mux(priv_s, ~Mux(io.ptw.status.pum, u_array, UInt(0)), u_array)
 | 
				
			||||||
 | 
					  val w_array = priv_ok & sw_array
 | 
				
			||||||
 | 
					  val x_array = priv_ok & sx_array
 | 
				
			||||||
 | 
					  val r_array = priv_ok & (sr_array | Mux(io.ptw.status.mxr, x_array, UInt(0)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val vm_enabled = Bool(usingVM) && io.ptw.status.vm(3) && priv_uses_vm && !io.req.bits.passthrough
 | 
				
			||||||
 | 
					  val bad_va =
 | 
				
			||||||
 | 
					    if (vpnBits == vpnBitsExtended) Bool(false)
 | 
				
			||||||
 | 
					    else io.req.bits.vpn(vpnBits) =/= io.req.bits.vpn(vpnBits-1)
 | 
				
			||||||
 | 
					  // it's only a store hit if the dirty bit is set
 | 
				
			||||||
 | 
					  val tag_hits = hits & (dirty_array | ~Mux(io.req.bits.store, w_array, UInt(0)))
 | 
				
			||||||
 | 
					  val tag_hit = tag_hits.orR
 | 
				
			||||||
 | 
					  val tlb_hit = vm_enabled && tag_hit
 | 
				
			||||||
 | 
					  val tlb_miss = vm_enabled && !tag_hit && !bad_va
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  when (io.req.valid && tlb_hit) {
 | 
				
			||||||
 | 
					    plru.access(OHToUInt(hits))
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val paddr = Cat(io.resp.ppn, UInt(0, pgIdxBits))
 | 
				
			||||||
 | 
					  val addr_prot = addrMap.getProt(paddr)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  io.req.ready := state === s_ready
 | 
				
			||||||
 | 
					  io.resp.xcpt_ld := bad_va || (!tlb_miss && !addr_prot.r) || (tlb_hit && !(r_array & hits).orR)
 | 
				
			||||||
 | 
					  io.resp.xcpt_st := bad_va || (!tlb_miss && !addr_prot.w) || (tlb_hit && !(w_array & hits).orR)
 | 
				
			||||||
 | 
					  io.resp.xcpt_if := bad_va || (!tlb_miss && !addr_prot.x) || (tlb_hit && !(x_array & hits).orR)
 | 
				
			||||||
 | 
					  io.resp.cacheable := addrMap.isCacheable(paddr)
 | 
				
			||||||
 | 
					  io.resp.miss := tlb_miss
 | 
				
			||||||
 | 
					  io.resp.ppn := Mux(vm_enabled, Mux1H(hitsVec, ppns), io.req.bits.vpn(ppnBits-1,0))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  io.ptw.req.valid := state === s_request
 | 
				
			||||||
 | 
					  io.ptw.req.bits := io.ptw.status
 | 
				
			||||||
 | 
					  io.ptw.req.bits.addr := r_refill_tag
 | 
				
			||||||
 | 
					  io.ptw.req.bits.store := r_req.store
 | 
				
			||||||
 | 
					  io.ptw.req.bits.fetch := r_req.instruction
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (usingVM) {
 | 
				
			||||||
 | 
					    when (io.req.fire() && tlb_miss) {
 | 
				
			||||||
 | 
					      state := s_request
 | 
				
			||||||
 | 
					      r_refill_tag := lookup_tag
 | 
				
			||||||
 | 
					      r_refill_waddr := repl_waddr
 | 
				
			||||||
 | 
					      r_req := io.req.bits
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    when (state === s_request) {
 | 
				
			||||||
 | 
					      when (io.ptw.invalidate) {
 | 
				
			||||||
 | 
					        state := s_ready
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      when (io.ptw.req.ready) {
 | 
				
			||||||
 | 
					        state := s_wait
 | 
				
			||||||
 | 
					        when (io.ptw.invalidate) { state := s_wait_invalidate }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    when (state === s_wait && io.ptw.invalidate) {
 | 
				
			||||||
 | 
					      state := s_wait_invalidate
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    when (io.ptw.resp.valid) {
 | 
				
			||||||
 | 
					      state := s_ready
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    when (io.ptw.invalidate) {
 | 
				
			||||||
 | 
					      valid := 0
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class DecoupledTLB(implicit p: Parameters) extends Module {
 | 
				
			||||||
 | 
					  val io = new Bundle {
 | 
				
			||||||
 | 
					    val req = Decoupled(new TLBReq).flip
 | 
				
			||||||
 | 
					    val resp = Decoupled(new TLBResp)
 | 
				
			||||||
 | 
					    val ptw = new TLBPTWIO
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val reqq = Queue(io.req)
 | 
				
			||||||
 | 
					  val tlb = Module(new TLB)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val resp_helper = DecoupledHelper(
 | 
				
			||||||
 | 
					    reqq.valid, tlb.io.req.ready, io.resp.ready)
 | 
				
			||||||
 | 
					  val tlb_miss = tlb.io.resp.miss
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  tlb.io.req.valid := resp_helper.fire(tlb.io.req.ready)
 | 
				
			||||||
 | 
					  tlb.io.req.bits := reqq.bits
 | 
				
			||||||
 | 
					  reqq.ready := resp_helper.fire(reqq.valid, !tlb_miss)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  io.resp.valid := resp_helper.fire(io.resp.ready, !tlb_miss)
 | 
				
			||||||
 | 
					  io.resp.bits := tlb.io.resp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  io.ptw <> tlb.io.ptw
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										179
									
								
								rocket/src/main/scala/util.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										179
									
								
								rocket/src/main/scala/util.scala
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,179 @@
 | 
				
			|||||||
 | 
					// See LICENSE for license details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package rocket
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import Chisel._
 | 
				
			||||||
 | 
					import uncore._
 | 
				
			||||||
 | 
					import scala.math._
 | 
				
			||||||
 | 
					import cde.{Parameters, Field}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					object Util {
 | 
				
			||||||
 | 
					  implicit def uintToBitPat(x: UInt): BitPat = BitPat(x)
 | 
				
			||||||
 | 
					  implicit def intToUInt(x: Int): UInt = UInt(x)
 | 
				
			||||||
 | 
					  implicit def bigIntToUInt(x: BigInt): UInt = UInt(x)
 | 
				
			||||||
 | 
					  implicit def booleanToBool(x: Boolean): Bits = Bool(x)
 | 
				
			||||||
 | 
					  implicit def intSeqToUIntSeq(x: Seq[Int]): Seq[UInt] = x.map(UInt(_))
 | 
				
			||||||
 | 
					  implicit def wcToUInt(c: WideCounter): UInt = c.value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  implicit class UIntToAugmentedUInt(val x: UInt) extends AnyVal {
 | 
				
			||||||
 | 
					    def sextTo(n: Int): UInt =
 | 
				
			||||||
 | 
					      if (x.getWidth == n) x
 | 
				
			||||||
 | 
					      else Cat(Fill(n - x.getWidth, x(x.getWidth-1)), x)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def extract(hi: Int, lo: Int): UInt = {
 | 
				
			||||||
 | 
					      if (hi == lo-1) UInt(0)
 | 
				
			||||||
 | 
					      else x(hi, lo)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  implicit def booleanToIntConv(x: Boolean) = new AnyRef {
 | 
				
			||||||
 | 
					    def toInt: Int = if (x) 1 else 0
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  implicit class SeqToAugmentedSeq[T <: Data](val x: Seq[T]) extends AnyVal {
 | 
				
			||||||
 | 
					    def apply(idx: UInt): T = {
 | 
				
			||||||
 | 
					      if (x.size == 1) {
 | 
				
			||||||
 | 
					        x.head
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        val half = 1 << (log2Ceil(x.size) - 1)
 | 
				
			||||||
 | 
					        val newIdx = idx & (half - 1)
 | 
				
			||||||
 | 
					        Mux(idx >= UInt(half), x.drop(half)(newIdx), x.take(half)(newIdx))
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def toBits(): UInt = Cat(x.map(_.toBits).reverse)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def minUInt(values: Seq[UInt]): UInt =
 | 
				
			||||||
 | 
					    values.reduce((a, b) => Mux(a < b, a, b))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def minUInt(first: UInt, rest: UInt*): UInt =
 | 
				
			||||||
 | 
					    minUInt(first +: rest.toSeq)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import Util._
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					object Str
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  def apply(s: String): UInt = {
 | 
				
			||||||
 | 
					    var i = BigInt(0)
 | 
				
			||||||
 | 
					    require(s.forall(validChar _))
 | 
				
			||||||
 | 
					    for (c <- s)
 | 
				
			||||||
 | 
					      i = (i << 8) | c
 | 
				
			||||||
 | 
					    UInt(i, s.length*8)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  def apply(x: Char): UInt = {
 | 
				
			||||||
 | 
					    require(validChar(x))
 | 
				
			||||||
 | 
					    UInt(x.toInt, 8)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  def apply(x: UInt): UInt = apply(x, 10)
 | 
				
			||||||
 | 
					  def apply(x: UInt, radix: Int): UInt = {
 | 
				
			||||||
 | 
					    val rad = UInt(radix)
 | 
				
			||||||
 | 
					    val w = x.getWidth
 | 
				
			||||||
 | 
					    require(w > 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var q = x
 | 
				
			||||||
 | 
					    var s = digit(q % rad)
 | 
				
			||||||
 | 
					    for (i <- 1 until ceil(log(2)/log(radix)*w).toInt) {
 | 
				
			||||||
 | 
					      q = q / rad
 | 
				
			||||||
 | 
					      s = Cat(Mux(Bool(radix == 10) && q === UInt(0), Str(' '), digit(q % rad)), s)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    s
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  def apply(x: SInt): UInt = apply(x, 10)
 | 
				
			||||||
 | 
					  def apply(x: SInt, radix: Int): UInt = {
 | 
				
			||||||
 | 
					    val neg = x < SInt(0)
 | 
				
			||||||
 | 
					    val abs = x.abs
 | 
				
			||||||
 | 
					    if (radix != 10) {
 | 
				
			||||||
 | 
					      Cat(Mux(neg, Str('-'), Str(' ')), Str(abs, radix))
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      val rad = UInt(radix)
 | 
				
			||||||
 | 
					      val w = abs.getWidth
 | 
				
			||||||
 | 
					      require(w > 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      var q = abs
 | 
				
			||||||
 | 
					      var s = digit(q % rad)
 | 
				
			||||||
 | 
					      var needSign = neg
 | 
				
			||||||
 | 
					      for (i <- 1 until ceil(log(2)/log(radix)*w).toInt) {
 | 
				
			||||||
 | 
					        q = q / rad
 | 
				
			||||||
 | 
					        val placeSpace = q === UInt(0)
 | 
				
			||||||
 | 
					        val space = Mux(needSign, Str('-'), Str(' '))
 | 
				
			||||||
 | 
					        needSign = needSign && !placeSpace
 | 
				
			||||||
 | 
					        s = Cat(Mux(placeSpace, space, digit(q % rad)), s)
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      Cat(Mux(needSign, Str('-'), Str(' ')), s)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private def digit(d: UInt): UInt = Mux(d < UInt(10), Str('0')+d, Str(('a'-10).toChar)+d)(7,0)
 | 
				
			||||||
 | 
					  private def validChar(x: Char) = x == (x & 0xFF)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					object Split
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  // is there a better way to do do this?
 | 
				
			||||||
 | 
					  def apply(x: Bits, n0: Int) = {
 | 
				
			||||||
 | 
					    val w = checkWidth(x, n0)
 | 
				
			||||||
 | 
					    (x(w-1,n0), x(n0-1,0))
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  def apply(x: Bits, n1: Int, n0: Int) = {
 | 
				
			||||||
 | 
					    val w = checkWidth(x, n1, n0)
 | 
				
			||||||
 | 
					    (x(w-1,n1), x(n1-1,n0), x(n0-1,0))
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  def apply(x: Bits, n2: Int, n1: Int, n0: Int) = {
 | 
				
			||||||
 | 
					    val w = checkWidth(x, n2, n1, n0)
 | 
				
			||||||
 | 
					    (x(w-1,n2), x(n2-1,n1), x(n1-1,n0), x(n0-1,0))
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private def checkWidth(x: Bits, n: Int*) = {
 | 
				
			||||||
 | 
					    val w = x.getWidth
 | 
				
			||||||
 | 
					    def decreasing(x: Seq[Int]): Boolean =
 | 
				
			||||||
 | 
					      if (x.tail.isEmpty) true
 | 
				
			||||||
 | 
					      else x.head >= x.tail.head && decreasing(x.tail)
 | 
				
			||||||
 | 
					    require(decreasing(w :: n.toList))
 | 
				
			||||||
 | 
					    w
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// a counter that clock gates most of its MSBs using the LSB carry-out
 | 
				
			||||||
 | 
					case class WideCounter(width: Int, inc: UInt = UInt(1))
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  private val isWide = width > 2*inc.getWidth
 | 
				
			||||||
 | 
					  private val smallWidth = if (isWide) inc.getWidth max log2Up(width) else width
 | 
				
			||||||
 | 
					  private val small = Reg(init=UInt(0, smallWidth))
 | 
				
			||||||
 | 
					  private val nextSmall = small +& inc
 | 
				
			||||||
 | 
					  small := nextSmall
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private val large = if (isWide) {
 | 
				
			||||||
 | 
					    val r = Reg(init=UInt(0, width - smallWidth))
 | 
				
			||||||
 | 
					    when (nextSmall(smallWidth)) { r := r + UInt(1) }
 | 
				
			||||||
 | 
					    r
 | 
				
			||||||
 | 
					  } else null
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val value = if (isWide) Cat(large, small) else small
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def := (x: UInt) = {
 | 
				
			||||||
 | 
					    small := x
 | 
				
			||||||
 | 
					    if (isWide) large := x >> smallWidth
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					object Random
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  def apply(mod: Int, random: UInt): UInt = {
 | 
				
			||||||
 | 
					    if (isPow2(mod)) random(log2Up(mod)-1,0)
 | 
				
			||||||
 | 
					    else PriorityEncoder(partition(apply(1 << log2Up(mod*8), random), mod))
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  def apply(mod: Int): UInt = apply(mod, randomizer)
 | 
				
			||||||
 | 
					  def oneHot(mod: Int, random: UInt): UInt = {
 | 
				
			||||||
 | 
					    if (isPow2(mod)) UIntToOH(random(log2Up(mod)-1,0))
 | 
				
			||||||
 | 
					    else PriorityEncoderOH(partition(apply(1 << log2Up(mod*8), random), mod)).toBits
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  def oneHot(mod: Int): UInt = oneHot(mod, randomizer)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private def randomizer = LFSR16()
 | 
				
			||||||
 | 
					  private def round(x: Double): Int =
 | 
				
			||||||
 | 
					    if (x.toInt.toDouble == x) x.toInt else (x.toInt + 1) & -2
 | 
				
			||||||
 | 
					  private def partition(value: UInt, slices: Int) =
 | 
				
			||||||
 | 
					    Seq.tabulate(slices)(i => value < round((i << value.getWidth).toDouble / slices))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user