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

Subversion Repositories wb2axip

[/] [wb2axip/] [trunk/] [bench/] [formal/] [fwb_master.v] - Blame information for rev 17

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

Line No. Rev Author Line
1 10 dgisselq
////////////////////////////////////////////////////////////////////////////////
2
//
3
// Filename:    fwb_master.v
4
//
5
// Project:     Zip CPU -- a small, lightweight, RISC CPU soft core
6
//
7
// Purpose:     This file describes the rules of a wishbone interaction from the
8
//              perspective of a wishbone master.  These formal rules may be used
9
//      with yosys-smtbmc to *prove* that the master properly handles outgoing
10
//      transactions and incoming responses.
11
//
12
//      This module contains no functional logic.  It is intended for formal
13
//      verification only.  The outputs returned, the number of requests that
14
//      have been made, the number of acknowledgements received, and the number
15
//      of outstanding requests, are designed for further formal verification
16
//      purposes *only*.
17
//
18
//      This file is different from a companion formal_slave.v file in that the
19
//      assertions are made on the outputs of the wishbone master: o_wb_cyc,
20
//      o_wb_stb, o_wb_we, o_wb_addr, o_wb_data, and o_wb_sel, while only
21
//      assumptions are made about the inputs: i_wb_stall, i_wb_ack, i_wb_data,
22
//      i_wb_err.  In the formal_slave.v, assumptions are made about the
23
//      slave inputs (the master outputs), and assertions are made about the
24
//      slave outputs (the master inputs).
25
//
26 16 dgisselq
//      In order to make it easier to compare the slave against the master,
27
//      assumptions with respect to the slave have been marked with the
28
//      `SLAVE_ASSUME macro.  Similarly, assertions the slave would make have
29
//      been marked with `SLAVE_ASSERT.  This allows the master to redefine
30
//      these two macros to be from his perspective, and therefore the
31
//      diffs between the two files actually show true differences, rather
32
//      than just these differences in perspective.
33 10 dgisselq
//
34
//
35
// Creator:     Dan Gisselquist, Ph.D.
36
//              Gisselquist Technology, LLC
37
//
38
////////////////////////////////////////////////////////////////////////////////
39
//
40 16 dgisselq
// Copyright (C) 2017-2018, Gisselquist Technology, LLC
41 10 dgisselq
//
42 16 dgisselq
// This file is part of the pipelined Wishbone to AXI converter project, a
43
// project that contains multiple bus bridging designs and formal bus property
44
// sets.
45 10 dgisselq
//
46 16 dgisselq
// The bus bridge designs and property sets are free RTL designs: you can
47
// redistribute them and/or modify any of them under the terms of the GNU
48
// Lesser General Public License as published by the Free Software Foundation,
49
// either version 3 of the License, or (at your option) any later version.
50 10 dgisselq
//
51 16 dgisselq
// The bus bridge designs and property sets are distributed in the hope that
52
// they will be useful, but WITHOUT ANY WARRANTY; without even the implied
53
// warranty of MERCHANTIBILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
54
// GNU Lesser General Public License for more details.
55
//
56
// You should have received a copy of the GNU Lesser General Public License
57
// along with these designs.  (It's in the $(ROOT)/doc directory.  Run make
58
// with no target there if the PDF file isn't present.)  If not, see
59 10 dgisselq
// <http://www.gnu.org/licenses/> for a copy.
60
//
61 16 dgisselq
// License:     LGPL, v3, as defined and found on www.gnu.org,
62
//              http://www.gnu.org/licenses/lgpl.html
63 10 dgisselq
//
64
////////////////////////////////////////////////////////////////////////////////
65
//
66
//
67
`default_nettype none
68
//
69
module  fwb_master(i_clk, i_reset,
70
                // The Wishbone bus
71
                i_wb_cyc, i_wb_stb, i_wb_we, i_wb_addr, i_wb_data, i_wb_sel,
72
                        i_wb_ack, i_wb_stall, i_wb_idata, i_wb_err,
73
                // Some convenience output parameters
74
                f_nreqs, f_nacks, f_outstanding);
75
        parameter               AW=32, DW=32;
76
        parameter               F_MAX_STALL = 0,
77
                                F_MAX_ACK_DELAY = 0;
78
        parameter               F_LGDEPTH = 4;
79
        parameter [(F_LGDEPTH-1):0] F_MAX_REQUESTS = 0;
80
        //
81
        // If true, allow the bus to be kept open when there are no outstanding
82
        // requests.  This is useful for any master that might execute a
83
        // read modify write cycle, such as an atomic add.
84
        parameter [0:0]           F_OPT_RMW_BUS_OPTION = 1;
85
        //
86
        // 
87
        parameter [0:0]           F_OPT_SHORT_CIRCUIT_PROOF = 0;
88
        //
89
        // If this is the source of a request, then we can assume STB and CYC
90
        // will initially start out high.  Master interfaces following the
91
        // source on the way to the slave may not have this property
92
        parameter [0:0]           F_OPT_SOURCE = 0;
93
        //
94
        // If true, allow the bus to issue multiple discontinuous requests.
95
        // Unlike F_OPT_RMW_BUS_OPTION, these requests may be issued while other
96
        // requests are outstanding
97
        parameter       [0:0]     F_OPT_DISCONTINUOUS = 0;
98
        //
99
        //
100 16 dgisselq
        // If true, insist that there be a minimum of a single clock delay
101
        // between request and response.  This defaults to off since the
102
        // wishbone specification specifically doesn't require this.  However,
103
        // some interfaces do, so we allow it as an option here.
104
        parameter       [0:0]     F_OPT_MINCLOCK_DELAY = 0;
105
        //
106
        //
107 10 dgisselq
        localparam [(F_LGDEPTH-1):0] MAX_OUTSTANDING = {(F_LGDEPTH){1'b1}};
108
        localparam      MAX_DELAY = (F_MAX_STALL > F_MAX_ACK_DELAY)
109
                                ? F_MAX_STALL : F_MAX_ACK_DELAY;
110
        localparam      DLYBITS= (MAX_DELAY < 4) ? 2
111
                                : ((MAX_DELAY <    16) ? 4
112
                                : ((MAX_DELAY <    64) ? 6
113
                                : ((MAX_DELAY <   256) ? 8
114
                                : ((MAX_DELAY <  1024) ? 10
115
                                : ((MAX_DELAY <  4096) ? 12
116
                                : ((MAX_DELAY < 16384) ? 14
117
                                : ((MAX_DELAY < 65536) ? 16
118
                                : 32)))))));
119
        //
120
        input   wire                    i_clk, i_reset;
121
        // Input/master bus
122
        input   wire                    i_wb_cyc, i_wb_stb, i_wb_we;
123
        input   wire    [(AW-1):0]       i_wb_addr;
124
        input   wire    [(DW-1):0]       i_wb_data;
125
        input   wire    [(DW/8-1):0]     i_wb_sel;
126
        //
127
        input   wire                    i_wb_ack;
128
        input   wire                    i_wb_stall;
129
        input   wire    [(DW-1):0]       i_wb_idata;
130
        input   wire                    i_wb_err;
131
        //
132
        output  reg     [(F_LGDEPTH-1):0]        f_nreqs, f_nacks;
133
        output  wire    [(F_LGDEPTH-1):0]        f_outstanding;
134
 
135 16 dgisselq
`define SLAVE_ASSUME    assert
136
`define SLAVE_ASSERT    assume
137 10 dgisselq
        //
138
        // Let's just make sure our parameters are set up right
139
        //
140 16 dgisselq
        initial assert(F_MAX_REQUESTS < {(F_LGDEPTH){1'b1}});
141 10 dgisselq
 
142
        //
143
        // Wrap the request line in a bundle.  The top bit, named STB_BIT,
144
        // is the bit indicating whether the request described by this vector
145
        // is a valid request or not.
146
        //
147
        localparam      STB_BIT = 2+AW+DW+DW/8-1;
148
        wire    [STB_BIT:0]      f_request;
149
        assign  f_request = { i_wb_stb, i_wb_we, i_wb_addr, i_wb_data, i_wb_sel };
150
 
151
        //
152
        // A quick register to be used later to know if the $past() operator
153
        // will yield valid result
154
        reg     f_past_valid;
155
        initial f_past_valid = 1'b0;
156
        always @(posedge i_clk)
157
                f_past_valid <= 1'b1;
158
        always @(*)
159 16 dgisselq
        if (!f_past_valid)
160
                `SLAVE_ASSUME(i_reset);
