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

Subversion Repositories zipcpu

[/] [zipcpu/] [trunk/] [rtl/] [peripherals/] [ziptimer.v] - Blame information for rev 209

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 201 dgisselq
////////////////////////////////////////////////////////////////////////////////
2 2 dgisselq
//
3
// Filename:    ziptimer.v
4
//
5
// Project:     Zip CPU -- a small, lightweight, RISC CPU soft core
6
//
7 9 dgisselq
// Purpose:     A lighter weight implementation of the Zip Timer.
8 2 dgisselq
//
9
// Interface:
10
//      Two options:
11
//      1. One combined register for both control and value, and ...
12
//              The reload value is set any time the timer data value is "set".
13
//              Reading the register returns the timer value.  Controls are
14
//              set so that writing a value to the timer automatically starts
15
//              it counting down.
16
//      2. Two registers, one for control one for value.
17
//              The control register would have the reload value in it.
18
//      On the clock when the interface is set to zero the interrupt is set.
19
//              Hence setting the timer to zero will disable the timer without
20
//              setting any interrupts.  Thus setting it to five will count
21
//              5 clocks: 5, 4, 3, 2, 1, Interrupt.
22
//
23
//
24
//      Control bits:
25 9 dgisselq
//              (Start_n/Stop.  This bit has been dropped.  Writing to this
26
//                      timer any value but zero starts it.  Writing a zero
27
//                      clears and stops it.)
28 2 dgisselq
//              AutoReload.  If set, then on reset the timer automatically
29
//                      loads the last set value and starts over.  This is
30
//                      useful for distinguishing between a one-time interrupt
31
//                      timer, and a repetitive interval timer.
32
//              (INTEN.  Interrupt enable--reaching zero always creates an
33
//                      interrupt, so this control bit isn't needed.  The
34
//                      interrupt controller can be used to mask the interrupt.)
35
//              (COUNT-DOWN/UP: This timer is *only* a count-down timer.
36
//                      There is no means of setting it to count up.)
37
//      WatchDog
38
//              This timer can be implemented as a watchdog timer simply by
39
//              connecting the interrupt line to the reset line of the CPU.
40
//              When the timer then expires, it will trigger a CPU reset.
41
//
42
//
43
// Creator:     Dan Gisselquist, Ph.D.
44 69 dgisselq
//              Gisselquist Technology, LLC
45 2 dgisselq
//
46 201 dgisselq
////////////////////////////////////////////////////////////////////////////////
47 2 dgisselq
//
48 209 dgisselq
// Copyright (C) 2015,2017-2019, Gisselquist Technology, LLC
49 2 dgisselq
//
50
// This program is free software (firmware): you can redistribute it and/or
51
// modify it under the terms of  the GNU General Public License as published
52
// by the Free Software Foundation, either version 3 of the License, or (at
53
// your option) any later version.
54
//
55
// This program is distributed in the hope that it will be useful, but WITHOUT
56
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
57
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
58
// for more details.
59
//
60 201 dgisselq
// You should have received a copy of the GNU General Public License along
61
// with this program.  (It's in the $(ROOT)/doc directory.  Run make with no
62
// target there if the PDF file isn't present.)  If not, see
63
// <http://www.gnu.org/licenses/> for a copy.
64
//
65 2 dgisselq
// License:     GPL, v3, as defined and found on www.gnu.org,
66
//              http://www.gnu.org/licenses/gpl.html
67
//
68
//
69 201 dgisselq
////////////////////////////////////////////////////////////////////////////////
70 2 dgisselq
//
71 201 dgisselq
//
72 209 dgisselq
`default_nettype        none
73
//
74
module  ziptimer(i_clk, i_reset, i_ce,
75 2 dgisselq
                i_wb_cyc, i_wb_stb, i_wb_we, i_wb_data,
76
                        o_wb_ack, o_wb_stall, o_wb_data,
77
                o_int);
78 144 dgisselq
        parameter       BW = 32, VW = (BW-1), RELOADABLE=1;
79 209 dgisselq
        input   wire            i_clk, i_reset, i_ce;
80 2 dgisselq
        // Wishbone inputs
81 209 dgisselq
        input   wire            i_wb_cyc, i_wb_stb, i_wb_we;
82
        input   wire [(BW-1):0]  i_wb_data;
83 2 dgisselq
        // Wishbone outputs
84
        output  reg                     o_wb_ack;
85
        output  wire                    o_wb_stall;
86
        output  wire    [(BW-1):0]       o_wb_data;
87
        // Interrupt line
88
        output  reg             o_int;
89
 
90 144 dgisselq
        reg                     r_running;
91 9 dgisselq
 
92
        wire    wb_write;
93 209 dgisselq
        assign  wb_write = ((i_wb_stb)&&(i_wb_we));
94 9 dgisselq
 
95 209 dgisselq
        wire                    auto_reload;
96
        wire    [(VW-1):0]       interval_count;
97 144 dgisselq
 
98 2 dgisselq
        initial r_running = 1'b0;
99
        always @(posedge i_clk)
100 209 dgisselq
                if (i_reset)
101 2 dgisselq
                        r_running <= 1'b0;
102 9 dgisselq
                else if (wb_write)
103
                        r_running <= (|i_wb_data[(VW-1):0]);
104 209 dgisselq
                else if ((r_zero)&&(!auto_reload))
105 9 dgisselq
                        r_running <= 1'b0;
106 2 dgisselq
 
107 144 dgisselq
        generate
108
        if (RELOADABLE != 0)
109
        begin
110 209 dgisselq
                reg                     r_auto_reload;
111
                reg     [(VW-1):0]       r_interval_count;
112 2 dgisselq
 
113 144 dgisselq
                initial r_auto_reload = 1'b0;
114 9 dgisselq
 
115 144 dgisselq
                always @(posedge i_clk)
116 209 dgisselq
                        if (i_reset)
117
                                r_auto_reload <= 1'b0;
118
                        else if (wb_write)
119
                                r_auto_reload <= (i_wb_data[(BW-1)])
120
                                        &&(|i_wb_data[(VW-1):0]);
121 9 dgisselq
 
122 144 dgisselq
                assign  auto_reload = r_auto_reload;
123
 
124
                // If setting auto-reload mode, and the value to other
125
                // than zero, set the auto-reload value
126
                always @(posedge i_clk)
127 209 dgisselq
                if (wb_write)
128
                        r_interval_count <= i_wb_data[(VW-1):0];
129
                assign  interval_count = r_interval_count;
130 144 dgisselq
        end else begin
131
                assign  auto_reload = 1'b0;
132 209 dgisselq
                assign  interval_count = 0;
133 144 dgisselq
        end endgenerate
134
 
135
 
136 2 dgisselq
        reg     [(VW-1):0]       r_value;
137
        initial r_value = 0;
138
        always @(posedge i_clk)
139 209 dgisselq
                if (i_reset)
140
                        r_value <= 0;
141
                else if (wb_write)
142 9 dgisselq
                        r_value <= i_wb_data[(VW-1):0];
143 209 dgisselq
                else if ((i_ce)&&(r_running))
144
                begin
145
                        if (!r_zero)
146
                                r_value <= r_value - 1'b1;
147
                        else if (auto_reload)
148
                                r_value <= interval_count;
149
                end
150 2 dgisselq
 
151 209 dgisselq
        reg     r_zero  = 1'b1;
152
        always @(posedge i_clk)
153
                if (i_reset)
154
                        r_zero <= 1'b1;
155
                else if (wb_write)
156
                        r_zero <= (i_wb_data[(VW-1):0] == 0);
157
                else if ((r_running)&&(i_ce))
158
                begin
159
                        if (r_value == { {(VW-1){1'b0}}, 1'b1 })
160
                                r_zero <= 1'b1;
161
                        else if ((r_zero)&&(auto_reload))
162
                                r_zero <= 1'b0;
163
                end
164
 
165 144 dgisselq
        // Set the interrupt on our last tick, as we transition from one to
166
        // zero.
167 2 dgisselq
        initial o_int   = 1'b0;
168
        always @(posedge i_clk)
169 209 dgisselq
                if ((i_reset)||(wb_write)||(!i_ce))
170 144 dgisselq
                        o_int <= 1'b0;
171 209 dgisselq
                else // if (i_ce)
172
                        o_int <= (r_value == { {(VW-1){1'b0}}, 1'b1 });
173 2 dgisselq
 
174
        initial o_wb_ack = 1'b0;
175
        always @(posedge i_clk)
176 209 dgisselq
                o_wb_ack <= (!i_reset)&&(i_wb_stb);
177 2 dgisselq
        assign  o_wb_stall = 1'b0;
178
 
179 144 dgisselq
        generate
180
        if (VW < BW-1)
181
                assign  o_wb_data = { auto_reload, {(BW-1-VW){1'b0}}, r_value };
182
        else
183
                assign  o_wb_data = { auto_reload, r_value };
184
        endgenerate
185 2 dgisselq
 
186 209 dgisselq
        // Make verilator happy
187
        // verilator lint_off UNUSED
188
        wire    [32:0]   unused;
189
        assign  unused = { i_wb_cyc, i_wb_data };
190
        // verilator lint_on  UNUSED
191
 
192
`ifdef  FORMAL
193
        reg     f_past_valid;
