hdlcoder 靠譜嗎?

HDLCODER 將.m 轉成可綜合的fpga項目。。依據matlab官網 關於hdlcoder 的例子(bisection 求sqrt ),發現自動生成的testbench 並不正確。。不知道在工業中是否成熟應用?


這個當然很有用。BCH的演算法就可以用matlab自動轉化生成,你可能不知道IC設計人員從無到有寫一個BCH有多痛苦,需要花費2個月以上的時間,然後才能進行綜合,查看gatecount和timing,然後開始驗證,bug估計一堆,驗證又需要2個月。

而驗證matlab的演算法就容易多了,一周就能寫出來BCH的matlab演算法,再一周就能折騰出RTL,還能保證功能基本沒問題,對於演算法的前期探索非常有利。誰也不希望花了2個月的時間,寫完RTL,一綜合發現gatecount老大了,然後又否定這個方案,重新再來。或者發現碼長過長,又改RTL,採用更短的編碼。採用matlab,很快就可以評估演算法需要的資源有多少,能跑多高的時鐘,從而確定時鐘,碼長,編碼率等一些關鍵參數,在定架構階段能幫上大忙。

當然,不會有IC工程師拿matlab自動生成的RTL做chip。


工業上肯定不成熟,或者成熟對於不同行業的定義不一樣。

對於研究所等在意驗證演算法正確與否而對性能、面積、穩定性不太在乎的用戶來說,夠用就行了,比如生成個FIR濾波器;

對於把FPGA當出貨產口而非驗證平台的廠商而言,這玩意基本沒啥用,直接用現有IP或花點錢招兩個人寫HDL代碼更好點;

對IC設計做演算法設計的人來說,我把自己matlab寫好能驗證就OK了,轉成HDL的事自有人干,要是拿這轉換的去設計ASIC晶元,想都不用想。

Xilinx HLS工具應比這家靠譜點,起碼更接近商用,OpenCL現在兩家都在熱推。

---------------------------------------------------------------------------------------

提供個例子,本人自己寫的,手工把C代碼寫成AXI4 Lite介面的RTL code

void bubble_sort(UINT32 a[],int n)
{
UINT32 temp;
int i,j;

for(j=0;j&a[i+1]) //ascending
{
temp=a[i];
a[i]=a[i+1];
a[i+1]=temp;
}
}
}

下面是RTL code
`timescale 1 ns / 100 ps
//`include "tb_include.vh"

module axi_bubble_sort
#(
parameter AXI_DW = 32,
parameter AXI_AW = 32
)
(
// AXI INTERFACE
// Global
input aclk,
input aresetn,
// Write address channel
output reg [AXI_AW-1:0] awaddr,
output reg [2:0] awprot,
output reg awvalid,
input awready,
// Write data channel
output reg [AXI_DW-1:0] wdata,
output reg [AXI_DW/8-1:0] wstrb,
output reg wvalid,
input wready,
// Write response channel
input [1:0] bresp,
input bvalid,
output reg bready,
// Read address channel
output reg [AXI_AW-1:0] araddr,
output reg [2:0] arprot,
output reg arvalid,
input arready,
// Read data channel
input [AXI_DW-1:0] rdata,
input [1:0] rresp,
input rvalid,
output reg rready,

input [63:0] start_addr,
input [15:0] total_dw,
input bubble_en,
input [AXI_AW-1:0] status_addr,
output reg [31:0] times_sort,
output reg [31:0] times_swap
);

parameter ST_BUBBLE_IDLE = 3d0;
parameter ST_BUBBLE_J = 3d1;
parameter ST_BUBBLE_I = 3d2;
parameter ST_BUBBLE_TAP = 3d3;
parameter ST_BUBBLE_OVR = 3d4;

parameter ST_SORT_IDLE = 3d0;
parameter ST_SORT_RD1 = 3d1;
parameter ST_SORT_RD2 = 3d2;
parameter ST_SORT_PROC = 3d3;
parameter ST_SORT_WR1 = 3d4;
parameter ST_SORT_WR2 = 3d5;
parameter ST_SORT_TAP = 3d6;
parameter ST_SORT_OVR = 3d7;

parameter ST_WR_IDLE = 3d0;
parameter ST_WR_AW = 3d1;
parameter ST_WR_W = 3d2;
parameter ST_WR_TAP = 3d3;

parameter ST_RD_IDLE = 3d0;
parameter ST_RD_AR = 3d1;
parameter ST_RD_TAP = 3d2;

reg [2:0] cur_st_bubble;
reg [2:0] nxt_st_bubble;
reg [2:0] lst_st_bubble;

reg [2:0] cur_st_sort;
reg [2:0] nxt_st_sort;
reg [2:0] lst_st_sort;

