一个对8位数据进行位计数的位计数器电路的总体思路是简单的,就是对于一个八位数的数据,从最低位到最高位依次判断其是否为1,若为1,则加1。用一个移位寄存器将数据载入后进行移位,数据按位或非后作为判断是否跳出循环的条件。
设计思路:
1、先画出算法状态机,确定三个状态和各个状态下的跳转条件;
2、数据通路电路:移位寄存器,计数器;
3、控制电路:通过状态机确定。
1、顶层模块
顶层部分,输入信号有时钟、复位,载入数据信号,起始触发信号,输入数据,
输出信号有数据,完成信号
代码中主要是三段式状态机,S1,S2,S3三个状态。有以下四个部分
(1)状态转换条件 即next_state(Y)=?
(2)状态跳转触发器 即 state <= next_state
(3)每个状态的控制信号,S1时应该计数器归零,S2时应该保持计数,计数使能信号,提供给移位寄存器移位信号,S3时应该发出完成信号。
(4)数据通路电路(计数器部分),复位时计数器为0,载入信号时计数器为0,有计数使能信号时计数+1
(5)例化移位寄存器,移位寄存器根据载入信号,移位信号,右移数据。输入信号:时钟、补位数据,载入数据,移位信号,载入信号,输出数据。
(6)结束循环的判断信号,移位寄存器中数据按位或非
`timescale 1ns/1ps
module BitCount(Clk,Rst_n,LA,s,Data,B,Done);
input Clk,Rst_n,LA,s;
input [7:0] Data;
output reg [3:0] B;
output reg Done;
wire [7:0] A;
wire z;
reg [1:0] Y,y;
reg EA,EB,LB;
parameter S1 = 2'b00,S2=2'b01,S3=2'b10;
always@(s,y,z)
begin:State_table
case(y)
S1:
if (!s) Y=S1;
else Y=S2;
S2:
if(z==0) Y=S2;
else Y= S3;
S3:
if(s) Y=S3;
else Y=S1;
default:Y=S1;
endcase
end
always@(posedge Clk,negedge Rst_n) begin
y<=~Rst_n?S1:Y;
end
always @(y,A[0]) begin
EA=0;LB=0;EB=0;Done=0;
case(y)
S1:LB=1;
S2:begin
EA=1;
if(A[0]) EB=1;
else EB =0;
end
S3:Done=1;
default:;
endcase
end
always@(posedge Clk,negedge Rst_n) begin
if (~Rst_n)
B <= 0;
else if (LB)
B <= 0;
else if (EB)
B <= B +1'b1;
end
shiftrne ShiftA(.Data(Data),.La(LA),.Ea(EA),.w(1'b0),.Clock(Clk),.A(A));
assign z= ~|A;
endmodule
2、移位寄存器部分
移位寄存器的输入信号:时钟、原始数据8位、补位数据1位、载入信号、移位信号;
输出:数据
`timescale 1ns/1ps
module shiftrne(Clock,Data,La,Ea,A,w);
input Clock,La,Ea,w;
input [7:0] Data;
output reg [7:0] A;
always @(posedge Clock) begin
if(La)
A <= Data;
else if (Ea)
A <= {w,A[7:1]};
end
endmodule
3、测试仿真
例化模块后,时钟信号定义,输出波形定义,
中间针对输入信号进行设置。复位、数据。
(1)时钟长期工作。首先复位信号有效,然后提供原始数据并且载入数据到移位寄存器中。触发信号为0。
(2)触发信号为1,进行移位并对1计数,计算8个周期完成后【实际上高位为0时要不了8个周期就done】可以改变触发为0
`timescale 1ns/1ps
`define clk_period 20
module tb_bitc();
reg clk,rst_n,s,la;
reg [7:0] data;
wire [3:0] b;
wire done;
BitCount bc0(.Clk(clk),.Rst_n(rst_n),.Data(data),.LA(la),.s(s),.B(b),.Done(done));
initial clk = 1'b0;
always #(`clk_period /2) clk = ~clk;
initial begin
rst_n = 0 ; la=0;
s = 0 ;
data = 8'd0;
# (5*`clk_period/2) rst_n =1;
# 20;data=8'b00111011;la=1;
#20;data=8'd0;la=0;
s=1;
#(8*`clk_period);
s=0;
#100;
# 20;data=8'b10111111;la=1;
#20;data=8'd0;la=0;
s=1;
#(8*`clk_period);
s=0;
#100;
# 20;data=8'b00100010;la=1;
#20;data=8'd0;la=0;
s=1;
#(8*`clk_period);
s=0;
#100;
end
initial
begin
$fsdbDumpfile("curve.fsdb");
$fsdbDumpvars;
$fsdbDumpon;
end
initial #5000 $finish;
endmodule
4、脚本运行
vcs -cpp gcc-4.8 -R shiftrne.v BitCount.v tb_bitc.v -P ${NOVAS_HOME}/share/PLI/VCS/linux64/novas.tab ${NOVAS_HOME}/share/PLI/VCS/linux64/pli.a -full64 +v2k -debug_all
理想仿真中,s和clk有效沿同时到来的话,s有效