当前位置:   article > 正文

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

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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

在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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178

自己编写一个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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53

在这里插入图片描述
这里与自己编写同样功能的计数器效果进行对比,自己写的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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/302849?site
推荐阅读
相关标签
  

闽ICP备14008679号