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

Subversion Repositories zipcpu

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

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 209 dgisselq
////////////////////////////////////////////////////////////////////////////////
2
//
3
// Filename:    wbdblpriarb.v
4
//
5
// Project:     Zip CPU -- a small, lightweight, RISC CPU soft core
6
//
7
// Purpose:     This should almost be identical to the priority arbiter, save
8
//              for a simple diffence: it allows the arbitration of two
9
//      separate wishbone buses.  The purpose of this is to push the address
10
//      resolution back one cycle, so that by the first clock visible to this
11
//      core, it is known which of two parts of the bus the desired address
12
//      will be on, save that we still use the arbiter since the underlying
13
//      device doesn't know that there are two wishbone buses.
14
//
15
//      So at this point we've deviated from the WB spec somewhat, by allowing
16
//      two CYC and two STB lines.  Everything else is the same.  This allows
17
//      (in this case the Zip CPU) to determine whether or not the access
18
//      will be to the local ZipSystem bus or the external WB bus on the clock
19
//      before the local bus access, otherwise peripherals were needing to do
20
//      multiple device selection comparisons/test within a clock: 1) is this
21
//      for the local or external bus, and 2) is this referencing me as a
22
//      peripheral.  This then caused the ZipCPU to fail all timing specs.
23
//      By creating the two pairs of lines, CYC_A/STB_A and CYC_B/STB_B, the
24
//      determination of local vs external can be made one clock earlier
25
//      where there's still time for the logic, and the second comparison
26
//      now has time to complete.
27
//
28
//      So let me try to explain this again.  To use this arbiter, one of the
29
//      two masters sets CYC and STB before, only the master determines which
30
//      of two address spaces the CYC and STB apply to before the clock and
31
//      only sets the appropriate CYC and STB lines.  Then, on the clock tick,
32
//      the arbiter determines who gets *both* busses, as they both share every
33
//      other WB line. Thus, only one of CYC_A and CYC_B going out will ever
34
//      be high at a given time.
35
//
36
//      Hopefully this makes more sense than it sounds. If not, check out the
37
//      code below for a better explanation.
38
//
39
//      20150919 -- Added supported for the WB error signal.
40
//
41
//
42
// Creator:     Dan Gisselquist, Ph.D.
43
//              Gisselquist Technology, LLC
44
//
45
////////////////////////////////////////////////////////////////////////////////
46
//
47
// Copyright (C) 2015,2018-2019, Gisselquist Technology, LLC
48
//
49
// This program is free software (firmware): you can redistribute it and/or
50
// modify it under the terms of  the GNU General Public License as published
51
// by the Free Software Foundation, either version 3 of the License, or (at
52
// your option) any later version.
53
//
54
// This program is distributed in the hope that it will be useful, but WITHOUT
55
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
56
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
57
// for more details.
58
//
59
// You should have received a copy of the GNU General Public License along
60
// with this program.  (It's in the $(ROOT)/doc directory.  Run make with no
61
// target there if the PDF file isn't present.)  If not, see
62
// <http://www.gnu.org/licenses/> for a copy.
63
//
64
// License:     GPL, v3, as defined and found on www.gnu.org,
65
//              http://www.gnu.org/licenses/gpl.html
66
//
67
//
68
////////////////////////////////////////////////////////////////////////////////
69
//
70
//
71
`default_nettype        none
72
//
73
module  wbdblpriarb(i_clk, i_reset,
74
        // Bus A
75
        i_a_cyc_a,i_a_cyc_b,i_a_stb_a,i_a_stb_b,i_a_we,i_a_adr, i_a_dat, i_a_sel, o_a_ack, o_a_stall, o_a_err,
76
        // Bus B
77
        i_b_cyc_a,i_b_cyc_b,i_b_stb_a,i_b_stb_b,i_b_we,i_b_adr, i_b_dat, i_b_sel, o_b_ack, o_b_stall, o_b_err,
78
        // Both buses
79
        o_cyc_a, o_cyc_b, o_stb_a, o_stb_b, o_we, o_adr, o_dat, o_sel,
80
                i_ack, i_stall, i_err
81
`ifdef  FORMAL
82
                        , f_nreqs_a, f_nacks_a, f_outstanding_a,