161 10 dgisselq
        //
162
        //
163
        // Assertions regarding the initial (and reset) state
164
        //
165
        //
166
 
167
        //
168
        // Assume we start from a reset condition
169
        initial assert(i_reset);
170 16 dgisselq
        initial `SLAVE_ASSUME(!i_wb_cyc);
171
        initial `SLAVE_ASSUME(!i_wb_stb);
172 10 dgisselq
        //
173 16 dgisselq
        initial `SLAVE_ASSERT(!i_wb_ack);
174
        initial `SLAVE_ASSERT(!i_wb_err);
175 10 dgisselq
 
176
        always @(posedge i_clk)
177 16 dgisselq
        if ((!f_past_valid)||($past(i_reset)))
178 10 dgisselq
        begin
179 16 dgisselq
                `SLAVE_ASSUME(!i_wb_cyc);
180
                `SLAVE_ASSUME(!i_wb_stb);
181 10 dgisselq
                //
182 16 dgisselq
                `SLAVE_ASSERT(!i_wb_ack);
183
                `SLAVE_ASSERT(!i_wb_err);
184 10 dgisselq
        end
185
 
186 16 dgisselq
        always @(*)
187
        if (!f_past_valid)
188
                `SLAVE_ASSUME(!i_wb_cyc);
189 10 dgisselq
 
190
        //
191
        //
192
        // Bus requests
193
        //
194
        //
195
 
196
        // Following any bus error, the CYC line should be dropped to abort
197
        // the transaction
198
        always @(posedge i_clk)
199
        if ((f_past_valid)&&($past(i_wb_err))&&($past(i_wb_cyc)))
200 16 dgisselq
                `SLAVE_ASSUME(!i_wb_cyc);
