soc/cores/jtag: Review/Cleanup JTAGTAPFSM and avoid specific CorrectedOngoingResetFSM.

This commit is contained in:
Florent Kermarrec 2022-01-31 15:53:36 +01:00
parent 40799332a0
commit b2448ba50e
2 changed files with 126 additions and 90 deletions

View File

@ -1,37 +0,0 @@
#
# This file is part of LiteX.
#
# Copyright (c) 2021 Jevin Sweval <jevinsweval@gmail.com>
# 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)

View File

@ -1,7 +1,7 @@
# #
# This file is part of LiteX. # This file is part of LiteX.
# #
# Copyright (c) 2019 Florent Kermarrec <florent@enjoy-digital.fr> # Copyright (c) 2019-2022 Florent Kermarrec <florent@enjoy-digital.fr>
# Copyright (c) 2019 Antti Lukats <antti.lukats@gmail.com> # Copyright (c) 2019 Antti Lukats <antti.lukats@gmail.com>
# Copyright (c) 2017 Robert Jordens <jordens@gmail.com> # Copyright (c) 2017 Robert Jordens <jordens@gmail.com>
# Copyright (c) 2021 Gregory Davill <greg.davill@gmail.com> # Copyright (c) 2021 Gregory Davill <greg.davill@gmail.com>
@ -18,70 +18,143 @@ from litex.soc.interconnect import stream
# JTAG TAP FSM ------------------------------------------------------------------------------------- # JTAG TAP FSM -------------------------------------------------------------------------------------
class JTAGTAPFSM(Module): class JTAGTAPFSM(Module):
def __init__(self, tms: Signal, tck: Signal, expose_signals=True): def __init__(self, tms):
self.submodules.fsm = fsm = ClockDomainsRenamer("jtag")(CorrectedOngoingResetFSM()) self.submodules.fsm = fsm = FSM(reset_state="TEST_LOGIC_RESET")
fsm.act("test_logic_reset", def JTAGTAPFSMState(name, transitions={}):
If(~tms, NextState("run_test_idle")) logic = []
)
fsm.act("run_test_idle", # Transitions logic.
If( tms, NextState("select_dr_scan")) 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 # Run-Test/Idle.
fsm.act("select_dr_scan", # --------------
If(~tms, NextState("capture_dr") ).Else(NextState("select_ir_scan")) JTAGTAPFSMState(
) name = "RUN_TEST_IDLE",
fsm.act("capture_dr", transitions = {
If(~tms, NextState("shift_dr") ).Else(NextState("exit1_dr")) 1 : "SELECT_DR_SCAN",
) }
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"))
) )
# IR # DR-Scan.
fsm.act("select_ir_scan", # --------
If(~tms, NextState("capture_ir") ).Else(NextState("test_logic_reset")) JTAGTAPFSMState(
name = "SELECT_DR_SCAN",
transitions = {
0 : "CAPTURE_DR",
1 : "SELECT_IR_SCAN",
}
) )
fsm.act("capture_ir", JTAGTAPFSMState(
If(~tms, NextState("shift_ir") ).Else(NextState("exit1_ir")) name = "CAPTURE_DR",
transitions = {
0 : "SHIFT_DR",
1 : "EXIT1_DR",
}
) )
fsm.act("shift_ir", JTAGTAPFSMState(
If( tms, NextState("exit1_ir")) name = "SHIFT_DR",
transitions = {
1 : "EXIT1_DR",
}
) )
fsm.act("exit1_ir", JTAGTAPFSMState(
If(~tms, NextState("pause_ir") ).Else(NextState("update_ir")) name = "EXIT1_DR",
transitions = {
0 : "PAUSE_DR",
1 : "UPDATE_DR",
}
) )
fsm.act("pause_ir", JTAGTAPFSMState(
If( tms, NextState("exit2_ir")) name = "PAUSE_DR",
transitions = {
1 : "EXIT2_DR",
}
) )
fsm.act("exit2_ir", JTAGTAPFSMState(
If( tms, NextState("update_ir") ).Else(NextState("shift_ir")) name = "EXIT2_DR",
transitions = {
0 : "SHIFT_DR",
1 : "UPDATE_DR",
}
) )
fsm.act("update_ir", JTAGTAPFSMState(
If( tms, NextState("select_dr_scan")).Else(NextState("run_test_idle")) name = "UPDATE_DR",
transitions = {
0 : "RUN_TEST_IDLE",
1 : "SELECT_DR_SCAN",
}
) )
if expose_signals: # IR-Scan.
for state_name in fsm.actions: # --------
state_sig = fsm.ongoing(state_name) JTAGTAPFSMState(
SHOUTING_NAME = state_name.upper() name = "SELECT_IR_SCAN",
shouting_sig = Signal(name=SHOUTING_NAME) transitions = {
setattr(self, SHOUTING_NAME, shouting_sig) 0 : "CAPTURE_IR",
self.comb += shouting_sig.eq(state_sig) 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 -------------------------------------------------------------------------------------- # Altera JTAG --------------------------------------------------------------------------------------
@ -124,7 +197,7 @@ class AlteraJTAG(Module):
self.comb += ResetSignal("jtag_inv").eq(ResetSignal("jtag")) self.comb += ResetSignal("jtag_inv").eq(ResetSignal("jtag"))
# connect the TAP state signals that LiteX expects but the HW IP doesn't provide # 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 += reset.eq(self.tap_fsm.TEST_LOGIC_RESET)
self.sync.jtag_inv += capture.eq(self.tap_fsm.CAPTURE_DR) self.sync.jtag_inv += capture.eq(self.tap_fsm.CAPTURE_DR)