OpenCores
URL https://opencores.org/ocsvn/wb2axip/wb2axip/trunk

Subversion Repositories wb2axip

[/] [wb2axip/] [trunk/] [rtl/] [wbarbiter.v] - Blame information for rev 17

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 8 dgisselq
////////////////////////////////////////////////////////////////////////////////
2
//
3
// Filename:    wbarbiter.v
4
//
5
// Project:     Pipelined Wishbone to AXI converter
6
//
7
// Purpose:     This is a priority bus arbiter.  It allows two separate wishbone
8
//              masters to connect to the same bus, while also guaranteeing
9 16 dgisselq
//      that the last master can have the bus with no delay any time it is
10
//      idle.  The goal is to minimize the combinatorial logic required in this
11
//      process, while still minimizing access time.
12 8 dgisselq
//
13 16 dgisselq
//      The core logic works like this:
14
//
15
//              1. If 'A' or 'B' asserts the o_cyc line, a bus cycle will begin,
16
//                      with acccess granted to whomever requested it.
17
//              2. If both 'A' and 'B' assert o_cyc at the same time, only 'A'
18
//                      will be granted the bus.  (If the alternating parameter 
19
//                      is set, A and B will alternate who gets the bus in
20
//                      this case.)
21
//              3. The bus will remain owned by whomever the bus was granted to
22
//                      until they deassert the o_cyc line.
23
//              4. At the end of a bus cycle, o_cyc is guaranteed to be
24
//                      deasserted (low) for one clock.
25
//              5. On the next clock, bus arbitration takes place again.  If
26
//                      'A' requests the bus, no matter how long 'B' was
27
//                      waiting, 'A' will then be granted the bus.  (Unless
28
//                      again the alternating parameter is set, then the
29
//                      access is guaranteed to switch to B.)
30
//
31
//
32 8 dgisselq
// Creator:     Dan Gisselquist, Ph.D.
33
//              Gisselquist Technology, LLC
34
//
35
////////////////////////////////////////////////////////////////////////////////
36
//
37 16 dgisselq
// Copyright (C) 2015-2019, Gisselquist Technology, LLC
38 8 dgisselq
//
39 16 dgisselq
// This file is part of the pipelined Wishbone to AXI converter project, a
40
// project that contains multiple bus bridging designs and formal bus property
41
// sets.
42 8 dgisselq
//
43 16 dgisselq
// The bus bridge designs and property sets are free RTL designs: you can
44
// redistribute them and/or modify any of them under the terms of the GNU
45
// Lesser General Public License as published by the Free Software Foundation,
46
// either version 3 of the License, or (at your option) any later version.
47 8 dgisselq
//
48 16 dgisselq
// The bus bridge designs and property sets are distributed in the hope that
49
// they will be useful, but WITHOUT ANY WARRANTY; without even the implied
50
// warranty of MERCHANTIBILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
51
// GNU Lesser General Public License for more details.
52
//
53
// You should have received a copy of the GNU Lesser General Public License
54
// along with these designs.  (It's in the $(ROOT)/doc directory.  Run make
55
// with no target there if the PDF file isn't present.)  If not, see
56 8 dgisselq
// <http://www.gnu.org/licenses/> for a copy.
57
//
58 16 dgisselq
// License:     LGPL, v3, as defined and found on www.gnu.org,
59
//              http://www.gnu.org/licenses/lgpl.html
60 8 dgisselq
//
61
////////////////////////////////////////////////////////////////////////////////
62
//
63
//
64
`default_nettype        none
65
//
66
`define WBA_ALTERNATING
67
//
68
module  wbarbiter(i_clk, i_reset,
69
        // Bus A -- the priority bus
70
        i_a_cyc, i_a_stb, i_a_we, i_a_adr, i_a_dat, i_a_sel,
71
                o_a_ack, o_a_stall, o_a_err,
72
        // Bus B
73
        i_b_cyc, i_b_stb, i_b_we, i_b_adr, i_b_dat, i_b_sel,
74
                o_b_ack, o_b_stall, o_b_err,
75
        // Combined/arbitrated bus
76 16 dgisselq
        o_cyc, o_stb, o_we, o_adr, o_dat, o_sel, i_ack, i_stall, i_err
77
`ifdef  FORMAL
78
        ,
79
        f_a_nreqs, f_a_nacks, f_a_outstanding,
80
        f_b_nreqs, f_b_nacks, f_b_outstanding,
81
        f_nreqs,   f_nacks,   f_outstanding
82
`endif
83
        );
84 8 dgisselq
        parameter                       DW=32, AW=32;
