forked from antonblanchard/microwatt
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathwishbone_debug_master.vhdl
178 lines (160 loc) · 5.41 KB
/
wishbone_debug_master.vhdl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
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 downto 0);
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;