201 10 dgisselq
 
202
        // STB can only be true if CYC is also true
203 16 dgisselq
        always @(*)
204
        if (i_wb_stb)
205
                `SLAVE_ASSUME(i_wb_cyc);
206 10 dgisselq
 
207
        // If a request was both outstanding and stalled on the last clock,
208
        // then nothing should change on this clock regarding it.
209
        always @(posedge i_clk)
210
        if ((f_past_valid)&&(!$past(i_reset))&&($past(i_wb_stb))
211
                        &&($past(i_wb_stall))&&(i_wb_cyc))
212
        begin
213 16 dgisselq
                `SLAVE_ASSUME(i_wb_stb);
214
                `SLAVE_ASSUME(i_wb_we   == $past(i_wb_we));
215
                `SLAVE_ASSUME(i_wb_addr == $past(i_wb_addr));
216
                `SLAVE_ASSUME(i_wb_sel  == $past(i_wb_sel));
217
                if (i_wb_we)
218
                        `SLAVE_ASSUME(i_wb_data == $past(i_wb_data));
219 10 dgisselq
        end
220
 
221
        // Within any series of STB/requests, the direction of the request
222
        // may not change.
223
        always @(posedge i_clk)
224 16 dgisselq
        if ((f_past_valid)&&($past(i_wb_stb))&&(i_wb_stb))
225
                `SLAVE_ASSUME(i_wb_we == $past(i_wb_we));
226 10 dgisselq
 
227
 
228
        // Within any given bus cycle, the direction may *only* change when
229
        // there are no further outstanding requests.
230
        always @(posedge i_clk)
231 16 dgisselq
        if ((f_past_valid)&&(f_outstanding > 0))
232
                `SLAVE_ASSUME(i_wb_we == $past(i_wb_we));
233 10 dgisselq
 
234
        // Write requests must also set one (or more) of i_wb_sel
235 16 dgisselq
        // always @(*)
236
        // if ((i_wb_stb)&&(i_wb_we))
237
        //      `SLAVE_ASSUME(|i_wb_sel);
238 10 dgisselq
 
239
 
240
        //
241
        //
242
        // Bus responses
243
        //
244
        //
245
 
246
        // If CYC was low on the last clock, then both ACK and ERR should be
247
        // low on this clock.
248
        always @(posedge i_clk)
249 16 dgisselq
        if ((f_past_valid)&&(!$past(i_wb_cyc))&&(!i_wb_cyc))
250 10 dgisselq
        begin
251 16 dgisselq
                `SLAVE_ASSERT(!i_wb_ack);
252
                `SLAVE_ASSERT(!i_wb_err);
253 10 dgisselq
                // Stall may still be true--such as when we are not
254
                // selected at some arbiter between us and the slave
255
        end
256
 
257 16 dgisselq
        //
258
        // Any time the CYC line drops, it is possible that there may be a
259
        // remaining (registered) ACK or ERR that hasn't yet been returned.
260
        // Restrict such out of band returns so that they are *only* returned
261
        // if there is an outstanding operation.
262
        always @(posedge i_clk)
