-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathtransactor_if.vhd
193 lines (150 loc) · 4.85 KB
/
transactor_if.vhd
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
179
180
181
182
183
184
185
186
187
188
189
190
191
192
-- Interface between transactor and packet buffers
--
-- This module knows nothing about the ipbus transaction protocol
--
-- Dave Newbold, October 2012
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.ipbus_trans_decl.all;
entity transactor_if is
port(
clk: in std_logic;
rst: in std_logic;
trans_in: in ipbus_trans_in;
trans_out: out ipbus_trans_out;
ipb_req: out std_logic; -- Bus request
ipb_grant: in std_logic; -- Bus grant
rx_ready: out std_logic; -- New data is available
rx_next: in std_logic; -- Request for new data from transactor
rx_data: out std_logic_vector(31 downto 0); -- Packet data to transactor
tx_data: in std_logic_vector(31 downto 0); -- Packet data from transactor
tx_we: in std_logic; -- Transactor data valid
tx_hdr: in std_logic; -- Header word flag from transactor
tx_err: in std_logic;
pkt_rx: out std_logic;
pkt_tx: out std_logic
);
end transactor_if;
architecture rtl of transactor_if is
type state_type is (ST_IDLE, ST_FIRST, ST_HDR, ST_PREBODY, ST_BODY, ST_DONE, ST_GAP);
signal state: state_type;
signal dinit, dinit_d, dnext, dnext_d, dsel: std_logic;
signal rxd, rxf: std_logic_vector(31 downto 0);
signal raddr, waddr, haddr, waddrh: unsigned(addr_width - 1 downto 0);
signal hlen, blen, rctr, wctr: unsigned(15 downto 0);
signal idata, rdata: std_logic_vector(31 downto 0);
signal first, start, start_d: std_logic;
begin
process(clk) -- Fall-through RAM
begin
if rising_edge(clk) then
if dinit = '1' then
raddr <= (others => '0');
elsif dnext = '1' or dinit_d = '1' then
raddr <= raddr + 1;
end if;
dinit_d <= dinit;
dnext_d <= dnext;
dsel <= dnext and dnext_d;
if dinit = '1' or dinit_d = '1' or dnext = '1' or dnext_d = '1' then
rxf <= trans_in.rdata;
end if;
end if;
end process;
trans_out.raddr <= std_logic_vector(raddr) when dinit = '0' else (others => '0');
rxd <= rxf when dsel = '0' else trans_in.rdata;
process(clk)
begin
if rising_edge(clk) then
if rst = '1' then
state <= ST_IDLE;
else
case state is
when ST_IDLE => -- Starting state
if start = '1' and start_d = '1' then
state <= ST_FIRST;
end if;
when ST_FIRST => -- Get packet length
if rxd(31 downto 16) = X"0000" then
if rxd(15 downto 0) = X"0000" then
state <= ST_DONE;
else
state <= ST_PREBODY;
end if;
else
state <= ST_HDR;
end if;
when ST_HDR => -- Transfer packet info
if rctr = hlen then
if blen = X"0000" then
state <= ST_DONE;
else
state <= ST_PREBODY;
end if;
end if;
when ST_PREBODY =>
if ipb_grant = '1' then
state <= ST_BODY;
end if;
when ST_BODY => -- Transfer body
if (rctr > blen and tx_hdr = '1') or tx_err = '1' then
state <= ST_DONE;
end if;
when ST_DONE => -- Write buffer header
state <= ST_GAP;
when ST_GAP =>
state <= ST_IDLE;
end case;
end if;
end if;
end process;
start <= trans_in.pkt_rdy and not trans_in.busy;
dinit <= not start;
dnext <= '1' when state = ST_FIRST or state = ST_HDR or (state = ST_BODY and rx_next = '1') else '0';
process(clk)
begin
if rising_edge(clk) then
start_d <= start;
if state = ST_IDLE and start = '1' then
hlen <= unsigned(rxd(31 downto 16));
blen <= unsigned(rxd(15 downto 0));
end if;
if state = ST_HDR or (state = ST_BODY and tx_we = '1') then
waddr <= waddr + 1;
elsif state = ST_DONE or rst = '1' then
waddr <= to_unsigned(1, addr_width);
end if;
if state = ST_IDLE or state = ST_PREBODY then
rctr <= X"0001";
elsif state = ST_HDR or (state = ST_BODY and rx_next = '1') then
rctr <= rctr + 1;
end if;
if state = ST_PREBODY then
wctr <= X"0000";
elsif state = ST_BODY and tx_we = '1' and first = '0' then
wctr <= wctr + 1;
end if;
if tx_hdr = '1' then
haddr <= waddr;
end if;
if state = ST_PREBODY then
first <= '1';
elsif tx_we = '1' then
first <= '0';
end if;
end if;
end process;
ipb_req <= '1' when state = ST_PREBODY or state = ST_BODY else '0';
rx_data <= rxd;
rx_ready <= '1' when state = ST_BODY and not (rctr > blen) else '0';
idata <= std_logic_vector(hlen) & std_logic_vector(wctr) when state = ST_DONE
else rxd;
waddrh <= (others => '0') when state = ST_DONE else waddr;
trans_out.pkt_done <= '1' when state = ST_DONE else '0';
trans_out.we <= '1' when state = ST_HDR or (tx_we = '1' and first = '0') or state = ST_DONE else '0';
trans_out.waddr <= std_logic_vector(haddr) when (state = ST_BODY and tx_hdr = '1') else std_logic_vector(waddrh);
trans_out.wdata <= tx_data when state = ST_BODY else idata;
pkt_rx <= '1' when state = ST_IDLE and start_d = '1' else '0';
pkt_tx <= '1' when state = ST_DONE else '0';
end rtl;