From: Cole Poirier Date: Wed, 16 Sep 2020 22:34:13 +0000 (-0700) Subject: complete first translation pass of dmi_dtm_xilinx.vhdl into nmigen, X-Git-Tag: semi_working_ecp5~14 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=d050717ae4063eb3b8f61d71a949d0a1d5a70e71;p=soc.git complete first translation pass of dmi_dtm_xilinx.vhdl into nmigen, 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 --- diff --git a/src/soc/experiment/dmi_dtm_xilinx.py b/src/soc/experiment/dmi_dtm_xilinx.py index 13ad20ce..ab80eade 100644 --- a/src/soc/experiment/dmi_dtm_xilinx.py +++ b/src/soc/experiment/dmi_dtm_xilinx.py @@ -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;