首页 > 解决方案 > Verilog 计数模块指南

问题描述

我正在尝试用 Verilog(或 VHDL)设计一个计数模块。它接收一个输入字节,并且在每个时钟脉冲上,它仅按字节中的“1”顺序计数。例如:如果输入字节是:'00001111;然后它计数并循环...... 00000001, 00000010, 00000100, 00001000,如果输入字节是:'00000011; 然后它计数并循环...... 00000001, 00000010,如果输入字节是:'01010101; 然后它计数并循环...... 00000001, 00000100, 00010000, 01000000,

我已经编写了这个 Verilog 代码。

module ripple_borrow ( req,    
                   grant,
                   o_count, 
                   o_shift_base1,
                   clk );

parameter WIDTH = 8;
parameter count_WIDTH = 3;

input  [WIDTH-1:0] req;     //input byte to enable which bits to count through
output [WIDTH-1:0] grant;  //output byte to enable which bit has been chosen
output [count_WIDTH-1:0] o_count;
output [WIDTH-1:0] o_shift_base1;
input  clk;

reg [WIDTH-1:0] shift_base1  = 8'b00000001; //bit to shift
wire [2*WIDTH-1:0] double_req = {req,req}; //double reg to accomodate roll over from calculations
wire [2*WIDTH-1:0] double_grant = double_req & ~(double_req- 
shift_base1);//dounle grant to accomdate roll over
reg [count_WIDTH-1:0] count  = 3'b000; //counter to drive shifted bit

always@(posedge clk)
begin

//adjust count via the grant to skip inactive clock cycles so granted value plays for one clock cycle only.
case(grant)
'h01: count = 3'b000; 
'h02: count = 3'b001; 
'h04: count = 3'b010; 
'h08: count = 3'b011; 
'h10: count = 3'b100; 
'h20: count = 3'b101; 
'h40: count = 3'b110; 
'h80: count = 3'b111; 
default: count = count; 
endcase

count = count-1;
shift_base1 = 8'b00000001;
shift_base1 = shift_base1 << count;  //shift bit by count amount.
end

assign grant = double_grant[WIDTH-1:0] | double_grant[2*WIDTH-1:WIDTH]; //concanterate double grant and pass to grant
assign o_count = count;
assign o_shift_base1 = shift_base1;

endmodule

这是测试台:

Heare is the testbench:

`timescale 1ns/1ns //Adjust to suit

module ripple_borrow_tb;  // No ports!
parameter WIDTH = 8;
parameter count_WIDTH = 3;

reg [WIDTH-1:0]req ;
wire [WIDTH-1:0]grant ;
wire [count_WIDTH-1:0]o_count ;
wire [WIDTH-1:0]o_shift_base1 ;
reg clk ;


 ripple_borrow uut (
.req ( req ),
.grant ( grant ),
.o_count ( o_count ),
.o_shift_base1 ( o_shift_base1 ),
.clk ( clk )
);

parameter PERIOD = 10; //adjust for your timescale


initial begin
   $dumpvars(2, ripple_borrow_tb);
   clk = 1'b0;
   #(PERIOD/2);
   forever
   #(PERIOD/2) clk = ~clk;
end

initial begin 

   req='b11111111;
   #(PERIOD*16);
   req='b01010101;
   #(PERIOD*8);
   req='b00000011;
   #(PERIOD*8);

  $finish;
end

endmodule

这是工作计数的模拟: 数数成功

在这个模拟中。一切都按预期工作。在每个时钟周期上,只有字节中有效的“1”被“授权”,并且它们仅在一个时钟周期内有效。然而。当我试着倒计时。“计数 = 计数-1”。授予的信号被卡住并保持在最高步骤。

这是失败倒计时的模拟: 在此处输入图像描述

如你看到的。除非整个字节都是'1'。它卡在 7 计数上。我的假设是,通过将 shift_base1 初始化为 '00000001,然后在每个时钟周期倒数到 7。它陷入了 0-7-0-7 循环。令人困惑的是,当整个字节处于活动状态时它才起作用。有人可以告诉我为什么会出错并帮助我解决问题。或者为我的问题提供更好的解决方案。甚至是VHDL中的东西。

我现在只使用 vivado 和编​​写 HDL 代码一两个月。我现在还在努力理解。我用 VHDL 和 Verilog 设计了一些基本的计数器。所以我的知识是有限的。任何帮助,将不胜感激。

谢谢你。

标签: verilogcountingvivado

解决方案


在您的情况下,如果req == 3 then --> grant = 01--> count = 7--> ... 在您更改reqshift = 80 之前,没有任何算术方法可以解决这个问题。

正如评论中提到的,你应该在翻牌的代码中使用非阻塞赋值。

但在编码时,至少有两个错误:你使用countandshift作为临时变量和翻牌的输出。这是一个不好的做法。一般来说,使用临时变量,您应该使用以下方案:

always @(posedge clk) begin
   tmp = some-expression;
   out <= tmp;
end

否则会造成混乱。如果是计数器,我认为您的意思与使用临时变量不同,可能是默认值分配,例如

always @(posedge clk)  begin
    count <= count - 1;
    case(grant)
       h01: count = 3'b000; 
       ...
     endcase
     ```

或者默认使用它

    default: count <= count - 1;

顺便说一句,永远不要使用像count = count;这样的表达式。这没有什么意义,可能会导致工具问题。

随着班次,你真的把它用作临时工。不。使用文字直接:shift_base1 <= 8'b1 << count;或制作一个parameter one=8'b1; ... shift <= shift << one;

其他建议:

切勿在 DUT 模块的声明中使用reglogic和其他 var 的初始化。它们可能无法合成。(电线没问题)。您应该使用重置信号创建正确的初始化。


推荐阅读