1
0
mirror of https://github.com/antonblanchard/microwatt.git synced 2026-01-11 23:43:15 +00:00
antonblanchard.microwatt/wishbone_debug_master.vhdl
Paul Mackerras ca4eb46aea Make wishbone addresses be in units of doublewords or words
This makes the 64-bit wishbone buses have the address expressed in
units of doublewords (64 bits), and similarly for the 32-bit buses the
address is in units of words (32 bits).  This is to comply with the
wishbone spec.  Previously the addresses on the wishbone buses were in
units of bytes regardless of the bus data width, which is not correct
and caused problems with interfacing with externally-generated logic.

Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
2021-09-15 18:18:09 +10:00

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;