1.输入序列连续的序列检测
- 题面
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kJH9kHFH-1690301233803)(https://s2.loli.net/2023/07/26/HJPXR2mhbaVCG6d.png)] - 思路
对于序列检测题目,常规的解法有两种:状态机法和序列缓存对比法。
状态机法的过程类似于:在初始状态中,先判断第一位是否符合,若符合则进入下一个状态,判断第二位是否符合;若第一位不符合则保持在初始状态,直到第一位匹配。如前两位匹配,则判断第三位是否符合,若第一位匹配,最新输入的数值和目标序列的第二位不匹配,则根据最新一位是否匹配第一位,进入第一位匹配状态或者初始状态。依次类推。
序列缓存对比法,则是将八个时刻的数据缓存,作为一个数组,每个时刻的输入位于数组的末尾,数组其它元素左移,把最早输入的数据移出。然后将数组和目标序列对比,如果数组和目标序列相等,则说明出现目标序列。
序列缓存对比法在实现上比较简单。首先声明一个数组,缓存八个时刻的a输入的数值。移位可以通过位截取操作和位拼接操作实现:a_tem[6:0]表示截取a_tem的低7位,{a_tem[6:0],a}表示把a_tem[6:0]和新输入的数值a拼接,a位于低位。
- 代码
`timescale 1ns/1ns
module sequence_detect(input clk,input rst_n,input a,output reg match);reg [7:0] a_tem;always @(posedge clk or negedge rst_n) beginif (!rst_n) beginmatch <=1'b0;endelse if (a_tem == 8'b0111_0001) beginmatch <= 1'b1;endelse beginmatch <= 1'b0;endendalways @(posedge clk or negedge rst_n) beginif (!rst_n) begina_tem <= 8'b0;endelse begina_tem <= {a_tem[6:0],a};endendendmodule
2.含有无关项的序列检测
- 题面
- 思路
序列缓存对比法,则是将九个时刻的数据缓存,作为一个数组,每个时刻的输入位于数组的末尾,数组其它元素左移,把最早输入的数据移出。然后截取数组的前三位和目标序列011对比,截取数组的后三位和目标序列110对比,如果两段数组都和目标序列相等,则说明出现目标序列。
序列缓存对比法在实现上比较简单,本题采用该方法实现。首先声明一个数组,缓存九个时刻的a输入的数值。移位可以通过位截取操作和位拼接操作实现:a_tem[7:0]表示截取a_tem的低7位,{a_tem[7:0],a}表示把a_tem[7:0]和新输入的数值a拼接,a位于低位。
- 代码
`timescale 1ns/1ns
module sequence_detect(input clk,input rst_n,input a,output match);reg [8:0] a_tem;reg match_f;reg match_b;always @(posedge clk or negedge rst_n) beginif (!rst_n) beginmatch_f <=1'b0;endelse if (a_tem[8:6] == 3'b011) beginmatch_f <= 1'b1;endelse beginmatch_f <= 1'b0;endendalways @(posedge clk or negedge rst_n) beginif (!rst_n) beginmatch_b <= 1'b0;endelse if (a_tem[2:0] == 3'b110) beginmatch_b <= 1'b1;endelse beginmatch_b <= 1'b0;endendalways @(posedge clk or negedge rst_n) beginif (!rst_n) begina_tem <= 9'b0;end else begina_tem <= {a_tem[7:0],a};endendassign match = match_b && match_f;
endmodule
- 解法2
`timescale 1ns/1ns
module sequence_detect(input clk,input rst_n,input a,output reg match);reg [8:0] sequence;always @(posedge clk or negedge rst_n) beginif (~rst_n) beginsequence <= 9'b0;endelse beginsequence <= {sequence[7:0],a};endendalways @(posedge clk or negedge rst_n) beginif (~rst_n) beginmatch <= 0;endelse if (sequence[8:6] == 3'b011 && sequence[2:0] == 3'b110) beginmatch <= 1;endelse beginmatch <= 0;endendendmodule
- 解法3
`timescale 1ns/1ns
module sequence_detect(input clk,input rst_n,input a,output reg match);reg [8:0] val;always @(posedge clk or negedge rst_n) beginif (!rst_n) beginval <= 9'b0;end else beginval <= {val[7:0],a};endendalways @(posedge clk or negedge rst_n) beginif (!rst_n) beginmatch <= 1'b0;end else begincasex (val)9'b011xxx110 : match <= 1'b1;default : match <= 1'b0;endcaseendendendmodule
3. 不重叠序列检测
- 题意
题目描写错误,应该是001110,而题目是011100,差评。 - 思路
使用数选器选择出来对应的位,再做同或与最后做与运算,资源用的也很少。
- 代码
`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)beginif(! rst_n) cnt <= 3'd0;else if(cnt == 3'd5)cnt <= 3'd0;else cnt <= cnt + 3'd1;endalways@(*)begincase(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;endcaseendalways@(posedge clk or negedge rst_n) beginif(! rst_n)detect_cmp <= 1'd1;else if(cnt == 3'd5)detect_cmp <= 1'd1;elsedetect_cmp <= detect_cmp && (~( cmp^ data));endalways@(posedge clk or negedge rst_n) beginif(! rst_n)match <= 1'd0;else if((detect_cmp )&&(cnt == 3'd5))match <= 1'd1;elsematch <= 1'd0;endalways@(posedge clk or negedge rst_n) beginif(! rst_n)not_match <= 1'd0;else if((!detect_cmp)&&(cnt == 3'd5))not_match <= 1'd1;elsenot_match <= 1'd0;end
endmodule
4. 简易秒表
- 题意
- 思路
首先确定second的取值逻辑:当minute=60时停止计数,即保持second为0;当second=60时,下一个周期second置为1。其余情况second 等于前一时刻的值加一。 然后明确minute的取值逻辑:当second=60,minute等于前一时刻的值加一。其余情况,minute保持不变。
- 代码
`timescale 1ns/1nsmodule count_module(input clk,input rst_n,output reg [5:0]second,output reg [5:0]minute);always @(posedge clk or negedge rst_n) beginif (!rst_n) beginminute <= 6'd0;end else if (second == 6'd60) beginminute <= minute + 1;endelse beginminute <= minute;endendalways @(posedge clk or negedge rst_n) beginif (!rst_n) beginsecond <= 6'd0;end else if (second == 6'd60) beginsecond <= 6'd1;endelse if (minute == 60) beginsecond <=0;end else second <= second + 1'd1;end
endmodule
5. 可置位计数器
- 题意
- 思路
首先明确number的取值逻辑,声明number变量为4位无符号数,数值每个时钟加一,则每次数值达到15,下一个时钟因为位宽的限制,自动变为1,可以实现十六进制计数。当set信号为1时,将set_num的值赋给number。
然后确定zero的取值逻辑,在默认情况下为0,当number=0时,zero值为1。
因为判断number4’d0需要一个时钟,zero信号为1,总是滞后number0一个时钟周期。所以可以考虑将number延迟一个时钟再输出。使用num变量代替上述的number,再通过以下语句实现number延迟一个时钟输出。【因为number是寄存器类型,无法通过组合逻辑进行阻塞赋值同时匹配。 如果直接使用number进行zero的判断来说,zero肯定是比number过“0”时刻慢一拍的; 所以不妨使用num_reg,进行延迟; 因为zero肯定是比num_reg慢一拍的,所以再通过num_reg延迟一拍给number,则number与zero同步输出匹配;】
- 代码
`timescale 1ns/1nsmodule count_module(input clk,input rst_n,input set,input [3:0] set_num,output reg [3:0]number,output reg zero);reg [3:0] num;always @(posedge clk or negedge rst_n) beginif (!rst_n) beginzero = 1'd0;end else if (num == 4'd0) beginzero <= 1'b1;end else beginzero <= 1'b0;endendalways @(posedge clk or negedge rst_n) beginif (!rst_n) beginnum <= 4'b0;endelse if (set) beginnum <= set_num;endelse beginnum <= num + 1'd1;endendalways @(posedge clk or negedge rst_n) beginif (!rst_n) beginnumber <= 1'd0;endelse beginnumber <= num;endend
endmodule
6. 加减计数器
-
题意
-
思路
首先确定zero的取值逻辑,在默认情况下为0,当number=0时,zero值为1。 always @(posedge clk or negedge rst_n)
然后将mode的值作为if-else的判断条件,当mode为1时,number每个时钟周期加一,当mode为0时,number每个时钟周期减一。
按照以上代码,因为判断number4’d0需要一个时钟,zero信号为1,总是滞后number0一个时钟周期。所以可以考虑将number延迟一个时钟再输出。使用num变量代替上述的number,再通过以下语句实现number延迟一个时钟输出。
- 代码
`timescale 1ns/1nsmodule count_module(input clk,input rst_n,input mode,output reg [3:0]number,output reg zero);reg [3:0] num;always @(posedge clk or negedge rst_n) beginif (!rst_n) beginzero <= 1'd0;endelse if (num == 4'd0) beginzero <= 1'b1;endelse beginzero <= 1'b0;endendalways @(posedge clk or negedge rst_n) beginif (!rst_n) beginnum <= 4'b0;end else if (mode) beginif (num == 9) num <= 0;else num <= num + 1'd1;end else if (!mode) beginif (num == 0) num <= 9;else num <= num - 1'd1;endelse num <= num ;endalways @(posedge clk or negedge rst_n) beginif (!rst_n) beginnumber <= 4'd0;end else beginnumber <= num;endend
endmodule
7.RAM的简单实现
- 题意
- 思路
要实现RAM,首先要声明数据的存储空间,例如:[3:0] rom [7:0];变量名称ram之前的[3:0]表示每个数据具有多少位,指位宽;变量名称ram之后的[7:0]表示需要多少个数据,指深度,注意这里深度为8,应该是使用[7:0],而不是[2:0];
声明存储变量之后,需要对ram进行初始化,写入数据,当write_en有效,向write_addr写入write_data,当read_en有效,根据输入的read_addr输出read_data。需要注意的是,题目要求实现真双端口RAM,即可以同时写入和读出,所以需要使用两个always语句块实现写入和读出逻辑,不可以在同一个always块中使用if-else if-else if结果。
- 代码
`timescale 1ns/1ns
module ram_mod(input clk,input rst_n,input write_en,input [7:0]write_addr,input [3:0]write_data,input read_en,input [7:0]read_addr,output reg [3:0]read_data
);reg [3:0] myRAM [7:0];reg [8:0] i;always @(posedge clk or negedge rst_n) beginif (!rst_n) beginfor (i = 0;i < 256;i = i+1)myRAM[i] = 0;endelse beginmyRAM[write_addr] <= write_en ? write_data:myRAM[write_addr];endendalways @(posedge clk or negedge rst_n) beginif (~rst_n) beginread_data <= 0;endelse read_data <= read_en?myRAM[read_addr]:read_data;end
endmodule