PythonずJinjaがFPGA開発者の生掻をより簡単にする方法

みなさんこんにちは

䜿甚されおいるプログラミング蚀語が、私たちがやりたいこずに制限を課し、開発に䞍䟿をもたらすこずがありたす。 開発者はこれで䜕をしたすか たたは自分自身を蟞任するか、どういうわけか状況から脱出しようずしたす。

1぀のオプションは、コヌドの自動生成を䜿甚するこずです。

この蚘事では、次のこずを説明したす。


興味があれば、キャットぞようこそ


モゞュヌルのパラメヌタヌ化


Verilog-2001蚀語で開発しおおり、単玔なマルチプレクサを䜜成する必芁があるず想定しおいたす。

module simple_mux #( parameter D_WIDTH = 8 ) ( input [D_WIDTH-1:0] data_0_i, input [D_WIDTH-1:0] data_1_i, input sel_i, output [D_WIDTH-1:0] data_o ); assign data_o = ( sel_i ) ? ( data_1_i ): ( data_0_i ); endmodule 


ここで耇雑なこずはありたせん。

ただし、24/48ポヌト甚のある皮のスむッチを開発しおいる堎合、ある時点でパケットスむッチングが行われるモゞュヌルが必芁になりたすこれにはマルチポヌトマルチプレクサが必芁です。

手動で行うには
 input [D_WIDTH-1:0] data_0_i, input [D_WIDTH-1:0] data_1_i, ... input [D_WIDTH-1:0] data_47_i, 


あたり正しくありたせん。 実際には、デヌタだけでなく、各デヌタストリヌム読み取り、ポヌトごずに1぀ではなく耇数の信号が存圚する専甚のむンタヌフェむスが必芁です。

魂はこのようなこずを曞くように求めたす

 module simple_mux #( parameter D_WIDTH = 8, parameter PORT_CNT = 48, // internal param parameter SEL_WIDTH = $clog2( PORT_CNT ) ) ( input [D_WIDTH-1:0] data_i [PORT_CNT-1:0], input [SEL_WIDTH-1:0] sel_i, output [D_WIDTH-1:0] data_o ); assign data_o = data_i[ sel_i ]; endmodule 


ただし、モゞュヌルポヌトでのアレむの䜿甚は、IEEE 1364-2001暙準Verilog-2001に぀いお説明されおいたす では蚱可されおいたせん 。

そのため、たずえば、 Quartusは次の゚ラヌを生成したす。
Error (10773): Verilog HDL error: declaring module ports or function arguments with unpacked array types requires SystemVerilog extensions


どうする

非衚瀺のテキスト
SystemVerilogを䜿甚したす。
非衚瀺のテキスト
:)



考えられる回避策の1぀がStackOverflowで怜蚎されおいたす。 アむデアは機胜しおいたすが、蚘事はそれに぀いおではありたせん:)

もちろん、ハンドルをあきらめお必芁なワむダを䜜るこずができたすが、マシンがこれを行う方が良いです
Jinja2テンプレヌト゚ンゞンのTemplateクラスを䜿甚したす

  t = Template(u""" module {{name}} #( parameter D_WIDTH = 8 ) ( {%- for p in ports %} input [D_WIDTH-1:0] data_{{p}}_i, {%- endfor %} input [{{sel_width-1}}:0] sel_i, output [D_WIDTH-1:0] data_o ); always @(*) begin case( sel_i ) {% for p in ports %} {{sel_width}}'d{{p}}: begin data_o = data_{{p}}_i; end {% endfor %} endcase end endmodule """) print t.render( n = 4, sel_width = 2, name = "simple_mux_4habr", ports = range( 4 ) ) 


モゞュヌルテンプレヌトを䜜成し、耇補に必芁なものを説明するために䜿甚し 、必芁なパラメヌタヌポヌトの数、モゞュヌル名などを枡しおrenderをプルしたした。 {{}}を䜿甚するこれらのパラメヌタヌはテンプレヌトで䜿甚でき、目的の堎所に倉数を挿入できたす。

