You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			179 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			VHDL
		
	
			
		
		
	
	
			179 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			VHDL
		
	
| library ieee;
 | |
| use ieee.std_logic_1164.all;
 | |
| use ieee.numeric_std.all;
 | |
| 
 | |
| library work;
 | |
| use work.wishbone_types.all;
 | |
| 
 | |
| entity wishbone_debug_master is
 | |
|     port(clk : in std_ulogic;
 | |
|          rst : in std_ulogic;
 | |
| 
 | |
|          -- Debug bus interface
 | |
|          dmi_addr : in std_ulogic_vector(1 downto 0);
 | |
|          dmi_din  : in std_ulogic_vector(63 downto 0);
 | |
|          dmi_dout : out std_ulogic_vector(63 downto 0);
 | |
|          dmi_req  : in std_ulogic;
 | |
|          dmi_wr   : in std_ulogic;
 | |
|          dmi_ack  : out std_ulogic;
 | |
| 
 | |
|          -- Wishbone master interface
 | |
|          wb_out : out wishbone_master_out;
 | |
|          wb_in  : in wishbone_slave_out
 | |
|          );
 | |
| end entity wishbone_debug_master;
 | |
| 
 | |
| architecture behaviour of wishbone_debug_master is
 | |
| 
 | |
|     -- ** Register offsets definitions. All registers are 64-bit
 | |
|     constant DBG_WB_ADDR : std_ulogic_vector(1 downto 0) := "00";
 | |
|     constant DBG_WB_DATA : std_ulogic_vector(1 downto 0) := "01";
 | |
|     constant DBG_WB_CTRL : std_ulogic_vector(1 downto 0) := "10";
 | |
|     constant DBG_WB_RSVD : std_ulogic_vector(1 downto 0) := "11";
 | |
| 
 | |
|     -- CTRL register:
 | |
|     --
 | |
|     -- bit  0..7 : SEL bits (byte enables)
 | |
|     -- bit     8 : address auto-increment
 | |
|     -- bit 10..9 : auto-increment value:
 | |
|     --                00 - +1
 | |
|     --                01 - +2
 | |
|     --                10 - +4
 | |
|     --                11 - +8
 | |
| 
 | |
|     -- ** Address and control registers and read data
 | |
|     signal reg_addr     : std_ulogic_vector(63 downto 0);
 | |
|     signal reg_ctrl_out : std_ulogic_vector(63 downto 0);
 | |
|     signal reg_ctrl     : std_ulogic_vector(10 downto 0);
 | |
|     signal data_latch   : std_ulogic_vector(63 downto 0);
 | |
|     
 | |
|     type state_t is (IDLE, WB_CYCLE, DMI_WAIT);
 | |
|     signal state : state_t;
 | |
|     signal do_inc : std_ulogic;
 | |
| 
 | |
| begin
 | |
| 
 | |
|     -- Hard wire unused bits to 0
 | |
|     reg_ctrl_out <= (63 downto 11 => '0',
 | |
|                      10 downto  0 => reg_ctrl);
 | |
| 
 | |
|     -- DMI read data mux
 | |
|     with dmi_addr select dmi_dout <=
 | |
|         reg_addr        when DBG_WB_ADDR,
 | |
|         data_latch      when DBG_WB_DATA,
 | |
|         reg_ctrl_out    when DBG_WB_CTRL,
 | |
|         (others => '0') when others;
 | |
| 
 | |
|     -- ADDR and CTRL register writes
 | |
|     reg_write : process(clk)
 | |
|         subtype autoinc_inc_t is integer range 1 to 8;
 | |
|         function decode_autoinc(c : std_ulogic_vector(1 downto 0))
 | |
|             return autoinc_inc_t is
 | |
|         begin
 | |
|             case c is
 | |
|             when "00" => return 1;
 | |
|             when "01" => return 2;
 | |
|             when "10" => return 4;
 | |
|             when "11" => return 8;
 | |
|             -- Below shouldn't be necessary but GHDL complains
 | |
|             when others => return 8;
 | |
|             end case;
 | |
|         end function decode_autoinc;
 | |
|     begin
 | |
|         if rising_edge(clk) then
 | |
|             if (rst) then
 | |
|                 reg_addr <= (others => '0');
 | |
|                 reg_ctrl <= (others => '0');
 | |
|             else             -- Standard register writes
 | |
|                 if do_inc = '1' then
 | |
|                     -- Address register auto-increment
 | |
