FPGA实现序列检测(训练testbench写法)

电路设计与状态机

  • FPGA的基础概念
    Cyclone IV器件采用了M9K的嵌入式块RAM,即每个嵌入式存储器块的容量为9216bit。4个PLL,一个PLL可以最多支持5路输出。
    cyclone IV E中,除了EP4CE6和EP4CE10两个容量等级的器件只含有两个PLL单元以外,其它容量的器件均含有4个PLL。
    M9K存储器,见名思意,该存储器每个M9K,存储容量是9Kbit,
    这些存储器可以配置为FIFO,RAM等
    18*18硬件乘法器,这些硬件乘法器的输入位宽都是18位。
    在这里插入图片描述

  • 序列检测
    功能:实现检测序列:Welcom
    在这里插入图片描述
    为什么这些资源为0呢,因为我们的输出,还没有被赋予值,这时候资源就是0.

好,下面我们来正式看如何检测序列;

module Sequence_detection
(
input clk,
input rst_n,
input data_valid,//信号输入有效标志信号
input [7:0]data,
output [3:0]num,//计数检测到多少个序列
output reg flag//检测完毕标志信号
);

reg [2:0] state=3'b0;
reg [3:0] counter=4'b0;
localparam CHECK_W=3'd0;
localparam CHECK_E=3'd1;
localparam CHECK_L=3'd2;
localparam CHECK_C=3'd3;
localparam CHECK_O=3'd4;
localparam CHECK_M=3'd5;



always @(posedge clk or negedge rst_n)
begin
	if(!rst_n)
	begin
	state<=CHECK_W;
	counter<=4'b0;
	flag<=1'b0;
	end
	else if(data_valid)
			begin
			case(state)
			CHECK_W://检测W
			begin
				if(data=="w")
				begin
				state<=CHECK_E;
				flag<=0;
				end
				else
				begin
				state<=CHECK_W;
				flag<=0;
				end
			end

			
			CHECK_E://检测e
			begin
				if(data=="e")
				state<=CHECK_L;
				else if(data=="w")
				state<=CHECK_E;
				else
				state<=CHECK_W;
			end

			CHECK_L://检测l

			begin
				if(data=="l")
				state<=CHECK_C	;	
				else if(data=="w")
				state<=CHECK_E;
				else
				state<=CHECK_W;
			end

			CHECK_C://检测c

			begin
				if(data=="c")
				state<=CHECK_O;
				else if(data=="w")
				state<=CHECK_E;
				else
				state<=CHECK_W;
			end

			CHECK_O://检测o

			begin
				if(data=="o")
				state<=CHECK_M;
				else if(data=="w")
				state<=CHECK_E;
				else
				state<=CHECK_W;
			end

			CHECK_M://检测m

			begin
				if(data=="m")
				begin
				counter<=counter+1;
				flag<=1'b1;
				state<=CHECK_W;
				end
				else if(data=="w")
				state<=CHECK_E;
				else
				state<=CHECK_W;
			end

			default:	state<=CHECK_W;
			endcase
			end
	else 
		begin
		state<=CHECK_W;
		end
			
end
assign num=counter;
endmodule

测试文件testbench:


`timescale 1 ns/ 1 ns
`define clk_period 20
module Sequence_detection_vlg_tst();
reg clk;
wire [7:0] data;
reg data_valid;
reg [511:0] reg_shift;
reg rst_n;
// wires                                               
wire flag;
wire [3:0]num;

// assign statements (if any)                          
Sequence_detection i1 (
	.clk(clk),
	.data(data),
	.data_valid(data_valid),
	.flag(flag),
	.num(num),
	.rst_n(rst_n)
);
initial                                                
begin                                                                                             
clk=1;                  
end                                                 
always #(`clk_period/2)  clk=~clk;       

wire [511:0] data_to_send ;
assign data_to_send="whwecomdwhusardwhuwelcomwhusdardwwelcomdwhusdardwhusdardwhusdard";


always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
reg_shift<=512'd0;
else if (data_valid)
reg_shift<=reg_shift<<8;
else
	reg_shift<=data_to_send;
end

assign data=(data_valid==1)?reg_shift[511:504]:8'bz;

initial
begin
rst_n=0;
data_valid=0;
#(`clk_period*20);
rst_n=1;
#(`clk_period*20);
data_valid=1;
#(`clk_period*64);
data_valid=0;
#(`clk_period*10);
$stop;
end
endmodule


在这里插入图片描述
在这里插入图片描述

  1. 解说部分
  2. 设计实例部分

首先,代码不用解释了,入了门的,都看得懂,下面说说一些注意的地方:
3. 快捷键的使用:ctrl+F查找
ctrl+H替换
4. 报告没有消耗逻辑资源,说明输出端口没有被赋予值。
5. 在这里插入图片描述
状态机每一个都返回W状态和E状态,为什么会返回E状态呢?
因为,比如WELWELCOM,如果在L状态了,发现下一个状态是W,不是我们要的C,于是,下个时钟,跳转到W状态,但此时,在W状态,就会检测是否此状态是否是E,发现不符合,就会出现漏检,因为出现一个跳转时钟,耽误了,所以导致出现漏检。(因为我们送来检测的时序是,一个时钟,检测一次)
所以,我们在每个状态,我们还要检测一下是否此字母是W,如果是W,就跳转到E,避免出现漏检。

  1. 状态机跳转条件
    在这里插入图片描述
    在这里插入图片描述
    我们可以看到L跳转到E的状态是1110111==h77
    我们查一下ASCII ,正是我们小写的w
    在这里插入图片描述

另外字也可以赋予到寄存器中,这也是我以前不太知道的,我以为只有数能赋予到寄存器中,字符根据ASCII码表。
在这里插入图片描述
我们对其是打双引号。data定义为8个位。

  1. Testbench写法
    宏定义
    在module外定义宏 `define a 8 //无等号无分号

    使用时 (1) b<=`a +3; //用`a,不是a
    
                 (2) `define b (`a+3)  //用`a,不是a
    

此处我们宏定义时钟周期20ns
`define clk_period 20
我们在tb里面写的clk_period都写的是‘clk_period

输入都是reg???!!
在这里插入图片描述
对于我们这个也不是输入就是定死的reg类型,这也是一般初学者的误区。
其实我们写TB就是给输入写值,把它当成寄存器来写,所以我们都是把实例中的input,在TB里面写成reg,这样我们就能对其赋值。
但是,如果我们在TB里面,自己定义个别的寄存器,然后,assign到如上图所示的data,我们就不需要非得把data变成reg

initial的写法
在这里插入图片描述
在这里插入图片描述
其他就按照always@(posedge or negedge)来写即可

wire也可赋予初值
在这里插入图片描述
modisim遇见no design不要怕
在这里插入图片描述
选中simulate就可以查看到TB的语法错误了。
另外最后提醒一点,更改了顶层文件的输入输出端口过后,一定要记得更改TB的输入输出端口。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值