// See LICENSE.jtag for license details. package jtag import util.{AsyncResetRegVec} import chisel3._ import chisel3.util._ object JtagState { sealed abstract class State(val id: Int) { def U: UInt = id.U(State.width.W) } object State { import scala.language.implicitConversions implicit def toInt(x: State) = x.id implicit def toBigInt(x: State):BigInt = x.id // TODO: this could be automatically generated with macros and stuff val all: Set[State] = Set( TestLogicReset, RunTestIdle, SelectDRScan, CaptureDR, ShiftDR, Exit1DR, PauseDR, Exit2DR, UpdateDR, SelectIRScan, CaptureIR, ShiftIR, Exit1IR, PauseIR, Exit2IR, UpdateIR ) val width = log2Up(all.size) def chiselType() = UInt(width.W) } // States as described in 6.1.1.2, numeric assignments from example in Table 6-3 case object TestLogicReset extends State(15) // no effect on system logic, entered when TMS high for 5 TCK rising edges case object RunTestIdle extends State(12) // runs active instruction (which can be idle) case object SelectDRScan extends State(7) case object CaptureDR extends State(6) // parallel-load DR shifter when exiting this state (if required) case object ShiftDR extends State(2) // shifts DR shifter from TDI towards TDO, last shift occurs on rising edge transition out of this state case object Exit1DR extends State(1) case object PauseDR extends State(3) // pause DR shifting case object Exit2DR extends State(0) case object UpdateDR extends State(5) // parallel-load output from DR shifter on TCK falling edge while in this state (not a rule?) case object SelectIRScan extends State(4) case object CaptureIR extends State(14) // parallel-load IR shifter with fixed logic values and design-specific when exiting this state (if required) case object ShiftIR extends State(10) // shifts IR shifter from TDI towards TDO, last shift occurs on rising edge transition out of this state case object Exit1IR extends State(9) case object PauseIR extends State(11) // pause IR shifting case object Exit2IR extends State(8) case object UpdateIR extends State(13) // latch IR shifter into IR (changes to IR may only occur while in this state, latch on TCK falling edge) } /** The JTAG state machine, implements spec 6.1.1.1a (Figure 6.1) * * Usage notes: * - 6.1.1.1b state transitions occur on TCK rising edge * - 6.1.1.1c actions can occur on the following TCK falling or rising edge * * */ class JtagStateMachine extends Module(override_reset=Some(false.B)) { class StateMachineIO extends Bundle { val tms = Input(Bool()) val currState = Output(JtagState.State.chiselType()) val jtag_reset = Input(Bool()) } val io = IO(new StateMachineIO) val nextState = Wire(JtagState.State.chiselType()) val currStateReg = Module (new AsyncResetRegVec(w = JtagState.State.width, init = JtagState.State.toInt(JtagState.TestLogicReset))) currStateReg.clock := clock currStateReg.reset := io.jtag_reset currStateReg.io.en := true.B currStateReg.io.d := nextState val currState = currStateReg.io.q switch (currState) { is (JtagState.TestLogicReset.U) { nextState := Mux(io.tms, JtagState.TestLogicReset.U, JtagState.RunTestIdle.U) } is (JtagState.RunTestIdle.U) { nextState := Mux(io.tms, JtagState.SelectDRScan.U, JtagState.RunTestIdle.U) } is (JtagState.SelectDRScan.U) { nextState := Mux(io.tms, JtagState.SelectIRScan.U, JtagState.CaptureDR.U) } is (JtagState.CaptureDR.U) { nextState := Mux(io.tms, JtagState.Exit1DR.U, JtagState.ShiftDR.U) } is (JtagState.ShiftDR.U) { nextState := Mux(io.tms, JtagState.Exit1DR.U, JtagState.ShiftDR.U) } is (JtagState.Exit1DR.U) { nextState := Mux(io.tms, JtagState.UpdateDR.U, JtagState.PauseDR.U) } is (JtagState.PauseDR.U) { nextState := Mux(io.tms, JtagState.Exit2DR.U, JtagState.PauseDR.U) } is (JtagState.Exit2DR.U) { nextState := Mux(io.tms, JtagState.UpdateDR.U, JtagState.ShiftDR.U) } is (JtagState.UpdateDR.U) { nextState := Mux(io.tms, JtagState.SelectDRScan.U, JtagState.RunTestIdle.U) } is (JtagState.SelectIRScan.U) { nextState := Mux(io.tms, JtagState.TestLogicReset.U, JtagState.CaptureIR.U) } is (JtagState.CaptureIR.U) { nextState := Mux(io.tms, JtagState.Exit1IR.U, JtagState.ShiftIR.U) } is (JtagState.ShiftIR.U) { nextState := Mux(io.tms, JtagState.Exit1IR.U, JtagState.ShiftIR.U) } is (JtagState.Exit1IR.U) { nextState := Mux(io.tms, JtagState.UpdateIR.U, JtagState.PauseIR.U) } is (JtagState.PauseIR.U) { nextState := Mux(io.tms, JtagState.Exit2IR.U, JtagState.PauseIR.U) } is (JtagState.Exit2IR.U) { nextState := Mux(io.tms, JtagState.UpdateIR.U, JtagState.ShiftIR.U) } is (JtagState.UpdateIR.U) { nextState := Mux(io.tms, JtagState.SelectDRScan.U, JtagState.RunTestIdle.U) } } io.currState := currState }