Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions docs/Prototyping/Arty.rst
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,47 @@ Adding this config. fragment will enable and connect the JTAG and UART interface

Future peripherals to be supported include the Arty A7-35T SPI Flash EEPROM, and I2C/PWM/SPI over the Arty A7-35T GPIO pins. These peripherals are available as part of sifive-blocks.

Arty35T: Debugging over the USB Cable (BSCAN Tunnel)
----------------------------------------------------

The Arty A7-35T's USB cable carries two FTDI channels: channel A programs the FPGA over the Artix-7's own JTAG TAP, and channel B is the UART.
The stock ``TinyRocketArtyConfig`` above brings the SoC's RISC-V JTAG DTM out on PMOD, so debugging needs a second JTAG adapter.
``TinyRocketArtyBScanConfig`` instead routes the DTM through the FPGA TAP's ``USER4`` register using the ``JTAGTUNNEL`` block from ``fpga-shells``, so the programming cable is also the debug cable.

.. literalinclude:: ../../fpga/src/main/scala/arty/Configs.scala
:language: scala
:start-after: DOC include start: Arty BSCAN JTAG
:end-before: DOC include end: Arty BSCAN JTAG

Build and program as usual:

.. code-block:: shell

cd fpga/
make SUB_PROJECT=arty35t CONFIG=TinyRocketArtyBScanConfig bitstream

Then attach OpenOCD with the provided configuration, which selects the Series-7 TAP and enables the nested-TAP BSCAN tunnel (``riscv use_bscan_tunnel 5``, Rocket's DTM IR width):

.. code-block:: shell

openocd -f fpga/scripts/arty35t_bscan_openocd.cfg

GDB connects to OpenOCD's GDB server on port 3333.
Declare the BootROM as read-only first; otherwise GDB single-steps by planting a software breakpoint at the next PC, which fails inside ROM:

.. code-block:: shell

riscv64-unknown-elf-gdb
(gdb) target extended-remote :3333
(gdb) mem 0x10000 0x1ffff ro
(gdb) info registers pc

Notes:

* The tunnelled DTM is clocked by the FPGA TCK only while ``USER4`` is selected, which is what OpenOCD's tunnel expects.
* ``openFPGALoader`` and OpenOCD both open FTDI channel A; program first, then start OpenOCD.
* Requires an OpenOCD with the ``riscv`` target and BSCAN tunnel support.

Brief Implementation Description and Guidance for Adding/Changing Xilinx Collateral
-----------------------------------------------------------------------------------

Expand Down
35 changes: 35 additions & 0 deletions fpga/scripts/arty35t_bscan_openocd.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# OpenOCD configuration for TinyRocketArtyBScanConfig on the Digilent Arty A7-35T.
#
# The RISC-V Debug Transport Module is tunnelled through the Artix-7 TAP's USER4
# register (fpga-shells JTAGTUNNEL), so the board's FTDI channel A -- the same
# cable used to program the FPGA -- also carries hart debug. Program the
# bitstream first (openFPGALoader / Vivado), then:
#
# openocd -f fpga/scripts/arty35t_bscan_openocd.cfg
# riscv64-unknown-elf-gdb -ex 'target extended-remote :3333'
#
# Requires OpenOCD with the riscv target and BSCAN tunnel support.

adapter driver ftdi
adapter speed 1000
transport select jtag

# Arty A7 on-board FT2232H; channel A is the FPGA JTAG.
ftdi vid_pid 0x0403 0x6010
ftdi channel 0
ftdi layout_init 0x0088 0x008b

# Series-7 TAP (xc7.tap, 6-bit IR). Script location differs between OpenOCD
# 0.12.0 (cpld/) and later releases (fpga/xlnx/).
if {[catch {source [find fpga/xlnx/xc7.cfg]}]} {
source [find cpld/xilinx-xc7.cfg]
}

target create tinyrocket.cpu riscv -chain-position xc7.tap

# Rocket's JTAG DTM has a 5-bit IR. Nested-TAP tunnel via USER4 (0x23) is the
# default tunnel type and IR for a 6-bit Series-7 TAP.
riscv use_bscan_tunnel 5

init
halt
9 changes: 9 additions & 0 deletions fpga/src/main/scala/arty/Configs.scala
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,12 @@ class TinyRocketArtyConfig extends Config(
new chipyard.TinyRocketConfig
)
// DOC include end: AbstractArty and Rocket

// DOC include start: Arty BSCAN JTAG
// Same TinyRocket SoC, but the JTAG DTM is reached through the FPGA's own TAP
// (BSCANE2 USER4 tunnel) over the USB programming cable instead of PMOD.
class TinyRocketArtyBScanConfig extends Config(
new WithArtyBScanJTAGHarnessBinder ++
new TinyRocketArtyConfig
)
// DOC include end: Arty BSCAN JTAG
29 changes: 29 additions & 0 deletions fpga/src/main/scala/arty/HarnessBinders.scala
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import sifive.blocks.devices.jtag.{JTAGPins, JTAGPinsFromPort}
import sifive.blocks.devices.pinctrl.{BasePin}

import sifive.fpgashells.ip.xilinx.{IBUFG, IOBUF, PULLUP, PowerOnResetFPGAOnly}
import sifive.fpgashells.ip.xilinx.bscan2.JTAGTUNNEL

import chipyard.harness.{HarnessBinder}
import chipyard.iobinders._
Expand Down Expand Up @@ -62,6 +63,34 @@ class WithArtyJTAGHarnessBinder extends HarnessBinder({
}
})

// Route the SoC's JTAG DTM through the Artix-7's own TAP instead of the PMOD
// pins. fpga-shells' JTAGTUNNEL places a BSCANE2 on USER4 and decodes each
// USER4 DR scan into a nested JTAG transaction, so the FPGA-programming USB
// cable (FTDI channel A) also carries hart debug. OpenOCD reaches the DTM with
// `riscv use_bscan_tunnel <DTM IR width>` (see fpga/scripts/arty35t_bscan_openocd.cfg).
// The DTM's TCK is the FPGA TCK gated by USER4 SEL (BUFGCE inside JTAGTUNNEL).
class WithArtyBScanJTAGHarnessBinder extends HarnessBinder({
case (th: Arty35THarness, port: JTAGPort, chipId: Int) => {
val tck = Wire(Bool())
val tms = Wire(Bool())
val tdi = Wire(Bool())
val tdo = Wire(Bool())
val tdo_en = Wire(Bool())

JTAGTUNNEL(tck, tms, tdi, tdo, tdo_en)

port.io.TCK := tck.asClock
port.io.TMS := tms
port.io.TDI := tdi
tdo := port.io.TDO
tdo_en := true.B
port.io.reset.foreach(_ := th.referenceReset)

// No PMOD SRST_n in this configuration: keep the harness reset vote inactive.
th.SRST_n := true.B
}
})

class WithArtyUARTHarnessBinder extends HarnessBinder({
case (th: Arty35THarness, port: UARTPort, chipId: Int) => {
withClockAndReset(th.clock_32MHz, th.ck_rst) {
Expand Down