笔试题解 | 输入序列连续的序列检测
最近牛客网开启了数字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 这仅仅是我的一个小小的想法,如果有大佬能提出我的代码还有那些问题,或者更好的解题思路,希望不吝赐教!
嘉士伯公司氛围 583人发布
查看2道真题和解析