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

Subversion Repositories zipcpu

[/] [zipcpu/] [trunk/] [rtl/] [ex/] [wbarbiter.v] - Blame information for rev 209

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 209 dgisselq
////////////////////////////////////////////////////////////////////////////////
2
//
3
// Filename:    wbarbiter.v
4
//
5
// Project:     Zip CPU -- a small, lightweight, RISC CPU soft core
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
//      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
//
13
//      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
// Creator:     Dan Gisselquist, Ph.D.
33
//              Gisselquist Technology, LLC
34
//
35
////////////////////////////////////////////////////////////////////////////////
36
//
37
// Copyright (C) 2015-2019, Gisselquist Technology, LLC
38
//
39
// This program is free software (firmware): you can redistribute it and/or
40
// modify it under the terms of  the GNU General Public License as published
41
// by the Free Software Foundation, either version 3 of the License, or (at
42
// your option) any later version.
43
//
44
// This program is distributed in the hope that it will be useful, but WITHOUT
45
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
46
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
47
// for more details.
48
//
49
// You should have received a copy of the GNU General Public License along
50
// with this program.  (It's in the $(ROOT)/doc directory.  Run make with no
51
// target there if the PDF file isn't present.)  If not, see
52
// <http://www.gnu.org/licenses/> for a copy.
53
//
54
// License:     GPL, v3, as defined and found on www.gnu.org,
55
//              http://www.gnu.org/licenses/gpl.html
56
//
57
//
58
////////////////////////////////////////////////////////////////////////////////
59
//
60
//
61
`default_nettype        none
62
//
63
`define WBA_ALTERNATING
64
//
65
module  wbarbiter(i_clk, i_reset,
66
        // Bus A -- the priority bus
67
        i_a_cyc, i_a_stb, i_a_we, i_a_adr, i_a_dat, i_a_sel,
68
                o_a_ack, o_a_stall, o_a_err,
69
        // Bus B
70
        i_b_cyc, i_b_stb, i_b_we, i_b_adr, i_b_dat, i_b_sel,
71
                o_b_ack, o_b_stall, o_b_err,
72
        // Combined/arbitrated bus
73
        o_cyc, o_stb, o_we, o_adr, o_dat, o_sel, i_ack, i_stall, i_err
74
`ifdef  FORMAL
75
        ,
76
        f_a_nreqs, f_a_nacks, f_a_outstanding,
77
        f_b_nreqs, f_b_nacks, f_b_outstanding,
78
        f_nreqs,   f_nacks,   f_outstanding
79
`endif
80
        );
81
        parameter                       DW=32, AW=32;
82
        parameter                       SCHEME="ALTERNATING";
83
        parameter       [0:0]             OPT_ZERO_ON_IDLE = 1'b0;
84
        parameter                       F_MAX_STALL = 3;
85
        parameter                       F_MAX_ACK_DELAY = 3;
86
`ifdef  FORMAL
87
        parameter                       F_LGDEPTH=3;
88
`endif
89
 
90
        //
91
        input   wire                    i_clk, i_reset;
92
        // Bus A
93
        input   wire                    i_a_cyc, i_a_stb, i_a_we;
94
        input   wire    [(AW-1):0]       i_a_adr;
95
        input   wire    [(DW-1):0]       i_a_dat;
96
        input   wire    [(DW/8-1):0]     i_a_sel;
97
        output  wire                    o_a_ack, o_a_stall, o_a_err;
98
        // Bus B
99
        input   wire                    i_b_cyc, i_b_stb, i_b_we;
100
        input   wire    [(AW-1):0]       i_b_adr;
101
        input   wire    [(DW-1):0]       i_b_dat;
102
        input   wire    [(DW/8-1):0]     i_b_sel;
103
        output  wire                    o_b_ack, o_b_stall, o_b_err;
104
        //
105
        output  wire                    o_cyc, o_stb, o_we;
106
        output  wire    [(AW-1):0]       o_adr;
107
        output  wire    [(DW-1):0]       o_dat;
108
        output  wire    [(DW/8-1):0]     o_sel;
109
        input   wire                    i_ack, i_stall, i_err;
110
        //
111
`ifdef  FORMAL
112
        output  wire    [(F_LGDEPTH-1):0] f_nreqs, f_nacks, f_outstanding,
113
                        f_a_nreqs, f_a_nacks, f_a_outstanding,
114
                        f_b_nreqs, f_b_nacks, f_b_outstanding;
115
`endif
116
 
117
        // Go high immediately (new cycle) if ...
118
        //      Previous cycle was low and *someone* is requesting a bus cycle
119
        // Go low immadiately if ...
120
        //      We were just high and the owner no longer wants the bus
121
        // WISHBONE Spec recommends no logic between a FF and the o_cyc
