MATLAB生成Verilog代码——HDL Coder使用初探

有关用HDL Coder生成Verilog的资料实在太少,且大多是由Simulink搭建模块生成。笔者经过初步探索,将MATLAB代码直接通过HDL Coder生成Verilog代码的过程总结于此。
以一个最大值为15可加减计数器为例
在MATLAB上方的APP里找到HDL Coder,HDL Coder需要MATLAB Function和MATLAB Testbench两个文件,第一个即纯粹的函数or算法,第二个需要对其进行调用并保证能现在MATLAB上成功运行。
这里已经将两个文件添加了进去,添加完毕后再Workflow Advisor里设置生成的代码为Verilog,再运行即可。里面还可以设置仿真工具并生成testbench,但笔者尝试用生成的testbench进行仿真,并不能成功运行,且代码本身就杂乱非常。

这里给出counter.m和counter_tb.m两段代码

function [count] = counter(clk, rst)
    persistent state
    
    if isempty(state) || ~rst
        state = 0;
    elseif clk
        state = state + 1;
        if state == 16
            state = 1;
        end
    end
    
    count = state;
end
function counter_tb
    % 创建时间和输入信号
    time = 0:19;
    clk = [0, ones(1, 9), 0, ones(1, 9)]; % 50% 占空比,10个时钟周期
    rst = [0, ones(1, 19)]; % 第一个周期的复位信号高
    
    % 初始化用于存储输出的数组
    count_out = zeros(size(time));
    
    % 模拟计数器
    for i = 1:length(time)
        count_out(i) = counter(clk(i), rst(i))
    end
    
end

在Workflow Advisor中运行后会生成.v文件,保存的路径可以在左侧选HDL Code Generation下查看,这里给出生成的verilog代码,可以发现可读性比较差,自己在分析时加了些中文注释。

// -------------------------------------------------------------
// Generated by MATLAB 9.7, MATLAB Coder 4.3 and HDL Coder 3.15
// 
// 
// 
// -- -------------------------------------------------------------
// -- Rate and Clocking Details
// -- -------------------------------------------------------------
// Design base rate: 1
// 
// 
// Clock Enable  Sample Time
// -- -------------------------------------------------------------
// ce_out        1
// -- -------------------------------------------------------------
// 
// 
// Output Signal                 Clock Enable  Sample Time
// -- -------------------------------------------------------------
// count                         ce_out        1
// -- -------------------------------------------------------------
// 
// -------------------------------------------------------------


// -------------------------------------------------------------
// 
// Module: counter_fixpt
// Source Path: counter_fixpt
// Hierarchy Level: 0
// 
// -------------------------------------------------------------

//生成的是可加可减的计数器
// reset置0, rst置1, clk_enable置1 时可用,clk_1为1时加,为0时减

