fix numbered list formatting, sigh
[libreriscv.git] / docs / pinmux.mdwn
index efecbfa8c7bb3afbad1731fec36e71b437f24bab..018a41fa23a63061cfd141098b8c3c9a3c01a218 100644 (file)
@@ -7,6 +7,7 @@ Links:
 * <https://ftp.libre-soc.org/Pin_Control_Subsystem_Overview.pdf>
 * <https://bugs.libre-soc.org/show_bug.cgi?id=50>
 * <https://git.libre-soc.org/?p=c4m-jtag.git;a=tree;hb=HEAD>
+* Extra info: [[/docs/pinmux/temp_pinmux_info]]
 
 Managing IO on an ASIC is nowhere near as simple as on an FPGA.
 An FPGA has built-in IO Pads, the wires terminate inside an
@@ -15,7 +16,7 @@ In an ASIC, you are going to have to do everything yourself.
 In an ASIC, a bi-directional IO Pad requires three wires (in, out,
 out-enable) to be routed right the way from the ASIC, all
 the way to the IO PAD, where only then does a wire bond connect
-it to a single pin.
+it to a single external pin.
 
 [[!img CH02-44.gif]]
 
@@ -63,7 +64,7 @@ on a given PCB, and they should not have to.
 
 Through the Resources, Platforms and Pins API, a level of abstraction
 between peripherals, boards and HDL designs is provided.  Peripherals
-may be given `(nane, number)` tuples, the HDL design may "request"
+may be given `(name, number)` tuples, the HDL design may "request"
 a peripheral, which is described in terms of Resources, managed
 by a ResourceManager, and a Platform may provide that peripheral.
 The Platform is given
@@ -85,8 +86,8 @@ Here is a function that defines a UART Resource:
 
 Note that the Subsignal is given a convenient name (tx, rx) and that
 there are Pins associated with it.
-UARTResource  would typically be part of a larger function that defines, for either
-an FPGA or an ASIC, a full array of IO Connections:
+UARTResource  would typically be part of a larger function that defines,
+for either an FPGA or an ASIC, a full array of IO Connections:
 
     def create_resources(pinset):
        resources = []
@@ -133,7 +134,7 @@ a UART (caveat below):
 The caveat here is that the Resources of the platform actually
 have to have a UART in order for it to be requestable! Thus:
 
-    resources = create_resources()
+    resources = create_resources() # contains resource named "uart"
     asic = ASICPlatform(resources)
     hdl = Blinker()
     asic.build(hdl)
@@ -162,7 +163,7 @@ Scan chaining can also connect multiple ASICs together so that
 the same test can be run on a large batch of ASICs at the same
 time.
 
-IO Pads generslly come in four primary different types:
+IO Pads generally come in four primary different types:
 
 * Input
 * Output
@@ -218,6 +219,150 @@ and triaging of faults.
 <img src="https://libre-soc.org/shakti/m_class/JTAG/jtag-block.jpg"
   width=500 />
 