83
                        f_nreqs_b, f_nacks_b, f_outstanding_b,
84
                        f_a_nreqs_a, f_a_nacks_a, f_a_outstanding_a,
85
                        f_a_nreqs_b, f_a_nacks_b, f_a_outstanding_b,
86
                        f_b_nreqs_a, f_b_nacks_a, f_b_outstanding_a,
87
                        f_b_nreqs_b, f_b_nacks_b, f_b_outstanding_b
88
`endif
89
        );
90
 
91
        parameter                       DW=32, AW=32;
92
        //
93
        // ZERO_ON_IDLE uses more logic than the alternative.  It should be
94
        // useful for reducing power, as these circuits tend to drive wires
95
        // all the way across the design, but it may also slow down the master
96
        // clock.  I've used it as an option when using VERILATOR, 'cause
97
        // zeroing things on idle can make them stand out all the more when
98
        // staring at wires and dumps and such.
99
        parameter       [0:0]             OPT_ZERO_ON_IDLE = 1'b0;
100
        //
101
        //
102
        parameter                       F_LGDEPTH = 3;
103
        //
104
        //
105
        parameter       F_MAX_STALL = 0;
106
        parameter       F_MAX_ACK_DELAY=0;
107
        //
108
        // Wishbone doesn't use an i_ce signal.  While it could, they dislike
109
        // what it would (might) do to the synchronous reset signal, i_reset.
110
        input   wire                    i_clk, i_reset;
111
        // Bus A
112
        input   wire                    i_a_cyc_a, i_a_cyc_b, i_a_stb_a, i_a_stb_b, i_a_we;
113
        input   wire    [(AW-1):0]       i_a_adr;
114
        input   wire    [(DW-1):0]       i_a_dat;
115
        input   wire    [(DW/8-1):0]     i_a_sel;
116
        output  wire                    o_a_ack, o_a_stall, o_a_err;
117
        // Bus B
118
        input   wire                    i_b_cyc_a, i_b_cyc_b, i_b_stb_a, i_b_stb_b, i_b_we;
119
        input   wire    [(AW-1):0]       i_b_adr;
120
        input   wire    [(DW-1):0]       i_b_dat;
121
        input   wire    [(DW/8-1):0]     i_b_sel;
122
        output  wire                    o_b_ack, o_b_stall, o_b_err;
123
        //
124
        output  wire                    o_cyc_a,o_cyc_b, o_stb_a, o_stb_b, o_we;
125
        output  wire    [(AW-1):0]       o_adr;
126
        output  wire    [(DW-1):0]       o_dat;
127
        output  wire    [(DW/8-1):0]     o_sel;
128
        input   wire                    i_ack, i_stall, i_err;
129
`ifdef  FORMAL
130
        output  wire    [(F_LGDEPTH-1):0]
131
                        f_nreqs_a, f_nacks_a, f_outstanding_a,
132
                        f_nreqs_b, f_nacks_b, f_outstanding_b,
133
                        f_a_nreqs_a, f_a_nacks_a, f_a_outstanding_a,
134
                        f_a_nreqs_b, f_a_nacks_b, f_a_outstanding_b,
135
                        f_b_nreqs_a, f_b_nacks_a, f_b_outstanding_a,
136
                        f_b_nreqs_b, f_b_nacks_b, f_b_outstanding_b;
