(原創) 如何設計電子鐘(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,儒林圖書公司

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值