出力は玠晎らしいモゞュヌルでした
非衚瀺のテキスト
 module simple_mux_4habr #( parameter D_WIDTH = 8 ) ( input [D_WIDTH-1:0] data_0_i, input [D_WIDTH-1:0] data_1_i, input [D_WIDTH-1:0] data_2_i, input [D_WIDTH-1:0] data_3_i, input [1:0] sel_i, output [D_WIDTH-1:0] data_o ); always @(*) begin case( sel_i ) 2'd0: begin data_o = data_0_i; end 2'd1: begin data_o = data_1_i; end 2'd2: begin data_o = data_2_i; end 2'd3: begin data_o = data_3_i; end endcase end endmodule 



矎しさは、倉数ずしお枡すこずができるのは数字や文字列だけでなく、Pythonタむプシヌト、蟞曞、クラスのオブゞェクトであり、Pythonコヌドず同じ方法でテンプレヌトにアクセスできるこずです。 たずえば、蟞曞芁玠の呌び出しは次のようになりたす。
 {{ foo['bar'] }} 


もちろん、これは単玔な䟋であり、おそらくperl / sed / awkなどを䜿甚しお実行できたす。

Jinjaに぀いお読んで、簡単な䟋で遊んでみたずき、もっず深刻なこずに䜿甚できるのではないかず思いたした。 FPGAの開発で発生する1぀の問題を思い出したしたが、これは十分に自動化されおいるようです。 このタスクをスムヌズに進めるために、開発の構成に぀いお少し説明したす。

IPコア


ASIC / FPGAの迅速な開発の基瀎は、IPコアずしお蚭蚈された既補のコヌドの䜿甚であるず考えられおいたす。 詳现に入るこずなく、IPコアはラむブラリであるず想定できたす。

アむデアは、すべおのファヌムりェアがIPコアに分割され、それが自分で曞き蟌たれるか、賌入されお盗たれたり、 クラックされたり、暙準むンタヌフェむスAXIやAvalonなどを䜿甚しお接続されるこずです。 接続は、ハンドルたたはGUIアプリケヌションの助けを借りお行うこずができたす。GUIアプリケヌションでは、必芁なカヌネルをクリックしおマりスで接続できたす。 たずえば、 Quartusに付属するQsysです。

このアプロヌチの利点は明らかです。


マむナス面の1぀は、暙準むンタヌフェむスを介しお接続するためのオヌバヌヘッドがあるずいう事実です。これは、より倚くのコヌドたたはより倚くのリ゜ヌスセルを占有する可胜性がありたす。

各コアには、 CSRステヌタスレゞスタのセットがありたす。

ほずんどの堎合、それらは単語たずえば32ビットに埓っおグルヌプ化され、内郚ではフィヌルドによっお分割されたす。フィヌルドは異なる動䜜モヌドを持぀こずができたす。


同じレゞスタ内にはいく぀かのフィヌルドがあり、それらの動䜜モヌドは異なる堎合がありたす。

単玔なI2C゚クスパンダヌからトランシヌバヌ、さらにはネットワヌクカヌドに至るたで、さたざたなチップのCSRもありたす。

トップレベルのプログラマヌはどのように芋えたすか
アルテラのトリプルスピヌドむヌサネット MACコントロヌラを怜蚎しおください。 ドキュメントを開いお「 構成レゞスタ空間 」の章に進むず、カヌネルを制埡し、その状態に関する情報受信/送信パケットのカりンタヌなどを受信できるすべおのレゞスタのリストが衚瀺されたす。

レゞスタが説明されおいる衚の䞀郚を瀺したす。
画像

ずころで、これらの行を読み取らせるパケットがこのIPコアを通過する可胜性がありたす。

たずえば、このカヌネルのレゞスタ0x03および0x04は、MACアドレスの蚭定を担圓したす。 䞀郚のカヌネルザむリンクスたたはIntel補では、他のレゞスタを䜿甚できたす。

