Emacsには標準でVerliog-modeというものが付いており、Verilog-HDLのいろんな部分を自動生成してくれる。
僕が最も気に入っている機能は、サブモジュールを自動的にインスタンス化してくれる機能だ。
pulsar2_top #(/*AUTOINSTPARAM*/) pulsar2_top_0 (/*AUTOINST*/
このように、AUTOINST, AUTOINSTPARAMという文字を記述しておき、C-c C-aとすると、
pulsar2_top #(/*AUTOINSTPARAM*/) pulsar2_top_0 (/*AUTOINST*/ // Outputs .IF_MARADDR (IF_MARADDR[31:0]), .IF_MARBURST (IF_MARBURST[1:0]), .IF_MARCACHE (IF_MARCACHE[3:0]), .IF_MARID (IF_MARID[axi_id_width-1:0]), .IF_MARLEN (IF_MARLEN[7:0]), .IF_MARLOCK (IF_MARLOCK), .IF_MARPROT (IF_MARPROT[2:0]), .IF_MARQOS (IF_MARQOS[3:0]), .IF_MARSIZE (IF_MARSIZE[2:0]), .IF_MARVALID (IF_MARVALID), .IF_MRREADY (IF_MRREADY), .RN_BUSY (RN_BUSY), .RN_CTRL_0 (RN_CTRL_0[`INST_CTRL_B]), .RN_CTRL_1 (RN_CTRL_1[`INST_CTRL_B]), .RN_CTRL_2 (RN_CTRL_2[`INST_CTRL_B]), .RN_CTRL_3 (RN_CTRL_3[`INST_CTRL_B]), ...
このように、自動的にポートを生成してくれる。このポート線は、デフォルトだとポート信号名と同じ名前になっているのだが、正規表現を記述することで、任意の信号線名に切り替えることが可能だ。 これは、AUTO_TEMPLATE識別子によって可能だ。例えば、
/* mips_ctrl AUTO_TEMPLATE "\([0-9]+\)$" ( .IF_INST_DEC (id0_inst_dec_w_@[]), .\(IF_INST_CTRL\) (id0_inst_ctrl_w_@[]), .\(IF_INST_TYPE\) (id0_inst_type_w_@[]), .\(IF_DST_ADDR\) (id0_dst_addr_w_@[]), .\(IF_R1_ADDR\) (id0_r1_addr_w_@[]), .\(IF_R2_ADDR\) (id0_r2_addr_w_@[]), .\(IF_IMM\) (id0_imm_w_@[]), )*/ mips_ctrl mips_ctrl_0 (/*AUTOINST*/ // Outputs .IF_INST_TYPE (id0_inst_type_w_0[`INST_TYPE_W-1:0]), // Templated .IF_INST_CTRL (id0_inst_ctrl_w_0[`INST_CTRL_W-1:0]), // Templated .IF_DST_ADDR (id0_dst_addr_w_0[`REGADDR_W-1:0]), // Templated .IF_R1_ADDR (id0_r1_addr_w_0[`REGADDR_W-1:0]), // Templated .IF_R2_ADDR (id0_r2_addr_w_0[`REGADDR_W-1:0]), // Templated .IF_IMM (id0_imm_w_0[`WORD_B]), // Templated // Inputs .IF_INST_DEC (id0_inst_dec_w_0[`INST_MAX-1:0])); // Templated
このように書くことにより、IF_INST_CTRLに接続されている信号線名がid0_inst_ctrl_w_0に変換されている。正規表現を記述することができ、@は、インスタンスの最後に識別されている名前に相当する。 ここでは、
"\([0-9]+\)$"
に相当し、mips_ctrl_0 の "0"の部分に相当する。
さて、これを使えば、ポートに接続される信号をさまざまに制御可能だが、例えば、3つのインスタンスから入ってくる信号を並べてポートに挿入するためにはどうしたらいいんだろう。 つまり、やりたいことは、XilinxのCrossbarインスタンスに対して、
module ( .A ({signal2[2:0], signal1[2:0], signal0[2:0]}), .B ({en2, en1, en0}) );
というような接続を正規表現で記載したい。ここで考えなければいけないのは、ビット幅をどのように記述するか、ということだ。
現在のビット幅を、3分割する
Verilog-Modeでは、自分のポートのビット幅は、vl-widthで取得できる。ただし、問題なのはこいつが、文字列として生成されていることだ。だから、このビット幅を3分割したければ、(string-to-integer)を利用しなければならない。
(string-to-number vl-width)
ビット幅が3であれば、(分割後は1ビットになるので、)ビット幅を表示しない。
これも結局、lispのif文で記載している。
(if (not (= 3 (string-to-number vl-width))) (concat \\"[\\" (...
この結果、長いが、1ポートを記述する正規表現は以下で生成することになる。
{axi_dw_\1@"(if (not (= 3 (string-to-number vl-width))) (concat \\"[\\" (concat (number-to-string (- (/ (string-to-number vl-width) 3) 1)) \\":0]\\")))"}
Verilog-modeの性質上、1行に書かなければならないため面倒だが、実際には、以下のようになる。
(if (not (= 3 (string-to-number vl-width))) (concat \\"[\\" (concat (number-to-string (- (/ (string-to-number vl-width) 3) 1)) \\":0]\\")) )
このようにすると、
module ( .axi_dw_awdata ({axi_dw_awdata[31:0}), .axi_dw_awready ({axi_dw_awready}), ... );
というものが生成されるため、これを3ポート文並べる。長い!
.s_axi_\(.*\) ({axi_dw_\1@"(if (not (= 3 (string-to-number vl-width))) (concat \\"[\\" (concat (number-to-string (- (/ (string-to-number vl-width) 3) 1)) \\":0]\\")))", axi_dr_\1@"(if (not (= 3 (string-to-number vl-width))) (concat \\"[\\" (concat (number-to-string (- (/ (string-to-number vl-width) 3) 1)) \\":0]\\")))", axi_if_\1@"(if (not (= 3 (string-to-number vl-width))) (concat \\"[\\" (concat (number-to-string (- (/ (string-to-number vl-width) 3) 1)) \\":0]\\")))"}),
これで、以下のようなポートが生成できるようになった。
pulsar1_connect #(/*AUTOINSTPARAM*/) pulsar1_connect_0 (/*AUTOINST*/ // Outputs .s_axi_awready ({axi_dw_awready, axi_dr_awready, axi_if_awready}), // Templated .s_axi_wready ({axi_dw_wready, axi_dr_wready, axi_if_wready}), // Templated .s_axi_bid ({axi_dw_bid[3:0], axi_dr_bid[3:0], axi_if_bid[3:0]}), // Templated .s_axi_bresp ({axi_dw_bresp[1:0], axi_dr_bresp[1:0], axi_if_bresp[1:0]}), // Templated .s_axi_bvalid ({axi_dw_bvalid, axi_dr_bvalid, axi_if_bvalid}), // Templated .s_axi_arready ({axi_dw_arready, axi_dr_arready, axi_if_arready}), // Templated .s_axi_rid ({axi_dw_rid[3:0], axi_dr_rid[3:0], axi_if_rid[3:0]}), // Templated .s_axi_rdata ({axi_dw_rdata[127:0], axi_dr_rdata[127:0], axi_if_rdata[127:0]}), // Templated .s_axi_rresp ({axi_dw_rresp[1:0], axi_dr_rresp[1:0], axi_if_rresp[1:0]}), // Templated .s_axi_rlast ({axi_dw_rlast, axi_dr_rlast, axi_if_rlast}), // Templated .s_axi_rvalid ({axi_dw_rvalid, axi_dr_rvalid, axi_if_rvalid}), // Templated
3つのポートを接続して、並べている。それぞれ、AXIのDW,DR,IFのポートを接続して、Crossbarに突っ込んだ形だ。