+## C4M JTAG TAP
+
+Staf Verhaegen's Chips4Makers JTAG TAP module includes everything
+needed to create JTAG Boundary Scan Shift Registers,
+as well as the IEEE 1149.1 Finite State Machine to access
+them through TMS, TDO, TDI and TCK Signalling.  However,
+connecting up cores (a hardware term: the equivalent software
+term is "peripherals") on one side and the pads on the other is
+especially confusing, but deceptively simple.  The actual addition
+to the Scan Shift Register is this straightforward:
+
+    from c4m.nmigen.jtag.tap import IOType, TAP
+
+    class JTAG(TAP):
+       def __init__(self):
+           TAP.__init__(self, ir_width=4)
+           self.u_tx = self.add_io(iotype=IOType.Out, name="tx")
+           self.u_rx = self.add_io(iotype=IOType.In, name="rx")
+
+This results in the creation of:
+
+* Two Records, one of type In named rx, the other an output
+  named tx
+* Each Record contains a pair of sub-Records: one core-side
+  and the other pad-side
+* Entries in the Boundary Scan Shift Register which if set
+  may control (or read) either the peripheral / core or
+  the IO PAD
+* A suite of Muxes (as shown in the diagrams above) which
+  allow either direct connection between pad and core
+  (bypassing JTAG) or interception
+
+During Interception Mode (Scanning) pad and core are connected
+to the Shift Register.  During "Production" Mode, pad and
+core are wired directly to each other (on a per-pin basis,
+for every pin. Clearly this is a lot of work).
+
+It is then your responsibility to:
+
+* connect up each and every peripheral input and output
+  to the right IO Core Record in your HDL
+* connect up each and every IO Pad input and output
+  to the right IO Pad in the Platform. **This
+  does not happen automatically and is not the
+  responsibility of the TAP Interface*
+
+The TAP interface connects the **other** side of the pads
+and cores Records: **to the Muxes**.  You **have** to
+connect **your** side of both core and pads Records in
+order for the Scan to be fully functional.
+
+Both of these tasks are painstaking and tedious in the
+extreme if done manually, and prone to either sheer boredom,
+transliteration errors, dyslexia triggering or just utter
+confusion.  Despite this, let us proceed, and, augmenting
+the Blinky example, wire up a JTAG instance:
+
+    class Blinker(Elaboratable): 
+      def elaborate(self, platform):
+          m = Module()
+          m.submodules.jtag = jtag = JTAG()
+
+          # get the records from JTAG instance
+          utx, urx = jtag.u_tx, jtag.u_rx
+          # get the UART resource, mess with the output tx
+          p_uart = platform.request('uart')
+
+          # uart core-side from JTAG
+          intermediary = Signal()
+          m.d.comb += utx.core.o.eq(~intermediary) # invert, for fun
+          m.d.comb += intermediary.eq(urx.core.i) # pass rx to tx
+
+          # wire up the IO Pads (in right direction) to Platform
+          m.d.comb += uart.rx.eq(utx.pad.i) # receive rx from JTAG input pad
+          m.d.comb += utx.pad.o.eq(uart.tx) # transmit tx to JTAG output pad
+          return m
+
+Compared to the non-scan-capable version, which connected UART
+Core Tx and Rx directly to the Platform Resource (and the Platform
+took care of wiring to IO Pads):
+
+* Core HDL is instead wired to the core-side of JTAG Scan
+* JTAG Pad side is instead wired to the Platform
+* (the Platform still takes care of wiring to actual IO Pads)
+
+JTAG TAP capability on UART TX and RX has now been inserted into
+the chain.  Using openocd or other program it is possible to
+send TDI, TMS, TDO and TCK signals according to IEEE 1149.1 in order
+to intercept both the core and IO Pads, both input and output,
+and confirm the correct functionality of one even if the other is
+broken, during ASIC testing.
+
+## Libre-SOC Automatic Boundary Scan
+
+Libre-SOC's JTAG TAP Boundary Scan system is a little more sophisticated:
+it hooks into (replaces) ResourceManager.request(), intercepting the request
+and recording what was requested.  The above manual linkup to JTAG TAP
+is then taken care of **automatically and transparently**, but to
+all intents and purposes looking exactly like a Platform even to
+the extent of taking the exact same list of Resources.
+
+    class Blinker(Elaboratable):
+      def __init__(self, resources):
+          self.jtag = JTAG(resources)
+
+      def elaborate(self, platform):
+          m = Module()
+          m.submodules.jtag = jtag = self.jtag
+
+          # get the UART resource, mess with the output tx
+          uart = jtag.request('uart')
+          intermediary = Signal()
+          m.d.comb += uart.tx.eq(~intermediary) # invert, for fun
+          m.d.comb += intermediary.eq(uart.rx) # pass rx to tx
+
+          return jtag.boundary_elaborate(m, platform)
+
+Connecting up and building the ASIC is as simple as a non-JTAG,
+non-scanning-aware Platform:
+
+    resources = create_resources()
+    asic = ASICPlatform(resources)
+    hdl = Blinker(resources)
+    asic.build(hdl)
+
+The differences:
+
+* The list of resources was also passed to the HDL Module
+  such that JTAG may create a complete identical list
+  of both core and pad matching Pins
+* Resources were requested from the JTAG instance,
+  not the Platform
+* A "magic function" (JTAG.boundary_elaborate) is called
+  which wires up all of the seamlessly intercepted
+  Platform resources to the JTAG core/pads Resources,
+  where the HDL connected to the core side, exactly
+  as if this was a non-JTAG-Scan-aware Platform.
+* ASICPlatform still takes care of connecting to actual
+  IO Pads, except that the Platform.resource requests were
+  triggered "behind the scenes". For that to work it
+  is absolutely essential that the JTAG instance and the
+  ASICPlatform be given the exact same list of Resources.
+
+
 ## Clock synchronisation
 
 Take for example USB ULPI:
@@ -268,6 +413,8 @@ there will be a lag on the output data compared to the incoming
 
 [[!img gpio_block.png]]
 
+[[!img io_mux_bank_planning.JPG]]
+
 # Core/Pad Connection + JTAG Mux
 
 Diagram constructed from the nmigen plat.py file.