85
        parameter                       SCHEME="ALTERNATING";
86
        parameter       [0:0]             OPT_ZERO_ON_IDLE = 1'b0;
87 16 dgisselq
        parameter                       F_MAX_STALL = 3;
88
        parameter                       F_MAX_ACK_DELAY = 3;
89 8 dgisselq
        parameter                       F_LGDEPTH=3;
90
 
91
        //
92
        input   wire                    i_clk, i_reset;
93
        // Bus A
94
        input   wire                    i_a_cyc, i_a_stb, i_a_we;
95
        input   wire    [(AW-1):0]       i_a_adr;
96
        input   wire    [(DW-1):0]       i_a_dat;
97
        input   wire    [(DW/8-1):0]     i_a_sel;
98
        output  wire                    o_a_ack, o_a_stall, o_a_err;
99
        // Bus B
100
        input   wire                    i_b_cyc, i_b_stb, i_b_we;
101
        input   wire    [(AW-1):0]       i_b_adr;
102
        input   wire    [(DW-1):0]       i_b_dat;
103
        input   wire    [(DW/8-1):0]     i_b_sel;
104
        output  wire                    o_b_ack, o_b_stall, o_b_err;
105
        //
106
        output  wire                    o_cyc, o_stb, o_we;
107
        output  wire    [(AW-1):0]       o_adr;
108
        output  wire    [(DW-1):0]       o_dat;
109
        output  wire    [(DW/8-1):0]     o_sel;
110
        input   wire                    i_ack, i_stall, i_err;
111 16 dgisselq
        //
112
`ifdef  FORMAL
113
        output  wire    [(F_LGDEPTH-1):0] f_nreqs, f_nacks, f_outstanding,
114
                        f_a_nreqs, f_a_nacks, f_a_outstanding,
115
                        f_b_nreqs, f_b_nacks, f_b_outstanding;
116
`endif
117 8 dgisselq
 
118
        // Go high immediately (new cycle) if ...
119
        //      Previous cycle was low and *someone* is requesting a bus cycle
120
        // Go low immadiately if ...
121
        //      We were just high and the owner no longer wants the bus
122
        // WISHBONE Spec recommends no logic between a FF and the o_cyc
123
        //      This violates that spec.  (Rec 3.15, p35)
124
        reg     r_a_owner;
125
 
126
        assign o_cyc = (r_a_owner) ? i_a_cyc : i_b_cyc;
127
        initial r_a_owner = 1'b1;
128
 
129
        generate if (SCHEME == "PRIORITY")
130
        begin : PRI
131
 
132
                always @(posedge i_clk)
133
                        if (!i_b_cyc)
134
                                r_a_owner <= 1'b1;
135
                        // Allow B to set its CYC line w/o activating this
136
                        // interface
137
                        else if ((i_b_stb)&&(!i_a_cyc))
138
                                r_a_owner <= 1'b0;
139
 
140
        end else if (SCHEME == "ALTERNATING")
141
        begin : ALT
142
 
143
                reg     last_owner;
144
                initial last_owner = 1'b0;
145
                always @(posedge i_clk)
146
                        if ((i_a_cyc)&&(r_a_owner))
147
                                last_owner <= 1'b1;
148
                        else if ((i_b_cyc)&&(!r_a_owner))
149
                                last_owner <= 1'b0;
150
 
151
                always @(posedge i_clk)
152
                        if ((!i_a_cyc)&&(!i_b_cyc))
153
                                r_a_owner <= !last_owner;
154
                        else if ((r_a_owner)&&(!i_a_cyc))
155
                        begin
156
 
157
                                if (i_b_stb)
158
                                        r_a_owner <= 1'b0;
159
 
160
                        end else if ((!r_a_owner)&&(!i_b_cyc))
161
                        begin
162
 
163
                                if (i_a_stb)
164
                                        r_a_owner <= 1'b1;
165
 
166
                        end
167
 
168
        end else // if (SCHEME == "LAST")
169
        begin : LST
170
                always @(posedge i_clk)
171
                        if ((!i_a_cyc)&&(i_b_stb))
172
                                r_a_owner <= 1'b0;
173
                        else if ((!i_b_cyc)&&(i_a_stb))
174
                                r_a_owner <= 1'b1;
175
        end endgenerate
176
 
177
 
178
        // Realistically, if neither master owns the bus, the output is a
179
        // don't care.  Thus we trigger off whether or not 'A' owns the bus.
180
        // If 'B' owns it all we care is that 'A' does not.  Likewise, if
181
        // neither owns the bus than the values on the various lines are
182
        // irrelevant.
183
        assign o_we  = (r_a_owner) ? i_a_we  : i_b_we;
