FPGA学习笔记:verilog基础代码与modelsim仿真(二)

补充组合逻辑电路实现:全加器
原理图:

在这里插入图片描述

使用两个半加器组成全加器,第一个半加器的输入in_1、in_2作为全加器的输入,同时in_1作为第二个半加器的输入;

第二个半加器的输入2作为全加器的进位cin;

将半加器1与半加器2的进位输出用或门连接作为全加器的进位输出,半加器2的求和输出作为全加器的求和输出。



verilog代码实现功能:

 module full_adder(
    
    input   wire    in_1,
    input   wire    in_2,
    input   wire    cin,
    
    output  wire    sum,
    output  wire    count
    
    
 );
 wire  h0_sum;
 wire  h0_count;
 wire  h1_count;
 half_adder  half_adder_inst0
(
     
    
    .in_1  (in_1 ) ,
    .in_2  (in_2 ) ,
    .sum   (h0_sum)  ,
    .count (h0_count)
   
);



 half_adder  half_adder_inst1
(
    
    
    .in_1  ( cin) ,
    .in_2  ( h0_sum) ,
    .sum   (sum)  ,
    .count ( h1_count)
   
);
 
 assign count = (h0_count | h1_count);
 
 
 endmodule

其中,需要用到半加器的功能实例化,半加器的代码具体参考上一篇文章: https://blog.csdn.net/qq_52899124/article/details/128219813



仿真逻辑文件:
 `timescale 1ns/1ns
 module tb_full_adder();
 
 reg in_1;
 reg in_2;
 reg cin;
 
 wire sum;
 wire  count;
 
 initial
    begin
        in_1  <= 1'b0;
        in_2 <= 1'b0;
        cin  <= 1'b0;
    end
 
 
 initial 
    begin
        $timeformat(-9,0,"ns",6);
        $monitor("@time %t :in_1=%b,in_2=%b,cin=%b,sum=%b,count=%b" ,$time,in_1,in_2,cin,sum,count);
    end
    
    
always #10 in_1 <= {$random} % 2;
always #10 in_2 <= {$random} % 2;
always #10 cin <= {$random} % 2;


full_adder  full_adder_inst
(
        .in_1(in_1)   ,
        .in_2(in_2)   ,
        .cin  (cin )    ,
           
        .sum  (sum )  ,
        .count(count)
);
    
endmodule




modelsim仿真波形图:

在这里插入图片描述










时序逻辑电路

D触发器:
波形图及原理图:

在这里插入图片描述

verilog代码:
 module flip_flop(
    
  input   wire  sys_clk ,   //50Mhz
  input   wire  sys_rst_n ,   
  input   wire  key_in  ,
  
  output  reg   led_out
    

    
    
 );        
        
//Asynchronous reset
 
always@(posedge  sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        led_out <= 1'b0;
    else
        led_out  <=  key_in; 

 
endmodule

上述采用异步清零的方式实现功能。若采用同步清零,代码应为:

 module flip_flop(
    
  input   wire  sys_clk ,   //50Mhz
  input   wire  sys_rst_n ,   
  input   wire  key_in  ,
  
  output  reg   led_out
    
 );
 
 //Synchronous reset
always@(posedge  sys_clk )
    if(sys_rst_n == 1'b0)
        led_out <= 1'b0;
    else
        led_out  <=  key_in;
        
        

 
endmodule



仿真逻辑代码:
  `timescale 1ns/1ns
  module tb_flip_flop();
  
  reg sys_clk;
  reg sys_rst_n;
  reg key_in;
  
  wire led_out;

  
initial
    begin
        sys_clk = 1'b1;
        sys_rst_n <= 1'b0;
        key_in <= 1'b0;
        #20         //delay 20ns
        sys_rst_n   <= 1'b1;
        #210
        sys_rst_n <= 1'b0; 
        sys_rst_n   <= 1'b1;

    end
  
 always #10 sys_clk =~sys_clk;
 
 always #20 key_in <= {$random} % 2;    //input signal period should be greater than or equal to the clock period
 
 initial 
     begin
         $timeformat(-9,0,"ns",6);
         $monitor("@time %t :key_in=%b,led_out=%b" ,$time,key_in,led_out);
     end
     
     


 
 
 flip_flop  flip_flop_inst
 (
         .sys_clk(sys_clk)   ,
         .key_in(key_in)   ,
         .sys_rst_n (sys_rst_n)    ,
            
         .led_out  (led_out)  
         
 );
     
 endmodule
 
 
 


