天天看点

1 Verilog入门篇:基础语法题意整理题解主体题意整理VL3 奇偶校验题意整理题解主体题意整理题解主体参考答案VL5 位拆分与运算题意整理题解主体VL6 多功能数据处理器VL7 求两个数的差值 VL9 使用子模块实现三输入数的大小比较 

※LV1 四选一多路器

描述

制作一个四选一的多路选择器,要求输出定义上为线网类型

信号示意图:

1 Verilog入门篇:基础语法题意整理题解主体题意整理VL3 奇偶校验题意整理题解主体题意整理题解主体参考答案VL5 位拆分与运算题意整理题解主体VL6 多功能数据处理器VL7 求两个数的差值 VL9 使用子模块实现三输入数的大小比较 

波形示意图:

1 Verilog入门篇:基础语法题意整理题解主体题意整理VL3 奇偶校验题意整理题解主体题意整理题解主体参考答案VL5 位拆分与运算题意整理题解主体VL6 多功能数据处理器VL7 求两个数的差值 VL9 使用子模块实现三输入数的大小比较 

输入描述:

输入信号   d1,d2,d3,d4 sel

类型 wire

输出描述:

输出信号 mux_out

类型  wire

题意整理

本题要求设计一个四选一的多路器,注意输出的定义是线网类型,因此不能使用always组合逻辑块,但是实际上,在语言中使用reg并不一定会被综合成寄存器。

题解主体

可以得到状态转换:

    sel

d0    11

d1    10

d2    01

d3    00

通过2/1选择器进行判断,需要三个这种结构

将电路转换成Verilog代码描述如下:

wire [1:0]line1,line2;

assign line1 = (sel[1]) ? d0 : d2;

assign line2 = (sel[1]) ? d1 : d3;

assign mux_out = (sel[0]) ? line1 : line2;

因此实现方式为如下的电路,综合得到:

`timescale 1ns/1ns
module mux4_1(
input [1:0]d1,d2,d3,d0,
input [1:0]sel,
output[1:0]mux_out
);
wire [1:0]line1,line2;
assign line1 = (sel[1]) ? d0 : d2;
assign line2 = (sel[1]) ? d1 : d3;
assign mux_out = (sel[0]) ? line1 : line2;
endmodule
           

解法2

`timescale 1ns/1ns
module mux4_1(
input [1:0]d1,d2,d3,d0,
input [1:0]sel,
output[1:0]mux_out
);
    assign mux_out = sel[0]?(sel[1]?d0:d2):(sel[1]?d1:d3);
    
endmodule
           

VL2 异步复位的串联T触发器

题目描述:  

用verilog实现两个串联的异步复位的T触发器的逻辑,结构如图:

信号示意图:

1 Verilog入门篇:基础语法题意整理题解主体题意整理VL3 奇偶校验题意整理题解主体题意整理题解主体参考答案VL5 位拆分与运算题意整理题解主体VL6 多功能数据处理器VL7 求两个数的差值 VL9 使用子模块实现三输入数的大小比较 

波形示意图:

1 Verilog入门篇:基础语法题意整理题解主体题意整理VL3 奇偶校验题意整理题解主体题意整理题解主体参考答案VL5 位拆分与运算题意整理题解主体VL6 多功能数据处理器VL7 求两个数的差值 VL9 使用子模块实现三输入数的大小比较 

输入描述:

输入信号   data, clk, rst

类型 wire

在testbench中,clk为周期5ns的时钟,rst为低电平复位

输出描述:

输出信号 q 

类型  reg 

题意整理

1、T触发器是进入的值为1的时候,寄存的值发生翻转

2、注意异步复位

3、需要注意寄存器翻转的逻辑,第二寄存器是否翻转取决于第一个寄存器是否为1,前者输出情况有三种:在data输入控制为1下从0到1到0不断翻转,data为0锁在1,data为0锁在0

ps: 考虑rst为1且完成了初始化

 题解主体

T触发器的特性方程

Qn+1 = T Qn ' +T ' Qn = T⊕Qn

(其中Qn为现态,Qn+1为次态)

T触发器的特性表

T    Q    Q*

0    0    0

0    1    1

1    0    1

1    1    0

Q过程为第一个触发器的输出(即下面的q1),Q输出为第二个触发器的输出

