概述
1. 多路选择器
学生实验
做一个4选1的mux,并且进行波形仿真 和2选1的mux对比,观察资源消耗的变化
//MUX21
module top(
IN0 , // input 1
IN1 , // input 2
SEL , // select
OUT ); // out data
parameter WL = 16; // 输入输出数据信号位宽
input [WL-1:0] IN0, IN1;// 选择器的两个输入数据信号
input SEL; // 通道选通的控制信号
output[WL-1:0] OUT; // 选择器的输入数据信号
reg [WL-1:0] OUT;
// 生成组合逻辑的代码
always @ (IN0 or IN1 or SEL) begin
if(SEL) // SEL为1 选择输入1
OUT = IN1;
else // SEL为0 选择输入0
OUT = IN0;
end
endmodule
//MUX41
// module top41, 选择器(mux41)的代码,
module top41(
IN0 , // input 1
IN1 , // input 2
IN2 , // input 3
IN3 , // input 4
SEL , // select1,2
OUT ); // out data
parameter WL = 16; // 输入输出数据信号位宽
input [WL-1:0] IN0, IN1, IN2, IN3;// 选择器的两个输入数据信号
input [1:0] SEL; // 通道选通的控制信号
output[WL-1:0] OUT; // 选择器的输入数据信号
reg [WL-1:0] OUT;
// 生成组合逻辑的代码
always @ (IN0 or IN1 or IN2 or IN3 or SEL) begin
//if(SEL=3) // SEL为1 选择输入1
//OUT = IN1;
//else // SEL为0 选择输入0
//OUT = IN0;
case(SEL)
0: OUT=IN0;
1: OUT=IN1;
2: OUT=IN2;
3: OUT=IN3;
default: OUT=0;
endcase
end
endmodule
// endmodule top
图像对比
4选1资源消耗是2选1MUX的两倍
2. 交叉开关
学生实验
编写一个4X4路交叉开关的RTL,然后编译,看RTL View 比较2x2与4x4之间消耗资源的区别。通过对比资源,你有什么结论? 返回顶部
// module top, a 2x2 crossbar switch circuit
module top(
IN0 , // input 1
IN1 , // input 2
SEL0 , // select the output0 source
SEL1 , // select the output1 source
OUT0 , // output data 0
OUT1 ); // output data 1
parameter WL = 16;
input [WL-1:0] IN0, IN1;
input SEL0, SEL1;
output[WL-1:0] OUT0, OUT1;
reg [WL-1:0] OUT0, OUT1;
// get the OUT0
always @ (IN0 or IN1 or SEL0) begin
if(SEL0)
OUT0 = IN1;
else
OUT0 = IN0;
end
// get the OUT1
always @ (IN0 or IN1 or SEL1) begin
if(SEL1)
OUT1 = IN1;
else
OUT1 = IN0;
end
endmodule
// module top, a 4x4 crossbar switch circuit
module top(
IN0 , // input 1
IN1 , // input 2
IN2 , // input 3
IN3 , // input 4
SEL0 , // select the output0 source
SEL1 , // select the output1 source
SEL2 , // select the output2 source
SEL3 , // select the output3 source
OUT0 , // output data 0
OUT1 , // output data 1
OUT2 , // output data 2
OUT3 ); // output data 3
parameter WL = 16;
input [WL-1:0] IN0, IN1, IN2, IN3;
input SEL0, SEL1, SEL2, SEL3;
output[WL-1:0] OUT0, OUT1, OUT2, OUT3;
reg [WL-1:0] OUT0, OUT1, OUT2, OUT3;
// get the OUT0
always @ (IN0 or IN1 or IN2 or IN3 or SEL0 or SEL1) begin
if(SEL0==0&&SEL1==0)
OUT0 = IN0;
else if(SEL0==0&&SEL1==1)
OUT0 = IN1;
else if(SEL0==1&&SEL1==0)
OUT0 = IN2;
else
OUT0 = IN3;
end
// get the OUT1
always @ (IN0 or IN1 or IN2 or IN3 or SEL1 or SEL2) begin
if(SEL1==0&&SEL2==0)
OUT1 = IN0;
else if(SEL1==0&&SEL2==1)
OUT1 = IN1;
else if(SEL1==1&&SEL2==0)
OUT1 = IN2;
else
OUT1 = IN3;
end
// get the OUT2
always @ (IN0 or IN1 or IN2 or IN3 or SEL2 or SEL3) begin
if(SEL2==0&&SEL3==0)
OUT2 = IN0;
else if(SEL2==0&&SEL3==1)
OUT2 = IN1;
else if(SEL2==1&&SEL3==0)
OUT2 = IN2;
else
OUT2 = IN3;
end
// get the OUT3
always @ (IN0 or IN1 or IN2 or IN3 or SEL0 or SEL3) begin
if(SEL0==0&&SEL3==0)
OUT3 = IN0;
else if(SEL0==0&&SEL3==1)
OUT3 = IN1;
else if(SEL0==1&&SEL3==0)
OUT3 = IN2;
else
OUT3 = IN3;
end
endmodule
资源对比:
3.优先编码器
学生实验
- 编写一个8输入的优先编码器,然后编译,看RTL View
// module top, 4 input priority encoder with zero input check
module top(
IN , // input
OUT ); // output
input [3:0] IN;
output[2:0] OUT;
reg [2:0] OUT;
// get the OUT
always @ (IN) begin
if(IN[3]) // 第一优先
OUT = 3'b011;
else if(IN[2]) // 第二优先
OUT = 3'b010;
else if(IN[1]) // 第三优先
OUT = 3'b001;
else if(IN[0]) // 第四优先
OUT = 3'b000;
else // 什么都没有检测到
OUT = 3'b111; // 输出值可自定义,不和上面的输出值混淆即可
end
endmodule
// module top, 8 input priority encoder with zero input check
module top(
IN , // input
OUT ); // output
input [7:0] IN;
output[3:0] OUT;
reg [3:0] OUT;
// get the OUT
always @ (IN) begin
if(IN[7]) // 第一优先
OUT = 4'b0111;
else if(IN[6]) // 第二优先
OUT = 4'b0110;
else if(IN[5]) // 第三优先
OUT = 4'b0101;
else if(IN[4]) // 第四优先
OUT = 4'b0100;
else if(IN[3]) // 第五优先
OUT = 4'b0011;
else if(IN[2]) // 第六优先
OUT = 4'b0010;
else if(IN[1]) // 第七优先
OUT = 4'b0001;
else if(IN[0]) // 第八优先
OUT = 4'b0000;
else // 什么都没有检测到
OUT = 4'b1111; // 输出值可自定义,不和上面的输出值混淆即可
end
endmodule
4. 多路译码器
学生实验
- 编写一个4-16的译码器,编译
- 和3-8译码器对比资源开销
- 看RTL View
// module top, 3 to 8 decoder
module top(
IN , // input
OUT ); // output
input [2:0] IN;
output[7:0] OUT;
reg [7:0] OUT;
// get the OUT
always @ (IN) begin
case(IN)
3'b000: OUT = 8'b0000_0001;
3'b001: OUT = 8'b0000_0010;
3'b010: OUT = 8'b0000_0100;
3'b011: OUT = 8'b0000_1000;
3'b100: OUT = 8'b0001_0000;
3'b101: OUT = 8'b0010_0000;
3'b110: OUT = 8'b0100_0000;
3'b111: OUT = 8'b1000_0000;
// full case 不需要写default,否则一定要有default
endcase
end
endmodule
// module top, 4 to 16 decoder
module top(
IN , // input
OUT ); // output
input [3:0] IN;
output[15:0] OUT;
reg [15:0] OUT;
// get the OUT
always @ (IN) begin
case(IN)
4'b0000: OUT = 16'b0000_0000-0000_0001;
4'b0001: OUT = 16'b0000_0000-0000_0010;
4'b0010: OUT = 16'b0000_0000-0000_0100;
4'b0011: OUT = 16'b0000_0000-0000_1000;
4'b0100: OUT = 16'b0000_0000-0001_0000;
4'b0101: OUT = 16'b0000_0000-0010_0000;
4'b0110: OUT = 16'b0000_0000-0100_0000;
4'b0111: OUT = 16'b0000_0000-1000_0000;
4'b1000: OUT = 16'b0000_0001-0000_0000;
4'b1001: OUT = 16'b0000_0010-0000_0000;
4'b1010: OUT = 16'b0000_0100-0000_0000;
4'b1011: OUT = 16'b0000_1000-0000_0000;
4'b1100: OUT = 16'b0001_0000-0000_0000;
4'b1101: OUT = 16'b0010_0000-0000_0000;
4'b1110: OUT = 16'b0100_0000-0000_0000;
4'b1111: OUT = 16'b1000_0000-0000_0000;
// full case 不需要写default,否则一定要有default
endcase
end
endmodule
5.无符号加法器
输入和输出数据都是无符号的整数,常用于计数器累加和计算地址序号
要点
- 目测一下,可以发现加法器的输入数据和对应结果在时间上是有延迟的,这是组合逻辑门的延迟造成的。(请估算一下延迟长度)
- 在相邻的两个正确的输出结果之间是有些“毛刺”结果的,而且“毛刺”的时间长度还不同
- 请思考,2比特的信号,00翻转成11,两个位能做到绝对的同时翻转么?
- 请思考,对比一下,00翻转成11,和 00翻转成 10,哪个变化的多?哪个翻转过程中的过渡状态多?
- 注意输入和输出的信号位宽数
- 请思考,如果本例中,所有输入信号和输出信号宽度都是4比特,那么输出结果会一直正确么?
学生实验
- 把加法器的输出信号改成4比特位宽,编译,波形仿真。观察输出结果,说出输出和输入的对应关系。
- 把加法器的输入信号改成8比特位宽,编译,波形仿真。观察加法器的输出延迟,和4比特输入位宽的情况对比,你有什么结论,为什么?
//module top,unsigned adder 4 bit
module top(
IN1 ,
IN2 ,
OUT );
input[3:0] IN1, IN2;
output[4:0] OUT;
reg[4:0] OUT;
always@(IN1 or IN2) begin // 生成组合逻辑的always 块
OUT = IN1 + IN2;
end
endmodule
//module top,unsigned adder 8 bit
module top(
IN1 ,
IN2 ,
OUT );
input[7:0] IN1, IN2;
output[7:0] OUT;
reg[8:0] OUT;
always@(IN1 or IN2) begin // 生成组合逻辑的always 块
OUT = IN1 + IN2;
end
endmodule
1.延迟12-14ns左右
2.2比特的信号,00翻转成11,两个位不能做到绝对的同时翻转。
3. 00翻转成10翻转过程中的过渡状态多。
8bit输入延迟大于4bit输入延迟。因为8bit输入涉及的位数更多,每一位的延迟叠加,自然会使延迟更大。
6.补码加法器
输入和输出数据都是2补码形式的有符号数,常用于数字信号处理电路
学生实验
把加法器的输出信号改成4比特位宽,编译,波形仿真。观察输出结果,观察输出结果在什么时候是正确的?。 把加法器的输入信号改成8比特位宽,编译,波形仿真。观察加法器的输出延迟,和4比特输入位宽的情况对比,你有什么结论,为什么?
module top(
IN1 ,
IN2 ,
OUT );
input signed [3:0] IN1, IN2;
output signed [4:0] OUT;
reg signed [4:0] OUT;
always@(IN1 or IN2) begin // 生成组合逻辑的always 块
OUT = IN1 + IN2;
end
endmodule
//4bit
module top(
IN1 ,
IN2 ,
OUT );
input signed [3:0] IN1, IN2;
output signed [3:0] OUT;
reg signed [3:0] OUT;
always@(IN1 or IN2) begin // 生成组合逻辑的always 块
OUT = IN1 + IN2;
end
endmodule
4比特位宽的输出最高位为符号位,而输出范围为:-7~7,即输出值在-7~7内计算结果正确,但超出该范围则计算错误。
//输入为8bit
module top(
IN1 ,
IN2 ,
OUT );
input signed [7:0] IN1, IN2;
output signed [7:0] OUT;
reg signed [12:0] OUT;
always@(IN1 or IN2) begin // 生成组合逻辑的always 块
OUT = IN1 + IN2;
end
endmodule
观察可得,8bit输入与4bit输入延迟差别不大。
7.带流水线的加法器
学生实验
不改变流水线的级数,把加法器的输入信号改成8比特位宽,编译,波形仿真,和不带流水线的情况对比一下,你有什么结论? 在8比特输入位宽的情况下,在输入上再添加一级流水线,观察编译和仿真的结果,你有什么结论?
//4bit带宽
module top(
IN1 ,
IN2 ,
CLK ,
OUT );
input [3:0] IN1, IN2;
input CLK;
output [4:0] OUT;
reg [3:0] in1_d1R, in2_d1R;
reg [4:0] adder_out, OUT;
always@(posedge CLK) begin // 生成D触发器的always块
in1_d1R <= IN1;
in2_d1R <= IN2;
OUT <= adder_out;
end
always@(in1_d1R or in2_d1R) begin // 生成组合逻辑的always 块
adder_out = in1_d1R + in2_d1R;
end
endmodule
带流水线的波形
不带流水线的波形
可以观察到,带流水线的波形毛刺明显少于不带流水线的波形。而带流水线的加法器输入数据和其对应的结果不在一个时钟周期。
//8bit带宽带流水线的波形
module top(
IN1 ,
IN2 ,
CLK ,
OUT );
input [7:0] IN1, IN2;
input CLK;
output [12:0] OUT;
reg [7:0] in1_d1R, in2_d1R;
reg [12:0] adder_out, OUT;
always@(posedge CLK) begin // 生成D触发器的always块
in1_d1R <= IN1;
in2_d1R <= IN2;
OUT <= adder_out;
end
always@(in1_d1R or in2_d1R) begin // 生成组合逻辑的always 块
adder_out = in1_d1R + in2_d1R;
end
endmodule
不改变流水线的级数,把加法器的输入信号改成8比特位宽,编译,波形仿真,和不带流水线的情况对比一下,与4比特位宽和不带流水线的波形无差别。
在8比特输入位宽的情况下,在输入上再添加一级流水线
module top(
IN1 ,
IN2 ,
CLK ,
OUT );
input [7:0] IN1, IN2;
input CLK;
output [12:0] OUT;
reg [7:0] in1_d1R, in2_d1R, in1_d2R, in2_d2R;
reg [12:0] adder_out, OUT;
always@(posedge CLK) begin // 生成D触发器的always块
in1_d1R <= IN1;
in2_d1R <= IN2;
in1_d2R <= in1_d1R;
in2_d2R <= in2_d1R;
OUT <= adder_out;
end
always@(in1_d1R or in2_d1R) begin // 生成组合逻辑的always 块
adder_out = in1_d2R + in2_d2R;
end
endmodule
对比发现,流水线的个数越多,毛刺越少,实验会逐次增加一个时钟周期。
8.乘法器
学生实验
- 改变乘法器的输入位宽为8比特,编译,波形仿真,观察信号毛刺的时间长度。
- 选一款没有硬件乘法器的FPGA芯片(例如Cyclone EP1C6)对比8比特的乘法器和加法器两者编译之后的资源开销(Logic Cell的数目)
- 编写一个输入和输出都有D触发器的流水线乘法器代码,编译后波形仿真,观察组合逻辑延迟和毛刺的时间,和不带流水线的情况下对比。
无符号4比特的乘法器 /
module top(
IN1 ,
IN2 ,
OUT );
input [3:0] IN1, IN2;
output [7:0] OUT;
reg [7:0] OUT;
always@(IN1 or IN2) begin // 生成组合逻辑的always 块
OUT = IN1 * IN2;
end
endmodule
无符号8比特的乘法器 /
module top(
IN1 ,
IN2 ,
OUT );
input [7:0] IN1, IN2;
output [12:0] OUT;
reg [12:0] OUT;
always@(IN1 or IN2) begin // 生成组合逻辑的always 块
OUT = IN1 * IN2;
end
endmodule
观察可知,毛刺数量非常多。
2.换成没有硬件乘法器的芯片
///一个输入和输出都有D触发器的流水线乘法器代码///
module top(
CLK ,
IN1 ,
IN2 ,
OUT );
input [3:0] IN1, IN2;
input CLK;
output [7:0] OUT;
reg [3:0] in1, in2;
reg [7:0] D_out, OUT;
always @ (posedge CLK) begin
in1 <= IN1;
in2 <= IN2;
OUT <= D_out;
end
always @ (in1 or in2) begin // 生成组合逻辑的always 块
D_out = in1 * in2;
end
endmodule
9.计数器
学生实验
请完成以下设计实验,编译电路并且进行波形仿真。
- 设计一个最简单的计数器,只有一个CLK输入和一个OVerflow输出,当计数到最大值的时钟周期CLK输出1
- 设计复杂的计数器,和本例相似,带有多种信号,其中同步清零CLR的优先级最高,使能EN次之,LOAD最低。
//最简单的计数器代码 //
module top(
CLK , // 时钟,上升沿有效
CNTVAL,
OV );// 计数溢出信号,计数值为最大值时该信号为1
input CLK;
output [3:0] CNTVAL;
output OV;
reg [3:0] CNTVAL, cnt_next;
reg OV;
// 电路编译参数,最大计数值
parameter CNT_MAX_VAL = 15;
always @ (posedge CLK ) begin
CNTVAL <= CNTVAL + 1;
end
// 组合逻辑,生成OV
always @ (CNTVAL) begin
if(CNTVAL == CNT_MAX_VAL)
OV = 1;
else
OV = 0;
end
endmodule
复杂计数器代码 /
//同步清零CLR的优先级最高,使能EN次之,LOAD最低
module top(
RST , // 异步复位, 高有效
CLK , // 时钟,上升沿有效
EN , // 输入的计数使能,高有效
CLR , // 输入的清零信号,高有效
LOAD , // 输入的数据加载使能信号,高有效
DATA , // 输入的加载数据信号
CNTVAL, // 输出的计数值信号
OV );// 计数溢出信号,计数值为最大值时该信号为1
input RST , CLK , EN , CLR , LOAD ;
input [3:0] DATA ;
output [3:0] CNTVAL;
output OV;
reg [3:0] CNTVAL, cnt_next;
reg OV;
// 电路编译参数,最大计数值
parameter CNT_MAX_VAL = 9;
// 组合逻辑,生成cnt_next
//同步清零CLR的优先级最高,使能EN次之,LOAD最低
always @(EN or CLR or LOAD or DATA or CNTVAL) begin
if(CLR) begin // 清零有效
cnt_next = 0;
end
else begin //
if(EN) begin // 使能有效
if(LOAD) begin // 加载有效
cnt_next = DATA;
end
else begin // 加载无效,正常计数
// 使能有效,清零和加载都无效,根据当前计数值计算下一值
if(CNTVAL < CNT_MAX_VAL) begin // 未计数到最大值, 下一值加1
cnt_next = CNTVAL + 1'b1;
end
else begin // 计数到最大值,下一计数值为0
cnt_next = 0;
end
end // else LOAD
end // if EN
else begin // 使能无效,计数值保持不动
cnt_next = CNTVAL;
end // else EN
end // else CLR
end
// 时序逻辑 更新下一时钟周期的计数值
// CNTVAL 会被编译为D触发器
always @ (posedge CLK or posedge RST) begin
if(RST)
CNTVAL <= 0;
else
CNTVAL <= cnt_next;
end
// 组合逻辑,生成OV
always @ (CNTVAL) begin
if(CNTVAL == CNT_MAX_VAL)
OV = 1;
else
OV = 0;
end
endmodule
10.状态机
学生实验
设计一个用于识别2进制序列“1011”的状态机
- 基本要求:
- 电路每个时钟周期输入1比特数据,当捕获到1011的时钟周期,电路输出1,否则输出0
- 使用序列101011010作为输出的测试序列
- 扩展要求:
- 给你的电路添加输入使能端口,只有输入使能EN为1的时钟周期,才从输入的数据端口向内部获取1比特序列数据。
三段式状态机代码设计一个用于识别2进制序列“1011”的状态机 ///
module top(
CLK , // clock
RST , // reset
EN , // en
CENT1IN , // input 1 cent coin
TINOUT ); // output 1 tin cola
input CLK ;
input RST ;
input EN,CENT1IN ;
output TINOUT ;
parameter ST_0_CENT = 0;
parameter ST_1_CENT = 1;
parameter ST_2_CENT = 2;
parameter ST_3_CENT = 3;
parameter ST_4_CENT = 4;
reg [4-2:0]stateR ;
reg [4-2:0]next_state ;
reg TINOUT ;
// calc next state
always @ (CENT1IN or stateR) begin
if(EN) begin
case (stateR)
ST_0_CENT :begin if(CENT1IN==1) next_state = ST_1_CENT ; else next_state = ST_0_CENT; end
ST_1_CENT :begin if(CENT1IN==0) next_state = ST_2_CENT ; else next_state = ST_0_CENT; end
ST_2_CENT :begin if(CENT1IN==1) next_state = ST_3_CENT ; else next_state = ST_0_CENT; end
ST_3_CENT :begin if(CENT1IN==1) next_state = ST_4_CENT ; else next_state = ST_0_CENT; end
ST_4_CENT :begin next_state = ST_0_CENT; end
endcase
end
else
next_state = ST_0_CENT;
end
// calc output
always @ (stateR) begin
if(stateR == ST_4_CENT)
TINOUT = 1'b1;
else
TINOUT = 1'b0;
end
// state DFF
always @ (posedge CLK or posedge RST)begin
if(RST)
stateR <= ST_0_CENT;
else
stateR <= next_state;
end
endmodule
11.移位寄存器
学生实验
设计一个如本节“电路描述”部分的“带加载使能和移位使能的并入串出”的移位寄存器,电路的RTL结构图如“电路描述”部分的RTL结构图所示。
“带加载使能和移位使能的并入串出”的移位寄存器 /
module top(
RST , // 异步复位, 高有效
CLK , // 时钟,上升沿有效
EN , // 输入数据串行移位使能
LOAD , // 输入数据带加载使能
IN , // 输入串行数据
OUT ); // 并行输出数据
input RST, CLK, EN, LOAD;
input [3:0]IN;
output[3:0] OUT;
reg [3:0] shift_R;
assign OUT[3:0] = shift_R[3:0];
// 时序逻辑 根据输入使能进行串行移位
// shift_R 会被编译为D触发器
always @ (posedge CLK or posedge RST or posedge LOAD) begin
if(RST)
shift_R[3:0] <= 0;
else begin
if(LOAD) begin
shift_R[3:0] <= IN[3:0];
end
else begin
if(EN) begin // 串行移位的使能有效
shift_R[3:1] <= shift_R[2:0];
shift_R[0] <= 0;
end
else begin // 使能无效保持不动
shift_R[3:0] <= shift_R[3:0];
end
end
end
end // always
endmodule
最后
以上就是美好流沙为你收集整理的Verilog RTL代码新手上路教程1. 多路选择器2. 交叉开关3.优先编码器4. 多路译码器8.乘法器9.计数器10.状态机11.移位寄存器的全部内容,希望文章能够帮你解决Verilog RTL代码新手上路教程1. 多路选择器2. 交叉开关3.优先编码器4. 多路译码器8.乘法器9.计数器10.状态机11.移位寄存器所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复