Sometimes, when debugging some firmware or hardware, it is
necessary to see how the internal state of a chip changes in
response to external signals.
With microcontrollers, this can be accomplished by adding
code that toggles some pin that is then used for debugging,
and watching that pin with an oscilloscope. Such a pin can
also serve as sophisticated trigger, e.g., to capture some
input signal only when an error is detected.
With M1, we can do the same, e.g., make LM32 or Navre toggle
an I/O under software control. But we can do better: we can
also route "hardware" signals directly, without involving
software.
Here are three ways to do this:
1) Change the Verilog to properly route the signal to the
output pad. This is nice and clean but has the following
disadvantages:
- need to run the full build process for each change of
taps,
- need to edit the sources (and remember to undo all the
changes once the problem is fixed),
- the signals need to be propagated step by step up the
module hierarchy (*), which means a lot of small
changes in many files,
(*) Verilog should support also direct references that
"jump" the hierarchy, but this doesn't seem to be
properly implemented in the Xilinx tools.
2) The pros just edit the FPGA with a WYSIWYG editor:
http://www.youtube.com/watch?v=wwkGmDaa4oM
(Part three shows how to route signals to a pad.)
What I don't like about this is that it's not
script-friendly. I'd also suspect that the changes are lost
or at least in danger when re-synthesizing.
3) Like above, but edit non-interactively. This is an
experimental hack I've now implemented.
It works as follows: after synthesis and mapping, the resulting
binary is converted into a human-readable format. Then, a script
"edits" this file and connects taps to the respective pads.
Finally, the file is converted back into the binary format the
Xilinx tools use, and we proceed with place & route.
This works for signals originating inside the FPGA. I've had
less luck with echoing signals from an input pad, but maybe
that's easy to fix.
The tools in question are xldtap which adds the taps and
xldfixes which works around a number of bugs in Xilinx's xdl
converter. The tools are here:
http://projects.qi-hardware.com/index.php/p/wernermisc/source/tree/master/m1/tools
The README briefly describes how to use them.
For M1, we can integrate all this into the build process with
the makefile changes at the end of this mail. Note that I had
to set the SHELL to /bin/bash in common.mak for $PIPESTATUS
and that I had to disable the DRC in bitgen to get past some
I/O driver configuration issues xdl creates.
Taps are then placed by listing them in a file and passing the
file to make with make TAP=filename soc.fpg
I currently use these taps for USB:
usb/sie/rx_pending=exp{10}
usb/sie/phy/rx/rx_active=exp{8}
usb/sie/phy/rx/dpll_ce=exp{11}
If changing the tap configuration, just run make again, and it
will apply the changes and work down the dependencies from
there. Note that switching between using taps and not using
taps usually requires a "make clean".
All this is still quite experimental. bitgen spits out a lot
of rather scary (non-fatal only due to turning off the DRC)
errors but things still seem to work.
- Werner
diff --git a/boards/milkymist-one/flash/Makefile
b/boards/milkymist-one/flash/Makefile
index c63c1a8..cee2cce 100644
--- a/boards/milkymist-one/flash/Makefile
+++ b/boards/milkymist-one/flash/Makefile
@@ -3,6 +3,8 @@ MMDIR?=../../..
TARGETS=standby.fpg soc-rescue.fpg bios-rescue.bin splash-rescue.raw soc.fpg
bios.bin splash.raw
SERIAL?=/dev/ttyUSB0
+.PHONY: soc.fpg
+
all: $(TARGETS)
clean:
rm -f $(TARGETS)
diff --git a/boards/milkymist-one/synthesis/common.mak
b/boards/milkymist-one/synthesis/common.mak
index e9b5a8d..ffe1f00 100644
--- a/boards/milkymist-one/synthesis/common.mak
+++ b/boards/milkymist-one/synthesis/common.mak
@@ -6,6 +6,8 @@ else
BUILDDIR=build
endif
+SHELL = /bin/bash
+
all: $(BUILDDIR)/system.bit $(BUILDDIR)/system.fpg
timing: $(BUILDDIR)/system-routed.twr
@@ -20,9 +22,38 @@ load: $(BUILDDIR)/system.bit
build/system.ncd: build/system.ngd
cd build && map -ol high -t 2 -w system.ngd
+ifeq ($(TAP),)
+
+BITGEN_DRC=
+
build/system-routed.ncd: build/system.ncd
cd build && par -ol high -w system.ncd system-routed.ncd
+else
+
+BITGEN_DRC=-d
+
+ifneq ($(patsubst /%, %, $(TAP)), $(TAP))
+TAP_ABS = $(TAP)
+else
+TAP_ABS = $(PWD)/$(TAP)
+endif
+
+build/system-routed.ncd: build/system-dbg.ncd
+ cd build && par -ol high -w system-dbg.ncd system-routed.ncd
+
+build/system.xdl: build/system.ncd
+ xdl -ncd2xdl $< $@
+
+build/system-dbg.ncd: build/system-dbg.xdl
+ xdl -xdl2ncd $< $@
+
+build/system-dbg.xdl: build/system.xdl $(TAP_ABS)
+ xdltap `cat "$(TAP_ABS)"` $< | xdlfixes >$@; \
+ [ "$${PIPESTATUS[*]}" = "0 0" ] || { rm -rf $@; exit 1; }
+
+endif
+
build-rescue/system.ncd: build-rescue/system.ngd
cd build-rescue && map -ol high -w system.ngd
@@ -30,7 +61,7 @@ build-rescue/system-routed.ncd: build-rescue/system.ncd
cd build-rescue && par -ol high -w system.ncd system-routed.ncd
$(BUILDDIR)/system.bit: $(BUILDDIR)/system-routed.ncd
- cd $(BUILDDIR) && bitgen -g LCK_cycle:6 -g Binary:Yes -g INIT_9K:Yes -w
system-routed.ncd system.bit
+ cd $(BUILDDIR) && bitgen $(BITGEN_DRC) -g LCK_cycle:6 -g Binary:Yes -g
INIT_9K:Yes -w system-routed.ncd system.bit
$(BUILDDIR)/system.bin: $(BUILDDIR)/system.bit
_______________________________________________
http://lists.milkymist.org/listinfo.cgi/devel-milkymist.org
IRC: #milkymist@Freenode