(原創) 如何設計電子鐘(II)? (SOC) (Verilog) (MegaCore) (DE2)

Abstract
之前曾完全使用Verilog的RTL撰寫一個電子鐘((原創) 如何設計電子鐘(I)? (SOC) (Verilog) (DE2)),這次功能一樣,但使用Altera所提供的Mega function:lpm_counter()與lpm_ff()來實現。

Introduction
使用環境:Quartus II 7.2 SP3 + DE2(Cyclone II EP2C35F627C6)

(原創) 如何設計電子鐘(I)? (SOC) (Verilog) (DE2)中,我們全部自己來,從除頻器到計數器通通自己來。這次我們用的是Altera所提供的Mega function。

digi_clock2.v / Verilog

  1 /* 
  2 (C) OOMusou 2008 http://oomusou.cnblogs.com
  3 
  4 Filename    : digi_clock2.v
  5 Compiler    : Quartus II 7.2 SP3 + ModelSim-Altera 6.1g
  6 Description : Demo how to write clock counter
  7 Release     : 07/31/2008 1.0
  8 */
  9 module digi_clock2 (
10   input         CLOCK_50,
11   input  [17:0] SW,
12   input  [3:0]  KEY,
13   output [6:0]  HEX2,
14   output [6:0]  HEX3,
15   output [6:0]  HEX4,
16   output [6:0]  HEX5,
17   output [6:0]  HEX6,
18   output [6:0]  HEX7
19 );
20 
21 wire       clk;      // 1 Hz clock
22 wire       en;       // counter enable
23 wire       clr;      // counter clear
24 wire       load;     // load new min & hour
25 wire       co;       // carry out for 23:59:59
26 wire [3:0] md0;      // original input for min[0]
27 wire [2:0] md1;      // original input for min[1]
28 wire [3:0] hd0;      // original input for hour[0]
29 wire [2:0] hd1;      // original input for hour[1]
30 
31 wire       w_clk;    // temp clk for lpm_counter
32 wire [3:0] w_md0;    // correct input for min[0]
33 wire [2:0] w_md1;    // correct input for min[1]
34 reg  [3:0] w_hd0;    // correct input for hour[0]
35 reg  [2:0] w_hd1;    // correct input for hour[1]
36 wire [3:0] w_sq0;    // correct output for sec[0]
37 wire [2:0] w_sq1;    // correct output for sec[1]
38 wire [3:0] w_mq0;    // corrent output for min[0]
39 wire [2:0] w_mq1;    // correct output for min[1]
40 wire [3:0] w_hq0;    // correct output for hour[0]
41 wire [2:0] w_hq1;    // correct output for hour[1]
42 
43 wire       w_co_sq0; // carry out for sec[0]
44 wire       w_co_sq1; // carry out for sec[1]
45 wire       w_co_mq0; // carry out for min[0]
46 wire       w_co_mq1; // carry out for min[1]
47 wire       w_co_hq0; // carry out for hour[0]
48 wire       w_co_hq1; // carry out for hour[1]
49 
50 assign en   = SW[17];
51 assign clr  = SW[16] | co;
52 assign load = SW[15];
53 assign md0  = SW[3:0];
54 assign md1  = SW[6:4];
55 assign hd0  = SW[10:7];
56 assign hd1  = SW[13:11];
57 
58 assign w_md0 = (!load) ? 0 :
59                (md0 < 10) ? md0 : 9;
60 assign w_md1 = (!load) ? 0 :
61                (md1 < 6? md1 : 5;
62               
63 // 23:59:59
64 /*
65 assign co   = ~ load
66             & w_hq1[1]             // 2
67             & w_hq0[1] & w_hq0[0]  // 3
68             & w_mq1[2] & w_mq1[0]  // 5
69             & w_mq0[3] & w_mq0[0]  // 9
70             & w_sq1[2] & w_sq0[0]  // 5
71             & w_sq0[2] & w_sq0[0]; // 9
72 */
73 assign co = w_co_sq1 & w_co_mq1 & w_co_hq1
74           & w_hq0[1] & w_hq0[0]; // 3              
75 
76 // 1Hz --------------------
77 lpm_counter # (
78   .lpm_width(25),
79   .lpm_direction("UP"),
80   .lpm_modulus(50000000>>1)
81 ) u0 (
82   .clock(CLOCK_50),
83   .cout(w_clk)
84 );
85 
86 lpm_ff # (
87   .lpm_width(1),
88   .lpm_fftype("TFF")
89 )
90 u1 (
91   .clock(CLOCK_50),
92   .data(w_clk),
93   .q(clk)
94 );
95 // -----------------------
96 
97 // sec[0].-------------------
98 lpm_counter # (
99   .lpm_width(4),
100   .lpm_direction("UP"),
101   .lpm_modulus(10)
102 ) u2 (
103   .cnt_en(en),
104   .sclr(clr),
105   .clock(clk),
106   .sload(load),
107   .data(4'h0),
108   .q(w_sq0),
109   .cout(w_co_sq0)
110 );
111 // -----------------------
112 
113 // sec[1].-------------------
114 lpm_counter # (
115   .lpm_width(3),
116   .lpm_direction("UP"),
117   .lpm_modulus(6)
118 ) u3 (
119   .cnt_en(en & w_co_sq0),
120   .sclr(clr),
121   .clock(clk),
122   .sload(load),
123   .data(3'h0),
124   .q(w_sq1),
125   .cout(w_co_sq1)
126 );
127 // -----------------------
128 
129 // min[0].-------------------
130 lpm_counter # (
131   .lpm_width(4),
132   .lpm_direction("UP"),
133   .lpm_modulus(10)
134 ) u4 (
135   .cnt_en(en & w_co_sq1 & w_co_sq0),
136   .sclr(clr),
137   .clock(clk),
138   .sload(load),
139   .data(w_md0),
140   .q(w_mq0),
141   .cout(w_co_mq0)
142 );
143 // -----------------------
144 
145 // min[1].-------------------
146 lpm_counter # (
147   .lpm_width(3),
148   .lpm_direction("UP"),
149   .lpm_modulus(6)
150 ) u5 (
151   .cnt_en(en & w_co_mq0 & w_co_sq1 & w_co_sq0),
152   .sclr(clr),
153   .clock(clk),
154   .sload(load),
155   .data(w_md1),
156   .q(w_mq1),
157   .cout(w_co_mq1)
158 );
159 // -----------------------
160 
161 // hour[0].-------------------
162 lpm_counter # (
163   .lpm_width(4),
164   .lpm_direction("UP"),
165   .lpm_modulus(10)
166 ) u6 (
167   .cnt_en(en & w_co_mq1 & w_co_mq0 & w_co_sq1 & w_co_sq0),
168   .sclr(clr),
169   .clock(clk),
170   .sload(load),
171   .data(w_hd0),
172   .q(w_hq0),
173   .cout(w_co_hq0)
174 );
175 // -----------------------
176 
177 // hour[1].-------------------
178 lpm_counter # (
179   .lpm_width(2),
180   .lpm_direction("UP"),
181   .lpm_modulus(3)
182 ) u7 (
183   .cnt_en(en & w_co_hq0 & w_co_mq1 & w_co_mq0 & w_co_sq1 & w_co_sq0),
184   .sclr(clr),
185   .clock(clk),
186   .sload(load),
187   .data(w_hd1),
188   .q(w_hq1),
189   .cout(w_co_hq1)
190 );
191 // -----------------------
192 
193 // sec. dig0 to seg7
194 seg7_lut u8 (
195   .i_dig(w_sq0),
196   .o_seg(HEX2)
197 );
198 
199 // sec. dig1 to seg7
200 seg7_lut u9 (
201   .i_dig({1'b0, w_sq1}),
202   .o_seg(HEX3)
203 );
204 
205 // min. dig0 to seg7
206 seg7_lut u10 (
207   .i_dig(w_mq0),
208   .o_seg(HEX4)
209 );
210 
211 // min. dig1 to seg7
212 seg7_lut u11 (
213   .i_dig({1'b0, w_mq1}),
214   .o_seg(HEX5)
215 );
216 
217 // hour dig0 to seg7
218 seg7_lut u12 (
219   .i_dig(w_hq0),
220   .o_seg(HEX6)
221 );
222 
223 // hour dig1 to seg7
224 seg7_lut u13 (
225   .i_dig({1'b0, w_hq1}),
226   .o_seg(HEX7)
227 );
228 
229 always@(load, hd0, hd1) begin
230   if (!load) begin
231     w_hd0 = 0;
232     w_hd1 = 0;
233   end
234   else begin
235     if (hd1 <= 1) begin // 0 1
236       w_hd1 = hd1;
237      
238       if (hd0 < 10)
239         w_hd0 = hd0;
240       else
241         w_hd0 = 9;
242     end
243     else begin // >= 2
244       w_hd1 = 2;
245      
246       if (hd0 < 4)
247         w_hd0 = hd0;
248       else
249         w_hd0 = 3;
250     end
251   end
252 end      
253 
254 endmodule


76行

// 1Hz --------------------
lpm_counter # (
  .lpm_width(
25),
  .lpm_direction(
"UP"),
  .lpm_modulus(
50000000>>1)
) u0 (
  .clock(CLOCK_50),
  .cout(w_clk)
);

lpm_ff # (
  .lpm_width(
1),
  .lpm_fftype(
"TFF")
)
u1 (
  .clock(CLOCK_50),
  .data(w_clk),
  .q(clk)
);
// -----------------------


使用lpm_counter + lpm_ff的T-FF來實現1 Hz的clock,請參閱(原創) 如何設計除頻器? (SOC) (Verilog) (MegaCore)

97行

// sec[0].-------------------
lpm_counter # (
  .lpm_width(
4),
  .lpm_direction(
"UP"),
  .lpm_modulus(
10)
) u2 (
  .cnt_en(en),
  .sclr(clr),
  .clock(clk),
  .sload(load),
  .data(
4'h0),
  .q(w_sq0),
  .cout(w_co_sq0)
);
// -----------------------


(原創) 如何設計電子鐘(I)? (SOC) (Verilog) (DE2),對於秒方面是自己寫的60計數器, 在這裏我們是一個位數一個位數的處理,由於分最多是59秒,也就是說,秒的個位數需要的是10計數器。計數器請參閱(筆記) 如何設計計數器? (SOC) (Verilog) (MegaCore)

113行

// sec[1].-------------------
lpm_counter # (
  .lpm_width(
3),
  .lpm_direction(
"UP"),
  .lpm_modulus(
6)
) u3 (
  .cnt_en(en
& w_co_sq0),
  .sclr(clr),
  .clock(clk),
  .sload(load),
  .data(
3'h0),
  .q(w_sq1),
  .cout(w_co_sq1)
);
// -----------------------


同理,秒的十位數需要的是一個6計數器。由於十位數是由個位數所進位,所以counter的enable由en與個位數的進位w_co_sq0共同決定。至於時與分,道理相同,我就不再多言。

63行

// 23:59:59

assign co   = ~ load
           
& w_hq1[1]             // 2
            & w_hq0[1] & w_hq0[0// 3
            & w_mq1[2] & w_mq1[0// 5
            & w_mq0[3] & w_mq0[0// 9
            & w_sq1[2] & w_sq0[0// 5
            & w_sq0[2] & w_sq0[0]; // 9


到23:59:59會歸00:00:00,這裡有兩種做法,一種是判斷都23:59:59時進位。且特意的避開load。

73行

assign co = w_co_sq1 & w_co_mq1 & w_co_hq1
         
& w_hq0[1] & w_hq0[0]; // 3   


這種方式與(原創) 如何設計電子鐘(I)? (SOC) (Verilog) (DE2)較類似,判斷時、分、秒十位數部分是否進位,但因為時是24小時進位, 還要確定時的個位是否為3才能進位。

58行

assign w_md0 = (!load) ? 0 :
               (md0
< 10) ? md0 : 9;
assign w_md1 = (!load) ? 0 :
               (md1
< 6? md1 : 5;


229行

always@(load, hd0, hd1) begin
 
if (!load) begin
    w_hd0
= 0;
    w_hd1
= 0;
 
end
 
else begin
   
if (hd1 <= 1) begin // 0 1
      w_hd1 = hd1;
     
     
if (hd0 < 10)
        w_hd0
= hd0;
     
else
        w_hd0
= 9;
   
end
   
else begin // >= 2
      w_hd1 = 2;
     
     
if (hd0 < 4)
        w_hd0
= hd0;
     
else
        w_hd0
= 3;
   
end
 
end
end


都只是為了輸入防呆,在(原創) 如何設計除頻器? (SOC) (Verilog) (MegaCore)都曾經討論過,只是將code搬過來而已。

完整程式碼下載
digi_clock2.7z

Conclusion
其實也不一定得用Mega function不可,只是趁機熟悉一下Mega function的使用方法。Mega function類似C++的STL,用STL會使程式短一點,但你要用C++自己實做演算法當然也可以。

See Also
(原創) 如何設計電子鐘(I)? (SOC) (Verilog) (DE2)
(原創) 如何設計除頻器? (SOC) (Verilog) (MegaCore)
(筆記) 如何設計計數器? (SOC) (Verilog) (MegaCore)

Reference
陸自強 2007,數位系統實習 Quartus II,儒林圖書公司

posted on 2008-07-31 22:19  真 OO无双  阅读(7884)  评论(0编辑  收藏  举报

导航