137
`endif
138
 
139
        // All of our logic is really captured in the 'r_a_owner' register.
140
        // This register determines who owns the bus.  If no one is requesting
141
        // the bus, ownership goes to A on the next clock.  Otherwise, if B is
142
        // requesting the bus and A is not, then ownership goes to not A on
143
        // the next clock.  (Sounds simple ...)
144
        //
145
        // The CYC logic is here to make certain that, by the time we determine
146
        // who the bus owner is, we can do so based upon determined criteria.
147
        reg     r_a_owner;
148
 
149
        initial r_a_owner = 1'b1;
150
        always @(posedge i_clk)
151
                if (i_reset)
152
                        r_a_owner <= 1'b1;
153
                /*
154
                // Remain with the "last owner" until 1) the other bus requests
155
                // access, and 2) the last owner no longer wants it.  This
156
                // logic "idles" on the last owner.
157
                //
158
                // This is an alternating bus owner strategy
159
                //
160
                else if ((!o_cyc_a)&&(!o_cyc_b))
161
                        r_a_owner <= ((i_b_stb_a)||(i_b_stb_b))? 1'b0:1'b1;
162
                //
163
                // Expanding this out
164
                //
165
                // else if ((r_a_owner)&&((i_a_cyc_a)||(i_a_cyc_b)))
166
                //              r_a_owner <= 1'b1;
167
                // else if ((!r_a_owner)&&((i_b_cyc_a)||(i_b_cyc_b)))
168
                //              r_a_owner <= 1'b0;
169
                // else if ((r_a_owner)&&((i_b_stb_a)||(i_b_stb_b)))
170
                //              r_a_owner <= 1'b0;
171
                // else if ((!r_a_owner)&&((i_a_stb_a)||(i_a_stb_b)))
172
                //              r_a_owner <= 1'b0;
173
                //
174
                // Logic required:
175
                //
176
                //      Reset line
177
                //      + 9 inputs (data)
178
                //      + 9 inputs (CE)
179
                //      Could be done with three LUTs
180
                //              First two evaluate o_cyc_a and o_cyc_b (above)
181
                */
182
                // Option 2:
183
                //
184
                // "Idle" on A as the owner.
185
                // If a request is made from B, AND A is idle, THEN
186
                // switch.  Otherwise, if B is ever idle, revert back to A
187
                // regardless of whether A wants it or not.
188
                else if ((!i_b_cyc_a)&&(!i_b_cyc_b))
189
                        r_a_owner <= 1'b1;
190
                else if ((!i_a_cyc_a)&&(!i_a_cyc_b)
191
                                &&((i_b_stb_a)||(i_b_stb_b)))
192
                        r_a_owner <= 1'b0;
193
 
194
        // Realistically, if neither master owns the bus, the output is a
195
        // don't care.  Thus we trigger off whether or not 'A' owns the bus.
196
        // If 'B' owns it all we care is that 'A' does not.  Likewise, if
197
        // neither owns the bus than the values on these various lines are
198
        // irrelevant.
199
 
200
        assign o_cyc_a = ((r_a_owner) ? i_a_cyc_a : i_b_cyc_a);
201
        assign o_cyc_b = ((r_a_owner) ? i_a_cyc_b : i_b_cyc_b);
202
        assign o_stb_a = (r_a_owner) ? i_a_stb_a : i_b_stb_a;
203
        assign o_stb_b = (r_a_owner) ? i_a_stb_b : i_b_stb_b;
204
        assign o_we    = (r_a_owner) ? i_a_we    : i_b_we;
205
        generate if (OPT_ZERO_ON_IDLE)
206
        begin
207
                wire    o_cyc, o_stb;
208
                assign  o_cyc     = ((o_cyc_a)||(o_cyc_b));
209
                assign  o_stb     = ((o_stb_a)||(o_stb_b));
210
                assign  o_adr     = (o_stb)?((r_a_owner) ? i_a_adr  : i_b_adr):0;
211
                assign  o_dat     = (o_stb)?((r_a_owner) ? i_a_dat  : i_b_dat):0;
212
                assign  o_sel     = (o_stb)?((r_a_owner) ? i_a_sel  : i_b_sel):0;
213
                assign  o_a_ack   = (o_cyc)&&( r_a_owner) ? i_ack   : 1'b0;
214
                assign  o_b_ack   = (o_cyc)&&(!r_a_owner) ? i_ack   : 1'b0;
215
                assign  o_a_stall = (o_cyc)&&( r_a_owner) ? i_stall : 1'b1;
216
                assign  o_b_stall = (o_cyc)&&(!r_a_owner) ? i_stall : 1'b1;
217
                assign  o_a_err   = (o_cyc)&&( r_a_owner) ? i_err : 1'b0;
218
                assign  o_b_err   = (o_cyc)&&(!r_a_owner) ? i_err : 1'b0;
219
        end else begin
220
                assign o_adr   = (r_a_owner) ? i_a_adr   : i_b_adr;
221
                assign o_dat   = (r_a_owner) ? i_a_dat   : i_b_dat;
222
                assign o_sel   = (r_a_owner) ? i_a_sel   : i_b_sel;
223
 
224
                // We cannot allow the return acknowledgement to ever go high if
225
                // the master in question does not own the bus.  Hence we force it
226
                // low if the particular master doesn't own the bus.
227
                assign  o_a_ack   = ( r_a_owner) ? i_ack   : 1'b0;
228
                assign  o_b_ack   = (!r_a_owner) ? i_ack   : 1'b0;
229
 
230
                // Stall must be asserted on the same cycle the input master asserts
231
                // the bus, if the bus isn't granted to him.
232
                assign  o_a_stall = ( r_a_owner) ? i_stall : 1'b1;
233
                assign  o_b_stall = (!r_a_owner) ? i_stall : 1'b1;
234
 
235
                //
236
                //
237
                assign  o_a_err = ( r_a_owner) ? i_err : 1'b0;
238
                assign  o_b_err = (!r_a_owner) ? i_err : 1'b0;
239
        end endgenerate
240
 
241
`ifdef  FORMAL
242
`define ASSERT  assert
243
`ifdef  WBDBLPRIARB
244
`define ASSUME  assume
245
`else
246
`define ASSUME  assert
247
`endif
248
 