设n为时钟沿,Q过程取决于n-1的T, Q输出取决于n-1的Q过程

因此有输出:

n T Q过程 Q输出
1 1
2 1 1
3 1 1
4 1 1 1
5 1
6 1
7 1 1
8 1
9 1 1
`timescale 1ns/1ns
module Tff_2 (
input wire data, clk, rst,
output reg q  
);

reg q1;

always @ ( posedge clk or negedge rst)

if (~rst) begin
  q1 <= 1'b0;
  q <= 1'b0;
end 
else begin
    if (data) begin
  		q1 <= !q1;
	end
	if (q1) begin
  		q <= !q;
    end
end   
endmodule 
           

VL3 奇偶校验

题目描述:           

现在需要对输入的32位数据进行奇偶校验,根据sel输出校验结果(0输出奇校验,1输出偶校验)

信号示意图:

 波形示意图:

 输入描述:

输入信号   bus sel

类型 wire

输出描述:

输出信号   check        

类型  wire

题意整理

1、简单理解奇偶校验

奇校验:原始码流+校验位 总共有奇数个1

偶校验:原始码流+校验位 总共有偶数个1

2、计算奇偶校验的方法  按位求异或得到奇校验结果,对其求反得到偶校验结果

3、连续进行异或 odd = ^bus  对bus进行异或位操作

题解主体

通过异或计算得到结果,对数据进行位运算。

根据激励方程和输出方程以及思路整理,关键电路如下:

1 Verilog入门篇:基础语法题意整理题解主体题意整理VL3 奇偶校验题意整理题解主体题意整理题解主体参考答案VL5 位拆分与运算题意整理题解主体VL6 多功能数据处理器VL7 求两个数的差值 VL9 使用子模块实现三输入数的大小比较 

将电路转换成Verilog代码描述如下

wire odd;

assign odd = ^bus;

assign check = sel?odd:~odd;

因此实现方式为如下的电路,综合得到: 

`timescale 1ns/1ns
module odd_sel(
input [31:0] bus,
input sel,
output check
);

wire odd;
assign odd = ^bus;
assign check = sel?odd:~odd;

endmodule 
           

VL4 移位运算与乘法

题目描述:           

已知d为一个8位数,请在每个时钟周期分别输出该数乘1/3/7/8,并输出一个信号通知此时刻输入的d有效(d给出的信号的上升沿表示写入有效)

信号示意图

1 Verilog入门篇:基础语法题意整理题解主体题意整理VL3 奇偶校验题意整理题解主体题意整理题解主体参考答案VL5 位拆分与运算题意整理题解主体VL6 多功能数据处理器VL7 求两个数的差值 VL9 使用子模块实现三输入数的大小比较 

波形示意图:

1 Verilog入门篇:基础语法题意整理题解主体题意整理VL3 奇偶校验题意整理题解主体题意整理题解主体参考答案VL5 位拆分与运算题意整理题解主体VL6 多功能数据处理器VL7 求两个数的差值 VL9 使用子模块实现三输入数的大小比较 

 输入描述:

输入信号   d, clk, rst

类型 wire

在testbench中,clk为周期5ns的时钟,rst为低电平复位

输出描述:

输出信号 input_grant    out

类型  reg 

题意整理

1、在硬件中进行乘除法运算是比较消耗资源的一种方法,想要在不影响延迟并尽量减少资源消耗,必须从硬件的特点上进行设计。根据寄存器的原理,由于是二进制,所以进位和退位为x2或者/2,同样除7可以使用进位3然后减去本身的做法,这样就将乘除法运算转化为位运算,这是一种比较简单的整数运算处理。

2、 需要给出一个计数器的状态机,注意d输入不是随时有效的,只有在cnt计数为0的那个时钟沿,d输入有效,因此需要设计一个寄存器din,在cnt为0时候锁存d的值

题解主体

根据题意分析,可以得到状态转换:

设输入为d,计数器为cnt

移位运算逻辑:

位运算
1 d
3 (din<<2)-din
7 (din<<3)-din
8 (din<<3)

状态机逻辑:

cnt out input_grant
直接输出d,并寄存d的值为din 1
1 (din<<2)-din
2 (din<<3)-din
3 (din<<3)

将电路转换成Verilog代码描述如下

reg [1:0]cnt;