reg [2:0] cur_st_wr;
reg [2:0] nxt_st_wr;
reg [2:0] lst_st_wr;
reg [2:0] cur_st_rd;
reg [2:0] nxt_st_rd;
reg [2:0] lst_st_rd;

integer i;
reg [AXI_AW-1:0] awaddr_in;
reg [AXI_DW-1:0] wdata_in;
reg [AXI_DW/8-1:0] wstrb_in;
wire fsm_wr_trg;
reg [2:0] aw_intrans_cnt;
wire aw_intrans_busy;

reg [AXI_AW-1:0] araddr_in;
reg [AXI_DW-1:0] rdata_out;
reg [2:0] ar_intrans_cnt;
wire ar_intrans_busy;

wire fsm_rd_trg;

reg b_ack;
reg r_ack;

reg [AXI_DW-1:0] wdata_in1;
reg [AXI_DW/8-1:0] wstrb_in1;
reg [AXI_DW-1:0] wdata_in2;
reg [AXI_DW/8-1:0] wstrb_in2;
reg [AXI_DW-1:0] rdata_out1;
reg [AXI_DW-1:0] rdata_out2;

reg bubble_en_d;
wire bubble_en_trg;
reg [31:0] sub_i;
reg [31:0] sub_j;
reg bubble_ovr_ask;
wire bubble_ovr_confirm;
wire fsm_sort_trg;

