-
Notifications
You must be signed in to change notification settings - Fork 136
/
exp_backoff.sv
94 lines (82 loc) · 3.39 KB
/
exp_backoff.sv
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
// Copyright 2019 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.
//
// Author: Michael Schaffner <schaffner@iis.ee.ethz.ch>, ETH Zurich
// Date: 10.04.2019
// Description: exponential backoff counter with randomization.
//
// For each failed trial (set_i pulsed), this unit exponentially increases the
// (average) backoff time by masking an LFSR with a shifted mask in order to
// create the backoff counter initial value.
//
// The shift register mask and the counter value are both reset to '0 in case of
// a successful trial (clr_i).
//
module exp_backoff #(
parameter int unsigned Seed = 'hffff, // seed for 16bit lfsr
parameter int unsigned MaxExp = 16 // 2**MaxExp-1 determines the maximum range from which random wait counts are drawn
) (
input logic clk_i,
input logic rst_ni,
//
input logic set_i, // sets the backoff counter (pulse) -> use when trial did not succeed
input logic clr_i, // clears the backoff counter (pulse) -> use when trial succeeded
output logic is_zero_o // indicates whether the backoff counter is equal to zero and a new trial can be launched
);
// leave this constant
localparam WIDTH = 16;
logic [WIDTH-1:0] lfsr_d, lfsr_q, cnt_d, cnt_q, mask_d, mask_q;
logic lfsr;
// generate random wait counts
// note: we use a flipped lfsr here to
// avoid strange correlation effects between
// the (left-shifted) mask and the lfsr
assign lfsr = lfsr_q[15-15] ^
lfsr_q[15-13] ^
lfsr_q[15-12] ^
lfsr_q[15-10];
assign lfsr_d = (set_i) ? {lfsr, lfsr_q[$high(lfsr_q):1]} :
lfsr_q;
// mask the wait counts with exponentially increasing mask (shift reg)
assign mask_d = (clr_i) ? '0 :
(set_i) ? {{(WIDTH-MaxExp){1'b0}},mask_q[MaxExp-2:0], 1'b1} :
mask_q;
assign cnt_d = (clr_i) ? '0 :
(set_i) ? (mask_q & lfsr_q) :
(!is_zero_o) ? cnt_q - 1'b1 : '0;
assign is_zero_o = (cnt_q=='0);
always_ff @(posedge clk_i or negedge rst_ni) begin : p_regs
if (!rst_ni) begin
lfsr_q <= WIDTH'(Seed);
mask_q <= '0;
cnt_q <= '0;
end else begin
lfsr_q <= lfsr_d;
mask_q <= mask_d;
cnt_q <= cnt_d;
end
end
///////////////////////////////////////////////////////
// assertions
///////////////////////////////////////////////////////
//pragma translate_off
`ifndef VERILATOR
initial begin
// assert wrong parameterizations
assert (MaxExp>0)
else $fatal(1,"MaxExp must be greater than 0");
assert (MaxExp<=16)
else $fatal(1,"MaxExp cannot be greater than 16");
assert (Seed>0)
else $fatal(1,"Zero seed is not allowed for LFSR");
end
`endif
//pragma translate_on
endmodule // exp_backoff