reg [7:0]din;

always@(posedge clk or negedge rst) begin

       if(!rst) begin

              cnt <= 0;

              out <= 0;

              input_grant <= 0;

              din <= 0;

       end

       else begin

              cnt <= cnt+1;

              case (cnt)

                     0: begin

                            din <= d;

                            input_grant <= 1;

                            out <= d;

                     end

                     1: begin

                            input_grant <= 0;

                            out <= (din<<2)-din;

                     end       

                     2: begin

                            input_grant <= 0;

                            out <= (din<<3)-din;

                     end

                     3: begin

                            input_grant <= 0;

                            out <= (din<<3);

                     end

              endcase

       end

end

因此实现方式为如下的电路,综合得到:

1 Verilog入门篇:基础语法题意整理题解主体题意整理VL3 奇偶校验题意整理题解主体题意整理题解主体参考答案VL5 位拆分与运算题意整理题解主体VL6 多功能数据处理器VL7 求两个数的差值 VL9 使用子模块实现三输入数的大小比较 

参考答案

`timescale 1ns/1ns
module multi_sel(
input [7:0]d ,
input clk,
input rst,
output reg input_grant,
output reg [10:0]out
);

reg [1:0]cnt;
reg [7:0]din;

always@(posedge clk or negedge rst) begin
	if(!rst) begin
		cnt <= 0;
		out <= 0;
		input_grant <= 0;
		din <= 0;
	end
	else begin
		cnt <= cnt+1;
		case (cnt)
			0: begin
				din <= d;
				input_grant <= 1;
				out <= d;
			end
			1: begin
				input_grant <= 0;
				out <= (din<<2)-din;
			end		
			2: begin
				input_grant <= 0;
				out <= (din<<3)-din;
			end
			3: begin
				input_grant <= 0;
				out <= (din<<3);
			end	
		endcase
	end
end
endmodule
           

VL5 位拆分与运算

题目描述:           

现在输入了一个压缩的16位数据,其实际上包含了四个数据[3:0][7:4][11:8][15:12],

现在请按照sel选择输出四个数据的相加结果,并输出valid_out信号(在不输出时候拉低)

0:   不输出且只有此时的输入有效 

1:输出[3:0]+[7:4]

2:输出[3:0]+[11:8]

3:输出[3:0]+[15:12]

输入描述:

输入信号   d, clk, rst

类型 wire

在testbench中,clk为周期5ns的时钟,rst为低电平复位

输出描述:

输出信号 validout    out

类型  reg 

题意整理

1、寄存器的位是可以分开单独运算的,并不是一个输入就一定是一个数据,在很多情况下,一个输入既包括数据又包括地址等其他有效信息

2、需要考虑数据锁存的问题,一定要在sel为0的时候进行锁存,只有此时的写入才是有效的(validout的下降沿写入有效),同时存在多种情况且没有优先级问题,建议使用case语句

题解主体

可以得到状态转换:

sel out validout
0  锁存输入
1 [3:0]+[7:4]  1
2 [3:0]+[11:8] 1
3 [3:0]+[15:12] 1

根据激励方程和输出方程以及思路整理,关键电路如下:

1 Verilog入门篇:基础语法题意整理题解主体题意整理VL3 奇偶校验题意整理题解主体题意整理题解主体参考答案VL5 位拆分与运算题意整理题解主体VL6 多功能数据处理器VL7 求两个数的差值 VL9 使用子模块实现三输入数的大小比较 

这段电路的意思是首先将锁存的16位数据分段移位到4位数据,然后进行相加,再组合成一个20位的数据,按照选择器进行输出其中的5位。

将电路转换成Verilog代码描述如下

reg [15:0]data_lock; 

always@(posedge clk or negedge rst) begin

       if (!rst)

              data_lock <= 0;

       else if(!sel)

              data_lock <= d;

end

always@(posedge clk or negedge rst) begin

       if (!rst) begin

              out <= 'b0;

              validout <=0;

       end

       else begin

              case(sel)

                     0:begin 

                            out <= 'b0;

                            validout <=0;

                     end

                     1:begin 

                            out <= data_lock[3:0]+data_lock[7:4];

                            validout <=1;       

                     end

                     2:begin 

                            out <= data_lock[3:0]+data_lock[11:8];

                            validout <=1;                     

                     end              

                     3:begin 

                            out <= data_lock[3:0]+data_lock[15:12];

                            validout <=1;                     

                     end

        endcase

       end

end

因此实现方式为如下的电路,综合得到:

1 Verilog入门篇:基础语法题意整理题解主体题意整理VL3 奇偶校验题意整理题解主体题意整理题解主体参考答案VL5 位拆分与运算题意整理题解主体VL6 多功能数据处理器VL7 求两个数的差值 VL9 使用子模块实现三输入数的大小比较 
`timescale 1ns/1ns