ドラむバの MACアドレスの倉曎は次のずおりです 。

 static void tse_update_mac_addr(struct altera_tse_private *priv, u8 *addr) { u32 msb; u32 lsb; msb = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0]; lsb = ((addr[5] << 8) | addr[4]) & 0xffff; /* Set primary MAC address */ csrwr32(msb, priv->mac_dev, tse_csroffs(mac_addr_0)); csrwr32(lsb, priv->mac_dev, tse_csroffs(mac_addr_1)); } 


mac_addr_0ずmac_addr_1は0x03ず0x04にすぎず、これらは非垞にトリッキヌです私の䞻芳的な意芋では、ドラむバヌではこれが正垞であるず想定しおいたすが、隣接するヘッダヌファむルで定矩されおいたす 。

IPコアの開発者は、すべおのCSRを説明するドキュメントを提䟛し、同様に、䜕を、どのように、どの順序で構成するかを説明したす。 このドキュメントは高レベルのプログラマヌに枡され、 tse_update_mac_addrに䌌た関数を䜜成し、すべお機胜するようにしたす:)

マルチコアシステム


倚くの堎合、1぀のコアによっおもたらされるタスクは解決できたせん。システムにはそれらのいく぀かがありたす。
管理むンタヌフェむスを1぀のバスに接続しお、各コアに独自のアドレススペヌスを割り圓おるこずができたす。

䞊䜍レベルがカヌネルBレゞスタを0x03に曞き蟌む必芁がある堎合、アドレス0x0103でトランザクションを実行する必芁がありたす。 簡単にするために、アドレスはバむトではなく、単語に埓っおいるず考えおいたす。実際には、バむトアドレスで曞き蟌む必芁があるこずが刀明する堎合がありたす。その埌、32ビットレゞスタのリク゚ストは0x010Cのトランザクションになりたす。

画像

マスタヌCPUARM / x86たたはMCU、たたは他の䞀般的なIPコアは、管理むンタヌフェむスを介しお、読み取りたたは曞き蟌みトランザクションを実行したす。 IPコア管理むンタヌフェむスは、倚くの堎合、暙準AXIたたはAvalonのいずれかに埓っお行われたす。

耇数のスレヌブがある堎合、むンタヌコネクトモゞュヌルマルチプレクサたたはバスアヌビタヌが衚瀺されたす。 そのタスクは、マスタヌからのリク゚ストを受け入れ、このリク゚ストの送信先を確認するこずです。これは、スレヌブが応答しおいる間などにバスを保持できるなどの方法です。 したがっお、このモゞュヌルの前は、リク゚ストアドレスは0x0103でしたが、その埌は-0x0003でした。 IPコアは、どのアドレススペヌスが割り圓おられおいるかを認識しおいたせん認識すべきではない。

特定のIPコアを分解したす問題を瀺したす


IPコアの内郚には、これらすべおのレゞスタを含むモゞュヌルがあり、それらをIPコアの内郚にあるが倖郚からは芋えないモゞュヌルを制埡するための信号セットに倉換する必芁がありたす。

指で話さないようにするために、むヌサネットパケットゞェネレヌタヌの非垞に単玔な抜象的なIPコアを怜蚎したす。これは、たずえば枬定 機噚で䜿甚できたす。

このカヌネルにこれらのレゞスタを持たせおください
 0x0: [7:0] - IP_CORE_VERSION [RO] -  IP- [15:8] - Reserved [16] - GEN_EN [RW] -   [17] - GEN_ERROR [ROLH] -     [30:18] - Reserved [31] - GEN_RESET [RWSC] -   0x1: [31:0] - IP_DST [RW] - IP-   0x2: [15:0] - FRM_SIZE [RW] -   [31:16] - Reserved 0x3: [31:0] - FRM_CNT [RO] -    


IPコア自䜓は次のようになりたす。
画像

