本次带来牛客网Verilog的第六题到第十题,本人才疏学浅,如有不对之处欢迎评论区指正。
VL6 多功能数据处理器
本题就是根据sel信号的不同,选择不同的输出。至于多功能选择,大家应该很自然的能想到使用case语句解决。
具体实现代码如下所示:
`timescale 1ns/1ns module data_select( input clk, input rst_n, input signed[7:0]a, input signed[7:0]b, input [1:0]select, output reg signed [8:0]c ); always@(posedge clk or negedge rst_n) begin if(!rst_n) begin c<='d0; end else begin case(select) 2'b00:c<=a; 2'b01:c<=b; 2'b10:c<=a+b; 2'b11:c<=a-b; default:c<='d0; endcase end end endmodule
VL7 求两个数的差值
和上一题差不多。情况不同输出不同。涉及判断,则使用if else语句即可。
具体实现代码如下所示:
`timescale 1ns/1ns module data_minus( input clk, input rst_n, input [7:0]a, input [7:0]b, output reg [8:0]c ); always @(posedge clk or negedge rst_n) if(!rst_n) c <= 0; else if(a > b) c <= a-b; else c <= b-a; endmodule
VL8 使用generate...for语句简化代码
generate的主要用法一是构造循环结构,比如多次实例化某个模块。还有一种是通过if-generate或者case-generate来在多个代码块之间选择一个作为综合的RTL代码。
对于本题而言,就是循环实现多个assign赋值语句。其实不使用generate也是可以的。直接用for就行。
具体实现代码如下所示:
`timescale 1ns/1ns module gen_for_module( input [7:0] data_in, output [7:0] data_out ); genvar i; generate for(i=0;i<8;i=i+1) begin:bit_reverse assign data_out[i] = data_in[7-i]; end endgenerate endmodule
bit_reverse是定义的例化名称,可以根据需要修改。需要注意的是,即使只有一个语句,也需要使用begin..end。同时需要使用endgenerate表示结束。尤其要注意begin...end的位置是在for之后。
VL9 使用子模块实现三输入数的大小比较
在数字芯片设计中,自顶向下和自底向上是两种典型的设计思路。在实际的设计过程中通常结合这两点。可以规划好整体架构设计,然后设计相应的子模块,最后在主模块进行例化即可。从而提高代码的可复用性以及设计层次性。
对于本题而言。可以先比较两个数中的较小值,再用这个较小值和剩下的一个数进行比较即可。但是有一点需要注意的是。比较得到的较小值与剩下的那个数在时序上是相对应的。
具体来说,对于a,b而言。得到它们中的最小值需要一拍的延迟。此时c可能被新的数据覆盖,就不是之前的那一组a,b,c了。直接比较会出现错误。所以应该将c进行一拍的寄存。然后再进行比较,这样得到的结果才是正确的。或者第一拍比较a、b,同时也比较a、c。然后第二拍比较这两个得到的数值。从而得到三者之间的最小值。
实现代码如下。下面的代码可以实现流水线式的输出数据,符合题目要求。
`timescale 1ns/1ns module main_mod( input clk, input rst_n, input [7:0]a, input [7:0]b, input [7:0]c, output [7:0]d ); wire [7:0]m,n; //先得到ab之中的较小值m sub_mod mod_ab( .clk(clk), .rst_n(rst_n), .data_a(a), .data_b(b), .data_c(m) ); //先得到ac之中的较小值n sub_mod mod_bc( .clk(clk), .rst_n(rst_n), .data_a(b), .data_b(c), .data_c(n) ); //最后对比mn的大小 sub_mod mod_mn( .clk(clk), .rst_n(rst_n), .data_a(m), .data_b(n), .data_c(d) ); endmodule module sub_mod( input clk, input rst_n, input [7:0]data_a, input [7:0]data_b, output reg [7:0]data_c ); always @(posedge clk or negedge rst_n) if(!rst_n) data_c <= 0; else if(data_a > data_b) data_c <= data_b; else data_c <= data_a; endmodule
VL10 使用函数实现数据大小端转换
函数function在verilog中使用还是比较少的。笔者在之前的设计中基本上没有用过,借此机会学习一下函数的使用。
Verilog中的函数不能包含时间控制的信息,也不能调用任务。必须要有输入变量,同时只有返回值,没有输出。大家使用的时候只建议用函数实现纯组合运算逻辑即可。避免出错。
本题代码如下。注意begin,end所在的位置。同时由于function是组合逻辑。所以输出要通过寄存器打一拍。至于为什么clk下降沿要求有效。。我也不知道。这题做得真恶心。
`timescale 1ns/1ns module function_mod( input clk, input rst_n, input [3:0]a, input [3:0]b, output [3:0]c, output [3:0]d ); reg [3:0]c; reg [3:0]d; function [3:0] bit_rev; input [3:0]bits; integer i; for(i=0;i<4;i=i+1) begin:reverse bit_rev[i]=bits[3-i]; end endfunction always @(negedge clk or negedge rst_n) begin if(!rst_n) begin c <= 4'd0; d <= 4'd0; end else begin c <= bit_rev(a); d <= bit_rev(b); end end endmodule