笔试题解 | 输入序列连续的序列检测
最近牛客网开启了数字IC的题库,本着凑热闹的原则做了一道题,发现有一道题看上去不难,还是很有思考价值的
题目:
题目是这样的:
描述
请编写一个序列检测模块,检测输入信号(a)是否满足011100序列, 要求以每六个输入为一组,不检测重复序列,例如第一位数据不符合,则不考虑后五位。一直到第七位数据即下一组信号的第一位开始检测。当信号满足该序列,给出指示信号match。当不满足时给出指示信号not_match。
模块的接口信号图如下:
模块的时序图如下:
请使用Verilog HDL实现以上功能,要求使用状态机实现,画出状态转化图。并编写testbench验证模块的功能。
输入描述:
clk:系统时钟信号
rst_n:异步复位信号,低电平有效
a:单比特信号,待检测的数据
输出描述:
match:当输入信号a满足目标序列,该信号为1,其余时刻该信号为0
not_match:当输入信号a不满足目标序列,该信号为1,其余时刻该信号为0
看到题目之后,首先第一想法肯定是状态机,但是状态机一定不是容易也不是资源最小的,结合之前的序列检测的想法
方法一:RAM+Counter
但是这个是并非确定6个一组,所以shift_reg有点浪费,不如直接使用RAM+counter,手边使用Vivado简单看了一下资源使用情况。
`timescale 1ns/1ns module sequence_detect( input clk, input rst_n, input data, output reg match, output reg not_match ); reg [2:0] cnt; reg [5:0] ram; always@(posedge clk&nbs***bsp;negedge rst_n)begin if(! rst_n) cnt <= 3'd0; else if(cnt == 3'd5) cnt <= 3'd0; else cnt <= cnt + 3'd1; end always@(posedge clk&nbs***bsp;negedge rst_n)begin if(! rst_n) ram <= 6'd0; else case(cnt) 3'd0:ram <= {ram[5:1],data}; 3'd1:ram <= {ram[5:2],data,ram[0]}; 3'd2:ram <= {ram[5:3],data,ram[1:0]}; 3'd3:ram <= {ram[5:4],data,ram[2:0]}; 3'd4:ram <= {ram[5],data,ram[3:0]}; 3'd5:ram <= {data,ram[4:0]}; endcase end always@(posedge clk&nbs***bsp;negedge rst_n) begin if(! rst_n) match <= 1'd0; else if((ram == 6'b001110 )&&(cnt == 3'd5)) match <= 1'd1; else match <= 1'd0; end always@(posedge clk&nbs***bsp;negedge rst_n) begin if(! rst_n) not_match <= 1'd0; else if((ram != 6'b001110)&&(cnt == 3'd5)) not_match <= 1'd1; else not_match <= 1'd0; end endmodule
但是这并不是最简单的,如何进一步优化呢?
方法二:MUX+Counter
如果能够使用数选器,使用计数器选择每一位与当前输入的同或,那么原来6位寄存器存的数据只需要一个寄存器和数选器就可以做出来,资源使用如下
可以看到资源大大的减少。
`timescale 1ns/1ns module sequence_detect( input clk, input rst_n, input data, output reg match, output reg not_match ); reg [2:0] cnt; reg cmp; reg detect_cmp; parameter detect = 6'b011100; always@(posedge clk or negedge rst_n)begin if(! rst_n) cnt <= 3'd0; else if(cnt == 3'd5) cnt <= 3'd0; else cnt <= cnt + 3'd1; end always@(*)begin case(cnt) 3'd0: cmp = 1'd0; 3'd1: cmp = 1'd1; 3'd2: cmp = 1'd1; 3'd3: cmp = 1'd1; 3'd4: cmp = 1'd0; 3'd5: cmp = 1'd0; default: cmp = 1'd0; endcase end always@(posedge clk or negedge rst_n) begin if(! rst_n) detect_cmp <= 1'd1; else if(cnt == 3'd5) detect_cmp <= 1'd1; else detect_cmp <= detect_cmp && (~( cmp^ data)); end always@(posedge clk or negedge rst_n) begin if(! rst_n) match <= 1'd0; else if((detect_cmp )&&(cnt == 3'd5)) match <= 1'd1; else match <= 1'd0; end always@(posedge clk or negedge rst_n) begin if(! rst_n) not_match <= 1'd0; else if((!detect_cmp)&&(cnt == 3'd5)) not_match <= 1'd1; else not_match <= 1'd0; end endmodule
这仅仅是我的一个小小的想法,如果有大佬能提出我的代码还有那些问题,或者更好的解题思路,希望不吝赐教!