122
        //      This violates that spec.  (Rec 3.15, p35)
123
        reg     r_a_owner;
124
 
125
        assign o_cyc = (r_a_owner) ? i_a_cyc : i_b_cyc;
126
        initial r_a_owner = 1'b1;
127
 
128
        generate if (SCHEME == "PRIORITY")
129
        begin : PRI
130
 
131
                always @(posedge i_clk)
132
                        if (!i_b_cyc)
133
                                r_a_owner <= 1'b1;
134
                        // Allow B to set its CYC line w/o activating this
135
                        // interface
136
                        else if ((i_b_stb)&&(!i_a_cyc))
137
                                r_a_owner <= 1'b0;
138
 
139
        end else if (SCHEME == "ALTERNATING")
140
        begin : ALT
141
 
142
                reg     last_owner;
143
                initial last_owner = 1'b0;
144
                always @(posedge i_clk)
145
                        if ((i_a_cyc)&&(r_a_owner))
146
                                last_owner <= 1'b1;
147
                        else if ((i_b_cyc)&&(!r_a_owner))
148
                                last_owner <= 1'b0;
149
 
150
                always @(posedge i_clk)
151
                        if ((!i_a_cyc)&&(!i_b_cyc))
152
                                r_a_owner <= !last_owner;
153
                        else if ((r_a_owner)&&(!i_a_cyc))
154
                        begin
155
 
156
                                if (i_b_stb)
157
                                        r_a_owner <= 1'b0;
158
 
159
                        end else if ((!r_a_owner)&&(!i_b_cyc))
160
                        begin
161
 
162
                                if (i_a_stb)
163
                                        r_a_owner <= 1'b1;
164
 
165
                        end
166
 
167
        end else // if (SCHEME == "LAST")
168
        begin : LST
169
                always @(posedge i_clk)
170
                        if ((!i_a_cyc)&&(i_b_stb))
171
                                r_a_owner <= 1'b0;
172
                        else if ((!i_b_cyc)&&(i_a_stb))
173
                                r_a_owner <= 1'b1;
174
        end endgenerate
175
 
176
 
177
        // Realistically, if neither master owns the bus, the output is a
178
        // don't care.  Thus we trigger off whether or not 'A' owns the bus.
179
        // If 'B' owns it all we care is that 'A' does not.  Likewise, if
180
        // neither owns the bus than the values on the various lines are
181
        // irrelevant.
182
        assign o_we  = (r_a_owner) ? i_a_we  : i_b_we;
183
 
184
        generate if (OPT_ZERO_ON_IDLE)
185
        begin
186
                //
187
                // OPT_ZERO_ON_IDLE will use up more logic and may even slow
188
                // down the master clock if set.  However, it may also reduce
189
                // the power used by the FPGA by preventing things from toggling
190
                // when the bus isn't in use.  The option is here because it
191
                // also makes it a lot easier to look for when things happen
192
                // on the bus via VERILATOR when timing and logic counts
193
                // don't matter.
194
                //
195
                assign o_stb     = (o_cyc)? ((r_a_owner) ? i_a_stb : i_b_stb):0;
196
                assign o_adr     = (o_stb)? ((r_a_owner) ? i_a_adr : i_b_adr):0;
197
                assign o_dat     = (o_stb)? ((r_a_owner) ? i_a_dat : i_b_dat):0;
198
                assign o_sel     = (o_stb)? ((r_a_owner) ? i_a_sel : i_b_sel):0;
199
                assign o_a_ack   = (o_cyc)&&( r_a_owner) ? i_ack   : 1'b0;
200
                assign o_b_ack   = (o_cyc)&&(!r_a_owner) ? i_ack   : 1'b0;
201
                assign o_a_stall = (o_cyc)&&( r_a_owner) ? i_stall : 1'b1;
202
                assign o_b_stall = (o_cyc)&&(!r_a_owner) ? i_stall : 1'b1;
203
                assign o_a_err   = (o_cyc)&&( r_a_owner) ? i_err : 1'b0;
204
                assign o_b_err   = (o_cyc)&&(!r_a_owner) ? i_err : 1'b0;
205
        end else begin
206
 
207
                assign o_stb = (r_a_owner) ? i_a_stb : i_b_stb;
208
                assign o_adr = (r_a_owner) ? i_a_adr : i_b_adr;
209
                assign o_dat = (r_a_owner) ? i_a_dat : i_b_dat;
210
                assign o_sel = (r_a_owner) ? i_a_sel : i_b_sel;
211
 
212
                // We cannot allow the return acknowledgement to ever go high if
213
                // the master in question does not own the bus.  Hence we force
214
                // it low if the particular master doesn't own the bus.
215
                assign  o_a_ack   = ( r_a_owner) ? i_ack   : 1'b0;