modelsim仿真波形图:

在这里插入图片描述






模M计数器——实现led灯闪烁

值得一提,模M的计算方式:
M = t / T M = t / T M=t/T
M:计数器模值 t:自定义时间周期 T:时钟周期(时钟频率的倒数)

波形图及原理图:

在这里插入图片描述

在这里插入图片描述

上述波形使用计数器全模值完成LED灯闪烁,耗费资源过多,可使用计数器一半模值使保持LED亮或灭,计数器计数达到一半模值后跳转到由0重新开始计数且LED灯状态取反即可实现。



verilog代码实现:
 module counter
 #(
     
   parameter    CNT_MAX = 25'd24_999_999
     
)
(
    input   wire    sys_clk     ,
    input   wire    sys_rst_n   ,
    
    output reg  led_out
);

reg     [24:0]  cnt;
reg             cnt_flag;
always@(posedge sys_clk or negedge sys_rst_n)
    
    if(sys_rst_n == 1'b0)
        cnt <=  25'd0;
    else    if(cnt == CNT_MAX)
        
        cnt <=  25'd0;
    else
        cnt <=  cnt +   25'd1;
        
always@(posedge sys_clk or negedge sys_rst_n)
    
    if(sys_rst_n == 1'b0)
        cnt_flag <= 1'b0;
    else    if(cnt == (CNT_MAX-25'd1))
        
        cnt_flag <=  1'b1;
    else
        cnt_flag <= 1'b0;
    
   
    
always@(posedge sys_clk or negedge sys_rst_n)
 
    if(sys_rst_n == 1'b0)
        led_out <=  1'b0;
        
    else if(cnt == CNT_MAX)
        led_out <= ~led_out;
    else
        led_out<= led_out;
    

  
endmodule
 


方法2 使用cnt_flag作为中间变量
波形图:

在这里插入图片描述

当计数器达到模值一半时,cnt_flag获得一个高脉冲,当cnt_flag取高脉冲时,leg_out状态曲反;

verilog代码实现仿真
 module counter
 #(
     
   parameter    CNT_MAX = 25'd24_999_999
     
)
(
    input   wire    sys_clk     ,
    input   wire    sys_rst_n   ,
    
    output reg  led_out
);

reg     [24:0]  cnt;
reg             cnt_flag;
always@(posedge sys_clk or negedge sys_rst_n)
    
    if(sys_rst_n == 1'b0)
        cnt <=  25'd0;
    else    if(cnt == CNT_MAX)
        
        cnt <=  25'd0;
    else
        cnt <=  cnt +   25'd1;
        
always@(posedge sys_clk or negedge sys_rst_n)
    
    if(sys_rst_n == 1'b0)
        cnt_flag <= 1'b0;
    else    if(cnt == (CNT_MAX-25'd1))
        
        cnt_flag <=  1'b1;
    else
        cnt_flag <= 1'b0;
    
   



always@(posedge sys_clk or negedge sys_rst_n)
    
    if(sys_rst_n == 1'b0)
        led_out<= 1'b0;
    else   if(cnt_flag == 1'b1)
        
        led_out <= ~led_out;
    else
        led_out <= led_out;
    

        
  
  
endmodule
 


仿真代码:
  `timescale 1ns/1ns
 module tb_counter();
  
 reg sys_clk ;
 reg sys_rst_n ;

  
 wire  led_out;
  
 initial
     begin
         sys_clk  <= 1'b1;
         sys_rst_n<= 1'b0;
         #20
         sys_rst_n <= 1'b1;
         
     end
  
  
initial 
     begin
         $timeformat(-9,0,"ns",6);
         $monitor("@time %t :sys_rst_n=%b,led_out=%b" ,$time,sys_rst_n,led_out);
     end
     
     
 always #10 sys_clk <= ~sys_clk;  //50HZ

 
 
 counter  
 #(
    .CNT_MAX(25'd24)  //Pass of parameters
 )counter_inst
 (
         .sys_clk(sys_clk)     ,
         .sys_rst_n(sys_rst_n)   ,   
         .led_out(led_out)
 );
     
 endmodule
 
 
 



方法一modelsim仿真波形图:

在这里插入图片描述

在这里插入图片描述






方法二modelsim仿真波形图:

在这里插入图片描述

在这里插入图片描述

  • 4
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: 单周期代码是一种基于时序逻辑的数字电路设计方法,模拟器是一种模拟数字电路的工具,可以帮助设计者评估设计的正确性和性能。Modelsim是一种常用的数字电路模拟器,可以支持VHDL和Verilog等不同的硬件描述语言。 在使用Modelsim进行单周期代码仿真时,需要先进行以下步骤: 1. 编写VHDL或Verilog代码,包括组合逻辑、时序逻辑和寄存器等部分。 2. 使用Modelsim创建一个项目,并将代码文件添加到项目中。 3. 设计测试计划,包括输入数据和期望输出数据,以便在仿真过程中验证电路功能的正确性。 4. 运行仿真,并注意检查仿真结果是否符合预期。 在仿真过程中,可以通过加入时钟等方式来模拟真实硬件环境下的运行情况。仿真结果可以帮助设计者发现和解决电路中的问题,同时也可以评估电路的性能指标,如时钟频率、功耗等。 总之,单周期代码Modelsim仿真对于数字电路的设计和优化非常重要,可以提高设计的正确性和可靠性,并且减少硬件缺陷和故障的风险。 ### 回答2: 单周期代码是一种基础的CPU设计模式,它将所有指令分成若干个阶段,每个阶段代表了CPU执行指令的不同步骤。在每个阶段,CPU都执行不同的操作,例如取指、译码、执行、访存和写回等。单周期代码较为简单,操作流程清晰,容易理解和实现。 Modelsim仿真,则是一种常用的数字电路仿真工具,它可以模拟数字电路系统的行为和功能,并对各个部件进行调试和验证。在使用Modelsim仿真单周期代码时,我们需要先将代码转化成VHDL或Verilog等语言,并通过仿真工具对代码进行编译和运行。在运行过程中,我们可以通过查看各个信号线的波形图,来分析和测试整个电路的逻辑是否正确和稳定。 具体来说,在单周期代码模拟中,我们可以通过给CPU输入不同的指令,并观察输出结果,来验证CPU是否能够正确地执行这些指令。同时,我们还可以通过修改代码,调整某些部分的逻辑实现,并观察输出结果变化,来发现和修复可能存在的错误和问题。 总的来说,单周期代码modelsim仿真是一种有效的数字电路设计和测试方法,可以帮助我们更好地理解和实现CPU的基本功能和原理,以及发现和解决可能存在的问题和异常情况。 ### 回答3: 单周期代码modelsim仿真是指将单周期CPU的Verilog代码导入到ModelSim仿真软件中进行验证和测试。单周期CPU是一种基于寄存器传输级的处理器,其执行指令需要一个完整的时钟周期。在进行仿真时,首先需要在ModelSim中创建一个工程,将CPU的Verilog代码和测试文件添加到工程中。然后进行综合以生成门级代码,并对其进行仿真仿真分为几个阶段,首先是时序检查,即检查指令执行的时间顺序是否正确。接着是功能验证,即检查CPU的指令执行是否符合设计要求。这个过程需要对每个指令进行测试,确保CPU的各个部件能正常工作,如寄存器、ALU等。同时,还需要对特殊情况进行测试,如跳转指令、中断等。最后是性能测试,即检查CPU的运行效率是否满足要求。这一步通常采用基准测试程序进行测试,比较CPU与其他处理器的性能表现。 单周期代码modelsim仿真不仅能帮助设计人员找出设计中的问题,还能预测处理器的性能表现,为后续的优化工作提供参考。同时,通过仿真还能发现设计中的不足之处,提高代码的可维护性和可重用性。因此,单周期代码modelsim仿真是CPU设计中必不可少的一步。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

保温杯配红牛

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值