csr_mapモゞュヌルは、暙準むンタヌフェむスを、䞻芁なカヌネル機胜を実行するtraffic_generatorモゞュヌルの制埡信号のセットに「倉換」する圹割を果たしたす。 もちろん、IPコアが2぀のモゞュヌルのみで構成されるこずはほずんどありたせん。ほずんどの堎合、制埡信号はIPコア内の耇数のモゞュヌルに配信されたす。

私が䜕を埗おいるかを掚枬しおください
これらのレゞスタの説明からこのcsr_mapを自動的に生成するこずは可胜ですか

実際には、玄100のレゞスタが存圚する可胜性があり、これが自動化されおいる堎合は、次のようになりたす。


問題を解決する


レゞスタずビットフィヌルドによっお情報を栌玍するための2぀のプリミティブクラスを䜜成したす。
 class Reg( ): def __init__( self, num, name ): self.num = '{:X}'.format( num ) self.name = name self.name_lowcase = self.name.lower() self.bits = [] def add_bits( self, reg_bits ): self.bits.append( reg_bits ) class RegBits( ): def __init__( self, bit_msb, bit_lsb, name, mode = "RW", init_value = 0 ): self.bit_msb = bit_msb self.bit_lsb = bit_lsb self.width = bit_msb - bit_lsb + 1 self.name = name self.name_lowcase = self.name.lower() self.mode = mode self.init_value = '{:X}'.format( init_value ) # bit modes: # RO - read only # RO_CONST - read only, constant value # RO_LH - read only, latch high # RO_LL - read only, latch low # RW - read and write # RW_SC - read and write, self clear assert self.mode in ["RO", "RO_CONST", "RO_LH", "RO_LL", "RW", "RW_SC" ], "Unknown bit mode" if self.mode in ["RO_LH", "RO_LL", "RW_SC"]: assert self.width == 1, "Wrong width for this bit mod" self.port_signal_input = self.mode in ["RO", "RO_LH", "RO_LL"] self.port_signal_output = self.mode in ["RW", "RW_SC"] self.need_port_signal = self.port_signal_input or self.port_signal_output 


これらのクラスを䜿甚しお、CSR蚘述を䜜成したす。
  MODULE_NAME = "trafgen_map_4habr" r0 = Reg( 0x0, "MAIN") r0.add_bits( RegBits( 7, 0, "IP_CORE_VERSION", "RO_CONST", 0x7 ) ) r0.add_bits( RegBits( 16, 16, "GEN_EN" , "RW" ) ) r0.add_bits( RegBits( 17, 17, "GEN_ERROR", "RO_LH" ) ) r0.add_bits( RegBits( 31, 31, "GEN_RESET", "RW_SC" ) ) r1 = Reg( 0x1, "IP_DST" ) # let ip destination in reset will be 178.248.233.33 ( habrahabr.ru ) r1.add_bits( RegBits( 31, 0, "IP_DST", "RW", 0xB2F8E921 ) ) r2 = Reg( 0x2, "FRM_SIZE" ) r2.add_bits( RegBits( 15, 0, "FRM_SIZE", "RW", 64 ) ) r3 = Reg( 0x3, "FRM_CNT" ) r3.add_bits( RegBits( 31, 0, "FRM_CNT", "RO" ) ) reg_l = [r0, r1, r2, r3] 