249
        reg     f_past_valid;
250
        initial f_past_valid = 1'b0;
251
        always @(posedge i_clk)
252
                f_past_valid <= 1'b1;
253
 
254
        initial `ASSUME(i_reset);
255
        always @(*)
256
        if (!f_past_valid)
257
                `ASSUME(i_reset);
258
 
259
        initial `ASSUME(!i_a_cyc_a);
260
        initial `ASSUME(!i_a_stb_a);
261
        initial `ASSUME(!i_a_cyc_b);
262
        initial `ASSUME(!i_a_stb_b);
263
 
264
        initial `ASSUME(!i_b_cyc_a);
265
        initial `ASSUME(!i_b_stb_a);
266
        initial `ASSUME(!i_b_cyc_b);
267
        initial `ASSUME(!i_b_stb_b);
268
 
269
        initial `ASSUME(!i_ack);
270
        initial `ASSUME(!i_err);
271
 
272
        always @(*)
273
                `ASSUME((!i_a_cyc_a)||(!i_a_cyc_b));
274
        always @(*)
275
                `ASSUME((!i_b_cyc_a)||(!i_b_cyc_b));
276
 
277
        always @(posedge i_clk)
278
        if ((f_past_valid)&&($past(i_a_cyc_a)))
279
                `ASSUME(!i_a_cyc_b);
280
 
281
        always @(posedge i_clk)
282
        if ((f_past_valid)&&($past(i_a_cyc_b)))
283
                `ASSUME(!i_a_cyc_a);
284
 
285
        always @(posedge i_clk)
286
        if ((f_past_valid)&&($past(i_b_cyc_a)))
287
                `ASSUME(!i_b_cyc_b);
288
 
289
        always @(posedge i_clk)
290
        if ((f_past_valid)&&($past(i_b_cyc_b)))
291
                `ASSUME(!i_b_cyc_a);
292
 
293
        wire    f_cyc, f_stb;
294
        assign  f_cyc = (o_cyc_a)||(o_cyc_b);
295
        assign  f_stb = (o_stb_a)||(o_stb_b);
296
        always @(posedge i_clk)
297
        begin
298
                if (o_cyc_a)
299
                        `ASSERT((i_a_cyc_a)||(i_b_cyc_a));
300
                if (o_cyc_b)
301
                        `ASSERT((i_a_cyc_b)||(i_b_cyc_b));
302
                `ASSERT((!o_cyc_a)||(!o_cyc_b));
303
        end
304
 
305
        always @(posedge i_clk)
306
        if ((f_past_valid)&&(!$past(i_reset)))
307
        begin
308
                if ($past(f_cyc))
309
                begin
310
                        if (($past(o_cyc_a))&&(o_cyc_a))
311
                                `ASSERT($past(r_a_owner) == r_a_owner);
312
                        if (($past(o_cyc_b))&&(o_cyc_b))
313
                                `ASSERT($past(r_a_owner) == r_a_owner);
314
                end else begin
315
                        if (($past(i_a_stb_a))||($past(i_a_stb_b)))
316
                                `ASSERT(r_a_owner);