always @(posedge aclk or negedge aresetn) begin
if (!aresetn)
bubble_en_d &<= 1b0; else bubble_en_d &<= bubble_en; end assign bubble_en_trg = bubble_en !bubble_en_d; //BFM AXI sort always @(posedge aclk or negedge aresetn) begin if (!aresetn) begin cur_st_bubble &<= ST_SORT_IDLE; lst_st_bubble &<= ST_SORT_IDLE; end else begin cur_st_bubble &<= nxt_st_bubble; lst_st_bubble &<= cur_st_bubble; end end always @(*) begin case (cur_st_bubble) ST_BUBBLE_IDLE: if (bubble_en_trg) nxt_st_bubble = ST_BUBBLE_J; else nxt_st_bubble = ST_BUBBLE_IDLE; ST_BUBBLE_J: nxt_st_bubble = ST_BUBBLE_I; ST_BUBBLE_I: if (cur_st_sort == ST_SORT_TAP) nxt_st_bubble = ST_BUBBLE_TAP; else nxt_st_bubble = ST_BUBBLE_I; ST_BUBBLE_TAP: if (sub_i &< total_dw - 1 -sub_j) nxt_st_bubble = ST_BUBBLE_I; else begin if (sub_j &< total_dw - 1) nxt_st_bubble = ST_BUBBLE_J; else nxt_st_bubble = ST_BUBBLE_OVR; end ST_BUBBLE_OVR: if (bubble_ovr_confirm) nxt_st_bubble = ST_BUBBLE_IDLE; else nxt_st_bubble = ST_BUBBLE_OVR; default: nxt_st_bubble = ST_BUBBLE_IDLE; endcase end always @(posedge aclk or negedge aresetn) begin if (!aresetn) sub_i &<= b0; else if (cur_st_bubble == ST_BUBBLE_IDLE) sub_i &<= b0; else if (cur_st_bubble == ST_BUBBLE_TAP lst_st_bubble != ST_BUBBLE_TAP) if (sub_i &< total_dw - 1 -sub_j) sub_i &<= sub_i + 1b1; else sub_i &<= b0; end always @(posedge aclk or negedge aresetn) begin if (!aresetn) sub_j &<= b0; else if (cur_st_bubble == ST_BUBBLE_IDLE) sub_j &<= b0; else if (cur_st_bubble == ST_BUBBLE_TAP lst_st_bubble != ST_BUBBLE_TAP) if (sub_i == total_dw - 1 -sub_j) if (sub_j &< total_dw - 1) sub_j &<= sub_j + 1b1; end assign fsm_sort_trg = (cur_st_bubble == ST_BUBBLE_I lst_st_bubble != ST_BUBBLE_I); //assign bubble_ovr_ask = (cur_st_bubble == ST_BUBBLE_OVR lst_st_bubble == ST_BUBBLE_TAP); always @(posedge aclk or negedge aresetn) begin if (!aresetn) bubble_ovr_ask &<= 1b0; else if (cur_st_bubble == ST_BUBBLE_OVR lst_st_bubble == ST_BUBBLE_TAP) bubble_ovr_ask &<= 1b1; else if (bubble_ovr_confirm) bubble_ovr_ask &<= 1b0; end //BFM AXI sort always @(posedge aclk or negedge aresetn) begin if (!aresetn) begin cur_st_sort &<= ST_SORT_IDLE; lst_st_sort &<= ST_SORT_IDLE; end else begin cur_st_sort &<= nxt_st_sort; lst_st_sort &<= cur_st_sort; end end always @(*) begin case (cur_st_sort) ST_SORT_IDLE: if (fsm_sort_trg) nxt_st_sort = ST_SORT_RD1; else if (bubble_ovr_ask) nxt_st_sort = ST_SORT_OVR; else nxt_st_sort = ST_SORT_IDLE; ST_SORT_RD1: if (r_ack) nxt_st_sort = ST_SORT_RD2; else nxt_st_sort = ST_SORT_RD1; ST_SORT_RD2: if (r_ack) nxt_st_sort = ST_SORT_PROC; else nxt_st_sort = ST_SORT_RD2; ST_SORT_PROC: nxt_st_sort = ST_SORT_WR1; ST_SORT_WR1: if (b_ack) nxt_st_sort = ST_SORT_WR2; else nxt_st_sort = ST_SORT_WR1; ST_SORT_WR2: if (b_ack) nxt_st_sort = ST_SORT_TAP; else nxt_st_sort = ST_SORT_WR2; ST_SORT_TAP: nxt_st_sort = ST_SORT_IDLE; ST_SORT_OVR: if (b_ack) nxt_st_sort = ST_SORT_IDLE; else nxt_st_sort = ST_SORT_OVR; default: nxt_st_sort = ST_SORT_IDLE; endcase end always @(posedge aclk or negedge aresetn) begin if (!aresetn) begin awaddr_in &<= b0; araddr_in &<= b0; rdata_out1 &<= b0; rdata_out2 &<= b0; wdata_in1 &<= b0; wstrb_in1 &<= b0; wdata_in2 &<= b0; wstrb_in2 &<= b0; end else begin case (cur_st_sort) ST_SORT_RD1: begin araddr_in &<= start_addr + (sub_i &<&< 2); if (r_ack) rdata_out1 &<= rdata_out; end ST_SORT_RD2: begin araddr_in &<= start_addr + (sub_i &<&< 2) + 4; if (r_ack) rdata_out2 &<= rdata_out; end ST_SORT_PROC: begin if($signed(rdata_out1) &> $signed(rdata_out2)) begin
wdata_in1 &<= rdata_out2; wdata_in2 &<= rdata_out1; end else begin wdata_in1 &<= rdata_out1; wdata_in2 &<= rdata_out2; end wstrb_in1 &<= 4hf; wstrb_in2 &<= 4hf; end ST_SORT_WR1: begin awaddr_in &<= start_addr + (sub_i &<&< 2); wdata_in &<= wdata_in1; wstrb_in &<= wstrb_in1; end ST_SORT_WR2: begin awaddr_in &<= start_addr + (sub_i &<&< 2) + 4; wdata_in &<= wdata_in2; wstrb_in &<= wstrb_in2; end ST_SORT_OVR: begin awaddr_in &<= status_addr; wdata_in &<= 32h1; wstrb_in &<= 4hf; end default:; endcase end end always @(posedge aclk or negedge aresetn) begin if (!aresetn) begin times_sort &<= b0; times_swap &<= b0; end else if (bubble_en_trg) begin times_sort &<= b0; times_swap &<= b0; end else if (cur_st_sort == ST_SORT_PROC) begin if (times_sort &< {32{1b1}}) begin times_sort &<= times_sort + 1b1; end if (rdata_out1 &> rdata_out2)
if (times_swap &< {32{1b1}}) begin times_swap &<= times_swap + 1b1; end end end assign fsm_wr_trg = (cur_st_sort == ST_SORT_WR1 lst_st_sort != ST_SORT_WR1) || (cur_st_sort == ST_SORT_WR2 lst_st_sort != ST_SORT_WR2) || (cur_st_sort == ST_SORT_OVR lst_st_sort != ST_SORT_OVR); assign fsm_rd_trg = (cur_st_sort == ST_SORT_RD1 lst_st_sort != ST_SORT_RD1) || (cur_st_sort == ST_SORT_RD2 lst_st_sort != ST_SORT_RD2); assign bubble_ovr_confirm = (cur_st_sort == ST_SORT_IDLE lst_st_sort == ST_SORT_OVR); //BFM AXI write always @(posedge aclk or negedge aresetn) begin if (!aresetn) begin cur_st_wr &<= ST_WR_IDLE; lst_st_wr &<= ST_WR_IDLE; end else begin cur_st_wr &<= nxt_st_wr; lst_st_wr &<= cur_st_wr; end end always @(*) begin case (cur_st_wr) ST_WR_IDLE: if (fsm_wr_trg) nxt_st_wr = ST_WR_AW; else nxt_st_wr = ST_WR_IDLE; ST_WR_AW: if (awvalid awready) nxt_st_wr = ST_WR_W; else nxt_st_wr = ST_WR_AW; ST_WR_W: if (wvalid wready) nxt_st_wr = ST_WR_TAP; else nxt_st_wr = ST_WR_W; ST_WR_TAP: if (!aw_intrans_busy) nxt_st_wr = ST_WR_IDLE; else nxt_st_wr = ST_WR_TAP; default: nxt_st_wr = ST_WR_IDLE; endcase end always @(posedge aclk or negedge aresetn) begin if (!aresetn) begin awaddr &<= b0; awprot &<= 3b0; wdata &<= b0; wstrb &<= b0; bready &<= 1b1; end else begin case (cur_st_wr) ST_WR_AW: begin awaddr &<= awaddr_in; end ST_WR_W: begin wdata &<= wdata_in; wstrb &<= wstrb_in; end default: ; endcase end end always @(posedge aclk or negedge aresetn) begin if (!aresetn) begin awvalid &<= 1b0; end else if (cur_st_wr == ST_WR_AW) begin if ((lst_st_wr != ST_WR_AW)) awvalid &<= 1b1; else if (awready) awvalid &<= 1b0; end else awvalid &<= 1b0; end always @(posedge aclk or negedge aresetn) begin if (!aresetn) wvalid &<= 1b0; else if (cur_st_wr == ST_WR_W) begin if ((lst_st_wr != ST_WR_W)) wvalid &<= 1b1; else if (wready) wvalid &<= 1b0; end else wvalid &<= 1b0; end always @(posedge aclk or negedge aresetn) begin if (!aresetn) b_ack &<= 1b0; else if (bvalid bready) b_ack &<= 1b1; else b_ack &<= 1b0; end always @(posedge aclk or negedge aresetn) begin if (!aresetn) aw_intrans_cnt &<= 3b0; else begin if (awvalid awready) aw_intrans_cnt &<= aw_intrans_cnt + 1b1; if (bvalid bready) aw_intrans_cnt &<= aw_intrans_cnt - 1b1; end end assign aw_intrans_busy = (aw_intrans_cnt &>= 3d4);

