当前位置:   article > 正文

HDLBits: 在线学习 SystemVerilog(十六)-Problem 98-105(计数器)

verilog16计数器代码为什么reg[3:0]

f5b5cce25edc5d8bf9fa12ca25cbdcd7.jpeg

HDLBits 是一组小型电路设计习题集,使用 Verilog/SystemVerilog 硬件描述语言 (HDL) 练习数字硬件设计~

网址如下:

https://hdlbits.01xz.net/

关于HDLBits的Verilog实现可以查看下面专栏:

https://www.zhihu.com/column/c_1131528588117385216

缩略词索引:

  • SV:SystemVerilog

从今天开始新的一章-时序电路,包括触发器、计数器、移位寄存器、状态机等。

今天更新计数器,这也是FPGA部分非常重要的设计技巧。

Problem 98-Count15

题目说明

构建一个4位二进制计数器,计数范围从0到15(包括0和15),计数周期为16。同步复位输入时,将计数器重置为0。

188c1447b81bf4b6055538b172ce897a.png图片来自HDLBits

模块端口声明

  1. module top_module (
  2.     input clk,
  3.     input reset,      // Synchronous active-high reset
  4.     output [3:0] q);

题目解析

这是一个基本计数器。同步复位情况下,复位不放在敏感列表里。

  1. module top_module (
  2.     input logic clk,
  3.     input logic reset,      // Synchronous active-high reset
  4.     output logic [3:0] q);
  5.     
  6.     always_ff@(posedge clk) begin
  7.         if(reset)  q <= '0 ;
  8.         else if(q == 4'd15) q <= '0 ;
  9.         else  q <= q + 1 ;
  10.     end
  11.             
  12. endmodule
be00d39d8711a93fad21bb3c67a1a803.png

点击Submit,等待一会就能看到下图结果:

10dd84d1768722a350ce1ceb211cf03a.png

注意图中的Ref是参考波形,Yours是你的代码生成的波形,网站会对比这两个波形,一旦这两者不匹配,仿真结果会变红。

这一题就结束了。

Problem 99-Count10

题目说明

构建一个十进制计数器,从0到9(包括0和9)计数,计数周期为10。同步复位输入时,将计数器重置为0。

5532d3bd814fd6b60ec7e80e1ce1ee78.png图片来自HDLBits

模块端口声明

  1. module top_module (
  2.     input clk,
  3.     input reset,        // Synchronous active-high reset
  4.     output [3:0] q);

题目解析

和上一题类似。

  1. module top_module (
  2.     input logic clk,
  3.     input logic reset,        // Synchronous active-high reset
  4.     output logic [3:0] q);
  5.     
  6.     always_ff@(posedge clk) begin
  7.         if(reset)           q <= '0 ;
  8.         else if(q == 4'd9)  q <= '0 ;
  9.         else                q <= q + 1;
  10.     end
  11.  
  12. endmodule
f115b44c4ccc3243bc4d41bdb66c4f0a.png

点击Submit,等待一会就能看到下图结果:

81892d6167f163fdace6b4748bd7bdc6.png

注意图中的Ref是参考波形,Yours是你的代码生成的波形,网站会对比这两个波形,一旦这两者不匹配,仿真结果会变红。

这一题就结束了。

Problem 100-Count1to10

题目说明

做一个十进制计数器,从1到10(包括1和10)计数,计数周期为10。同步复位输入时,将计数器重置为1。

226d28bcbdb8a902813918fa584d9880.png图片来自HDLBits

模块端口声明

  1. module top_module (
  2.     input clk,
  3.     input reset,
  4.     output [3:0] q);

题目解析

和上一节一样,上一节是从0到9,这题从1到10,计数结束条件和重置条件不一样,其他一样。

  1. module top_module (
  2.     input logic clk,
  3.     input logic reset,
  4.     output logic [3:0] q);
  5.     
  6.     always_ff@(posedge clk)begin
  7.         if(reset)           q <= 4'd1;
  8.         else if(q == 4'd10) q <= 4'd1;
  9.         else                q <= q + 1;
  10.     end
  11. endmodule
5729255cc91f8cfb313cc7983e90598c.png

点击Submit,等待一会就能看到下图结果:

46205729d57f4888d4e9dad4491a87eb.png

注意图中的Ref是参考波形,Yours是你的代码生成的波形,网站会对比这两个波形,一旦这两者不匹配,仿真结果会变红。

这一题就结束了。

Problem 101-Countslow

题目说明

构建一个十进制计数器,从0到9(包括0和9)计数,计数周期为10。同步复位输入时,将计数器重置为0。但是本题是希望该计数器并不是随着clk的变化而递增,而是随着一个slowena使能信号来控制增加。时序图如下图所示:

a38b3797f1535950f93b06482aab3ffa.png图片来自HDLBits

模块端口声明

  1. module top_module (
  2.     input clk,
  3.     input slowena,
  4.     input reset,
  5.     output [3:0] q);

题目解析

本题相比于之前的计数器,不同点在于多了一个enable信号来控制计数器的增加(这应该叫使能同步计数器(战术后仰))。

af7462e62b72a68450c4301c36e74678.png
  1. module top_module (
  2.     input logic clk,
  3.     input logic slowena,
  4.     input logic reset,
  5.     output logic [3:0] q);
  6.     always_ff@(posedge clk) begin
  7.         if(reset)                  q <= '0 ;
  8.         else if(slowena & q==4'd9) q <= '0 ;
  9.         else if(slowena & q!=4'd9) q <= q + 1 ;
  10.         else                       q <= q  ;
  11.     end
  12. endmodule
550520b22e05cab0b0376219c6064a88.png

点击Submit,等待一会就能看到下图结果:

cc5b59b0d143887853aa17c5c4e57fb1.png

注意图中的Ref是参考波形,Yours是你的代码生成的波形,网站会对比这两个波形,一旦这两者不匹配,仿真结果会变红。

这一题就结束了。

Problem 102-ece241_2014_q7a

题目说明

根据以下输入输出信号设计一个计算1~12的计数器

Reset:同步复位信号,高复位,将计数器复位为1.

Enable:使能信号高有效

Clk:时钟上升沿触发计数器工作

Q[3:0]:计数器输出

c_enable, c_load, c_d[3:0]:题目中给我们提供了一个4-bit的计数器,这三个信号是用于该4-bit计数器的控制信号。

题目提供给我们4-bit计数器

有enable信号,带复位和置位的计数器,将该计数器例化至我们的代码中。

再用一些其他的逻辑门来完成本题

  1. //题目提供的4-bit计数器代码
  2. module count4(
  3.     input clk,
  4.     input enable,
  5.     input load,
  6.     input [3:0] d,
  7.     output reg [3:0] Q
  8. );

模块端口声明

  1. module top_module (
  2.     input clk,
  3.     input reset,
  4.     input enable,
  5.     output [3:0] Q,
  6.     output c_enable,
  7.     output c_load,
  8.     output [3:0] c_d
  9. );

题目解析

本题相当于用c_enale、c_load和c_d[3:0]三个控制信号来控制题目中给我们提供的4-bit计数器,使得该计数器的技术范围改变为1~12.

  1. module top_module (
  2.     input logic clk,
  3.     input logic reset,
  4.     input logic enable,
  5.     output logic [3:0] Q,
  6.     output logic c_enable,
  7.     output logic c_load,
  8.     output logic [3:0] c_d
  9. ); //
  10.     count4 u1_count4 (clk, c_enable, c_load, c_d ,Q);
  11.     
  12.     assign c_enable = enable ;
  13.     assign c_load   = reset | ((Q == 4'd12)&&enable) ;
  14.     assign c_d      = c_load ? 4'd1:4'd0 ;
  15. endmodule
648f27db33bb7bc6965251dd7cf51fe1.png

点击Submit,等待一会就能看到下图结果:

10dd03fc59f4d252baa69fc24cd771ee.png

注意图中的Ref是参考波形,Yours是你的代码生成的波形,网站会对比这两个波形,一旦这两者不匹配,仿真结果会变红。

这一题就结束了。

Problem 103-ece241_2014_q7b

题目说明

从1000Hz中分离出1Hz的信号,叫做OneHertz。这个主要用作与数字时钟中。利用一个模10的BCD计数器和尽量少的逻辑门来建立一个时钟分频器。同时输出每个BCD计算器的使能信号(c_enable[0]为高位,c_enable[2]为低位)。

题目已经给我们提供了BCD计数器。Enable信号高有效。Reset信号高有效且复位为0。我们设计的电路中均要采用1000Hz的时钟。

  1. module bcdcount (
  2.     input clk,
  3.     input reset,
  4.     input enable,
  5.     output reg [3:0] Q
  6. );

模块端口声明

  1. module top_module (
  2.     input clk,
  3.     input reset,
  4.     output OneHertz,
  5.     output [2:0] c_enable
  6. );

题目解析

题目已经提供了一个模块,但是是个模10的BCD计数器,1000Hz提取1Hz,那么需要3个上面的计数器(1000/10/10/10=1).

  1. module top_module (
  2.     input logic clk,
  3.     input logic reset,
  4.     output logic OneHertz,
  5.     output logic [2:0] c_enable
  6. ); //
  7.     wire logic [3:0] unit, ten, hundred;
  8.     
  9.     assign c_enable = {unit == 4'd9 && ten == 4'd9, unit == 4'd9, 1'b1};
  10.     assign OneHertz = (unit == 4'd9 && ten == 4'd9 && hundred == 4'd9);
  11.  
  12.     bcdcount counter0 (clk, reset, c_enable[0], unit);
  13.     bcdcount counter1 (clk, reset, c_enable[1], ten);
  14.     bcdcount counter2 (clk, reset, c_enable[2], hundred);
  15.  
  16. endmodule
ecbe7c33827cdf3173444cc250a7b01b.png

点击Submit,等待一会就能看到下图结果:

1b9da87971602eec7ee50ef90ca4d548.png

注意图中的Ref是参考波形,Yours是你的代码生成的波形,网站会对比这两个波形,一旦这两者不匹配,仿真结果会变红。

这一题就结束了。

Problem 104-Countbcd

题目说明

构建一个4位BCD(二进制编码十进制)计数器。每个十进制数字使用4位进行编码:q[3:0]是一位数字,q[7:4]是十位数字,等等。对于ena[3:1],该信号用来表示个位、十位和百位的进位。时序图如下图所示:

89c9b30aef959775aca3d767f2c4ad76.png图片来自HDLBits

模块端口声明

  1. module top_module (
  2.     input clk,
  3.     input reset,   // Synchronous active-high reset
  4.     output [3:1] ena,
  5.     output [15:0] q);

题目解析

这是一个数字时钟的一部分。

  1. module top_module (
  2.     input logic clk,
  3.     input logic reset,   // Synchronous active-high reset
  4.     output logic [3:1] ena,
  5.     output logic [15:0] q);
  6.     
  7.     reg [3:0] ones;
  8.     reg [3:0] tens;
  9.     reg [3:0] hundreds;
  10.     reg [3:0] thousands;
  11.     
  12.     always@(posedge clk)begin
  13.         if(reset)               ones <= 4'd0;
  14.         else if(ones == 4'd9)   ones <= 4'd0;
  15.         else                    ones <= ones + 4'd1 ;
  16.     end
  17.     
  18.     always@(posedge clk)begin
  19.         if(reset)               tens <= 4'd0;
  20.             
  21.         else if(tens == 4'd9 && ones == 4'd9)  
  22.                                 tens <= 4'd0;
  23.         else if(ones == 4'd9)   tens <= tens + 4'd1;
  24.     end
  25.     
  26.     always@(posedge clk)begin
  27.         if(reset)               hundreds <= 4'd0;
  28.             
  29.         else if(hundreds == 4'd9 && tens == 4'd9 && ones == 4'd9)
  30.                                 hundreds <= 4'd0;
  31.         else if(tens == 4'd9 && ones == 4'd9) 
  32.                                 hundreds <= hundreds + 4'd1;
  33.     end
  34.     
  35.     always@(posedge clk)begin
  36.         if(reset)               thousands <= 4'd0;
  37.         else if(thousands == 4'd9 && hundreds == 4'd9 && tens == 4'd9 && ones == 4'd9)
  38.                                 thousands <= 4'd0;
  39.         else if(hundreds == 4'd9 && tens == 4'd9 && ones == 4'd9) 
  40.                                 thousands <= thousands + 4'd1;
  41.     end
  42.     
  43.     assign q = {thousands, hundreds, tens, ones};
  44.     assign ena[1] = (ones == 4'd9) ? 1'b1 : 1'b0;
  45.     assign ena[2] = (tens == 4'd9 && ones == 4'd9) ? 1'b1 : 1'b0;
  46.     assign ena[3] = (hundreds == 4'd9 && tens == 4'd9 && ones == 4'd9) ? 1'b1 : 1'b0;
  47.  
  48. endmodule
bcfbf039f0a58149d69031307be777ea.png

点击Submit,等待一会就能看到下图结果:

bc1976c99400538f625c1eeefa486b51.png

注意图中的Ref是参考波形,Yours是你的代码生成的波形,网站会对比这两个波形,一旦这两者不匹配,仿真结果会变红。

这一题就结束了。

Problem 105-Count_clock

题目说明

用计数器设计一个带am/pm的12小时时钟。该计数器通过一个CLK进行计时,用ena使能信号来驱动时钟的递增。

reset信号将时钟复位为12:00 AM。 信号pm为0代表AM,为1代表PM。hh、mm和ss由两个BCD计数器构成hours(01~12), minutes(00~59) , second(00~59)。Reset信号比enable信号有更高的优先级,即使没有enable信号也可以进行复位操作。

下图所示的时序图给出了从11:59:59 AM 到12 :00 : 00 PM的变化。

9812a6814a72f5a10250b3e833dc8642.png图片来自HDLBits

模块端口声明

  1. module top_module(
  2.     input clk,
  3.     input reset,
  4.     input ena,
  5.     output pm,
  6.     output [7:0] hh,
  7.     output [7:0] mm,
  8.     output [7:0] ss);

题目解析

  1. module top_module(
  2.     input logic clk,
  3.     input logic reset,
  4.     input logic ena,
  5.     output logic pm,
  6.     output logic [7:0] hh,
  7.     output logic [7:0] mm,
  8.     output logic [7:0] ss); 
  9.     
  10.     //ss var
  11.     var logic [3:0] ss_one , ss_ten ;
  12.     var logic ena_ss_one , ena_ss_ten ;
  13.     var logic rst_ss_one , rst_ss_ten ;
  14.     
  15.     //mm var
  16.     var logic [3:0] mm_one , mm_ten ;
  17.     var logic ena_mm_one , ena_mm_ten ;
  18.     var logic rst_mm_one , rst_mm_ten ;
  19.     
  20.     //hh var
  21.     var logic [3:0] hh_one , hh_ten ;
  22.     var logic ena_hh_one , ena_hh_ten ;
  23.     var logic rst_hh_one_0 , rst_hh_one_1 , rst_hh_ten_0 , rst_hh_ten_1 ;
  24.     
  25.     //pm var
  26.     var logic rev_pm ;
  27.     
  28.     
  29.     //ss cout part
  30.     assign ena_ss_one = ena ;
  31.     assign rst_ss_one = ena_ss_one && (ss_one == 4'd9) ;
  32.     
  33.     always_ff@(posedge clk) begin
  34.         if(reset)           ss_one <= '0 ;
  35.         else if(ena_ss_one) begin
  36.             if(rst_ss_one)  ss_one <= '0 ;
  37.             else            ss_one <= ss_one + 4'd1 ;
  38.         end
  39.     end
  40.     
  41.     assign ena_ss_ten = rst_ss_one ;
  42.     assign rst_ss_ten = ena_ss_ten && (ss_ten == 4'd5) ;
  43.     
  44.     always_ff@(posedge clk) begin
  45.         if(reset)           ss_ten <= '0 ;
  46.         else if(ena_ss_ten) begin
  47.             if(rst_ss_ten)  ss_ten <= '0 ;
  48.             else            ss_ten <= ss_ten + 4'd1 ;
  49.         end
  50.     end
  51.    
  52.     
  53.     //mm cout part
  54.     
  55.     assign ena_mm_one = rst_ss_ten ;
  56.     assign rst_mm_one = ena_mm_one && (mm_one == 4'd9) ;
  57.        
  58.     always_ff@(posedge clk) begin
  59.         if(reset)           mm_one <= '0 ;
  60.         else if(ena_mm_one) begin
  61.             if(rst_mm_one)  mm_one <= '0 ;
  62.             else            mm_one <= mm_one + 4'd1 ;
  63.         end
  64.     end 
  65.     
  66.     
  67.     assign ena_mm_ten = rst_mm_one ;
  68.     assign rst_mm_ten = ena_mm_ten && (mm_ten == 4'd5) ;
  69.     
  70.     always_ff@(posedge clk) begin
  71.         if(reset)           mm_ten <= '0 ;
  72.         else if(ena_mm_ten) begin
  73.             if(rst_mm_ten)  mm_ten <= '0 ;
  74.             else            mm_ten <= mm_ten + 4'd1 ;
  75.         end
  76.     end
  77.     
  78.     //hh cout part
  79.     
  80.     assign ena_hh_one = rst_mm_ten ;
  81.     assign rst_hh_one_0 = ena_hh_one && (hh_one == 4'd9) ;
  82.     assign rst_hh_one_1 = ena_hh_one && (hh_one == 4'd2 && hh_ten == 4'd1) ;
  83.     
  84.     always_ff@(posedge clk) begin
  85.         if(reset)             hh_one <= 4'd2 ;
  86.         else if(ena_hh_one) begin
  87.             if(rst_hh_one_0)  hh_one <= 4'd0 ;
  88.             else if(rst_hh_one_1)           
  89.                               hh_one <= 4'd1 ;
  90.             else              hh_one <= hh_one + 4'd1 ;
  91.         end
  92.     end 
  93.     
  94.     
  95.     assign ena_hh_ten = ena_hh_one ;
  96.     assign rst_hh_ten_0 = ena_hh_ten && (hh_one == 4'd2 && hh_ten == 4'd1) ;
  97.     assign rst_hh_ten_1 = ena_hh_ten && (hh_one == 4'd9) ;
  98.     
  99.     always_ff@(posedge clk) begin
  100.         if(reset)             hh_ten <= 4'd1 ;
  101.         else if(ena_hh_ten) begin
  102.             if(rst_hh_ten_0)  hh_ten <= 4'd0 ;
  103.             else if(rst_hh_ten_1)            
  104.                               hh_ten <= 4'd1 ;
  105.         end
  106.     end
  107.     
  108.     
  109.     //pm display part
  110.     
  111.     assign rev_pm = (hh_ten == 4'd1) && (hh_one == 4'd1) && ena_hh_one ;
  112.     
  113.     always_ff@(posedge clk) begin
  114.         if(reset)       pm <= '0  ;
  115.         else if(rev_pm) pm <= ~pm ;
  116.     end
  117.     
  118.     //assign time output
  119.     
  120.     assign ss = {ss_ten,ss_one} ;
  121.     assign mm = {mm_ten,mm_one} ;
  122.     assign hh = {hh_ten,hh_one} ;
  123. endmodule
124a06d72fef79736dee7c5e41d4219a.png 6676c3a88ba7d1ab4c8b2e460e2e6eef.png abe8eb3ec338c84c37d02107865e3497.png

点击Submit,等待一会就能看到下图结果:

08c68e53a331fce84d524190efe3c1dc.png

注意图中的Ref是参考波形,Yours是你的代码生成的波形,网站会对比这两个波形,一旦这两者不匹配,仿真结果会变红。

这一题就结束了。

总结

今天的几道题就结束了,对于计数器的设计真的需要掌握,不仅是时序电路的基础,同时在后续FPGA设计也是一个重要的设计技巧。

最后我这边做题的代码也是个人理解使用,有错误欢迎大家批评指正,祝大家学习愉快~

代码链接:

https://github.com/suisuisi/SystemVerilog/tree/main/SystemVerilogHDLBits

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/725211
推荐阅读
相关标签
  

闽ICP备14008679号