317
                        if (($past(i_b_stb_a))||($past(i_b_stb_b)))
318
                                `ASSERT(!r_a_owner);
319
                end
320
        end
321
 
322
 
323
        fwb_master #(.AW(AW), .DW(DW),
324
                        .F_MAX_STALL(F_MAX_STALL),
325
                        .F_LGDEPTH(F_LGDEPTH),
326
                        .F_MAX_ACK_DELAY(F_MAX_ACK_DELAY),
327
                        .F_OPT_RMW_BUS_OPTION(1),
328
                        .F_OPT_DISCONTINUOUS(1))
329
                f_wbm_a(i_clk, i_reset,
330
                        o_cyc_a, o_stb_a, o_we, o_adr, o_dat, o_sel,
331
                        (o_cyc_a)&&(i_ack), i_stall, 32'h0, (o_cyc_a)&&(i_err),
332
                        f_nreqs_a, f_nacks_a, f_outstanding_a);
333
        fwb_master #(.AW(AW), .DW(DW),
334
                        .F_MAX_STALL(F_MAX_STALL),
335
                        .F_MAX_ACK_DELAY(F_MAX_ACK_DELAY),
336
                        .F_LGDEPTH(F_LGDEPTH),
337
                        .F_OPT_RMW_BUS_OPTION(1),
338
                        .F_OPT_DISCONTINUOUS(1))
339
                f_wbm_b(i_clk, i_reset,
340
                        o_cyc_b, o_stb_b, o_we, o_adr, o_dat, o_sel,
341
                        (o_cyc_b)&&(i_ack), i_stall, 32'h0, (o_cyc_b)&&(i_err),
342
                        f_nreqs_b, f_nacks_b, f_outstanding_b);
343
 
344
`ifdef  WBDBLPRIARB
345
`define F_SLAVE fwb_slave
346
`else
347
`define F_SLAVE fwb_counter
348
`endif
349
 
350
        `F_SLAVE  #(.AW(AW), .DW(DW), .F_MAX_STALL(0),
351
                        .F_LGDEPTH(F_LGDEPTH),
352
                        .F_MAX_ACK_DELAY(0),
353
                        .F_OPT_RMW_BUS_OPTION(1),
354
                        .F_OPT_DISCONTINUOUS(1))
355
                f_wba_a(i_clk, i_reset,
356
                        i_a_cyc_a, i_a_stb_a, i_a_we, i_a_adr, i_a_dat, i_a_sel,
357
                        (o_cyc_a)&&(o_a_ack), o_a_stall, 32'h0, (o_cyc_a)&&(o_a_err),
358
                        f_a_nreqs_a, f_a_nacks_a, f_a_outstanding_a);
359
        `F_SLAVE  #(.AW(AW), .DW(DW), .F_MAX_STALL(0),
360
                        .F_LGDEPTH(F_LGDEPTH),
361
                        .F_MAX_ACK_DELAY(0),
362
                        .F_OPT_RMW_BUS_OPTION(1),
363
                        .F_OPT_DISCONTINUOUS(1))
364
                f_wba_b(i_clk, i_reset,
365
                        i_a_cyc_b, i_a_stb_b, i_a_we, i_a_adr, i_a_dat, i_a_sel,
366
                        (o_cyc_b)&&(o_a_ack), o_a_stall, 32'h0, (o_cyc_b)&&(o_a_err),
367
                        f_a_nreqs_b, f_a_nacks_b, f_a_outstanding_b);
368
        `F_SLAVE  #(.AW(AW), .DW(DW), .F_MAX_STALL(0),
369
                        .F_LGDEPTH(F_LGDEPTH),
370
                        .F_MAX_ACK_DELAY(0),
371
                        .F_OPT_RMW_BUS_OPTION(1),
372
                        .F_OPT_DISCONTINUOUS(1))
373
                f_wbb_a(i_clk, i_reset,
374
                        i_b_cyc_a, i_b_stb_a, i_b_we, i_b_adr, i_b_dat, i_b_sel,
375
                        (o_cyc_a)&&(o_b_ack), o_b_stall, 32'h0, (o_cyc_a)&&(o_b_err),
376
                        f_b_nreqs_a, f_b_nacks_a, f_b_outstanding_a);
377
        `F_SLAVE  #(.AW(AW), .DW(DW), .F_MAX_STALL(0),
