1
0
rocket-chip/src/main/scala/regmapper/RegisterCrossing.scala
Wesley W. Terpstra 8c7d469a95 Revert "async_queue: Give names to all the registers which show up in the queue (#390)"
This reverts commit a84a961a39.

The changes to RegisterCrossing.scala were unneeded after application of this branch.
The name changes made to the AsyncQueue.scala are reapplied at the end of this branch.
2016-10-10 13:13:31 -07:00

191 lines
6.9 KiB
Scala

// See LICENSE for license details.
package regmapper
import Chisel._
import chisel3.util.{Irrevocable}
import util.{AsyncQueue,AsyncResetRegVec}
// A very simple flow control state machine, run in the specified clock domain
class BusyRegisterCrossing(clock: Clock, reset: Bool)
extends Module(_clock = clock, _reset = reset) {
val io = new Bundle {
val progress = Bool(INPUT)
val request_valid = Bool(INPUT)
val response_ready = Bool(INPUT)
val busy = Bool(OUTPUT)
}
val busy = RegInit(Bool(false))
when (io.progress) {
busy := Mux(busy, !io.response_ready, io.request_valid)
}
io.busy := busy
}
// 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
}
// To turn on/off a domain:
// 1. lower allow on the other side
// 2. wait for inflight traffic to resolve
// 3. assert reset in the domain
// 4. turn off the domain
// 5. turn on the domain
// 6. deassert reset in the domain
// 7. raise allow on the other side
class RegisterWriteCrossingIO[T <: Data](gen: T) extends Bundle {
// Master clock domain
val master_clock = Clock(INPUT)
val master_reset = Bool(INPUT)
val master_allow = Bool(INPUT) // actually wait for the slave
val master_port = new RegisterWriteIO(gen)
// Slave clock domain
val slave_clock = Clock(INPUT)
val slave_reset = Bool(INPUT)
val slave_allow = Bool(INPUT) // honour requests from the master
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 crossing = Module(new AsyncQueue(gen, 1, sync))
// We can just randomly reset one-side of a single entry AsyncQueue.
// If the enq side is reset, at worst deq.bits is reassigned from mem(0), which stays fixed.
// If the deq side is reset, at worst the master rewrites mem(0) once, deq.bits stays fixed.
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
crossing.io.enq.bits := io.master_port.request.bits
io.slave_register := crossing.io.deq.bits
io.slave_valid := crossing.io.deq.valid
// If the slave is not operational, just drop the write.
val progress = crossing.io.enq.ready || !io.master_allow
val reg = Module(new BusyRegisterCrossing(io.master_clock, io.master_reset))
reg.io.progress := progress
reg.io.request_valid := io.master_port.request.valid
reg.io.response_ready := io.master_port.response.ready
crossing.io.deq.ready := Bool(true)
crossing.io.enq.valid := io.master_port.request.valid && !reg.io.busy
io.master_port.request.ready := progress && !reg.io.busy
io.master_port.response.valid := progress && reg.io.busy
}
// 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)
}
class RegisterReadCrossingIO[T <: Data](gen: T) extends Bundle {
// Master clock domain
val master_clock = Clock(INPUT)
val master_reset = Bool(INPUT)
val master_allow = Bool(INPUT) // actually wait for the slave
val master_port = new RegisterReadIO(gen)
// Slave clock domain
val slave_clock = Clock(INPUT)
val slave_reset = Bool(INPUT)
val slave_allow = Bool(INPUT) // honour requests from the master
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 crossing = Module(new AsyncQueue(gen, 1, sync))
// We can just randomly reset one-side of a single entry AsyncQueue.
// If the enq side is reset, at worst deq.bits is reassigned from mem(0), which stays fixed.
// If the deq side is reset, at worst the slave rewrites mem(0) once, deq.bits stays fixed.
crossing.io.enq_clock := io.slave_clock
crossing.io.enq_reset := io.slave_reset
crossing.io.deq_clock := io.master_clock
crossing.io.deq_reset := io.master_reset
crossing.io.enq.bits := io.slave_register
io.master_port.response.bits := crossing.io.deq.bits
// If the slave is not operational, just repeat the last value we saw.
val progress = crossing.io.deq.valid || !io.master_allow
val reg = Module(new BusyRegisterCrossing(io.master_clock, io.master_reset))
reg.io.progress := progress
reg.io.request_valid := io.master_port.request.valid
reg.io.response_ready := io.master_port.response.ready
io.master_port.response.valid := progress && reg.io.busy
io.master_port.request.ready := progress && !reg.io.busy
crossing.io.deq.ready := io.master_port.request.valid && !reg.io.busy
crossing.io.enq.valid := Bool(true)
}
/** 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_allow: Bool = Bool(true),
slave_allow: 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_allow := master_allow
wr_crossing.io.slave_clock := slave_clock
wr_crossing.io.slave_reset := slave_reset
wr_crossing.io.slave_allow := slave_allow
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_allow := master_allow
rd_crossing.io.slave_clock := slave_clock
rd_crossing.io.slave_reset := slave_reset
rd_crossing.io.slave_allow := slave_allow
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))
}
}