186 lines
6.1 KiB
Scala
186 lines
6.1 KiB
Scala
// See LICENSE.jtag for license details.
|
|
|
|
package jtag
|
|
|
|
import chisel3._
|
|
import chisel3.core.DataMirror
|
|
import chisel3.internal.firrtl.KnownWidth
|
|
import chisel3.util._
|
|
|
|
/** Base JTAG shifter IO, viewed from input to shift register chain.
|
|
* Can be chained together.
|
|
*/
|
|
class ShifterIO extends Bundle {
|
|
val shift = Bool() // advance the scan chain on clock high
|
|
val data = Bool() // as input: bit to be captured into shifter MSB on next rising edge; as output: value of shifter LSB
|
|
val capture = Bool() // high in the CaptureIR/DR state when this chain is selected
|
|
val update = Bool() // high in the UpdateIR/DR state when this chain is selected
|
|
|
|
/** Sets a output shifter IO's control signals from a input shifter IO's control signals.
|
|
*/
|
|
def chainControlFrom(in: ShifterIO) {
|
|
shift := in.shift
|
|
capture := in.capture
|
|
update := in.update
|
|
}
|
|
}
|
|
|
|
trait ChainIO extends Bundle {
|
|
val chainIn = Input(new ShifterIO)
|
|
val chainOut = Output(new ShifterIO)
|
|
}
|
|
|
|
class Capture[+T <: Data](gen: T) extends Bundle {
|
|
val bits = Input(gen) // data to capture, should be always valid
|
|
val capture = Output(Bool()) // will be high in capture state (single cycle), captured on following rising edge
|
|
override def cloneType = Capture(gen).asInstanceOf[this.type]
|
|
}
|
|
|
|
object Capture {
|
|
def apply[T <: Data](gen: T): Capture[T] = new Capture(gen)
|
|
}
|
|
|
|
/** Trait that all JTAG chains (data and instruction registers) must extend, providing basic chain
|
|
* IO.
|
|
*/
|
|
trait Chain extends Module {
|
|
val io: ChainIO
|
|
}
|
|
|
|
/** One-element shift register, data register for bypass mode.
|
|
*
|
|
* Implements Clause 10.
|
|
*/
|
|
class JtagBypassChain extends Chain {
|
|
class ModIO extends ChainIO
|
|
val io = IO(new ModIO)
|
|
io.chainOut chainControlFrom io.chainIn
|
|
|
|
val reg = Reg(Bool()) // 10.1.1a single shift register stage
|
|
|
|
io.chainOut.data := reg
|
|
|
|
when (io.chainIn.capture) {
|
|
reg := false.B // 10.1.1b capture logic 0 on TCK rising
|
|
} .elsewhen (io.chainIn.shift) {
|
|
reg := io.chainIn.data
|
|
}
|
|
assert(!(io.chainIn.capture && io.chainIn.update)
|
|
&& !(io.chainIn.capture && io.chainIn.shift)
|
|
&& !(io.chainIn.update && io.chainIn.shift))
|
|
}
|
|
|
|
object JtagBypassChain {
|
|
def apply() = new JtagBypassChain
|
|
}
|
|
|
|
/** Simple shift register with parallel capture only, for read-only data registers.
|
|
*
|
|
* Number of stages is the number of bits in gen, which must have a known width.
|
|
*
|
|
* Useful notes:
|
|
* 7.2.1c shifter shifts on TCK rising edge
|
|
* 4.3.2a TDI captured on TCK rising edge, 6.1.2.1b assumed changes on TCK falling edge
|
|
*/
|
|
class CaptureChain[+T <: Data](gen: T) extends Chain {
|
|
class ModIO extends ChainIO {
|
|
val capture = Capture(gen)
|
|
}
|
|
val io = IO(new ModIO)
|
|
io.chainOut chainControlFrom io.chainIn
|
|
|
|
val n = DataMirror.widthOf(gen) match {
|
|
case KnownWidth(x) => x
|
|
case _ => require(false, s"can't generate chain for unknown width data type $gen"); -1 // TODO: remove -1 type hack
|
|
}
|
|
|
|
val regs = (0 until n) map (x => Reg(Bool()))
|
|
|
|
io.chainOut.data := regs(0)
|
|
|
|
when (io.chainIn.capture) {
|
|
(0 until n) map (x => regs(x) := io.capture.bits.asUInt()(x))
|
|
io.capture.capture := true.B
|
|
} .elsewhen (io.chainIn.shift) {
|
|
regs(n-1) := io.chainIn.data
|
|
(0 until n-1) map (x => regs(x) := regs(x+1))
|
|
io.capture.capture := false.B
|
|
} .otherwise {
|
|
io.capture.capture := false.B
|
|
}
|
|
assert(!(io.chainIn.capture && io.chainIn.update)
|
|
&& !(io.chainIn.capture && io.chainIn.shift)
|
|
&& !(io.chainIn.update && io.chainIn.shift))
|
|
}
|
|
|
|
object CaptureChain {
|
|
def apply[T <: Data](gen: T) = new CaptureChain(gen)
|
|
}
|
|
|
|
/** Simple shift register with parallel capture and update. Useful for general instruction and data
|
|
* scan registers.
|
|
*
|
|
* Number of stages is the max number of bits in genCapture and genUpdate, both of which must have
|
|
* known widths. If there is a width mismatch, the unused most significant bits will be zero.
|
|
*
|
|
* Useful notes:
|
|
* 7.2.1c shifter shifts on TCK rising edge
|
|
* 4.3.2a TDI captured on TCK rising edge, 6.1.2.1b assumed changes on TCK falling edge
|
|
*/
|
|
class CaptureUpdateChain[+T <: Data, +V <: Data](genCapture: T, genUpdate: V) extends Chain {
|
|
class ModIO extends ChainIO {
|
|
val capture = Capture(genCapture)
|
|
val update = Valid(genUpdate) // valid high when in update state (single cycle), contents may change any time after
|
|
}
|
|
val io = IO(new ModIO)
|
|
io.chainOut chainControlFrom io.chainIn
|
|
|
|
val captureWidth = DataMirror.widthOf(genCapture) match {
|
|
case KnownWidth(x) => x
|
|
case _ => require(false, s"can't generate chain for unknown width data type $genCapture"); -1 // TODO: remove -1 type hack
|
|
}
|
|
val updateWidth = DataMirror.widthOf(genUpdate) match {
|
|
case KnownWidth(x) => x
|
|
case _ => require(false, s"can't generate chain for unknown width data type $genUpdate"); -1 // TODO: remove -1 type hack
|
|
}
|
|
val n = math.max(captureWidth, updateWidth)
|
|
|
|
val regs = (0 until n) map (x => Reg(Bool()))
|
|
|
|
io.chainOut.data := regs(0)
|
|
|
|
val updateBits = Cat(regs.reverse)(updateWidth-1, 0)
|
|
io.update.bits := io.update.bits.fromBits(updateBits)
|
|
|
|
val captureBits = io.capture.bits.asUInt()
|
|
|
|
when (io.chainIn.capture) {
|
|
(0 until math.min(n, captureWidth)) map (x => regs(x) := captureBits(x))
|
|
(captureWidth until n) map (x => regs(x) := 0.U)
|
|
io.capture.capture := true.B
|
|
io.update.valid := false.B
|
|
} .elsewhen (io.chainIn.update) {
|
|
io.capture.capture := false.B
|
|
io.update.valid := true.B
|
|
} .elsewhen (io.chainIn.shift) {
|
|
regs(n-1) := io.chainIn.data
|
|
(0 until n-1) map (x => regs(x) := regs(x+1))
|
|
io.capture.capture := false.B
|
|
io.update.valid := false.B
|
|
} .otherwise {
|
|
io.capture.capture := false.B
|
|
io.update.valid := false.B
|
|
}
|
|
assert(!(io.chainIn.capture && io.chainIn.update)
|
|
&& !(io.chainIn.capture && io.chainIn.shift)
|
|
&& !(io.chainIn.update && io.chainIn.shift))
|
|
}
|
|
|
|
object CaptureUpdateChain {
|
|
/** Capture-update chain with matching capture and update types.
|
|
*/
|
|
def apply[T <: Data](gen: T) = new CaptureUpdateChain(gen, gen)
|
|
def apply[T <: Data, V <: Data](genCapture: T, genUpdate: V) =
|
|
new CaptureUpdateChain(genCapture, genUpdate)
|
|
}
|