184
 
185
        generate if (OPT_ZERO_ON_IDLE)
186
        begin
187
                //
188
                // OPT_ZERO_ON_IDLE will use up more logic and may even slow
189
                // down the master clock if set.  However, it may also reduce
190
                // the power used by the FPGA by preventing things from toggling
191
                // when the bus isn't in use.  The option is here because it
192
                // also makes it a lot easier to look for when things happen
193
                // on the bus via VERILATOR when timing and logic counts
194
                // don't matter.
195
                //
196
                assign o_stb     = (o_cyc)? ((r_a_owner) ? i_a_stb : i_b_stb):0;
197
                assign o_adr     = (o_stb)? ((r_a_owner) ? i_a_adr : i_b_adr):0;
198
                assign o_dat     = (o_stb)? ((r_a_owner) ? i_a_dat : i_b_dat):0;
199
                assign o_sel     = (o_stb)? ((r_a_owner) ? i_a_sel : i_b_sel):0;
200
                assign o_a_ack   = (o_cyc)&&( r_a_owner) ? i_ack   : 1'b0;
201
                assign o_b_ack   = (o_cyc)&&(!r_a_owner) ? i_ack   : 1'b0;
202
                assign o_a_stall = (o_cyc)&&( r_a_owner) ? i_stall : 1'b1;
203
                assign o_b_stall = (o_cyc)&&(!r_a_owner) ? i_stall : 1'b1;
204
                assign o_a_err   = (o_cyc)&&( r_a_owner) ? i_err : 1'b0;
205
                assign o_b_err   = (o_cyc)&&(!r_a_owner) ? i_err : 1'b0;
206
        end else begin
207
 
208
                assign o_stb = (r_a_owner) ? i_a_stb : i_b_stb;
209
                assign o_adr = (r_a_owner) ? i_a_adr : i_b_adr;
210
                assign o_dat = (r_a_owner) ? i_a_dat : i_b_dat;
211
                assign o_sel = (r_a_owner) ? i_a_sel : i_b_sel;
212
 
213
                // We cannot allow the return acknowledgement to ever go high if
214
                // the master in question does not own the bus.  Hence we force
215
                // it low if the particular master doesn't own the bus.
216
                assign  o_a_ack   = ( r_a_owner) ? i_ack   : 1'b0;
217
                assign  o_b_ack   = (!r_a_owner) ? i_ack   : 1'b0;
218
 
219
                // Stall must be asserted on the same cycle the input master
220
                // asserts the bus, if the bus isn't granted to him.
221
                assign  o_a_stall = ( r_a_owner) ? i_stall : 1'b1;
222
                assign  o_b_stall = (!r_a_owner) ? i_stall : 1'b1;
223
 
224
                //
225
                //
226
                assign  o_a_err = ( r_a_owner) ? i_err : 1'b0;
227
                assign  o_b_err = (!r_a_owner) ? i_err : 1'b0;
228
        end endgenerate
229
 
230
        // Make Verilator happy
231
        // verilator lint_off UNUSED
232
        wire    unused;
233
        assign  unused = i_reset;
234
        // verilator lint_on  UNUSED
235
 
236
`ifdef  FORMAL
237
 
238
`ifdef  WBARBITER
239 16 dgisselq
 
240 8 dgisselq
`define ASSUME  assume
241
`else
242
`define ASSUME  assert
243
`endif
244
 
245
        reg     f_past_valid;
246
        initial f_past_valid = 1'b0;
247 16 dgisselq
        always @(posedge i_clk)
248 8 dgisselq
                f_past_valid <= 1'b1;
249
 
250
        initial `ASSUME(!i_a_cyc);
251
        initial `ASSUME(!i_a_stb);
252
 
253
        initial `ASSUME(!i_b_cyc);
254
        initial `ASSUME(!i_b_stb);
255
 
256
        initial `ASSUME(!i_ack);
257
        initial `ASSUME(!i_err);
258
 
259 16 dgisselq
        always @(*)
260
        if (!f_past_valid)