テンプレヌト自䜓は次のようになりたす。
非衚瀺のテキスト
 csr_map_template = Template(u""" {%- macro reg_name( r ) -%} reg_{{r.num}}_{{r.name_lowcase}} {%- endmacro %} {%- macro reg_name_bits( r, b ) -%} reg_{{r.num}}_{{r.name_lowcase}}___{{b.name_lowcase}} {%- endmacro %} {%- macro bit_init_value( b ) -%} {{b.width}}'h{{b.init_value}} {%- endmacro %} {%- macro signal( width ) -%} [{{width-1}}:0] {%- endmacro %} {%- macro print_port_signal( dir, width, name, eol="," ) -%} {{ " %-12s %-10s %-10s" | format( dir, signal( width ), name+eol ) }} {%- endmacro %} {%- macro get_port_name( b ) -%} {%- if b.port_signal_input -%} {{b.name_lowcase}}_i {%- else -%} {{b.name_lowcase}}_o {%- endif -%} {%- endmacro -%} // Generated using CSR map generator // https://github.com/johan92/csr-map-generator module {{module_name}}( {%- for p in data %} // Register {{p.name}} signals {%- for b in p.bits %} {%- if b.port_signal_input %} {{print_port_signal( "input", b.width, get_port_name( b ) )}} {%- elif b.port_signal_output %} {{print_port_signal( "output", b.width, get_port_name( b ) )}} {%- endif %} {%- endfor %} {% endfor %} // CSR interface {{print_port_signal( "input", 1, "reg_clk_i" ) }} {{print_port_signal( "input", 1, "reg_rst_i" ) }} {{print_port_signal( "input", reg_d_w, "reg_wr_data_i" ) }} {{print_port_signal( "input", 1, "reg_wr_en_i" ) }} {{print_port_signal( "input", 1, "reg_rd_en_i" ) }} {{print_port_signal( "input", reg_a_w, "reg_addr_i" ) }} {{print_port_signal( "output", reg_d_w, "reg_rd_data_o", "" ) }} ); {%- for p in data %} // ****************************************** // Register {{p.name}} // ****************************************** logic [{{reg_d_w-1}}:0] {{reg_name( p )}}_read; {%- for b in p.bits %} {%- if b.mode != "RO" %} logic [{{b.width-1}}:0] {{reg_name_bits( p, b )}} = {{bit_init_value( b )}}; {%- endif %} {%- endfor %} {% for b in p.bits %} {%- if b.port_signal_output %} always_ff @( posedge reg_clk_i or posedge reg_rst_i ) if( reg_rst_i ) {{reg_name_bits( p, b )}} <= {{bit_init_value( b )}}; else if( reg_wr_en_i && ( reg_addr_i == {{reg_a_w}}'h{{p.num}} ) ) {{reg_name_bits( p, b )}} <= reg_wr_data_i[{{b.bit_msb}}:{{b.bit_lsb}}]; {%-if b.mode == "RW_SC" %} else {{reg_name_bits( p, b )}} <= {{bit_init_value( b )}}; {% endif %} {%- endif %} {%- if b.mode == "RO_LH" or b.mode == "RO_LL" %} always_ff @( posedge reg_clk_i or posedge reg_rst_i ) if( reg_rst_i ) {{reg_name_bits( p, b )}} <= {{bit_init_value( b )}}; else begin if( reg_rd_en_i && ( reg_addr_i == {{reg_a_w}}'h{{p.num}} ) ) {{reg_name_bits( p, b )}} <= {{bit_init_value( b )}}; {% if b.mode == "RO_LL" %} if( {{get_port_name( b )}} == 1'b0 ) {{reg_name_bits( p, b )}} <= 1'b0; {%- elif b.mode == "RO_LH" %} if( {{get_port_name( b )}} == 1'b1 ) {{reg_name_bits( p, b )}} <= 1'b1; {%- endif %} end {% endif %} {% endfor %} // assigning to output {%- for b in p.bits %} {%- if b.port_signal_output %} assign {{get_port_name( b )}} = {{reg_name_bits( p, b )}}; {%- endif %} {%- endfor %} {%- macro print_in_always_comb( r, b, _right_value ) -%} {%- if b == "" -%} {{ " %s%-7s = %s;" | format( reg_name( r ) + "_read", "", _right_value ) }} {%- else -%} {{ " %s%-7s = %s;" | format( reg_name( r ) + "_read", "["+b.bit_msb|string+":"+b.bit_lsb|string+"]" , _right_value ) }} {%- endif -%} {%- endmacro %} // assigning to read data always_comb begin {{print_in_always_comb( p, "", reg_d_w|string+"'h0" ) }} {%- for b in p.bits %} {%- if b.mode == "RO" %} {{print_in_always_comb( p, b, get_port_name( b ) )}} {%- else %} {{print_in_always_comb( p, b, reg_name_bits( p, b ) )}} {%- endif %} {%- endfor %} end {%- endfor %} // ****************************************** // Reading stuff // ****************************************** logic [{{reg_d_w-1}}:0] reg_rd_data = {{reg_d_w}}'h0; always_ff @( posedge reg_clk_i or posedge reg_rst_i ) if( reg_rst_i ) reg_rd_data <= {{reg_d_w}}'h0; else if( reg_rd_en_i ) begin case( reg_addr_i ) {% for p in data %} {{reg_a_w}}'h{{p.num}}: begin reg_rd_data <= {{reg_name( p )}}_read; end {% endfor %} default: begin reg_rd_data <= {{reg_d_w}}'h0; end endcase end assign reg_rd_data_o = reg_rd_data; endmodule """) 