//BFM AXI read
always @(posedge aclk or negedge aresetn) begin
if (!aresetn) begin
cur_st_rd &<= ST_RD_IDLE; lst_st_rd &<= ST_RD_IDLE; end else begin cur_st_rd &<= nxt_st_rd; lst_st_rd &<= cur_st_rd; end end always @(*) begin case (cur_st_rd) ST_RD_IDLE: if (fsm_rd_trg) nxt_st_rd = ST_RD_AR; else nxt_st_rd = ST_RD_IDLE; ST_RD_AR: if (arvalid arready) nxt_st_rd = ST_RD_TAP; else nxt_st_rd = ST_RD_AR; ST_RD_TAP: if (rvalid rvalid) nxt_st_rd = ST_RD_IDLE; else nxt_st_rd = ST_RD_TAP; default: nxt_st_rd = ST_RD_IDLE; endcase end always @(posedge aclk or negedge aresetn) begin if (!aresetn) begin araddr &<= b0; arprot &<= 3b0; rready &<= 1b1; end else begin case (cur_st_rd) ST_RD_AR: begin araddr &<= araddr_in; end default: ; endcase end end always @(posedge aclk or negedge aresetn) begin if (!aresetn) begin arvalid &<= 1b0; end else if (cur_st_rd == ST_RD_AR) begin if (lst_st_rd != ST_RD_AR) arvalid &<= 1b1; else if (arready) arvalid &<= 1b0; end else arvalid &<= 1b0; end always @(posedge aclk or negedge aresetn) begin if (!aresetn) rdata_out &<= b0; else if (rvalid rready) rdata_out &<= rdata; end always @(posedge aclk or negedge aresetn) begin if (!aresetn) r_ack &<= 1b0; else if (rvalid rready) r_ack &<= 1b1; else r_ack &<= 1b0; end always @(posedge aclk or negedge aresetn) begin if (!aresetn) ar_intrans_cnt &<= 3b0; else begin if (arvalid arready) ar_intrans_cnt &<= ar_intrans_cnt + 1b1; if (rvalid rready) ar_intrans_cnt &<= ar_intrans_cnt - 1b1; end end assign ar_intrans_busy = (ar_intrans_cnt &>= 3d4);

endmodule


一般高校或者政府機構用


目前fpga的項目中演算法先用MATLAb驗證其正確性然後,然後人工轉換成hdl是嗎?例如你寫的例子,自動生成的hdl代碼結構代碼冗長,資源佔用多是嗎?求知


推薦閱讀:

TAG:MATLAB | 現場可編輯邏輯門陣列FPGA | veriloghdl |