module data_cal(
input clk,
input rst,
input [15:0]d,
input [1:0]sel,

output reg[4:0]out,
output reg validout
);

reg [15:0]data_lock;  


always@(posedge clk or negedge rst) begin
	if (!rst)
		data_lock <= 0;
	else if(!sel)
		data_lock <= d;
end

always@(posedge clk or negedge rst) begin
	if (!rst) begin
		out <= 'b0;
		validout <=0;
	end	
	else begin
		case(sel)
			0:begin  
				out <= 'b0;
				validout <=0;
			end
			1:begin  
				out <= data_lock[3:0]+data_lock[7:4];
				validout <=1;		
			end
			2:begin  
				out <= data_lock[3:0]+data_lock[11:8];
				validout <=1;				
			end			
			3:begin  
				out <= data_lock[3:0]+data_lock[15:12];
				validout <=1;				
			end	
        endcase
	end
end
endmodule
           

VL6 多功能数据处理器

 描述

根据指示信号select的不同,对输入信号a,b实现不同的运算。输入信号a,b为8bit有符号数,当select信号为0,输出a;当select信号为1,输出b;当select信号为2,输出a+b;当select信号为3,输出a-b.

接口信号图如下:

输入描述:

clk:系统时钟

rst_n:复位信号,低电平有效

a,b:8bit位宽的有符号数

select:2bit位宽的无符号数

输出描述:

c:9bit位宽的有符号数

题意整理

题目要求根据指示信号select的不同取值,执行不同的操作,有两种方法可以实现:一种是使用嵌套的if-else语句,第二种是使用case语句。使用if-else语句逻辑层次上不够清晰,代码也稍显冗余,所以本题采用case语句。注意题目要求输入信号为有符号数,另外输出信号可能是输入信号的和,所以需要拓展一位,防止溢出。

题解主体

根据题目的要求,模块的输入端口包括:

系统时钟和复位信号:clk,rst_n;

两个8bit输入信号a,b;

一个指示信号select.

       输出端口包括:

               输出信号c.

select信号共有4种不同的取值,需要声明为2比特无符号数据。输入信号和输出信号为有符号数,输出信号可能是输入信号的和,所以需要拓展一位,防止溢出。再加上系统时钟信号和复位信号,完整的模块端口声明是:

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

);

       在复位信号有效时,输出置为0,否则根据指示信号select的不同取值,对数据做不同的运算。另外,对于case语句的使用,保持良好的代码风格,需要添加default情况,防止select出现以上列举的取值之外的数值,导致电路中出现不必要的锁存器。另一方面,当每个取值情况下执行的代码超过一句,需要使用begin…end包含,如果只有一句,则可以省略begin…end。代码如下:

       always @(posedge clk or negedge rst_n)

       if(!rst_n)

              c <= 9'd0;                   //当复位信号有效时,输出置为0

       else case(select)                  //select作为关键字case的参数

       2'b00:    c <= a;                 //根据select的不同取值,执行不同的操作。

       2'b01:    c <= b;

       2'b10:    c <= a+b;

       2'b11:    c <= a-b;

       default: c <= 9'd0;              //表示当select取值不在上述列举的范围内,将输出置0

       endcase                              //以endcase关键字结束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)
	if(!rst_n)
		c <= 9'd0;
	else case(select)
	2'b00:	c <= a;
	2'b01:	c <= b;
	2'b10:	c <= a+b;
	2'b11:	c <= a-b;
	default: c <= 9'd0;
	endcase

endmodule
           

VL7 求两个数的差值 

描述

根据输入信号a,b的大小关系,求解两个数的差值:输入信号a,b为8bit位宽的无符号数。如果a>b,则输出a-b,如果a≤b,则输出b-a。