263
        if ((f_past_valid)&&(!$past(i_reset))&&($past(i_wb_cyc))&&(!i_wb_cyc))
264
        begin
265
                if (($past(f_outstanding == 0))
266
                        &&((!$past(i_wb_stb && !i_wb_stall))
267
                                ||($past(i_wb_ack|i_wb_err))))
268
                begin
269
                        `SLAVE_ASSERT(!i_wb_ack);
270
                        `SLAVE_ASSERT(!i_wb_err);
271
                end
272
        end
273
 
274 10 dgisselq
        // ACK and ERR may never both be true at the same time
275
        always @(*)
276 16 dgisselq
                `SLAVE_ASSERT((!i_wb_ack)||(!i_wb_err));
277 10 dgisselq
 
278
        generate if (F_MAX_STALL > 0)
279
        begin : MXSTALL
280
                //
281
                // Assume the slave cannnot stall for more than F_MAX_STALL
282
                // counts.  We'll count this forward any time STB and STALL
283
                // are both true.
284
                //
285
                reg     [(DLYBITS-1):0]          f_stall_count;
286
 
287
                initial f_stall_count = 0;
288
                always @(posedge i_clk)
289 16 dgisselq
                if ((!i_reset)&&(i_wb_stb)&&(i_wb_stall))
290
                        f_stall_count <= f_stall_count + 1'b1;
291
                else
292
                        f_stall_count <= 0;
293
 
294
                always @(*)
295
                if (i_wb_cyc)
296
                        `SLAVE_ASSERT(f_stall_count < F_MAX_STALL);
297 10 dgisselq
        end endgenerate
298
 
299
        generate if (F_MAX_ACK_DELAY > 0)
300
        begin : MXWAIT
301
                //
302
                // Assume the slave will respond within F_MAX_ACK_DELAY cycles,
303
                // counted either from the end of the last request, or from the
304
                // last ACK received
305
                //
306
                reg     [(DLYBITS-1):0]          f_ackwait_count;
307
 
308
                initial f_ackwait_count = 0;
309
                always @(posedge i_clk)
310 16 dgisselq
                if ((!i_reset)&&(i_wb_cyc)&&(!i_wb_stb)
311
                                &&(!i_wb_ack)&&(!i_wb_err)
312
                                &&(f_outstanding > 0))
313
                        f_ackwait_count <= f_ackwait_count + 1'b1;
314
                else
315
                        f_ackwait_count <= 0;
316
 
317
                always @(*)
318
                if ((!i_reset)&&(i_wb_cyc)&&(!i_wb_stb)
319
                                        &&(!i_wb_ack)&&(!i_wb_err)
320
                                        &&(f_outstanding > 0))
321
                        `SLAVE_ASSERT(f_ackwait_count < F_MAX_ACK_DELAY);
322 10 dgisselq
        end endgenerate
323
 
324
        //
325
        // Count the number of requests that have been made
326
        //
327
        initial f_nreqs = 0;
328
        always @(posedge i_clk)
329 16 dgisselq
        if ((i_reset)||(!i_wb_cyc))
330
                f_nreqs <= 0;
331
        else if ((i_wb_stb)&&(!i_wb_stall))
332
                f_nreqs <= f_nreqs + 1'b1;
333 10 dgisselq
 
334
 
335
        //
336
        // Count the number of acknowledgements that have been received
337
        //
338
        initial f_nacks = 0;
339
        always @(posedge i_clk)
340 16 dgisselq
        if (i_reset)
341
                f_nacks <= 0;
342
        else if (!i_wb_cyc)
343
                f_nacks <= 0;
344
        else if ((i_wb_ack)||(i_wb_err))
345
                f_nacks <= f_nacks + 1'b1;
346 10 dgisselq
 
347
        //
348
        // The number of outstanding requests is the difference between
349
        // the number of requests and the number of acknowledgements
350
        //
351
        assign  f_outstanding = (i_wb_cyc) ? (f_nreqs - f_nacks):0;
352
 
353 16 dgisselq
        always @(*)
354
        if ((i_wb_cyc)&&(F_MAX_REQUESTS > 0))
355
        begin
356
                if (i_wb_stb)
357
                        `SLAVE_ASSUME(f_nreqs < F_MAX_REQUESTS);
358
                else
359
                        `SLAVE_ASSUME(f_nreqs <= F_MAX_REQUESTS);
360
                `SLAVE_ASSERT(f_nacks <= f_nreqs);
