// See LICENSE.SiFive for license details. package freechips.rocketchip.regmapper import Chisel._ import chisel3.util.{Irrevocable} import freechips.rocketchip.util.{AsyncQueue,AsyncResetRegVec} // A very simple flow control state machine, run in the specified clock domain class BusyRegisterCrossing extends Module { val io = new Bundle { val bypass = Bool(INPUT) val master_request_valid = Bool(INPUT) val master_request_ready = Bool(OUTPUT) val master_response_valid = Bool(OUTPUT) val master_response_ready = Bool(INPUT) val crossing_request_valid = Bool(OUTPUT) val crossing_request_ready = Bool(INPUT) // ... no crossing_response_ready; we are always ready } val busy = RegInit(Bool(false)) val bypass = Reg(Bool()) when (io.crossing_request_ready || Mux(busy, bypass, io.bypass)) { busy := Mux(busy, !io.master_response_ready, io.master_request_valid) } when (io.master_request_valid && io.master_request_ready) { bypass := io.bypass } io.crossing_request_valid := io.master_request_valid && !io.bypass && !busy io.master_request_ready := (io.bypass || io.crossing_request_ready) && !busy io.master_response_valid := (bypass || io.crossing_request_ready) && busy } class RegisterCrossingAssertion extends Module { val io = new Bundle { val master_bypass = Bool(INPUT) val slave_reset = Bool(INPUT) } val up = RegInit(Bool(false)) up := !io.slave_reset assert (io.master_bypass || !up || !io.slave_reset) } // RegField should support connecting to one of these class RegisterWriteIO[T <: Data](gen: T) extends Bundle { val request = Decoupled(gen).flip val response = Irrevocable(Bool()) // ignore .bits override def cloneType = new RegisterWriteIO(gen).asInstanceOf[this.type] } // To turn off=>on a domain: // A. To turn disable the master domain // 1. wait for all inflight traffic to resolve // 2. assert master reset // 3. (optional) stop the master clock // --- YOU MAY NOT TURN OFF POWER --- // 4. re-enable the clock // 5. deassert reset // B. To turn off the slave domain // 1. assert bypass // 2. wait for inflight traffic to resolve // 3. assert slave reset // 4. (optional) stop the slave clock // --- YOU MAY NOT TURN OFF POWER --- // 5. re-enable the clock // 6. deassert reset // 7. deassert bypass // // If you need to cut power, use something that support isolation gates. class RegisterWriteCrossingIO[T <: Data](gen: T) extends Bundle { // Master clock domain val master_clock = Clock(INPUT) val master_reset = Bool(INPUT) val master_port = new RegisterWriteIO(gen) // Bypass requests from the master to be noops val master_bypass = Bool(INPUT) // Slave clock domain val slave_clock = Clock(INPUT) val slave_reset = Bool(INPUT) val slave_register = gen.asOutput val slave_valid = Bool(OUTPUT) // is high on 1st cycle slave_register has a new value } class RegisterWriteCrossing[T <: Data](gen: T, sync: Int = 3) extends Module { val io = new RegisterWriteCrossingIO(gen) // The crossing must only allow one item inflight at a time val control = Module(new BusyRegisterCrossing) val crossing = Module(new AsyncQueue(gen, 1, sync, safe=false)) control.clock := io.master_clock control.reset := io.master_reset crossing.io.enq_clock := io.master_clock crossing.io.enq_reset := io.master_reset crossing.io.deq_clock := io.slave_clock crossing.io.deq_reset := io.slave_reset control.io.bypass := io.master_bypass control.io.master_request_valid := io.master_port.request.valid control.io.master_response_ready := io.master_port.response.ready io.master_port.request.ready := control.io.master_request_ready io.master_port.response.valid := control.io.master_response_valid control.io.crossing_request_ready := crossing.io.enq.ready crossing.io.enq.valid := control.io.crossing_request_valid crossing.io.enq.bits := io.master_port.request.bits crossing.io.deq.ready := Bool(true) io.slave_valid := crossing.io.deq.valid io.slave_register := crossing.io.deq.bits val assertion = Module(new RegisterCrossingAssertion) assertion.clock := io.master_clock assertion.reset := io.master_reset assertion.io.master_bypass := io.master_bypass assertion.io.slave_reset := io.slave_reset } // RegField should support connecting to one of these class RegisterReadIO[T <: Data](gen: T) extends Bundle { val request = Decoupled(Bool()).flip // ignore .bits val response = Irrevocable(gen) override def cloneType = new RegisterReadIO(gen).asInstanceOf[this.type] } class RegisterReadCrossingIO[T <: Data](gen: T) extends Bundle { // Master clock domain val master_clock = Clock(INPUT) val master_reset = Bool(INPUT) val master_port = new RegisterReadIO(gen) // Bypass requests from the master to be noops val master_bypass = Bool(INPUT) // Slave clock domain val slave_clock = Clock(INPUT) val slave_reset = Bool(INPUT) val slave_register = gen.asInput } class RegisterReadCrossing[T <: Data](gen: T, sync: Int = 3) extends Module { val io = new RegisterReadCrossingIO(gen) // The crossing must only allow one item inflight at a time val control = Module(new BusyRegisterCrossing) val crossing = Module(new AsyncQueue(gen, 1, sync, safe=false)) control.clock := io.master_clock control.reset := io.master_reset crossing.io.deq_clock := io.master_clock crossing.io.deq_reset := io.master_reset crossing.io.enq_clock := io.slave_clock crossing.io.enq_reset := io.slave_reset control.io.bypass := io.master_bypass control.io.master_request_valid := io.master_port.request.valid control.io.master_response_ready := io.master_port.response.ready io.master_port.request.ready := control.io.master_request_ready io.master_port.response.valid := control.io.master_response_valid control.io.crossing_request_ready := crossing.io.deq.valid crossing.io.deq.ready := control.io.crossing_request_valid io.master_port.response.bits := crossing.io.deq.bits crossing.io.enq.valid := Bool(true) crossing.io.enq.bits := io.slave_register val assertion = Module(new RegisterCrossingAssertion) assertion.clock := io.master_clock assertion.reset := io.master_reset assertion.io.master_bypass := io.master_bypass assertion.io.slave_reset := io.slave_reset } /** Wrapper to create an * asynchronously reset slave register which can be * both read and written * using crossing FIFOs. * The reset and allow assertion & de-assertion * should be synchronous to their respective * domains. */ object AsyncRWSlaveRegField { def apply( master_clock: Clock, master_reset: Bool, slave_clock: Clock, slave_reset: Bool, width: Int, init: Int, name: Option[String] = None, master_bypass: Bool = Bool(true) ): (UInt, RegField) = { val async_slave_reg = Module(new AsyncResetRegVec(width, init)) name.foreach(async_slave_reg.suggestName(_)) async_slave_reg.reset := slave_reset async_slave_reg.clock := slave_clock val wr_crossing = Module (new RegisterWriteCrossing(UInt(width = width))) name.foreach(n => wr_crossing.suggestName(s"${n}_wcrossing")) wr_crossing.io.master_clock := master_clock wr_crossing.io.master_reset := master_reset wr_crossing.io.master_bypass := master_bypass wr_crossing.io.slave_clock := slave_clock wr_crossing.io.slave_reset := slave_reset async_slave_reg.io.en := wr_crossing.io.slave_valid async_slave_reg.io.d := wr_crossing.io.slave_register val rd_crossing = Module (new RegisterReadCrossing(UInt(width = width ))) name.foreach(n => rd_crossing.suggestName(s"${n}_rcrossing")) rd_crossing.io.master_clock := master_clock rd_crossing.io.master_reset := master_reset rd_crossing.io.master_bypass := master_bypass rd_crossing.io.slave_clock := slave_clock rd_crossing.io.slave_reset := slave_reset rd_crossing.io.slave_register := async_slave_reg.io.q (async_slave_reg.io.q, RegField(width, rd_crossing.io.master_port, wr_crossing.io.master_port)) } }