complete first translation pass of dmi_dtm_xilinx.vhdl into nmigen,
authorCole Poirier <colepoirier@gmail.com>
Wed, 16 Sep 2020 22:34:13 +0000 (15:34 -0700)
committerCole Poirier <colepoirier@gmail.com>
Wed, 16 Sep 2020 22:36:37 +0000 (15:36 -0700)
different sync domains indicated as 'sync = m.d.[SYS|JTAG]_sync', left
some parts undone, didn't rearrange or clean up so Luke can easily
compare with original

src/soc/experiment/dmi_dtm_xilinx.py

index 13ad20cec5a27ba01f10df362cf43d58f173118d..ab80eade71d6d90e9f8e8ef132d9a50f3a7e0da2 100644 (file)
@@ -94,9 +94,25 @@ from nmigen.util import log2_int
 # --    dmi_err        : in std_ulogic TODO: Add error response
 #       );
 # end entity dmi_dtm;
-#
+class JTAGToDMI(Elaboratable):
+    def __init__(self):
+        self.sys_clk   = Signal()
+        self.sys_reset = Signal()
+        self.dmi_addr  = Signal(ABITS)
+        self.dmi_din   = Signal(DBITS)
+        self.dmi_dout  = Signal(DBITS)
+        self.dmi_req   = Signal()
+        self.dmi_wr    = Signal()
+        self.dmi_ack   = Signal()
+        self.dmi_err   = Signal()
+
 # architecture behaviour of dmi_dtm is
-#
+    def elaborate(self, platform):
+        m = Module()
+
+        comb = m.d.comb
+        sync = m.d.sync
+
 #     -- Signals coming out of the BSCANE2 block
 #     signal jtag_reset                : std_ulogic;
 #     signal capture           : std_ulogic;
@@ -108,45 +124,89 @@ from nmigen.util import log2_int
 #     signal tdi                       : std_ulogic;
 #     signal tdo                       : std_ulogic;
 #     signal tck                       : std_ulogic;
-#
+    # Signal coming out of the BSCANE2 block
+    jtag_reset = Signal()
+    capture    = Signal()
+    update     = Signal()
+    drck       = Signal()
+    jtag_clk   = Signal()
+    sel        = Signal()
+    shift      = Signal()
+    tdi        = Signal()
+    tdo        = Signal()
+    tck        = Signal()
+
 #     -- ** JTAG clock domain **
-#
+    # ** JTAG clock domain **
+
 #     -- Shift register
 #     signal shiftr    : std_ulogic_vector(ABITS + DBITS + 1 downto 0);
-#
+    # Shift register
+    shiftr = Signal(ABITS + DBITS)
+
 #     -- Latched request
 #     signal request   : std_ulogic_vector(ABITS + DBITS + 1 downto 0);
-#
+    # Latched request
+    request = Signal(ABITS + DBITS)
+
 #     -- A request is present
 #     signal jtag_req  : std_ulogic;
-#
+    # A request is present
+    jtag_req = Signal()
+
 #     -- Synchronizer for jtag_rsp (sys clk -> jtag_clk)
 #     signal dmi_ack_0 : std_ulogic;
 #     signal dmi_ack_1 : std_ulogic;
-#
+    # Synchronizer for jtag_rsp (sys clk -> jtag_clk)
+    dmi_ack_0 = Signal()
+    dmi_ack_1 = Signal()
+
 #     -- ** sys clock domain **
-#
+    # ** SYS clock domain
+
 #     -- Synchronizer for jtag_req (jtag clk -> sys clk)
 #     signal jtag_req_0        : std_ulogic;
 #     signal jtag_req_1        : std_ulogic;
-#
+    # Syncrhonizer for jtag_req (jtag clk -> sys clk)
+    jtag_req_0 = Signal()
+    jtag_req_1 = Signal()
+
 #     -- ** combination signals
 #     signal jtag_bsy  : std_ulogic;
 #     signal op_valid  : std_ulogic;
 #     signal rsp_op    : std_ulogic_vector(1 downto 0);