378
                        .F_LGDEPTH(F_LGDEPTH),
379
                        .F_MAX_ACK_DELAY(0),
380
                        .F_OPT_RMW_BUS_OPTION(1),
381
                        .F_OPT_DISCONTINUOUS(1))
382
                f_wbb_b(i_clk, i_reset,
383
                        i_b_cyc_b, i_b_stb_b, i_b_we, i_b_adr, i_b_dat, i_b_sel,
384
                        (o_cyc_b)&&(o_b_ack), o_b_stall, 32'h0, (o_cyc_b)&&(o_b_err),
385
                        f_b_nreqs_b, f_b_nacks_b, f_b_outstanding_b);
386
 
387
        always @(posedge i_clk)
388
        if ((f_past_valid)&&(!$past(i_reset)))
389
        begin
390
                if (r_a_owner)
391
                begin
392
                        `ASSERT(f_b_nreqs_a == 0);
393
                        `ASSERT(f_b_nreqs_b == 0);
394
                        //
395
                        `ASSERT(f_b_nacks_a == 0);
396
                        `ASSERT(f_b_nacks_b == 0);
397
                        //
398
                        if (i_a_cyc_a)
399
                        begin
400
                                `ASSERT(f_a_outstanding_a == f_outstanding_a);
401
                                `ASSERT(f_a_outstanding_b == 0);
402
                                `ASSERT(f_outstanding_b == 0);
403
                                `ASSERT(f_a_nreqs_b == 0);
404
                                `ASSERT(f_a_nacks_b == 0);
405
                        end else if (i_a_cyc_b)
406
                        begin
407
                                `ASSERT(f_a_outstanding_b == f_outstanding_b);
408
                                `ASSERT(f_a_outstanding_a == 0);
409
                                `ASSERT(f_outstanding_a == 0);
410
                                `ASSERT(f_a_nreqs_a == 0);
411
                                `ASSERT(f_a_nacks_a == 0);
412
                        end
413
                end else begin
414
                        `ASSERT(f_a_nreqs_a == 0);
415
                        `ASSERT(f_a_nreqs_b == 0);
416
                        //
417
                        `ASSERT(f_a_nacks_a == 0);
418
                        `ASSERT(f_a_nacks_b == 0);
419
                        //
420
                        if (i_b_cyc_a)
421
                        begin
422
                                `ASSERT(f_b_outstanding_a == f_outstanding_a);
423
                                `ASSERT(f_b_outstanding_b == 0);
424
                                `ASSERT(f_outstanding_b == 0);
425
                                `ASSERT(f_b_nreqs_b == 0);
426
                                `ASSERT(f_b_nacks_b == 0);
427
                        end else if (i_b_cyc_b)
428
                        begin
429
                                `ASSERT(f_b_outstanding_b == f_outstanding_b);
430
                                `ASSERT(f_b_outstanding_a == 0);
431
                                `ASSERT(f_outstanding_a == 0);
432
                                `ASSERT(f_b_nreqs_a == 0);
433
                                `ASSERT(f_b_nacks_a == 0);
434
                        end
435
                end
436
        end
437
 
438
        always @(posedge i_clk)
439
                if ((r_a_owner)&&(i_b_cyc_a))
440
                        `ASSUME((i_b_stb_a)&&(!i_b_stb_b));
441
        always @(posedge i_clk)
442
                if ((r_a_owner)&&(i_b_cyc_b))
443
                        `ASSUME((i_b_stb_b)&&(!i_b_stb_a));
444
 
445
        always @(posedge i_clk)
446
                if ((!r_a_owner)&&(i_a_cyc_a))
447
                        `ASSUME((i_a_stb_a)&&(!i_a_stb_b));
448
        always @(posedge i_clk)
449
                if ((!r_a_owner)&&(i_a_cyc_b))
450
                        `ASSUME((i_a_stb_b)&&(!i_a_stb_a));
451
 
452
`endif
453
endmodule
454
 

powered by: WebSVN 2.1.0

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