2016-09-14 00:26:59 +02:00
|
|
|
// See LICENSE for license details.
|
|
|
|
|
2016-10-04 00:17:36 +02:00
|
|
|
package regmapper
|
2016-09-14 00:26:59 +02:00
|
|
|
|
|
|
|
import Chisel._
|
2016-10-02 09:35:57 +02:00
|
|
|
import chisel3.util.{Irrevocable}
|
2016-10-10 00:51:23 +02:00
|
|
|
import util.{AsyncQueue,AsyncResetRegVec}
|
2016-09-14 00:26:59 +02:00
|
|
|
|
|
|
|
// A very simple flow control state machine, run in the specified clock domain
|
2016-10-07 20:45:20 +02:00
|
|
|
class BusyRegisterCrossing extends Module {
|
2016-09-14 00:26:59 +02:00
|
|
|
val io = new Bundle {
|
2016-10-07 20:45:20 +02:00
|
|
|
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
|
2016-09-14 00:26:59 +02:00
|
|
|
}
|
|
|
|
|
2016-10-07 20:45:20 +02:00
|
|
|
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
|
2016-09-14 00:26:59 +02:00
|
|
|
}
|
2016-10-07 20:45:20 +02:00
|
|
|
|
|
|
|
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
|
2016-09-14 00:26:59 +02:00
|
|
|
}
|
|
|
|
|
2016-10-08 00:06:37 +02:00
|
|
|
class RegisterCrossingAssertion extends Module {
|
|
|
|
val io = new Bundle {
|
|
|
|
val master_bypass = Bool(INPUT)
|
|
|
|
val slave_reset = Bool(INPUT)
|
|
|
|
}
|
|
|
|
|
|
|
|
assert (io.master_bypass || !io.slave_reset)
|
|
|
|
}
|
|
|
|
|
2016-09-14 00:26:59 +02:00
|
|
|
// RegField should support connecting to one of these
|
|
|
|
class RegisterWriteIO[T <: Data](gen: T) extends Bundle {
|
2016-10-07 05:41:21 +02:00
|
|
|
val request = Decoupled(gen).flip
|
2016-09-15 02:43:07 +02:00
|
|
|
val response = Irrevocable(Bool()) // ignore .bits
|
2016-09-14 00:26:59 +02:00
|
|
|
}
|
|
|
|
|
2016-10-07 20:45:20 +02:00
|
|
|
// 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.
|
2016-09-14 00:26:59 +02:00
|
|
|
|
|
|
|
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)
|
2016-10-07 20:45:20 +02:00
|
|
|
// Bypass requests from the master to be noops
|
|
|
|
val master_bypass = Bool(INPUT)
|
2016-09-14 00:26:59 +02:00
|
|
|
// Slave clock domain
|
|
|
|
val slave_clock = Clock(INPUT)
|
|
|
|
val slave_reset = Bool(INPUT)
|
|
|
|
val slave_register = gen.asOutput
|
2016-09-14 09:17:26 +02:00
|
|
|
val slave_valid = Bool(OUTPUT) // is high on 1st cycle slave_register has a new value
|
2016-09-14 00:26:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
2016-10-07 20:45:20 +02:00
|
|
|
val control = Module(new BusyRegisterCrossing)
|
2016-09-14 00:26:59 +02:00
|
|
|
val crossing = Module(new AsyncQueue(gen, 1, sync))
|
|
|
|
|
2016-10-07 20:45:20 +02:00
|
|
|
control.clock := io.master_clock
|
|
|
|
control.reset := io.master_reset
|
2016-09-14 00:26:59 +02:00
|
|
|
crossing.io.enq_clock := io.master_clock
|
2016-09-27 22:36:28 +02:00
|
|
|
crossing.io.enq_reset := io.master_reset
|
2016-09-14 00:26:59 +02:00
|
|
|
crossing.io.deq_clock := io.slave_clock
|
2016-09-27 22:36:28 +02:00
|
|
|
crossing.io.deq_reset := io.slave_reset
|
2016-09-14 00:26:59 +02:00
|
|
|
|
2016-10-07 20:45:20 +02:00
|
|
|
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
|
2016-09-14 00:26:59 +02:00
|
|
|
|
2016-10-07 20:45:20 +02:00
|
|
|
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
|
2016-09-14 00:26:59 +02:00
|
|
|
|
|
|
|
crossing.io.deq.ready := Bool(true)
|
2016-10-07 20:45:20 +02:00
|
|
|
io.slave_valid := crossing.io.deq.valid
|
|
|
|
io.slave_register := crossing.io.deq.bits
|
2016-10-08 00:06:37 +02:00
|
|
|
|
|
|
|
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
|
2016-09-14 00:26:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// RegField should support connecting to one of these
|
|
|
|
class RegisterReadIO[T <: Data](gen: T) extends Bundle {
|
2016-10-07 05:41:21 +02:00
|
|
|
val request = Decoupled(Bool()).flip // ignore .bits
|
2016-09-15 02:43:07 +02:00
|
|
|
val response = Irrevocable(gen)
|
2016-09-14 00:26:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
2016-10-07 20:45:20 +02:00
|
|
|
// Bypass requests from the master to be noops
|
|
|
|
val master_bypass = Bool(INPUT)
|
2016-09-14 00:26:59 +02:00
|
|
|
// 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
|
2016-10-07 20:45:20 +02:00
|
|
|
val control = Module(new BusyRegisterCrossing)
|
2016-09-14 00:26:59 +02:00
|
|
|
val crossing = Module(new AsyncQueue(gen, 1, sync))
|
|
|
|
|
2016-10-07 20:45:20 +02:00
|
|
|
control.clock := io.master_clock
|
|
|
|
control.reset := io.master_reset
|
2016-09-14 00:26:59 +02:00
|
|
|
crossing.io.deq_clock := io.master_clock
|
2016-09-27 22:36:28 +02:00
|
|
|
crossing.io.deq_reset := io.master_reset
|
2016-10-07 20:45:20 +02:00
|
|
|
crossing.io.enq_clock := io.slave_clock
|
|
|
|
crossing.io.enq_reset := io.slave_reset
|
2016-09-14 00:26:59 +02:00
|
|
|
|
2016-10-07 20:45:20 +02:00
|
|
|
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
|
2016-09-14 00:26:59 +02:00
|
|
|
|
2016-10-07 20:45:20 +02:00
|
|
|
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
|
2016-09-14 00:26:59 +02:00
|
|
|
|
|
|
|
crossing.io.enq.valid := Bool(true)
|
2016-10-07 20:45:20 +02:00
|
|
|
crossing.io.enq.bits := io.slave_register
|
2016-10-08 00:06:37 +02:00
|
|
|
|
|
|
|
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
|
2016-09-14 00:26:59 +02:00
|
|
|
}
|
2016-09-15 01:30:59 +02:00
|
|
|
|
|
|
|
/** Wrapper to create an
|
2016-09-27 22:36:28 +02:00
|
|
|
* 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.
|
2016-09-15 01:30:59 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
object AsyncRWSlaveRegField {
|
|
|
|
|
2016-10-10 00:51:23 +02:00
|
|
|
def apply(
|
|
|
|
master_clock: Clock,
|
|
|
|
master_reset: Bool,
|
|
|
|
slave_clock: Clock,
|
2016-09-15 01:30:59 +02:00
|
|
|
slave_reset: Bool,
|
|
|
|
width: Int,
|
|
|
|
init: Int,
|
2016-10-01 01:19:25 +02:00
|
|
|
name: Option[String] = None,
|
2016-10-07 20:45:20 +02:00
|
|
|
master_bypass: Bool = Bool(true)
|
2016-09-15 01:30:59 +02:00
|
|
|
): (UInt, RegField) = {
|
|
|
|
|
|
|
|
val async_slave_reg = Module(new AsyncResetRegVec(width, init))
|
2016-10-01 01:19:25 +02:00
|
|
|
name.foreach(async_slave_reg.suggestName(_))
|
2016-09-15 01:30:59 +02:00
|
|
|
async_slave_reg.reset := slave_reset
|
|
|
|
async_slave_reg.clock := slave_clock
|
|
|
|
|
|
|
|
val wr_crossing = Module (new RegisterWriteCrossing(UInt(width = width)))
|
2016-10-01 01:19:25 +02:00
|
|
|
name.foreach(n => wr_crossing.suggestName(s"${n}_wcrossing"))
|
2016-09-15 01:30:59 +02:00
|
|
|
|
2016-10-07 20:45:20 +02:00
|
|
|
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
|
2016-09-15 01:30:59 +02:00
|
|
|
|
|
|
|
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 )))
|
2016-10-01 01:19:25 +02:00
|
|
|
name.foreach(n => rd_crossing.suggestName(s"${n}_rcrossing"))
|
2016-09-15 01:30:59 +02:00
|
|
|
|
2016-10-07 20:45:20 +02:00
|
|
|
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
|
2016-09-15 01:30:59 +02:00
|
|
|
|
|
|
|
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))
|
|
|
|
}
|
|
|
|
}
|