-#
+    # combination signals
+    jtag_bsy = Signal()
+    op_valid = Signal()
+    rsp_op   = Signal(2)
+
 #     -- ** Constants **
 #     constant DMI_REQ_NOP : std_ulogic_vector(1 downto 0) := "00";
 #     constant DMI_REQ_RD  : std_ulogic_vector(1 downto 0) := "01";
 #     constant DMI_REQ_WR  : std_ulogic_vector(1 downto 0) := "10";
 #     constant DMI_RSP_OK  : std_ulogic_vector(1 downto 0) := "00";
 #     constant DMI_RSP_BSY : std_ulogic_vector(1 downto 0) := "11";
-#
+    # ** Constants **
+    DMI_REQ_NOP = Const(0b00, 2)
+    DMI_REQ_RD  = Const(0b01, 2)
+    DMI_REQ_WR  = Const(0b10, 2)
+    DMI_RSP_OK  = Const(0b00, 2)
+    DMI_RSP_BSY = Const(0b11, 2)
+
+
 #     attribute ASYNC_REG : string;
 #     attribute ASYNC_REG of jtag_req_0: signal is "TRUE";
 #     attribute ASYNC_REG of jtag_req_1: signal is "TRUE";
 #     attribute ASYNC_REG of dmi_ack_0: signal is "TRUE";
 #     attribute ASYNC_REG of dmi_ack_1: signal is "TRUE";
+    # TODO nmigen attributes
+    # attribute ASYNC_REG : string;
+    # attribute ASYNC_REG of jtag_req_0: signal is "TRUE";
+    # attribute ASYNC_REG of jtag_req_1: signal is "TRUE";
+    # attribute ASYNC_REG of dmi_ack_0: signal is "TRUE";
+    # attribute ASYNC_REG of dmi_ack_1: signal is "TRUE";
+
+
 # begin
 #
 #     -- Implement the Xilinx bscan2 for series 7 devices (TODO: use PoC
@@ -196,7 +256,18 @@ from nmigen.util import log2_int
 #      end if;
 #     end process;
 #     dmi_req <= jtag_req_1;
-#
+    # DMI req synchronization
+    def dmi_req_sync(self, m, jtag_req, jtag_req_0, jtag_req_1):
+        sync = m.d.SYS_sync
+
+        with m.If(sys_reset):
+            sync += jtag_req_0.eq(0)
+            sync += jtag_req_1.eq(0)
+
+        with m.Else():
+            sync += jtag_req_0.eq(jtag_req)
+            sync += jtag_req_1.eq(jtag_req_0)
+
 #     -- dmi_ack synchronization
 #     dmi_ack_sync: process(jtag_clk, jtag_reset)
 #     begin
@@ -209,46 +280,85 @@ from nmigen.util import log2_int
 #          dmi_ack_1 <= dmi_ack_0;
 #      end if;
 #     end process;
-#
+    # DMI ack synchronization
+    def dmi_ack_sync(self, dmi_ack, dmi_ack_0, dmi_ack_1):
+        comb = m.d.comb
+        sync = m.d.JTAG_sync
+
+        with m.If(jtag_reset):
+            comb += dmi_ack_0.eq(0)
+            comb += dmi_ack_1.eq(0)
+
+        sync += dmi_ack_0.eq(dmi_ack)
+        sync += dmi_ack_1.eq(dmi_ack_0)
+
 #     -- jtag_bsy indicates whether we can start a new request,
 #     -- we can when we aren't already processing one (jtag_req)
 #     -- and the synchronized ack of the previous one is 0.
 #     --
 #     jtag_bsy <= jtag_req or dmi_ack_1;
-#
+    comb += jtag_bsy.eq(jtag_req | dmi_ack_1)
+
 #     -- decode request type in shift register
 #     with shiftr(1 downto 0) select op_valid <=
 #      '1' when DMI_REQ_RD,
 #      '1' when DMI_REQ_WR,
 #      '0' when others;
-#
+    with m.Switch(shitr[:2]):
+        with m.Case(DMI_REQ_RD): comb += op_valid.eq(1)
+        with m.Case(DMI_REQ_WR): comb += op_valid.eq(1)
+        with m.Default():        comb += op_valid.eq(0)
+
 #     -- encode response op
 #     rsp_op <= DMI_RSP_BSY when jtag_bsy = '1' else DMI_RSP_OK;