`timescale 1 ns / 1 ns

module counter_fixpt
          (clk,
           reset,
           clk_enable,
           clk_1,
           rst,
           ce_out,
           count);


  input   clk;
  input   reset;
  input   clk_enable;
  input   clk_1;  // ufix1
  input   rst;  // ufix1
  output  ce_out;
  output  [3:0] count;  // ufix4


  wire enb;
  wire state_not_empty;
  reg  state_not_empty_1;
  wire tmp;
  wire tmp_1;
  wire tmp_2;
  wire tmp_3;
  wire [4:0] state;  // ufix5
  wire [4:0] state_1;  // ufix5
  reg [4:0] state_2;  // ufix5
  wire [4:0] state_3;  // ufix5
  wire tmp_4;
  wire [4:0] tmp_5;  // ufix5
  wire [4:0] tmp_6;  // ufix5
  wire [4:0] tmp_7;  // ufix5


  // HDL code generation from MATLAB function: counter_fixpt_trueregionp7
  assign state_not_empty = 1'b1;



  assign enb = clk_enable;

  // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  // 
  //                                                                          %
  // 
  //           Generated by MATLAB 9.7 and Fixed-Point Designer 6.4           %
  // 
  //                                                                          %
  // 
  // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  assign tmp =  ! state_not_empty_1 || ( ! (rst != 1'b0));  // rst为0或state_not_empty_1为0时,temp为1,都为1时temp为0



  assign tmp_1 = (tmp == 1'b0 ? state_not_empty_1 :
              state_not_empty);  // 永远为1



  always @(posedge clk or posedge reset)
    begin : state_not_empty_reg_process
      if (reset == 1'b1) begin
        state_not_empty_1 <= 1'b0;
      end
      else begin
        if (enb) begin   // clk_enable置1时有效,state_not_empty_1为1
          state_not_empty_1 <= tmp_1;
        end
      end
    end



  assign tmp_2 =  ! state_not_empty_1 || ( ! (rst != 1'b0)); // 都1时为0,正常运作时两参数为1,tmp_2为0



  assign tmp_3 = clk_1 != 1'b0;  // clk_1为1时加,为0时减————tmp_3也为1、0



  // HDL code generation from MATLAB function: counter_fixpt_trueregionp13
  assign state = 5'b00001;



  // HDL code generation from MATLAB function: counter_fixpt_trueregionp2
  assign state_1 = 5'b00000;



  // HDL code generation from MATLAB function: counter_fixpt
  assign state_3 = state_2 + 5'b00001;



  assign tmp_4 = state_3 == 5'b10000; // 代表计数器是否满15,是为1



  // HDL code generation from MATLAB function: counter_fixpt_trueregionp10
  assign tmp_5 = (tmp_4 == 1'b0 ? state_3 :
              state); // 若超过01111则置00001,代表计数从15回到1,否则正常加一



  always @(posedge clk or posedge reset) // reset高电平复位
    begin : state_reg_process
      if (reset == 1'b1) begin
        state_2 <= 5'b00000;
      end
      else begin
        if (enb) begin
          state_2 <= tmp_6;
        end
      end
    end



  // HDL code generation from MATLAB function: counter_fixpt_falseregionp2
  assign tmp_7 = (tmp_3 == 1'b0 ? state_2 :
              tmp_5); // tmp_3 == 0时为减法,执行state_2 即tmp_6,此时正常运转tmp_2为0,执行tmp_7(??)tmp_3 == 1时为加法,执行tmp_5。



  assign tmp_6 = (tmp_2 == 1'b0 ? tmp_7 :
              state_1); 



  assign count = tmp_6[3:0];



  assign ce_out = clk_enable;

endmodule  // counter_fixpt

自己编写一个testbench在Modelsim上进行仿真,发现结果是可靠的,reset置0, rst置1, clk_enable置1 时可用,clk_1为1时加,为0时减。

`timescale 1 ps/ 1 ps
module counter_fixpt_tb();
// constants                                           
// general purpose registers
reg eachvec;
// test vector input registers
reg clk;
reg clk_1;
reg clk_enable;
reg reset;
reg rst;
// wires                                               
wire ce_out;
wire [3:0]  count;

parameter clk_period = 10;

// assign statements (if any)                          
counter_fixpt i1 (
// port map - connection between master ports and signals/registers   
	.ce_out(ce_out),
	.clk(clk),
	.clk_1(clk_1),
	.clk_enable(clk_enable),
	.count(count),
	.reset(reset),
	.rst(rst)
);
// reset置0, rst置1, clk_enable置1 时可用,clk_1为1时加,为0时减

initial  
    clk = 0;  
always #(clk_period/2) clk = ~clk;  // 时钟

initial begin
    reset = 1;
	# 10 reset = 0;
end  // 使能

initial begin
    rst = 0;
	# 10 rst = 1;
end  // 使能

initial begin
    clk_enable = 0;
	# 10 clk_enable = 1;
end  // 使能

initial clk_1 = 0;
always #(clk_period) clk_1 = {$random} % 2; //clk_1为随机的0或1
                                            
endmodule

在这里插入图片描述
这里与自己编写同样功能的计数器效果进行对比,自己写的verilog代码就简单易懂了许多,同样编写testbench仿真结果一致。

module counter(
    input clk,
    input rst,
    input add_sub,  // 0 for subtract, 1 for add
    output reg [3:0] count
);

always @(posedge clk or negedge rst) begin
    if (rst == 0) begin
        count <= 4'b0000;  // Reset the counter to 0
    end else if (add_sub) begin
        if (count == 4'b1111) begin
            count <= 4'b0000;  // Wrap around to 0 if max value reached
        end else begin
            count <= count + 1;  // Increment the counter
        end
    end else begin
        if (count == 4'b0000) begin
            count <= 4'b1111;  // Wrap around to max value if 0 reached
        end else begin
            count <= count - 1;  // Decrement the counter
        end
    end
end

endmodule

在这里插入图片描述
尽管仿真显示二者的功能一致,但从代码来看区别还是很大的,用QuartusII对.v文件进行编译再生成RTL电路图,可以更加直观地发现区别,前者明显更繁琐且消耗资源更多。若是在面向具体项目的实际设计中,或者在更加负责的系统或算法的设计中,HDL Coder生成的代码便可能不合适。
HDL Coder生成的代码经过编译得到电路图
自己的代码经过编译生成电路图

  • 11
    点赞
  • 58
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

MozerLie

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

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

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

打赏作者

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

抵扣说明:

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

余额充值