From b2448ba50ecddbf8d2278e290499aca84d6b1486 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 31 Jan 2022 15:53:36 +0100 Subject: [PATCH] soc/cores/jtag: Review/Cleanup JTAGTAPFSM and avoid specific CorrectedOngoingResetFSM. --- litex/gen/fhdl/fsm.py | 37 --------- litex/soc/cores/jtag.py | 179 ++++++++++++++++++++++++++++------------ 2 files changed, 126 insertions(+), 90 deletions(-) delete mode 100644 litex/gen/fhdl/fsm.py diff --git a/litex/gen/fhdl/fsm.py b/litex/gen/fhdl/fsm.py deleted file mode 100644 index 2c849a8ce..000000000 --- a/litex/gen/fhdl/fsm.py +++ /dev/null @@ -1,37 +0,0 @@ -# -# This file is part of LiteX. -# -# Copyright (c) 2021 Jevin Sweval -# SPDX-License-Identifier: BSD-2-Clause - -from collections import OrderedDict - -from migen.genlib.fsm import FSM - - - -class CorrectedOngoingResetFSM(FSM): - """ - This wrapper is needed for FSMs where an ongoing signal from the FSM's reset state is used. - - With the existing FSM, on SoC reset the FSM will be in the reset state - but its ongoing signal will not be asserted because the existing FSM - does not set the reset values of the ongoing signals. - """ - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self.ongoing_signals = OrderedDict() - - def ongoing(self, state, *args, **kwargs): - is_ongoing = super().ongoing(state, *args, **kwargs) - self.ongoing_signals[state] = is_ongoing - return is_ongoing - - def do_finalize(self, *args, **kwargs): - for state, is_ongoing in self.ongoing_signals.items(): - is_ongoing.reset = 1 if state == self.reset_state else 0 - if is_ongoing.reset.value: - # since the default is high, must explicitly deassert in all other states - for other_state in set(self.actions) - set([state]): - self.actions[other_state].append(is_ongoing.eq(0)) - super().do_finalize(*args, **kwargs) diff --git a/litex/soc/cores/jtag.py b/litex/soc/cores/jtag.py index 9e0627618..f24ac030a 100644 --- a/litex/soc/cores/jtag.py +++ b/litex/soc/cores/jtag.py @@ -1,7 +1,7 @@ # # This file is part of LiteX. # -# Copyright (c) 2019 Florent Kermarrec +# Copyright (c) 2019-2022 Florent Kermarrec # Copyright (c) 2019 Antti Lukats # Copyright (c) 2017 Robert Jordens # Copyright (c) 2021 Gregory Davill @@ -18,70 +18,143 @@ from litex.soc.interconnect import stream # JTAG TAP FSM ------------------------------------------------------------------------------------- class JTAGTAPFSM(Module): - def __init__(self, tms: Signal, tck: Signal, expose_signals=True): - self.submodules.fsm = fsm = ClockDomainsRenamer("jtag")(CorrectedOngoingResetFSM()) + def __init__(self, tms): + self.submodules.fsm = fsm = FSM(reset_state="TEST_LOGIC_RESET") - fsm.act("test_logic_reset", - If(~tms, NextState("run_test_idle")) - ) - fsm.act("run_test_idle", - If( tms, NextState("select_dr_scan")) + def JTAGTAPFSMState(name, transitions={}): + logic = [] + + # Transitions logic. + nextstates = {} + nextstates[0] = NextState(transitions.get(0, name)) + nextstates[1] = NextState(transitions.get(1, name)) + logic.append(Case(tms, nextstates)) + + # Ongoing logic. + ongoing = Signal() + setattr(self, name, ongoing) + logic.append(ongoing.eq(1)) + + # Add logic to state. + fsm.act(name, *logic) + + # Test-Logic-Reset. + # ----------------- + JTAGTAPFSMState( + name = "TEST_LOGIC_RESET", + transitions = { + 0 : "RUN_TEST_IDLE", + } ) - # DR - fsm.act("select_dr_scan", - If(~tms, NextState("capture_dr") ).Else(NextState("select_ir_scan")) - ) - fsm.act("capture_dr", - If(~tms, NextState("shift_dr") ).Else(NextState("exit1_dr")) - ) - fsm.act("shift_dr", - If( tms, NextState("exit1_dr")) - ) - fsm.act("exit1_dr", - If(~tms, NextState("pause_dr") ).Else(NextState("update_dr")) - ) - fsm.act("pause_dr", - If( tms, NextState("exit2_dr")) - ) - fsm.act("exit2_dr", - If( tms, NextState("update_dr") ).Else(NextState("shift_dr")) - ) - fsm.act("update_dr", - If( tms, NextState("select_dr_scan")).Else(NextState("run_test_idle")) + # Run-Test/Idle. + # -------------- + JTAGTAPFSMState( + name = "RUN_TEST_IDLE", + transitions = { + 1 : "SELECT_DR_SCAN", + } ) - # IR - fsm.act("select_ir_scan", - If(~tms, NextState("capture_ir") ).Else(NextState("test_logic_reset")) + # DR-Scan. + # -------- + JTAGTAPFSMState( + name = "SELECT_DR_SCAN", + transitions = { + 0 : "CAPTURE_DR", + 1 : "SELECT_IR_SCAN", + } ) - fsm.act("capture_ir", - If(~tms, NextState("shift_ir") ).Else(NextState("exit1_ir")) + JTAGTAPFSMState( + name = "CAPTURE_DR", + transitions = { + 0 : "SHIFT_DR", + 1 : "EXIT1_DR", + } ) - fsm.act("shift_ir", - If( tms, NextState("exit1_ir")) + JTAGTAPFSMState( + name = "SHIFT_DR", + transitions = { + 1 : "EXIT1_DR", + } ) - fsm.act("exit1_ir", - If(~tms, NextState("pause_ir") ).Else(NextState("update_ir")) + JTAGTAPFSMState( + name = "EXIT1_DR", + transitions = { + 0 : "PAUSE_DR", + 1 : "UPDATE_DR", + } ) - fsm.act("pause_ir", - If( tms, NextState("exit2_ir")) + JTAGTAPFSMState( + name = "PAUSE_DR", + transitions = { + 1 : "EXIT2_DR", + } ) - fsm.act("exit2_ir", - If( tms, NextState("update_ir") ).Else(NextState("shift_ir")) + JTAGTAPFSMState( + name = "EXIT2_DR", + transitions = { + 0 : "SHIFT_DR", + 1 : "UPDATE_DR", + } ) - fsm.act("update_ir", - If( tms, NextState("select_dr_scan")).Else(NextState("run_test_idle")) + JTAGTAPFSMState( + name = "UPDATE_DR", + transitions = { + 0 : "RUN_TEST_IDLE", + 1 : "SELECT_DR_SCAN", + } ) - if expose_signals: - for state_name in fsm.actions: - state_sig = fsm.ongoing(state_name) - SHOUTING_NAME = state_name.upper() - shouting_sig = Signal(name=SHOUTING_NAME) - setattr(self, SHOUTING_NAME, shouting_sig) - self.comb += shouting_sig.eq(state_sig) - + # IR-Scan. + # -------- + JTAGTAPFSMState( + name = "SELECT_IR_SCAN", + transitions = { + 0 : "CAPTURE_IR", + 1 : "TEST_LOGIC_RESET", + } + ) + JTAGTAPFSMState( + name = "CAPTURE_IR", + transitions = { + 0 : "SHIFT_IR", + 1 : "EXIT1_IR", + } + ) + JTAGTAPFSMState( + name = "SHIFT_IR", + transitions = { + 1 : "EXIT1_IR", + } + ) + JTAGTAPFSMState( + name = "EXIT1_IR", + transitions = { + 0 : "PAUSE_IR", + 1 : "UPDATE_IR", + } + ) + JTAGTAPFSMState( + name = "PAUSE_IR", + transitions = { + 1 : "EXIT2_IR", + } + ) + JTAGTAPFSMState( + name = "EXIT2_IR", + transitions = { + 0 : "SHIFT_IR", + 1 : "UPDATE_IR", + } + ) + JTAGTAPFSMState( + name = "UPDATE_IR", + transitions = { + 0 : "RUN_TEST_IDLE", + 1 : "SELECT_DR_SCAN", + } + ) # Altera JTAG -------------------------------------------------------------------------------------- @@ -124,7 +197,7 @@ class AlteraJTAG(Module): self.comb += ResetSignal("jtag_inv").eq(ResetSignal("jtag")) # connect the TAP state signals that LiteX expects but the HW IP doesn't provide - self.submodules.tap_fsm = JTAGTAPFSM(tms, tck) + self.submodules.tap_fsm = ClockDomainsRenamer("jtag")(JTAGTAPFSM(tms)) self.sync.jtag_inv += reset.eq(self.tap_fsm.TEST_LOGIC_RESET) self.sync.jtag_inv += capture.eq(self.tap_fsm.CAPTURE_DR)