接口信号图如下:

1 Verilog入门篇:基础语法题意整理题解主体题意整理VL3 奇偶校验题意整理题解主体题意整理题解主体参考答案VL5 位拆分与运算题意整理题解主体VL6 多功能数据处理器VL7 求两个数的差值 VL9 使用子模块实现三输入数的大小比较 

 输入描述:

clk:系统时钟

rst_n:复位信号,低电平有效

a,b:8bit位宽的无符号数

输出描述:

c:8bit位宽的无符号数

题意整理

题目要求求解两个无符号数的差值,也就是将较大值减去较小值,首先需要比较输入数值的大小关系,然后选择不同的操作。对于输入数值a,b,可能存在两种情况:a>b和a≤b,符合if-else语句的逻辑,可以使用if-else语句完成功能的实现。

题解主题

根据题目的要求,模块的输入端口包括:

       系统时钟和复位信号:clk,rst_n;

        两个8bit输入信号a,b.

输出端口包括:

               输出信号c.

输入信号和输出信号为8比特无符号数,加上系统时钟信号和复位信号,完整的模块端口声明是:

module data_minus(                  //if-else-module

       input clk,

       input rst_n,

       input [7:0]a,

       input [7:0]b,

       output reg [8:0]c

);

       在复位信号有效时,输出置为0,否则根据输入信号的大小关系,对数据做不同的运算。if…else语句的使用格式如下:

       if (判断条件)                      

              begin                          //当判断条件满足时,执行的语句

                     语句1;

                     语句2;

              end

       else begin                           //当判断条件不满足时,执行的语句

                     语句1;

                     语句2;

              end

       判断条件可以是

当执行的代码超过一句,需要使用begin…end包含,如果只有一句,则可以省略begin…end。代码如下:

always @(posedge clk or negedge rst_n)

       if(!rst_n)

              c <= 0;

       else if(a > b)

              c <= a-b;

       else

              c <= b-a;

`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语句简化代码 

描述

在某个module中包含了很多相似的连续赋值语句,请使用generata…for语句编写代码,替代该语句,要求不能改变原module的功能。

使用Verilog HDL实现以上功能并编写testbench验证。

module template_module( 

    input [7:0] data_in,

    output [7:0] data_out

);

    assign data_out [0] = data_in [7];

    assign data_out [1] = data_in [6];

    assign data_out [2] = data_in [5];

    assign data_out [3] = data_in [4];

    assign data_out [4] = data_in [3];

    assign data_out [5] = data_in [2];

    assign data_out [6] = data_in [1];

    assign data_out [7] = data_in [1];

endmodule

题意主体

根据题目的要求,不需要改变模块的输入端口:

module template_module(

    input [7:0] data_in,

    output [7:0] data_out

);

       generate…for语句是Verilog HDL语言特有的语句,使用循环结构编写可综合的多个形式相近的代码,循环变量必须由特定关键字genvar声明。使用格式如下:

    genvar i;                                    //声明循环变量为非负整数

    generate

        for(i = 0; i < 8; i = i + 1)      //循环条件

              begin : bit_reverse              //begin…end块中为待生成的代码原型

            assign data_out[i] = data_in[7 - i];

        end

       endgenerate

     在begin之后的bit_reverse是需要的,表示该generate…for语句块的名称,可以根据需要修改。特别需要注意的是,即使只有一个语句,也需要使用begin…end。同时需要使用endgenerate表示结束。

`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
           

VL9 使用子模块实现三输入数的大小比较 

描述

在数字芯片设计中,通常把完成特定功能且相对独立的代码编写成子模块,在需要的时候再在主模块中例化使用,以提高代码的可复用性和设计的层次性,方便后续的修改。

请编写一个子模块,将输入两个8bit位宽的变量data_a,data_b,并输出data_a,data_b之中较小的数。并在主模块中例化,实现输出三个8bit输入信号的最小值的功能。

子模块的信号接口图如下:

主模块的信号接口图如下:

输入描述:

clk:系统时钟

rst_n:异步复位信号,低电平有效

a,b,c:8bit位宽的无符号数

输出描述:

d:8bit位宽的无符号数,表示a,b,c中的最小值

题意整理

