-
-
Save jevinskie/811a4fd6deba7fff7280f6908ae37437 to your computer and use it in GitHub Desktop.
# JTAG TAP FSM ------------------------------------------------------------------------------------- | |
class JTAGTAPFSM(Module): | |
def __init__(self, tms: Signal, tck: Signal, use_ieee_encoding=False, expose_signals=True): | |
self.submodules.fsm = fsm = ClockDomainsRenamer("jtag")(FSM()) | |
# Debug counter | |
# self.tck_cnt = tck_cnt = Signal(16) | |
# self.sync.jtag += tck_cnt.eq(tck_cnt + 1) | |
fsm.act('test_logic_reset', | |
If(~tms, NextState('run_test_idle')) | |
) | |
fsm.act('run_test_idle', | |
If( tms, NextState('select_dr_scan')) | |
) | |
# 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')) | |
) | |
# IR | |
fsm.act('select_ir_scan', | |
If(~tms, NextState('capture_ir') ).Else(NextState('test_logic_reset')) | |
) | |
fsm.act('capture_ir', | |
If(~tms, NextState('shift_ir') ).Else(NextState('exit1_ir')) | |
) | |
fsm.act('shift_ir', | |
If( tms, NextState('exit1_ir')) | |
) | |
fsm.act('exit1_ir', | |
If(~tms, NextState('pause_ir') ).Else(NextState('update_ir')) | |
) | |
fsm.act('pause_ir', | |
If( tms, NextState('exit2_ir')) | |
) | |
fsm.act('exit2_ir', | |
If( tms, NextState('update_ir') ).Else(NextState('shift_ir')) | |
) | |
fsm.act('update_ir', | |
If( tms, NextState('select_dr_scan')).Else(NextState('run_test_idle')) | |
) | |
if use_ieee_encoding: | |
# 11491.1-2013 Table 6-3 "State assignments for example TAP controller" page 36 pdf page 58 | |
self.fsm.encoding = { | |
'exit2_dr': 0, | |
'exit1_dr': 1, | |
'shift_dr': 2, | |
'pause_dr': 3, | |
'select_ir_scan': 4, | |
'update_dr': 5, | |
'capture_dr': 6, | |
'select_dr_scan': 7, | |
'exit2_ir': 8, | |
'exit1_ir': 9, | |
'shift_ir': 0xA, | |
'pause_ir': 0xB, | |
'run_test_idle': 0xC, | |
'update_ir': 0xD, | |
'capture_ir': 0xE, | |
'test_logic_reset': 0xF, | |
} | |
if expose_signals: | |
for state_name in fsm.actions: | |
reset_val = 0 | |
if state_name == 'test_logic_reset': | |
reset_val = 1 | |
sig = fsm.ongoing(state_name, reset=reset_val) | |
SHOUTING_NAME = state_name.upper() | |
hcs_name = SHOUTING_NAME | |
hcs = Signal(name=hcs_name) | |
setattr(self, hcs_name, hcs) | |
self.comb += hcs.eq(sig) | |
class AlteraJTAG(Module): | |
def __init__(self, primitive: str, reserved_pads: Record, chain=1): | |
self.reset = reset = Signal() | |
self.capture = capture = Signal() | |
self.shift = shift = Signal() | |
self.update = update = Signal() | |
# | |
self.runtest = runtest = Signal() | |
self.drck = drck = Signal() | |
self.sel = sel = Signal() | |
self.tck = tck = Signal() | |
self.tms = tms = Signal() | |
self.tdi = tdi = Signal() | |
self.tdo = tdo = Signal() | |
self.altera_reserved_tck = rtck = Signal() | |
self.altera_reserved_tms = rtms = Signal() | |
self.altera_reserved_tdi = rtdi = Signal() | |
self.altera_reserved_tdo = rtdo = Signal() | |
# inputs | |
# self.tdoutap = tdoutap = Signal() # fails synth on max10 | |
self.tdouser = tdouser = Signal() | |
# self.tmscore = tmscore = Signal() | |
# self.tckcore = tckcore = Signal() | |
# self.tdicore = tdicore = Signal() | |
# self.corectl = corectl = Signal() | |
# self.ntdopinena = ntdopinena = Signal() | |
# outputs | |
self.tmsutap = tmsutap = Signal() | |
self.tckutap = tckutap = Signal() | |
self.tdiutap = tdiutap = Signal() | |
# self.tdocore = tdocore = Signal() | |
assert chain == 1 | |
# # # | |
self.clock_domains.cd_jtag_inv = cd_jtag_inv = ClockDomain("jtag_inv") | |
self.comb += ClockSignal("jtag_inv").eq(~ClockSignal("jtag")) | |
self.comb += ResetSignal('jtag_inv').eq(ResetSignal("jtag")) | |
self.submodules.tap_fsm = JTAGTAPFSM(tms, tck) | |
self.sync.jtag_inv += reset.eq(self.tap_fsm.TEST_LOGIC_RESET) | |
self.sync.jtag_inv += capture.eq(self.tap_fsm.CAPTURE_DR) | |
self.specials += Instance(primitive, | |
o_shiftuser = shift, | |
o_updateuser = update, | |
# | |
o_runidleuser = runtest, | |
o_clkdruser = drck, | |
o_usr1user = sel, | |
# etc? | |
# i_tdoutap = tdoutap, # fails synth on max10 | |
i_tdouser = tdouser, | |
# i_tmscore = tmscore, # nope on cyclone 10 lp | |
# i_tckcore = tckcore, # nope on cyclone 10 lp | |
# i_tdicore = tdicore, # nope on cyclone 10 lp | |
# i_corectl = corectl, | |
# i_ntdopinena = ntdopinena, | |
o_tmsutap = tmsutap, | |
o_tckutap = tckutap, | |
o_tdiutap = tdiutap, | |
# o_tdocore = tdocore, # nope on cyclone 10 lp | |
# reserved pins | |
i_tms = rtms, | |
i_tck = rtck, | |
i_tdi = rtdi, | |
o_tdo = rtdo, | |
) | |
self.comb += [ | |
rtms.eq(reserved_pads.altera_reserved_tms), | |
rtck.eq(reserved_pads.altera_reserved_tck), | |
rtdi.eq(reserved_pads.altera_reserved_tdi), | |
reserved_pads.altera_reserved_tdo.eq(rtdo), | |
] | |
self.comb += [ | |
tck.eq(tckutap), | |
tms.eq(tmsutap), | |
tdi.eq(tdiutap), | |
] | |
self.sync.jtag_inv += tdouser.eq(tdo) | |
class MAX10JTAG(AlteraJTAG): | |
def __init__(self, reserved_pads: Record, *args, **kwargs): | |
AlteraJTAG.__init__(self, "fiftyfivenm_jtag", reserved_pads, *args, **kwargs) | |
class Cyclone10LPJTAG(AlteraJTAG): | |
def __init__(self, reserved_pads: Record, *args, **kwargs): | |
AlteraJTAG.__init__(self, "cyclone10lp_jtag", reserved_pads, *args, **kwargs) |
Thanks! I'll take a look at it later. This needs to be merged.
I’m working on this updated topic branch to get it merged. Right now it seems to be broken from the copy-pasta from the September base so it might need some fixes still (or it might be user error…):
Here is an example of adding support to an Altera board:
jevinskie/litex-boards@dd5106e
@jevinskie
Thanks for your work. It would be very helpful.
Unfortunately, I don't have DECA board. So I modified for my DE2_115.
Basically, I add following code to litex/litex/soc/cores/jtag.py
class CycloneIVEJTAG(AlteraJTAG):
def __init__(self, reserved_pads, *args, **kwargs):
AlteraJTAG.__init__(self, "cycloneive_jtag", reserved_pads, *args, **kwargs)
It was built and loaded successfully.
$ ./terasic_de2_115.py --csr-csv csr.csv --with-jtagbone --build --load
If I run litex_server with uart port, I can debug successuflly
$ sudo litex_server --uart --uart-port=/dev/ttyUSB0
(I referred https://github.com/timvideos/litex-buildenv/wiki/Debugging to debug)
However, If I run litex_server with virtual jtag, it was failed.
$ litex_server --jtag --jtag-config ../prog/openocd_de2_115_blaster.cfg
$ ./src/openocd -c 'interface dummy' \
-c 'adapter_khz 1' \
-c 'jtag newtap lx cpu -irlen 4' \
-c 'target create lx.cpu0 vexriscv -endian little -chain-position lx.cpu -dbgbase 0xF00F0000' \
-c 'vexriscv cpuConfigFile cpu0.yaml' \
-c 'vexriscv networkProtocol etherbone' \
-c 'init' \
-c 'reset halt
Open On-Chip Debugger 0.11.0+dev-02577-g3eee6eb04-dirty (2022-02-08-06:16)
Licensed under GNU GPL v2
For bug reports, read
http://openocd.org/doc/doxygen/bugs.html
DEPRECATED! use 'adapter driver' not 'interface'
Info : only one transport option; autoselect 'jtag'
DEPRECATED! use 'adapter speed' not 'adapter_khz'
adapter speed: 1 kHz
4027514880
Info : clock speed 1 kHz
Info : TAP lx.cpu does not have valid IDCODE (idcode=0x0)
Info : TAP auto0.tap does not have valid IDCODE (idcode=0x80000000)
Info : TAP auto1.tap does not have valid IDCODE (idcode=0xc0000000)
Info : TAP auto2.tap does not have valid IDCODE (idcode=0xe0000000)
Info : TAP auto3.tap does not have valid IDCODE (idcode=0xf0000000)
Info : TAP auto4.tap does not have valid IDCODE (idcode=0xf8000000)
Info : TAP auto5.tap does not have valid IDCODE (idcode=0xfc000000)
Info : TAP auto6.tap does not have valid IDCODE (idcode=0xfe000000)
Info : TAP auto7.tap does not have valid IDCODE (idcode=0xff000000)
Info : TAP auto8.tap does not have valid IDCODE (idcode=0xff800000)
Info : TAP auto9.tap does not have valid IDCODE (idcode=0xffc00000)
Info : TAP auto10.tap does not have valid IDCODE (idcode=0xffe00000)
Info : TAP auto11.tap does not have valid IDCODE (idcode=0xfff00000)
Info : TAP auto12.tap does not have valid IDCODE (idcode=0xfff80000)
Info : TAP auto13.tap does not have valid IDCODE (idcode=0xfffc0000)
Info : TAP auto14.tap does not have valid IDCODE (idcode=0xfffe0000)
Info : TAP auto15.tap does not have valid IDCODE (idcode=0xffff0000)
Info : TAP auto16.tap does not have valid IDCODE (idcode=0xffff8000)
Info : TAP auto17.tap does not have valid IDCODE (idcode=0xffffc000)
Info : TAP auto18.tap does not have valid IDCODE (idcode=0xffffe000)
Info : TAP auto19.tap does not have valid IDCODE (idcode=0xfffff000)
Warn : Unexpected idcode after end of chain: 21 0xfffff800
Error: double-check your JTAG setup (interface, speed, ...)
Error: Trying to use configured scan chain anyway...
Error: lx.cpu: IR capture error; saw 0x0f not 0x01
Warn : Bypassing JTAG setup events due to errors
It was stuck here and gdb server did not start, so I cannot debug it.
Could you show me an example how to debug vexriscv by using virtual jtag and openocd?
Any help would be very appreciated!
Thank you @jevinskie