概述
※LV1 四选一多路器
描述
制作一个四选一的多路选择器,要求输出定义上为线网类型
信号示意图:
波形示意图:
输入描述:
输入信号 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触发器的逻辑,结构如图:
信号示意图:
波形示意图:
输入描述:
输入信号 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输出 |
0 | 0 | 0 | 0 |
1 | 1 | 0 | 0 |
2 | 1 | 1 | 0 |
3 | 1 | 0 | 1 |
4 | 1 | 1 | 1 |
5 | 1 | 0 | 0 |
6 | 0 | 1 | 0 |
7 | 0 | 1 | 1 |
8 | 0 | 1 | 0 |
9 | 0 | 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进行异或位操作
题解主体
通过异或计算得到结果,对数据进行位运算。
根据激励方程和输出方程以及思路整理,关键电路如下:
将电路转换成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给出的信号的上升沿表示写入有效)
信号示意图
波形示意图:
输入描述:
输入信号 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 |
0 | 直接输出d,并寄存d的值为din | 1 |
1 | (din<<2)-din | 0 |
2 | (din<<3)-din | 0 |
3 | (din<<3) | 0 |
将电路转换成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
因此实现方式为如下的电路,综合得到:
参考答案
`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 | 0 锁存输入 | 0 |
1 | [3:0]+[7:4] | 1 |
2 | [3:0]+[11:8] | 1 |
3 | [3:0]+[15:12] | 1 |
根据激励方程和输出方程以及思路整理,关键电路如下:
这段电路的意思是首先将锁存的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
因此实现方式为如下的电路,综合得到:
`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。
接口信号图如下:
输入描述:
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
最后
以上就是淡淡红牛为你收集整理的1 Verilog入门篇:基础语法题意整理题解主体题意整理VL3 奇偶校验题意整理题解主体题意整理题解主体参考答案VL5 位拆分与运算题意整理题解主体VL6 多功能数据处理器VL7 求两个数的差值 VL9 使用子模块实现三输入数的大小比较 的全部内容,希望文章能够帮你解决1 Verilog入门篇:基础语法题意整理题解主体题意整理VL3 奇偶校验题意整理题解主体题意整理题解主体参考答案VL5 位拆分与运算题意整理题解主体VL6 多功能数据处理器VL7 求两个数的差值 VL9 使用子模块实现三输入数的大小比较 所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复