216
                assign  o_b_ack   = (!r_a_owner) ? i_ack   : 1'b0;
217
 
218
                // Stall must be asserted on the same cycle the input master
219
                // asserts the bus, if the bus isn't granted to him.
220
                assign  o_a_stall = ( r_a_owner) ? i_stall : 1'b1;
221
                assign  o_b_stall = (!r_a_owner) ? i_stall : 1'b1;
222
 
223
                //
224
                //
225
                assign  o_a_err = ( r_a_owner) ? i_err : 1'b0;
226
                assign  o_b_err = (!r_a_owner) ? i_err : 1'b0;
227
        end endgenerate
228
 
229
        // Make Verilator happy
230
        // verilator lint_off UNUSED
231
        wire    unused;
232
        assign  unused = i_reset;
233
        // verilator lint_on  UNUSED
234
 
235
`ifdef  FORMAL
236
 
237
`ifdef  WBARBITER
238
`define ASSUME  assume
239
`else
240
`define ASSUME  assert
241
`endif
242
 
243
        reg     f_past_valid;
244
        initial f_past_valid = 1'b0;
245
        always @(posedge i_clk)
246
                f_past_valid <= 1'b1;
247
 
248
        initial `ASSUME(!i_a_cyc);
249
        initial `ASSUME(!i_a_stb);
250
 
251
        initial `ASSUME(!i_b_cyc);
252
        initial `ASSUME(!i_b_stb);
253
 
254
        initial `ASSUME(!i_ack);
255
        initial `ASSUME(!i_err);
256
 
257
        always @(*)
258
        if (!f_past_valid)
259
                `ASSUME(i_reset);
260
 
261
        always @(posedge i_clk)
262
        begin
263
                if (o_cyc)
264
                        assert((i_a_cyc)||(i_b_cyc));
265
                if ((f_past_valid)&&($past(o_cyc))&&(o_cyc))
266
                        assert($past(r_a_owner) == r_a_owner);
267
        end
268
 
269
        fwb_master #(.DW(DW), .AW(AW),
270
                        .F_MAX_STALL(F_MAX_STALL),
271
                        .F_LGDEPTH(F_LGDEPTH),
272
                        .F_MAX_ACK_DELAY(F_MAX_ACK_DELAY),
273
                        .F_OPT_RMW_BUS_OPTION(1),
274
                        .F_OPT_DISCONTINUOUS(1),
275
                        .F_OPT_CLK2FFLOGIC(1'b0))
276
                f_wbm(i_clk, i_reset,
277
                        o_cyc, o_stb, o_we, o_adr, o_dat, o_sel,
278
                        i_ack, i_stall, 32'h0, i_err,
279
                        f_nreqs, f_nacks, f_outstanding);
280
 
281
        fwb_slave  #(.DW(DW), .AW(AW),
282
                        .F_MAX_STALL(0),
283
                        .F_LGDEPTH(F_LGDEPTH),
284
                        .F_MAX_ACK_DELAY(0),
285
                        .F_OPT_RMW_BUS_OPTION(1),
286
                        .F_OPT_DISCONTINUOUS(1),
287
                        .F_OPT_CLK2FFLOGIC(1'b0))
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_OPT_CLK2FFLOGIC(1'b0))
300
                f_wbb(i_clk, i_reset,
301
                        i_b_cyc, i_b_stb, i_b_we, i_b_adr, i_b_dat, i_b_sel,
302
                        o_b_ack, o_b_stall, 32'h0, o_b_err,
303
                        f_b_nreqs, f_b_nacks, f_b_outstanding);
304
 
305
        always @(posedge i_clk)
306
                if (r_a_owner)
307
                begin
308
                        assert(f_b_nreqs == 0);
309
                        assert(f_b_nacks == 0);
310
                        assert(f_a_outstanding == f_outstanding);
311
                end else begin
312
                        assert(f_a_nreqs == 0);
313
                        assert(f_a_nacks == 0);
314
                        assert(f_b_outstanding == f_outstanding);
315
                end
316
 
317
        always @(posedge i_clk)
318
        if ((f_past_valid)&&(!$past(i_reset))
319
                        &&($past(i_a_stb))&&(!$past(i_b_cyc)))
320
                assert(r_a_owner);
321
        always @(posedge i_clk)
322
        if ((f_past_valid)&&(!$past(i_reset))
323
                        &&(!$past(i_a_cyc))&&($past(i_b_stb)))
324
                assert(!r_a_owner);
325
 
326
        always @(posedge i_clk)
327
                if ((f_past_valid)&&(r_a_owner != $past(r_a_owner)))
328
                        assert(!$past(o_cyc));
329
 
330
`endif
331
endmodule
332
 

powered by: WebSVN 2.1.0

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