-
Notifications
You must be signed in to change notification settings - Fork 195
Expand file tree
/
Copy pathstream_to_mem.sv
More file actions
134 lines (120 loc) · 5.1 KB
/
stream_to_mem.sv
File metadata and controls
134 lines (120 loc) · 5.1 KB
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
// Copyright 2020 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
// Authors:
// - Andreas Kurth <akurth@iis.ee.ethz.ch>
`include "common_cells/registers.svh"
`include "common_cells/assertions.svh"
/// `stream_to_mem`: Allows to use memories with flow control (`valid`/`ready`) for requests but without flow
/// control for output data to be used in streams.
module stream_to_mem #(
/// Memory request payload type, usually write enable, write data, etc.
parameter type mem_req_t = logic,
/// Memory response payload type, usually read data
parameter type mem_resp_t = logic,
/// Number of buffered responses (fall-through, thus no additional latency). This defines the
/// maximum number of outstanding requests on the memory interface. If the attached memory
/// responds in the same cycle a request is applied, this MUST be 0. If the attached memory
/// responds at least one cycle after a request, this MUST be >= 1 and should be equal to the
/// response latency of the memory to saturate bandwidth.
parameter int unsigned BufDepth = 32'd1
) (
/// Clock
input logic clk_i,
/// Asynchronous reset, active low
input logic rst_ni,
/// Request stream interface, payload
input mem_req_t req_i,
/// Request stream interface, payload is valid for transfer
input logic req_valid_i,
/// Request stream interface, payload can be accepted
output logic req_ready_o,
/// Response stream interface, payload
output mem_resp_t resp_o,
/// Response stream interface, payload is valid for transfer
output logic resp_valid_o,
/// Response stream interface, payload can be accepted
input logic resp_ready_i,
/// Memory request interface, payload
output mem_req_t mem_req_o,
/// Memory request interface, payload is valid for transfer
output logic mem_req_valid_o,
/// Memory request interface, payload can be accepted
input logic mem_req_ready_i,
/// Memory response interface, payload
input mem_resp_t mem_resp_i,
/// Memory response interface, payload is valid
input logic mem_resp_valid_i
);
typedef logic [$clog2(BufDepth+1):0] cnt_t;
cnt_t cnt_d, cnt_q;
logic buf_ready,
req_ready;
if (BufDepth > 0) begin : gen_buf
// Count number of outstanding requests.
always_comb begin
cnt_d = cnt_q;
if (req_valid_i && req_ready_o) begin
cnt_d++;
end
if (resp_valid_o && resp_ready_i) begin
cnt_d--;
end
end
// Can issue another request if the counter is not at its limit or a response is delivered in
// the current cycle.
assign req_ready = (cnt_q < BufDepth) | (resp_valid_o & resp_ready_i);
// Control request and memory request interface handshakes.
assign req_ready_o = mem_req_ready_i & req_ready;
assign mem_req_valid_o = req_valid_i & req_ready;
// Buffer responses.
stream_fifo #(
.FALL_THROUGH ( 1'b1 ),
.DEPTH ( BufDepth ),
.T ( mem_resp_t )
) i_resp_buf (
.clk_i,
.rst_ni,
.flush_i ( 1'b0 ),
.testmode_i ( 1'b0 ),
.data_i ( mem_resp_i ),
.valid_i ( mem_resp_valid_i ),
.ready_o ( buf_ready ),
.data_o ( resp_o ),
.valid_o ( resp_valid_o ),
.ready_i ( resp_ready_i ),
.usage_o ( /* unused */ )
);
// Register
`FFARN(cnt_q, cnt_d, '0, clk_i, rst_ni)
end else begin : gen_no_buf
// Control request, memory request, and response interface handshakes.
assign mem_req_valid_o = req_valid_i;
assign resp_valid_o = mem_req_valid_o & mem_req_ready_i & mem_resp_valid_i;
assign req_ready_o = resp_ready_i & resp_valid_o;
// Forward responses.
assign resp_o = mem_resp_i;
end
// Forward requests.
assign mem_req_o = req_i;
// Assertions
`ifndef COMMON_CELLS_ASSERTS_OFF
if (BufDepth > 0) begin : gen_buf_asserts
`ASSERT(memory_response_lost, mem_resp_valid_i |-> buf_ready, clk_i, !rst_ni,
"Memory response lost!")
`ASSERT(counter_underflowed, cnt_q == '0 |=> cnt_q != '1, clk_i, !rst_ni,
"Counter underflowed!")
`ASSERT(counter_overflowed, cnt_q == BufDepth |=> cnt_q != BufDepth + 1, clk_i, !rst_ni,
"Counter overflowed!")
end else begin : gen_no_buf_asserts
`ASSUME(no_memory_response, mem_req_valid_o & mem_req_ready_i |-> mem_resp_valid_i,
clk_i, !rst_ni, "Without BufDepth = 0, the memory must respond in the same cycle!")
end
`endif
endmodule