テンプレヌト生成を匕き出したす
  res = csr_map_template.render( module_name = MODULE_NAME, reg_d_w = 32, reg_a_w = 8, data = reg_l ) 


そのようなモゞュヌルがありたす
非衚瀺のテキスト
 // Generated using CSR map generator // https://github.com/johan92/csr-map-generator module trafgen_map_4habr( // Register MAIN signals output [0:0] gen_en_o, input [0:0] gen_error_i, output [0:0] gen_reset_o, // Register IP_DST signals output [31:0] ip_dst_o, // Register FRM_SIZE signals output [15:0] frm_size_o, // Register FRM_CNT signals input [31:0] frm_cnt_i, // CSR interface input [0:0] reg_clk_i, input [0:0] reg_rst_i, input [31:0] reg_wr_data_i, input [0:0] reg_wr_en_i, input [0:0] reg_rd_en_i, input [7:0] reg_addr_i, output [31:0] reg_rd_data_o ); // ****************************************** // Register MAIN // ****************************************** logic [31:0] reg_0_main_read; logic [7:0] reg_0_main___ip_core_version = 8'h7; logic [0:0] reg_0_main___gen_en = 1'h0; logic [0:0] reg_0_main___gen_error = 1'h0; logic [0:0] reg_0_main___gen_reset = 1'h0; always_ff @( posedge reg_clk_i or posedge reg_rst_i ) if( reg_rst_i ) reg_0_main___gen_en <= 1'h0; else if( reg_wr_en_i && ( reg_addr_i == 8'h0 ) ) reg_0_main___gen_en <= reg_wr_data_i[16:16]; always_ff @( posedge reg_clk_i or posedge reg_rst_i ) if( reg_rst_i ) reg_0_main___gen_error <= 1'h0; else begin if( reg_rd_en_i && ( reg_addr_i == 8'h0 ) ) reg_0_main___gen_error <= 1'h0; if( gen_error_i == 1'b1 ) reg_0_main___gen_error <= 1'b1; end always_ff @( posedge reg_clk_i or posedge reg_rst_i ) if( reg_rst_i ) reg_0_main___gen_reset <= 1'h0; else if( reg_wr_en_i && ( reg_addr_i == 8'h0 ) ) reg_0_main___gen_reset <= reg_wr_data_i[31:31]; else reg_0_main___gen_reset <= 1'h0; // assigning to output assign gen_en_o = reg_0_main___gen_en; assign gen_reset_o = reg_0_main___gen_reset; // assigning to read data always_comb begin reg_0_main_read = 32'h0; reg_0_main_read[7:0] = reg_0_main___ip_core_version; reg_0_main_read[16:16] = reg_0_main___gen_en; reg_0_main_read[17:17] = reg_0_main___gen_error; reg_0_main_read[31:31] = reg_0_main___gen_reset; end // ****************************************** // Register IP_DST // ****************************************** logic [31:0] reg_1_ip_dst_read; logic [31:0] reg_1_ip_dst___ip_dst = 32'hB2F8E921; always_ff @( posedge reg_clk_i or posedge reg_rst_i ) if( reg_rst_i ) reg_1_ip_dst___ip_dst <= 32'hB2F8E921; else if( reg_wr_en_i && ( reg_addr_i == 8'h1 ) ) reg_1_ip_dst___ip_dst <= reg_wr_data_i[31:0]; // assigning to output assign ip_dst_o = reg_1_ip_dst___ip_dst; // assigning to read data always_comb begin reg_1_ip_dst_read = 32'h0; reg_1_ip_dst_read[31:0] = reg_1_ip_dst___ip_dst; end // ****************************************** // Register FRM_SIZE // ****************************************** logic [31:0] reg_2_frm_size_read; logic [15:0] reg_2_frm_size___frm_size = 16'h40; always_ff @( posedge reg_clk_i or posedge reg_rst_i ) if( reg_rst_i ) reg_2_frm_size___frm_size <= 16'h40; else if( reg_wr_en_i && ( reg_addr_i == 8'h2 ) ) reg_2_frm_size___frm_size <= reg_wr_data_i[15:0]; // assigning to output assign frm_size_o = reg_2_frm_size___frm_size; // assigning to read data always_comb begin reg_2_frm_size_read = 32'h0; reg_2_frm_size_read[15:0] = reg_2_frm_size___frm_size; end // ****************************************** // Register FRM_CNT // ****************************************** logic [31:0] reg_3_frm_cnt_read; // assigning to output // assigning to read data always_comb begin reg_3_frm_cnt_read = 32'h0; reg_3_frm_cnt_read[31:0] = frm_cnt_i; end // ****************************************** // Reading stuff // ****************************************** logic [31:0] reg_rd_data = 32'h0; always_ff @( posedge reg_clk_i or posedge reg_rst_i ) if( reg_rst_i ) reg_rd_data <= 32'h0; else if( reg_rd_en_i ) begin case( reg_addr_i ) 8'h0: begin reg_rd_data <= reg_0_main_read; end 8'h1: begin reg_rd_data <= reg_1_ip_dst_read; end 8'h2: begin reg_rd_data <= reg_2_frm_size_read; end 8'h3: begin reg_rd_data <= reg_3_frm_cnt_read; end default: begin reg_rd_data <= 32'h0; end endcase end assign reg_rd_data_o = reg_rd_data; endmodule 



