目录
多路选择器
实验要求:
做一个4选1的mux,并且进行波形仿真 和2选1的mux对比,观察资源消耗的变化
实验内容:
代码
// module topmux, 选择器(mux4*1)的代码,
module topmux(
IN0 , // input 1
IN1 , // input 2
IN2 , // input 3
IN3 , // input 4
SEL0 , // select0
OUT ); // out data
parameter WL = 16; // 输入输出数据信号位宽
input [WL-1:0] IN0, IN1,IN2,IN3;// 选择器的两个输入数据信号
input [1:0] SEL0; // 通道选通的控制信号
output[WL-1:0] OUT; // 选择器的输入数据信号
reg [WL-1:0] OUT;// 生成组合逻辑的代码
always @ (IN0 or IN1 or IN2 or IN3 or SEL0) begin
if(SEL0==0) // SEL为0 选择输入0
OUT = IN0;
else if(SEL0==1) // SEL为1 选择输入1
OUT = IN1;
else if(SEL0==2) // SEL为2 选择输入2
OUT = IN2;
else if(SEL0==3) // SEL为3 选择输入3
OUT = IN3;
end
endmodule
// endmodule
RTL图
波形仿真
资源消耗对比
4选1的mux
2选1的mux
交叉开关
实验要求:
编写一个4X4路交叉开关的RTL,然后编译,看RTL View 比较2x2与4x4之间消耗资源的区别。通过对比资源,你有什么结论?
实验内容:
代码
// module top, a 2x2 crossbar switch circuit
module Verilog1(
IN0,
IN1,
IN2,
IN3,
SEL0,
SEL1,
SEL2,
SEL3,
OUT0,
OUT1,
OUT2,
OUT3);
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 ((SEL1)&&(SEL0))
OUT0 = IN3;
else if((SEL1)&&(!SEL0))
OUT0 = IN2;
else if((!SEL1)&&(SEL0))
OUT0 = IN1;
else
OUT0 = IN0;
end
always @ (IN0 or IN1 or IN2 or IN3 or SEL1 or SEL2)
begin
if ((SEL2)&&(SEL1))
OUT1 = IN3;
else if((SEL2)&&(!SEL1))
OUT1 = IN2;
else if((!SEL2)&&(SEL1))
OUT1 = IN1;
else
OUT1 = IN0;
end
always @ (IN0 or IN1 or IN2 or IN3 or SEL3 or SEL2)
begin
if ((SEL3)&&(SEL2))
OUT2 = IN3;
else if((SEL3)&&(!SEL2))
OUT2 = IN2;
else if((!SEL3)&&(SEL2))
OUT2 = IN1;
else
OUT2 = IN0;
end
always @ (IN0 or IN1 or IN2 or IN3 or SEL0 or SEL3)
begin
if ((SEL0)&&(SEL3))
OUT3 = IN3;
else if((SEL0)&&(!SEL3))
OUT3 = IN2;
else if((!SEL0)&&(SEL3))
OUT3 = IN1;
else
OUT3 = IN0;
end
endmodule
RTL图
资源消耗对比
4X4路
2X2路
优先编码器
实验要求:
编写一个8输入的优先编码器,然后编译,看RTL View
实验内容:
代码
// 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
RTL图
波形仿真
多路译码器
实验要求:
- 编写一个4-16的译码器,编译
- 和3-8译码器对比资源开销
- 看RTL View
实验内容:
代码
// module top, 8 input priority encoder with zero input check
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
RTL图
波形仿真
资源消耗对比
4-16
3-8
加法器
实验要求:
- 把加法器的输出信号改成4比特位宽,编译,波形仿真。观察输出结果,说出输出和输入的对应关系。
- 把加法器的输入信号改成8比特位宽,编译,波形仿真。观察加法器的输出延迟,和4比特输入位宽的情况对比,你有什么结论,为什么?
实验内容:
代码
//4输入-4输出
module Verilog1(
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
//8输入,5输出
module Verilog1(
IN1 ,
IN2 ,
OUT );
input[7:0] IN1, IN2;
output[4:0] OUT;
reg[4:0] OUT;
always@(IN1 or IN2) begin // 生成组合逻辑的always 块
OUT = IN1 + IN2;
end
endmodule
波形仿真
当输入仍为4位而输出改为4位时,输出结果范围仅为0~15,当两位输入相加结果大于15后输出结果会出现错误,仅能输出正确结果的后四位;
输入改为8位而输出仍为5位时,两个0~127的数相加,可结果范围只能为0~31,这时只能输出正确结果的后5位,然而加法器仍然要运算正确结果的前3位,所以输出延时应该要大于4输入-5输出的加法器。
补码加法器
实验要求
把加法器的输出信号改成4比特位宽,编译,波形仿真。观察输出结果,观察输出结果在什么时候是正确的?把加法器的输入信号改成8比特位宽,编译,波形仿真。观察加法器的输出延迟,和4比特输入位宽的情况对比,你有什么结论,为什么?
实验内容
代码
//4输入-4输出补码加法器
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
//8输入-5输出补码加法器
module top(
IN1 ,
IN2 ,
OUT );
input signed [7:0] IN1, IN2;
output signed [4:0] OUT;
reg signed [4:0] OUT;
always@(IN1 or IN2) begin // 生成组合逻辑的always 块
OUT = IN1 + IN2;
end
endmodule
波形仿真
其基本原理与无符号加法器相同,只不过其运算法则变为补码运算,故不加赘述。
带流水线的加法器
实验要求:
不改变流水线的级数,把加法器的输入信号改成8比特位宽,编译,波形仿真,和不带流水线的情况对比一下,你有什么结论? 在8比特输入位宽的情况下,在输入上再添加一级流水线,观察编译和仿真的结果,你有什么结论?
实验内容:
代码:
//8输入-5输出带流水线加法器
module top(
IN1 ,
IN2 ,
CLK ,
OUT );
input [7:0] IN1, IN2;
input CLK;
output [4:0] OUT;
reg [7: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
adder_out = in1_d1R + in2_d1R;
end
endmodule
//4输入-5输出2级流水线加法器
module top(
IN1 ,
IN2 ,
CLK ,
OUT );
input [3:0] IN1, IN2;
input CLK;
output [4:0] OUT;
reg [3:0] in1_d1R, in2_d1R,in1_d2R,in2_d2R;
reg [4: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
adder_out = in1_d2R + in2_d2R;
end
endmodule
RTL图
8输入-5输出带流水线加法器
4输入-5输出2级流水线加法器
波形仿真
与不加流水线的加法器相比,带流水线的加法器即在加法器的输入与输出都连接了D触发器,有效的减少了组合逻辑的竞争与冒险,从而明显减少了“毛刺”的长度。而流水线的级数越高,毛刺也随之越短,但输出的时延也会相应的对一个时钟周期。
乘法器
实验要求:
- 改变乘法器的输入位宽为8比特,编译,波形仿真,观察信号毛刺的时间长度。
- 选一款没有硬件乘法器的FPGA芯片(例如Cyclone EP1C6)对比8比特的乘法器和加法器两者编译之后的资源开销(Logic Cell的数目)
- 编写一个输入和输出都有D触发器的流水线乘法器代码,编译后波形仿真,观察组合逻辑延迟和毛刺的时间,和不带流水线的情况下对比。
实验内容:
代码
//8输入-8输出无符号乘法器
module top(
IN1 ,
IN2 ,
OUT );
input [7:0] IN1, IN2;
output [7:0] OUT;
reg [7:0] OUT;
always@(IN1 or IN2) begin // 生成组合逻辑的always 块
OUT = IN1 * IN2;
end
endmodule
//4输入-8输出带流水线乘法器
module top(
IN1 ,
IN2 ,
CLK ,
OUT );
input signed [3:0] IN1, IN2;
input CLK;
output signed[7:0] OUT;
reg signed [7:0] muler_out,OUT;
reg signed [3:0]in1_d1r,in2_d1r;
always@(posedge CLK) begin // 生成组合逻辑的always 块
in1_d1r <= IN1;
in2_d1r <= IN2;
OUT<=muler_out;
end
always@ (in1_d1r or in2_d1r) begin
muler_out = in1_d1r * in2_d1r;
end
endmodule
波形仿真
8输入-8输出无符号乘法器
4输入-8输出带流水线乘法器
相较4输入-8输出无流水线乘法器,其毛刺时间相较更短,但输出延时更长
资源消耗
无硬件乘法器芯片的无符号乘法器硬件资源消耗非常巨大。
计数器
实验要求:
- 设计一个最简单的计数器,只有一个CLK输入和一个OVerflow输出,当计数到最大值的时钟周期CLK输出1
- 设计复杂的计数器,和本例相似,带有多种信号,其中同步清零CLR的优先级最高,使能EN次之,LOAD最低。
实验内容:
代码
//只有CLK和Overflow信号的简单计数器
odule top(
CLK , // 时钟,上升沿有效
OV );// 计数溢出信号,计数值为最大值时该信号为1
input CLK ;
output OV;
reg OV;
reg [3:0] CNT_now, cnt_next;
parameter CNT_MAX_VAL = 9;
// 组合逻辑,生成cnt_next
always @(CNT_now) begin
if(CNT_now < CNT_MAX_VAL) begin // 未计数到最大值, 下一值加1
cnt_next = CNT_now + 1'b1;
end
else begin // 计数到最大值,下一计数值为0
cnt_next = 0;
end
end
// 时序逻辑 更新下一时钟周期的计数值
always @ (posedge CLK) begin
CNT_now <= cnt_next;
end
// 组合逻辑,生成OV
always @ (CNT_now) begin
if(CNT_now == CNT_MAX_VAL)
OV = 1;
else
OV = 0;
end
endmodule
module top(
CLK , // 时钟,上升沿有效
OV );// 计数溢出信号,计数值为最大值时该信号为1
input CLK ;
output OV;
reg OV;
reg [3:0] CNT_now, cnt_next;
parameter CNT_MAX_VAL = 9;
// 组合逻辑,生成cnt_next
always @(CNT_now) begin
if(CNT_now < CNT_MAX_VAL) begin // 未计数到最大值, 下一值加1
cnt_next = CNT_now + 1'b1;
end
else begin // 计数到最大值,下一计数值为0
cnt_next = 0;
end
end
// 时序逻辑 更新下一时钟周期的计数值
always @ (posedge CLK) begin
CNT_now <= cnt_next;
end
// 组合逻辑,生成OV
always @ (CNT_now) begin
if(CNT_now == CNT_MAX_VAL)
OV = 1;
else
OV = 0;
end
endmodule
//改变三种信号优先级的计数器
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
// 清零最优先,计数使能第二优先,加载第三优先
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 // 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
RTL图
简单计数器
复杂计数器
波形仿真
简单计数器
复杂计数器
状态机
实验要求:
设计一个用于识别2进制序列“1011”的状态机
- 基本要求:
- 电路每个时钟周期输入1比特数据,当捕获到1011的时钟周期,电路输出1,否则输出0
- 使用序列101011010作为输出的测试序列
- 扩展要求:
- 给你的电路添加输入使能端口,只有输入使能EN为1的时钟周期,才从输入的数据端口向内部获取1比特序列数据。
实验内容:
代码
module Verilog1(
CLK, // clock
RST, // reset
IN, // input
EN, // EN
OUT); // output
input CLK;
input RST;
input IN;
input EN;
output OUT;
parameter ST_0 = 0;
parameter ST_1 = 1;
parameter ST_2 = 2;
parameter ST_3 = 3;
parameter ST_4 = 4;
reg [2:0] stateR;
reg [2:0] next_state;
reg OUT;
//calc next_state
always @(IN or EN or stateR)
begin
case(stateR)
ST_0:begin if(IN==0&&EN==0) next_state = ST_0; else if(IN==1&&EN==0) next_state = ST_0;
else if(IN==0&&EN==1) next_state = ST_0; else next_state = ST_1;end
ST_1:begin if(IN==0&&EN==0) next_state = ST_1; else if(IN==1&&EN==0) next_state = ST_1;
else if(IN==0&&EN==1) next_state = ST_2; else next_state = ST_1;end
ST_2:begin if(IN==0&&EN==0) next_state = ST_2; else if(IN==1&&EN==0) next_state = ST_2;
else if(IN==0&&EN==1) next_state = ST_0; else next_state = ST_3;end
ST_3:begin if(IN==0&&EN==0) next_state = ST_3; else if(IN==1&&EN==0) next_state = ST_3;
else if(IN==0&&EN==1) next_state = ST_2; else next_state = ST_4;end
ST_4:begin next_state = ST_0;end
endcase
end
//calc output
always @(stateR)
begin
if(stateR == ST_4)
OUT = 1'b1;
else
OUT = 1'b0;
end
//state DFF
always @(posedge CLK or posedge RST)
begin
if(RST)
stateR <= ST_0;
else
stateR <= next_state;
end
endmodule
RTL图
状态转移图
波形仿真
移位寄存器
实验要求:
设计一个如本节“电路描述”部分的“带加载使能和移位使能的并入串出”的移位寄存器,电路的RTL结构图如“电路描述”部分的RTL结构图所示。
实验内容:
代码
带加载使能和移位使能的并入串出 /
module top(
RST , // 异步复位, 高有效
CLK , // 时钟,上升沿有效
LOAD ,
EN , // 输入数据串行移位使能
IN , // 输入串行数据
OUT ); // 并行输出数据
input RST, CLK, EN,LOAD;
input [3:0]IN;
output OUT;
reg [3:0] shift_R;
reg OUT;
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
OUT = shift_R[3];
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
endmodule
RTL图
波形仿真
实验总结:
通过对各种实例加强了对Verilog代码的学习和理解。