361
                assert(f_outstanding < (1<<F_LGDEPTH)-1);
362
        end else
363
                assume(f_outstanding < (1<<F_LGDEPTH)-1);
364 10 dgisselq
 
365 16 dgisselq
        always @(*)
366
        if ((i_wb_cyc)&&(f_outstanding == 0))
367
        begin
368
                // If nothing is outstanding, then there should be
369
                // no acknowledgements ... however, an acknowledgement
370
                // *can* come back on the same clock as the stb is
371
                // going out.
372
                if (F_OPT_MINCLOCK_DELAY)
373 10 dgisselq
                begin
374 16 dgisselq
                        `SLAVE_ASSERT(!i_wb_ack);
375
                        `SLAVE_ASSERT(!i_wb_err);
376
                end else begin
377
                        `SLAVE_ASSERT((!i_wb_ack)||((i_wb_stb)&&(!i_wb_stall)));
378
                        // The same is true of errors.  They may not be
379
                        // created before the request gets through
380
                        `SLAVE_ASSERT((!i_wb_err)||((i_wb_stb)&&(!i_wb_stall)));
381 10 dgisselq
                end
382 16 dgisselq
        end
383 10 dgisselq
 
384
        generate if (F_OPT_SOURCE)
385
        begin : SRC
386
                // Any opening bus request starts with both CYC and STB high
387
                // This is true for the master only, and more specifically
388
                // only for those masters that are the initial source of any
389
                // transaction.  By the time an interaction gets to the slave,
390
                // the CYC line may go high or low without actually affecting
391
                // the STB line of the slave.
392
                always @(posedge i_clk)
393 16 dgisselq
                if ((f_past_valid)&&(!$past(i_wb_cyc))&&(i_wb_cyc))
394
                        `SLAVE_ASSUME(i_wb_stb);
395 10 dgisselq
        end endgenerate
396
 
397
 
398
        generate if (!F_OPT_RMW_BUS_OPTION)
399
        begin
400
                // If we aren't waiting for anything, and we aren't issuing
401
                // any requests, then then our transaction is over and we
402
                // should be dropping the CYC line.
403 16 dgisselq
                always @(*)
404
                if (f_outstanding == 0)
405
                        `SLAVE_ASSUME((i_wb_stb)||(!i_wb_cyc));
406 10 dgisselq
                // Not all masters will abide by this restriction.  Some
407
                // masters may wish to implement read-modify-write bus
408
                // interactions.  These masters need to keep CYC high between
409
                // transactions, even though nothing is outstanding.  For
410
                // these busses, turn F_OPT_RMW_BUS_OPTION on.
411
        end endgenerate
412
 
413
        generate if (F_OPT_SHORT_CIRCUIT_PROOF)
414
        begin
415
                // In many ways, we don't care what happens on the bus return
416
                // lines if the cycle line is low, so restricting them to a
417
                // known value makes a lot of sense.
418
                //
419
                // On the other hand, if something above *does* depend upon
420
                // these values (when it shouldn't), then we might want to know
421
                // about it.
422
                //
423
                //
424
                always @(posedge i_clk)
425
                begin
426
                        if (!i_wb_cyc)
427
                        begin
428 16 dgisselq
                                assume(!i_wb_stall);
429
                                assume($stable(i_wb_idata));
430 10 dgisselq
                        end else if ((!$past(i_wb_ack))&&(!i_wb_ack))
431 16 dgisselq
                                assume($stable(i_wb_idata));
432 10 dgisselq
                end
433
        end endgenerate
434
 
435
        generate if ((!F_OPT_DISCONTINUOUS)&&(!F_OPT_RMW_BUS_OPTION))
436
        begin : INSIST_ON_NO_DISCONTINUOUS_STBS
437
                // Within my own code, once a request begins it goes to
438
                // completion and the CYC line is dropped.  The master
439
                // is not allowed to raise STB again after dropping it.
440
                // Doing so would be a *discontinuous* request.
441
                //
442
                // However, in any RMW scheme, discontinuous requests are
443
                // necessary, and the spec doesn't disallow them.  Hence we
444
                // make this check optional.
445
                always @(posedge i_clk)
446 16 dgisselq
                if ((f_past_valid)&&($past(i_wb_cyc))&&(!$past(i_wb_stb)))
447
                        `SLAVE_ASSUME(!i_wb_stb);
448 10 dgisselq
        end endgenerate
449
 
450
endmodule

powered by: WebSVN 2.1.0

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