-#
+    with m.If(jtag_bsy):
+        comb += rsp_op.eq(DMI_RSP_BSY)
+
+    with m.Else():
+        comb += rsp_op.eq(DMI_RSP_OK)
+
 #     -- Some DMI out signals are directly driven from the request register
 #     dmi_addr <= request(ABITS + DBITS + 1 downto DBITS + 2);
 #     dmi_dout <= request(DBITS + 1 downto 2);
 #     dmi_wr   <= '1' when request(1 downto 0) = DMI_REQ_WR else '0';
-#
+    comb += dmi_addr.eq(request[DBITS + 2:ABITS + DBITS + 2])
+    comb += dmi_dout.eq(request[2:DBITS])
+
+    with m.If(request[:2] == DMI_REQ_WR):
+        comb += dmi_wr.eq(1)
+
+    with m.Else():
+        comb += dmi_wr.eq(0)
+
 #     -- TDO is wired to shift register bit 0
 #     tdo <= shiftr(0);
-#
+    comb += tdo.eq(shiftr[0])
+
 #     -- Main state machine. Handles shift registers, request latch and
 #     -- jtag_req latch. Could be split into 3 processes but it's probably
 #     -- not worthwhile.
 #     --
 #     shifter: process(jtag_clk, jtag_reset)
+    def shifter(self, m, jtag_clk, jtag_reset)
+        comb = m.d.comb
+        sync = m.d.JTAG_sync
 #     begin
 #      if jtag_reset = '1' then
 #          shiftr <= (others => '0');
 #          jtag_req <= '0';
+        with m.If(jtag_reset):
+            comb += shiftr.eq(~1)
+            comb += jtag_req.eq(0)
+
 #      elsif rising_edge(jtag_clk) then
-#
 #          -- Handle jtag "commands" when sel is 1
 #          if sel = '1' then
+        with m.If(sel):
 #              -- Shift state, rotate the register
 #              if shift = '1' then
+            with m.If(shift):
 #                  shiftr <= tdi & shiftr(ABITS + DBITS + 1 downto 1);
+                sync += shiftr.eq(Cat(shiftr[1:ABITS + DBITS], tdi))
 #              end if;
 #
 #              -- Update state (trigger)
@@ -257,15 +367,20 @@ from nmigen.util import log2_int
 #               -- one and it has a valid command opcode.
 #              --
 #              if update = '1' and op_valid = '1' then
+            with m.If(update & op_valid):
 #                  if jtag_bsy = '0' then
+                with m.If(~jtag_bsy):
 #                      request <= shiftr;
 #                      jtag_req <= '1';
+                    sync += request.eq(shiftr)
+                    sync += jtag_req.eq(1)
 #                  end if;
 #                  -- Set the shift register "op" to "busy".
 #                   -- This will prevent us from re-starting
 #                   -- the command on the next update if
 #                  -- the command completes before that.
 #                  shiftr(1 downto 0) <= DMI_RSP_BSY;
+                sync += shiftr[:2].eq(DMI_RSP_BSY)
 #              end if;
 #
 #              -- Request completion.
@@ -279,15 +394,21 @@ from nmigen.util import log2_int
 #               -- Slaves must be resilient to this.
 #              --
 #              if jtag_req = '1' and dmi_ack_1 = '1' then
+            with m.If(jtag_rq & dmi_ack):
 #                  jtag_req <= '0';
+                sync += jtag_req.eq(0)
 #                  if request(1 downto 0) = DMI_REQ_RD then
 #                      request(DBITS + 1 downto 2) <= dmi_din;
+                with m.If(request[:2] == DMI_REQ_RD):
+                    sync += request[2:DBITS].eq(dmi_din)
 #                  end if;
 #              end if;
 #
 #              -- Capture state, grab latch content with updated status
 #              if capture = '1' then
 #                  shiftr <= request(ABITS + DBITS + 1 downto 2) & rsp_op;
+            with m.If(capture):
+                sync += shiftr.eq(Cat(rsp_op, request[2:ABITS + DBITS]))
 #              end if;
 #
 #          end if;