194
        initial f_past_valid = 1'b0;
195
        always @(posedge i_clk)
196
                f_past_valid <= 1'b1;
197
        initial assume(i_reset);
198
        always @(*)
199
                if (!f_past_valid)
200
                        assume(i_reset);
201
 
202
        always @(posedge i_clk)
203
        if ((!f_past_valid)||($past(i_reset)))
204
        begin
205
                assert(r_value     == 0);
206
                assert(r_running   == 0);
207
                assert(auto_reload == 0);
208
                assert(r_zero      == 1'b1);
209
        end
210
 
211
 
212
        always @(*)
213
                assert(r_zero == (r_value == 0));
214
 
215
        always @(*)
216
                if (r_value != 0)
217
                        assert(r_running);
218
 
219
        always @(*)
220
                if (auto_reload)
221
                        assert(r_running);
222
 
223
        always @(*)
224
                if (!RELOADABLE)
225
                        assert(auto_reload == 0);
226
 
227
        always @(*)
228
                if (auto_reload)
229
                        assert(interval_count != 0);
230
 
231
        always @(posedge i_clk)
232
        if ((f_past_valid)&&($past(r_value)==0)
233
                        &&(!$past(wb_write))&&(!$past(auto_reload)))
234
                assert(r_value == 0);
235
 
236
        always @(posedge i_clk)
237
        if ((f_past_valid)&&(!$past(i_reset))&&(!$past(wb_write))
238
                        &&($past(r_value)==0)&&($past(auto_reload)))
239
        begin
240
                if ($past(i_ce))
241
                        assert(r_value == interval_count);
242
                else
243
                        assert(r_value == $past(r_value));
244
        end
245
 
246
        always @(posedge i_clk)
247
        if ((f_past_valid)&&(!$past(i_reset))
248
                        &&(!$past(wb_write))&&($past(r_value)!=0))
249
        begin
250
                if ($past(i_ce))
251
                        assert(r_value == $past(r_value)-1'b1);
252
                else
253
                        assert(r_value == $past(r_value));
254
        end
255
 
256
        always @(posedge i_clk)
257
        if ((f_past_valid)&&(!$past(i_reset))&&($past(wb_write)))
258
                assert(r_value == $past(i_wb_data[(VW-1):0]));
259
        always @(posedge i_clk)
260
        if ((f_past_valid)&&(!$past(i_reset))&&($past(wb_write))
261
                        &&(RELOADABLE)&&(|$past(i_wb_data[(VW-1):0])))
262
                assert(auto_reload == $past(i_wb_data[(BW-1)]));
263
 
264
        always @(posedge i_clk)
265
        if (!(f_past_valid)||($past(i_reset)))
266
                assert(!o_int);
267
        else if (($past(wb_write))||(!$past(i_ce)))
268
                assert(!o_int);
269
        else
270
                assert(o_int == ((r_running)&&(r_value == 0)));
271
 
272
        always @(posedge i_clk)
273
        if ((!f_past_valid)||($past(i_reset)))
274
                assert(!o_wb_ack);
275
        else if ($past(i_wb_stb))
276
                assert(o_wb_ack);
277
 
278
        always @(*)
279
                assert(!o_wb_stall);
280
        always @(*)
281
                assert(o_wb_data[BW-1] == auto_reload);
282
        always @(*)
283
                assert(o_wb_data[VW-1:0] == r_value);
284
`endif
285 2 dgisselq
endmodule

powered by: WebSVN 2.1.0

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