题目要求编写子模块实现两个输入数的大小比较并输出较小值,可以使用if-else语句实现。同时要求在主模块中实现三个输入数值的大小比较,假设三个输入变量为a,b,c。则可以先比较得到a,b中的较小值m,再得到b,c之中的较小值n。最后比较m,n的大小,输入较小值,即可得到a,b,c的最小值。

题解主题

Verilog HDL中,在声明过程中,主模块和子模块在声明方式上没有差别,都是以module开始,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

 模块的例化需要指定例化的模块名称和端口连接关系,对于没有使用的端口,可以不列出。例化模板如下:

       module_a a_inst(

              .data_a(data_m),

              .data_b(data_n)

);

module_a是子模块的模块名,a_inst是例化之后的子模块名,当多次例化同一个模块,需要使用不同的例化模块名称。端口列写于括号之中,.data_a(data_a),前一个data_a是子模块的端口名称,括号中的data_m是存在于主模块的信号名,表示子模块的data_a连接到主模块的data_m。题目要求实现输出三个输入的最小值。以a,b,c为例,可以先比较a.b,得到其中的较小值d,再比较得到c,d的较小值e。最后比较d,e的大小,得到最小值。可以按照如下的方式例化。

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)

       );    

`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 使用函数实现数据大小端转换

描述

在数字芯片设计中,经常把实现特定功能的模块编写成函数,在需要的时候再在主模块中调用,以提高代码的复用性和提高设计的层次,分别后续的修改。

请用函数实现一个4bit数据大小端转换的功能。实现对两个不同的输入分别转换并输出。

程序的接口信号图如下:

 输入描述:

clk:系统时钟

rst_n:异步复位信号,低电平有效

a,b:4bit位宽的无符号数

输出描述:

c,d:8bit位宽的无符号数

题意整理

题目要求使用函数实现4bit数据大小端转换的功能,所谓大端,即数据的高位写在左侧,低位写在右侧。小端则反过来:高位写在右侧,低位写在左侧。实现N比特数的大小端转换,只需要把数据的N位赋值给0位,N-1位赋值给1位,依此类推。

在函数编写完成之后,实现对两个不同的输入分别转换,只需要调用两次函数,分别对两个输入进行转换即可。

题解主体

在Verilog HDL中,函数的声明由关键字function开始,endfunction结束。对于函数中的语句需要用begin…end包含,即使只有一句。函数的声明模板如下:

       function [range-1:0] function_name ;

input_declaration ;

             other_declaration ;

procedural_statement ;

endfunction

函数在声明时,会隐式的声明一个宽度为 range、 名字为 function_id 的寄存器变量,函数的返回值通过这个变量进行传递。当该寄存器变量没有指定位宽时,默认位宽为 1。然后进行输入变量的声明和其它声明。

函数通过指明函数名与输入变量进行调用。函数结束时,返回值被传递到调用处。

函数调用格式如下:

function_name(input1, input2, …);

通过函数名调用函数,并在参数列表中填入输入参数。

要实现大小端转换,即将输入数值的最高位赋予输出的最低位,次高位赋予次低位,依次类推即可。

function [3:0] data_rev;

              input [3:0] data_in;

       begin

        data_rev[0] = data_in[3];

        data_rev[1] = data_in[2];

        data_rev[2] = data_in[1];

        data_rev[3] = data_in[0];

       end

endfunction

函数编写完成,则可以在多个位置进行调用,输入不同的参数,实现对不同数据的操作,完整的实现代码如下:

module function_mod(

       input clk,

       input rst_n,

       input [3:0]a,

       input [3:0]b,

       output [3:0]c,

       output [3:0]d

);

       assign c = data_rev(a);

       assign d = data_rev(b);

       function [3:0] data_rev;

                     input [3:0] data_in;

              begin

                      data_rev[0] = data_in[3];

                      data_rev[1] = data_in[2];

                      data_rev[2] = data_in[1];

                      data_rev[3] = data_in[0];

              end

       endfunction

endmodule

`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
);

	assign c = data_rev(a);
	assign d = data_rev(b);
	
	function [3:0] data_rev;
			input [3:0] data_in;
		begin
			 data_rev[0] = data_in[3];
			 data_rev[1] = data_in[2];
			 data_rev[2] = data_in[1];
			 data_rev[3] = data_in[0];
		end
	endfunction
	
endmodule
           

继续阅读