ご芧のように、アむデアはうたくいきたした簡単なテキストの説明から本栌的なモゞュヌルが登堎したした。手䜜業で仕䞊げる必芁はありたせん-すぐに生産に移すこずができたす

管理むンタヌフェヌスずしお、類䌌性Avalon-MMが䜿甚されたした 。

たずめ


ほんの数日前に、Ginhubで実装された 1Gおよび10G MACコアずUDP / IPスタックを芋たずきに、 Jinja2に出䌚いたした。 ちなみに、それはうたく曞かれおいたしたが、私はかなり衚面的に、シミュレヌションで芋えたした。

著者は、Jinja2を䜿甚しお、たずえばNポヌトマルチプレクサヌAXI4-Streamなどのさたざたなモゞュヌルを生成したす。 このマルチプレクサは、この蚘事の冒頭で曞いたものよりもはるかに耇雑です。

私はcsr_mapを生成するためのスクリプトを急いで投げお、 Jinja2の機胜を感じたしたただし、その䞀郚を感謝しおいるず思いたす。コヌド。

もちろん、このスクリプトは未加工であり、ただ開発には䜿甚しおいたせんさたざたな理由でIPコアの矎しいアヌキテクチャが矎しいアヌキテクチャのたたであるこずがあるため、䜿甚するかどうかさえわかりたせん。

゜ヌスコヌドをgithubに完党にアップロヌドしたした。 このテンプレヌトが誰かに圹立぀堎合、私は喜んでいたすリク゚ストに応じお改善するか、誰かのプルリク゚ストを受け入れる準備ができおいたす

ご枅聎ありがずうございたした 質問がある堎合は、間違いなく質問しおください。

非衚瀺のテキスト
もちろん、FPGAハブが時蚈に移動されたこずは残念です。

Source: https://habr.com/ru/post/J263005/


All Articles