|                     reg_addr <= std_ulogic_vector(unsigned(reg_addr) +
 | |
|                                                   decode_autoinc(reg_ctrl(10 downto 9)));
 | |
|                 elsif dmi_req and dmi_wr then
 | |
|                     if dmi_addr = DBG_WB_ADDR then
 | |
|                         reg_addr <= dmi_din;
 | |
|                     elsif dmi_addr = DBG_WB_CTRL then
 | |
|                         reg_ctrl <= dmi_din(10 downto 0);
 | |
|                     end if;
 | |
|                 end if;
 | |
|             end if;
 | |
|         end if;
 | |
|     end process;
 | |
| 
 | |
|     -- ACK is hard wired to req for register writes. For data read/writes
 | |
|     -- (aka commands), it's sent when the state machine got the WB ack.
 | |
|     --
 | |
|     -- Note: We never set it to 1, we just pass dmi_req back when acking.
 | |
|     --       This fullfills two purposes:
 | |
|     --
 | |
|     --        * Avoids polluting the ack signal when another DMI slave is
 | |
|     --          selected. This allows the decoder to just OR all the acks
 | |
|     --          together rather than mux them.
 | |
|     --
 | |
|     --        * Makes ack go down on the same cycle as req goes down, thus
 | |
|     --          saving a clock cycle. This is safe because we know that
 | |
|     --          the state machine will no longer be in DMI_WAIT state on
 | |
|     --          the next cycle, so we won't be bouncing the signal back up.
 | |
|     --
 | |
|     dmi_ack <= dmi_req when (dmi_addr /= DBG_WB_DATA or state = DMI_WAIT) else '0';
 | |
| 
 | |
|         -- Some WB signals are direct wires from registers or DMI
 | |
|     wb_out.adr <= reg_addr(wb_out.adr'left + wishbone_log2_width downto wishbone_log2_width);
 | |
|     wb_out.dat <= dmi_din;
 | |
|     wb_out.sel <= reg_ctrl(7 downto 0);
 | |
|     wb_out.we  <= dmi_wr;
 | |
| 
 | |
|     -- We always move WB cyc and stb simultaneously (no pipelining yet...)
 | |
|     wb_out.cyc <= '1' when state = WB_CYCLE else '0';
 | |
| 
 | |
|     -- Data latch. WB will take the read data away as soon as the cycle
 | |
|     -- terminates but we must maintain it on DMI until req goes down, so
 | |
|     -- we latch it. (Q: Should we move that latch to dmi_dtm itself ?)
 | |
|     --
 | |
|     latch_reads : process(clk)
 | |
|     begin
 | |
|         if rising_edge(clk) then
 | |
|             if state = WB_CYCLE and wb_in.ack = '1' and dmi_wr = '0' then
 | |
|                 data_latch <= wb_in.dat;
 | |
|             end if;
 | |
|         end if;
 | |
|     end process;
 | |
| 
 | |
|     -- Command state machine (generate wb_cyc)
 | |
|     wb_trigger : process(clk)
 | |
|     begin
 | |
|         if rising_edge(clk) then
 | |
|             if (rst) then
 | |
|                 state <= IDLE;
 | |
|                 wb_out.stb <= '0';
 | |
|                 do_inc <= '0';
 | |
|             else
 | |
|                 case state is
 | |
|                 when IDLE =>
 | |
|                     if dmi_req = '1' and dmi_addr = DBG_WB_DATA then
 | |
|                         state <= WB_CYCLE;
 | |
|                         wb_out.stb <= '1';
 | |
|                     end if;
 | |
|                 when WB_CYCLE =>
 | |
|                     if wb_in.stall = '0' then
 | |
|                         wb_out.stb <= '0';
 | |
|                     end if;
 | |
|                     if wb_in.ack then
 | |
|                         -- We shouldn't get the ack if we hadn't already cleared
 | |
|                         -- stb above but if this happen, don't leave it dangling.
 | |
|                         --
 | |
|                         wb_out.stb <= '0';
 | |
|                         state <= DMI_WAIT;
 | |
|                         do_inc <= reg_ctrl(8);
 | |
|                     end if;
 | |
|                 when DMI_WAIT =>
 | |
|                     if dmi_req = '0' then
 | |
|                         state <= IDLE;
 | |
|                     end if;
 | |
|                     do_inc <= '0';
 | |
|                 end case;
 | |
|             end if;
 | |
|         end if;
 | |
|     end process;
 | |
| end architecture behaviour;
 |