Verilog HDL新手上路 学生实验

本文详细介绍了使用Verilog设计数字逻辑电路,包括4选1多路选择器、交叉开关、优先编码器、多路译码器、加法器(含补码加法器)、带流水线的加法器、乘法器、计数器和状态机。通过波形仿真和资源消耗对比,展示了不同电路的特性,如资源占用、延迟和功能实现。实验总结强调了Verilog代码在理解和实现数字逻辑电路中的重要作用。
摘要由CSDN通过智能技术生成

目录

多路选择器

实验要求:

实验内容:

交叉开关

 实验要求:

实验内容:

 

优先编码器

实验要求:

实验内容:

 

多路译码器

实验要求:

实验内容:

加法器

实验要求:

实验内容:

补码加法器

实验要求

实验内容

 

带流水线的加法器

实验要求:

实验内容:

乘法器 

实验要求:

实验内容:

 计数器

实验要求:

实验内容:

 

 状态机

实验要求:

实验内容:

 移位寄存器

实验要求:

实验内容:

实验总结: 


多路选择器

实验要求:

做一个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代码的学习和理解。 

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值