261
                `ASSUME(i_reset);
262
 
263 8 dgisselq
        always @(posedge i_clk)
264
        begin
265
                if (o_cyc)
266
                        assert((i_a_cyc)||(i_b_cyc));
267
                if ((f_past_valid)&&($past(o_cyc))&&(o_cyc))
268
                        assert($past(r_a_owner) == r_a_owner);
269
        end
270
 
271
        fwb_master #(.DW(DW), .AW(AW),
272 16 dgisselq
                        .F_MAX_STALL(F_MAX_STALL),
273 8 dgisselq
                        .F_LGDEPTH(F_LGDEPTH),
274 16 dgisselq
                        .F_MAX_ACK_DELAY(F_MAX_ACK_DELAY),
275 8 dgisselq
                        .F_OPT_RMW_BUS_OPTION(1),
276
                        .F_OPT_DISCONTINUOUS(1))
277
                f_wbm(i_clk, i_reset,
278
                        o_cyc, o_stb, o_we, o_adr, o_dat, o_sel,
279
                        i_ack, i_stall, 32'h0, i_err,
280
                        f_nreqs, f_nacks, f_outstanding);
281
 
282
        fwb_slave  #(.DW(DW), .AW(AW),
283
                        .F_MAX_STALL(0),
284
                        .F_LGDEPTH(F_LGDEPTH),
285
                        .F_MAX_ACK_DELAY(0),
286
                        .F_OPT_RMW_BUS_OPTION(1),
287
                        .F_OPT_DISCONTINUOUS(1))
288
                f_wba(i_clk, i_reset,
289
                        i_a_cyc, i_a_stb, i_a_we, i_a_adr, i_a_dat, i_a_sel,
290
                        o_a_ack, o_a_stall, 32'h0, o_a_err,
291
                        f_a_nreqs, f_a_nacks, f_a_outstanding);
292
 
293
        fwb_slave  #(.DW(DW), .AW(AW),
294
                        .F_MAX_STALL(0),
295
                        .F_LGDEPTH(F_LGDEPTH),
296
                        .F_MAX_ACK_DELAY(0),
297
                        .F_OPT_RMW_BUS_OPTION(1),
298
                        .F_OPT_DISCONTINUOUS(1))
299
                f_wbb(i_clk, i_reset,
300
                        i_b_cyc, i_b_stb, i_b_we, i_b_adr, i_b_dat, i_b_sel,
301
                        o_b_ack, o_b_stall, 32'h0, o_b_err,
302
                        f_b_nreqs, f_b_nacks, f_b_outstanding);
303
 
304
        always @(posedge i_clk)
305
                if (r_a_owner)
306
                begin
307
                        assert(f_b_nreqs == 0);
308
                        assert(f_b_nacks == 0);
309
                        assert(f_a_outstanding == f_outstanding);
310
                end else begin
311
                        assert(f_a_nreqs == 0);
312
                        assert(f_a_nacks == 0);
313
                        assert(f_b_outstanding == f_outstanding);
314
                end
315
 
316
        always @(posedge i_clk)
317
        if ((f_past_valid)&&(!$past(i_reset))
318
                        &&($past(i_a_stb))&&(!$past(i_b_cyc)))
319
                assert(r_a_owner);
320
        always @(posedge i_clk)
321
        if ((f_past_valid)&&(!$past(i_reset))
322
                        &&(!$past(i_a_cyc))&&($past(i_b_stb)))
323
                assert(!r_a_owner);
324
 
325
        always @(posedge i_clk)
326
                if ((f_past_valid)&&(r_a_owner != $past(r_a_owner)))
327
                        assert(!$past(o_cyc));
328
 
329 16 dgisselq
        reg     f_prior_a_ack, f_prior_b_ack;
330
 
331
        initial f_prior_a_ack = 1'b0;
332
        always @(posedge i_clk)
333
        if ((i_reset)||(o_a_err)||(o_b_err))
334
                f_prior_a_ack = 1'b0;
335
        else if ((o_cyc)&&(o_a_ack))
336
                f_prior_a_ack <= 1'b1;
337
 
338
        initial f_prior_b_ack = 1'b0;
339
        always @(posedge i_clk)
340
        if ((i_reset)||(o_a_err)||(o_b_err))
341
                f_prior_b_ack = 1'b0;
342
        else if ((o_cyc)&&(o_b_ack))
343
                f_prior_b_ack <= 1'b1;
344
 
345
        always @(posedge i_clk)
346
        begin
347
                cover(f_prior_b_ack && o_cyc && o_a_ack);
348
 
349
                cover((o_cyc && o_a_ack)
350
                        &&($past(o_cyc && o_a_ack))
351
                        &&($past(o_cyc && o_a_ack,2)));
352
 
353
 
354
                cover(f_prior_a_ack && o_cyc && o_b_ack);
355
 
356
                cover((o_cyc && o_b_ack)
357
                        &&($past(o_cyc && o_b_ack))
358
                        &&($past(o_cyc && o_b_ack,2)));
359
        end
360
 
361
        always @(*)
362
                cover(o_cyc && o_b_ack);
363 8 dgisselq
`endif
364
endmodule
365
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.