Intellectual Highwayでは、東京工業大学で開発され、新システムビジョン研究開発機構(NSV)
によって提供されているC/C++によるRTL設計技術(C2RTL技術)を活用して短期間でのIPコア開発を実現しています。

C2RTLとは

東工大(一色研究室)で開発されたC2RTLは、C/C++言語によるRTL記述を可能にする技術です。
C/C++で記述されたソースコードから、論理合成可能なVerilogコード、Verilogコードと等価なC言語のシミュレーションモデル、テストベンチを同時に生成します。
設計した回路に対してテストベンチをverilogで記述し、RTLシミュレーションによる検証、実機デバッグを行っていた従来の開発手法に比べ、C2RTLを使えばIPコア、SoCの開発効率を飛躍的に向上させることができます。

C2RTLの特徴

  • C/C++記述

    ソフトウェアによる抽象度の高い記述、高い再利用性、柔軟なパラメータ化が可能です。C/C++言語で記述する一般的な高位合成とは異なり、RTL記述をそのままC/C++で表現する形式であるためHW回路の性能を最大限引き出すことができます。

  • プロセッサ・SoC設計に有効

    C2RTLはプロセッサの挙動のパイプライン化を自動で行えるため、非常に簡単にプロセッサ設計が行えます。またC2RTLはIPコア単体の設計だけでなく、C2RTLで開発された複数のIPコアを組み合わせるSoCの設計にも利用することができます。

  • 高速開発

    C2RTLにより生成される等価Cモデルは、C言語で記述されているため高速にサイクル精度シミュレーションが可能です。
    等価Cモデルによるシミュレーションでは、既存のソフトウェア用ツールを利用して開発生産性を向上させることができます。

C2RTLのコード記述例

FIFOのRTLを生成するコードの例です。
このコードでは、インスタンス化時にFIFOの段数と、ユーザが定義した構造体を型パラメータとして使用できます。
このように、verilog(System Verilog)やVHDLで記述するよりも、継承, テンプレート, コンパイル時処理関数, 型推論といった、C++の強力な抽象化表現を使うことが出来るため、少ないコード量で、非常に再利用性の高いモジュールを作ることが出来ます。
また、高位合成機能(High Level Synthesis)とは異なり、サイクルレベル・レジスタ転送レベルの制御をダイレクトに記述するため、意図しない遅延や並列回路が発生することもありません。

template <typename T>
struct FifoIF {
  BIT ren;
  BIT wen;
  BIT empty;
  BIT full;
  T din;
  T dout;
} _TYPE(direct_signal);

template <typename T>
class FifoL {
private:
  T dbuf[depth] _TYPE(state);
  UintxType ridx _BWT(idx_w) _TYPE(state); // current read index
  UintxType widx _BWT(idx_w) _TYPE(state); // current write index

public:
  void run(FifoIF<T>& fifo_if) {
    BIT empty = (ridx == widx) ? 1 : 0;
    BIT full = ((ridx ^ widx) == depth) ? 1 : 0;
    fifo_if.empty = empty;
    fifo_if.full = full;

    int oidx = ridx & C2R_MAXVAL((idx_w - 1));
    fifo_if.dout = dbuf[oidx];
    if (fifo_if.ren == 1 & empty) {
      ridx = (ridx + 1) & (C2R_MAXVAL(idx_w));
    }
    if (fifo_if.wen == 1 & full) {
      int iidx = widx & C2R_MAXVAL((idx_w - 1));
      dbuf[iidx] = fifo_if.din;
      widx = (widx + 1) & (C2R_MAXVAL(idx_w));
    }
  }
};

インスタンス化コード

struct DataSt {
  BIT flag;
  unsigned short data;
};

_C2R_FUNC(1)
void Sfifo(FifoIF<DataSt>& fifo_if) {
  static FifoL<DataSt, 4> inst;
  inst.run(fifo_if);
}

0.4秒ほどのコンパイル時間で、以下のようなRTLが生成されます。

module Sfifo_no_mem   (
    /* global inputs*/
    clk, rst_n,

    /*inputs*/
    G_fifo_if_ren, G_fifo_if_wen, G_fifo_if_din_flag, G_fifo_if_din_data, 

    /*outputs*/
    G_fifo_if_empty, G_fifo_if_full, G_fifo_if_dout_flag, G_fifo_if_dout_data, 

    /*probes*/
    _prb_Sfifo_pSetup

  );
  parameter M_ID = 0; // module ID

  
  /*input ports*/
  input        clk;
  input        rst_n;
  input        G_fifo_if_ren     ; /// <0,1> [U1]     ;
  input        G_fifo_if_wen     ; /// <0,1> [U1]     ;
  input        G_fifo_if_din_flag; /// <0,1> [U1]     ;
  input [15:0] G_fifo_if_din_data; /// <0,65535> [U16];

  /*output ports*/
  output       G_fifo_if_empty    ; /// <0,1> [U1]     ;
  output       G_fifo_if_full     ; /// <0,1> [U1]     ;
  output       G_fifo_if_dout_flag; /// <0,1> [U1]     ;
  output[15:0] G_fifo_if_dout_data; /// <0,65535> [U16];

  /*probe ports*/
  output       _prb_Sfifo_pSetup;

  wire      ROOT_CP = 1'b1; /// root control path (always active)

  wire      Sfifo_pSetup = 1'b1; /// pipeStageCount = 1

  reg       G_Sfifo_inst_dbuf_0_flag;
  reg[15:0] G_Sfifo_inst_dbuf_0_data;
  reg       G_Sfifo_inst_dbuf_1_flag;
  reg[15:0] G_Sfifo_inst_dbuf_1_data;
  reg       G_Sfifo_inst_dbuf_2_flag;
  reg[15:0] G_Sfifo_inst_dbuf_2_data;
  reg       G_Sfifo_inst_dbuf_3_flag;
  reg[15:0] G_Sfifo_inst_dbuf_3_data;
  reg[ 1:0] G_Sfifo_inst_ridx, G_Sfifo_inst_widx;



  //// pipe-stage(1) : combinational-logic...

wire       I_run_B1_9          = G_Sfifo_inst_ridx/*prv*/[0]/*&1'h1*/    ; //  (comb-Out)  [F0<0>,B4<0>] <0,1> [U1] P1(./SfifoReg.hpp:L28)
wire       N_07                = I_run_B1_9 & 1'h1                       ; //  (comb-Out)  [F0<0>,B4<0>] <0,1> [U1] P1(./SfifoReg.hpp:L29)
wire       N_40                = ! N_07                                  ; //  (comb-Out)  [F0<0>,B3<0>] <0,1> [U1] P1(./SfifoReg.hpp:L29)
wire       N_41         = (N_40) ? G_Sfifo_inst_dbuf_0_flag/*prv*/ : 1'h0; //  (comb-Out) (L1,A1) [F1<0>,B3<0>] <0,1> [U1] P1(./SfifoReg.hpp:L29)
wire       N_42                = N_07 == 1'h1                            ; //  (comb-Out) (S) [F0<0>,B3<0>] <0,1> [U1] P1(./SfifoReg.hpp:L29)
wire       N_43         = (N_42) ? G_Sfifo_inst_dbuf_1_flag/*prv*/ : 1'h0; //  (comb-Out) (L1,A1) [F1<0>,B3<0>] <0,1> [U1] P1(./SfifoReg.hpp:L29)
wire       N_48                = N_41 | N_43                             ; //  (comb-Out) (L1,A1) [F2<0>,B2<0>] <0,1> [U1] P1(./SfifoReg.hpp:L29)
wire       N_44                = {1'b0,N_07} == 2'h2                     ; //  (comb-Out) (L1,A1,S) [F1<0>,B4<0>] <0,1> [U1] P1(./SfifoReg.hpp:L29)
wire       N_45         = (N_44) ? G_Sfifo_inst_dbuf_2_flag/*prv*/ : 1'h0; //  (comb-Out) (L1,A1) [F2<0>,B3<0>] <0,1> [U1] P1(./SfifoReg.hpp:L29)
wire       N_46                = {1'b0,N_07} == 2'h3                     ; //  (comb-Out) (L1,A1,S) [F1<0>,B4<0>] <0,1> [U1] P1(./SfifoReg.hpp:L29)
wire       N_47         = (N_46) ? G_Sfifo_inst_dbuf_3_flag/*prv*/ : 1'h0; //  (comb-Out) (L1,A1) [F2<0>,B3<0>] <0,1> [U1] P1(./SfifoReg.hpp:L29)
wire       N_49                = N_45 | N_47                             ; //  (comb-Out) (L1,A1) [F3<0>,B2<0>] <0,1> [U1] P1(./SfifoReg.hpp:L29)
wire       N_50                = N_48 | N_49                             ; //  (comb-Out) (L1,A1) [F4<0>,B1<0>] <0,1> [U1] P1(./SfifoReg.hpp:L29)
assign     G_fifo_if_dout_flag = N_50                                    ; //  (comb-Out)  [F4<0>,B0<0>] <0,1> [U1] P1(./SfifoReg.hpp:L29)
wire       I_run_B1_2 = G_Sfifo_inst_ridx/*prv*/ == G_Sfifo_inst_widx/*prv*/; //  (comb-Out/FFSink) (L3,A5,S) [F3<0>,B4<0>] <0,1> [U1] P1(./SfifoReg.hpp:L23)
assign     G_fifo_if_empty     = I_run_B1_2                              ; //  (comb-Out)  [F3<0>,B0<0>] <0,1> [U1] P1(./SfifoReg.hpp:L25)
wire[ 1:0] I_run_B1_4 = G_Sfifo_inst_widx/*prv*/ ^ G_Sfifo_inst_ridx/*prv*/; //  (comb-Out/FFSink) (L2,A4) [F2<0>,B5<0>] <0,3> [U2] P1(./SfifoReg.hpp:L24)
wire       I_run_B1_5          = {1'b0,I_run_B1_4} == 3'h4               ; //  (comb-Out/FFSink) (L2,A2,S) [F4<0>,B3<0>] <0,1> [U1] P1(./SfifoReg.hpp:L24)
assign     G_fifo_if_full      = I_run_B1_5                              ; //  (comb-Out)  [F4<0>,B0<0>] <0,1> [U1] P1(./SfifoReg.hpp:L26)
wire[15:0] N_52        = (N_40) ? G_Sfifo_inst_dbuf_0_data/*prv*/ : 16'h0; //  (comb-Out) (L1,A1) [F1<0>,B3<0>] <0,65535> [U16] P1(./SfifoReg.hpp:L29)
wire[15:0] N_54        = (N_42) ? G_Sfifo_inst_dbuf_1_data/*prv*/ : 16'h0; //  (comb-Out) (L1,A1) [F1<0>,B3<0>] <0,65535> [U16] P1(./SfifoReg.hpp:L29)
wire[15:0] N_59                = N_52 | N_54                             ; //  (comb-Out) (L1,A16) [F2<0>,B2<0>] <0,65535> [U16] P1(./SfifoReg.hpp:L29)
wire[15:0] N_56        = (N_44) ? G_Sfifo_inst_dbuf_2_data/*prv*/ : 16'h0; //  (comb-Out) (L1,A1) [F2<0>,B3<0>] <0,65535> [U16] P1(./SfifoReg.hpp:L29)
wire[15:0] N_58        = (N_46) ? G_Sfifo_inst_dbuf_3_data/*prv*/ : 16'h0; //  (comb-Out) (L1,A1) [F2<0>,B3<0>] <0,65535> [U16] P1(./SfifoReg.hpp:L29)
wire[15:0] N_60                = N_56 | N_58                             ; //  (comb-Out) (L1,A16) [F3<0>,B2<0>] <0,65535> [U16] P1(./SfifoReg.hpp:L29)
wire[15:0] N_61                = N_59 | N_60                             ; //  (comb-Out) (L1,A16) [F4<0>,B1<0>] <0,65535> [U16] P1(./SfifoReg.hpp:L29)
assign     G_fifo_if_dout_data = N_61                                    ; //  (comb-Out)  [F4<0>,B0<0>] <0,65535> [U16] P1(./SfifoReg.hpp:L29)
wire       I_run_B5_1          = G_Sfifo_inst_widx/*prv*/[0]/*&1'h1*/    ; //   [F0<0>,B3<0>] <0,1> [U1] P1(./SfifoReg.hpp:L34)
wire       N_06                = I_run_B5_1 & 1'h1                       ; //   [F0<0>,B3<0>] <0,1> [U1] P1(./SfifoReg.hpp:L35)
wire       N_10                = ! N_06                                  ; //   [F0<0>,B2<0>] <0,1> [U1] P1(./SfifoReg.hpp:L35)
wire       I_run_B4_1          = G_fifo_if_wen == 1'h1                   ; //  (S) [F0<0>,B2<0>] <0,1> [U1] P1(./SfifoReg.hpp:L33)
wire       A_62                = N_10 & I_run_B4_1                       ; //  (L1,A1) [F1<0>,B2<0>] <0,1> [U1] P1(./SfifoReg.hpp:L35)
wire       N_11                = A_62 & I_run_B1_5                       ; //  (L1,A1) [F5<0>,B1<0>] <0,1> [U1] P1(./SfifoReg.hpp:L35)
wire       N_18                = N_06 == 1'h1                            ; //  (S) [F0<0>,B2<0>] <0,1> [U1] P1(./SfifoReg.hpp:L35)
wire       A_63                = N_18 & I_run_B4_1                       ; //  (L1,A1) [F1<0>,B2<0>] <0,1> [U1] P1(./SfifoReg.hpp:L35)
wire       N_19                = A_63 & I_run_B1_5                       ; //  (L1,A1) [F5<0>,B1<0>] <0,1> [U1] P1(./SfifoReg.hpp:L35)
wire       N_26                = {1'b0,N_06} == 2'h2                     ; //  (L1,A1,S) [F1<0>,B3<0>] <0,1> [U1] P1(./SfifoReg.hpp:L35)
wire       A_64                = N_26 & I_run_B4_1                       ; //  (L1,A1) [F2<0>,B2<0>] <0,1> [U1] P1(./SfifoReg.hpp:L35)
wire       N_27                = A_64 & I_run_B1_5                       ; //  (L1,A1) [F5<0>,B1<0>] <0,1> [U1] P1(./SfifoReg.hpp:L35)
wire       N_34                = {1'b0,N_06} == 2'h3                     ; //  (L1,A1,S) [F1<0>,B3<0>] <0,1> [U1] P1(./SfifoReg.hpp:L35)
wire       A_65                = N_34 & I_run_B4_1                       ; //  (L1,A1) [F2<0>,B2<0>] <0,1> [U1] P1(./SfifoReg.hpp:L35)
wire       N_35                = A_65 & I_run_B1_5                       ; //  (L1,A1) [F5<0>,B1<0>] <0,1> [U1] P1(./SfifoReg.hpp:L35)
wire       I_run_B2_1          = G_fifo_if_ren == 1'h1                   ; //  (S) [F0<0>,B1<0>] <0,1> [U1] P1(./SfifoReg.hpp:L30)
wire       CP_run_B2_F1        = I_run_B1_2 & I_run_B2_1                 ; //  (L1,A1) [F4<0>,B1<0>] <0,1> [U1] P1(./SfifoReg.hpp:L30)
wire[ 2:0] I_run_B3_1          = {1'b0,G_Sfifo_inst_ridx/*prv*/} + 3'h1  ; //  (L2,C3,A9) [F(3,2)<0>,B0<0>] <1,4> [U3] P1(./SfifoReg.hpp:L31)
wire[ 1:0] I_run_B3_2          = I_run_B3_1[1:0]/*&2'h3*/                ; //   [F(3,2)<0>,B0<0>] <0,3> [U2] P1(./SfifoReg.hpp:L31)
wire       CP_run_B4_F1        = I_run_B1_5 & I_run_B4_1                 ; //  (L1,A1) [F5<0>,B1<0>] <0,1> [U1] P1(./SfifoReg.hpp:L33)
wire[ 2:0] I_run_B6_1          = {1'b0,G_Sfifo_inst_widx/*prv*/} + 3'h1  ; //  (L2,C3,A9) [F(3,2)<0>,B0<0>] <1,4> [U3] P1(./SfifoReg.hpp:L36)
wire[ 1:0] I_run_B6_2          = I_run_B6_1[1:0]/*&2'h3*/                ; //  [F(3,2)<0>,B0<0>] <0,3> [U2] P1(./SfifoReg.hpp:L36)


  //// pipe-stage(1) : state-registers...

  always @ (posedge clk or negedge rst_n) begin
  if (rst_n == 1'b0) begin
    G_Sfifo_inst_dbuf_0_flag <= 1'h0 ;
    G_Sfifo_inst_dbuf_0_data <= 16'h0;
    G_Sfifo_inst_dbuf_1_flag <= 1'h0 ;
    G_Sfifo_inst_dbuf_1_data <= 16'h0;
    G_Sfifo_inst_dbuf_2_flag <= 1'h0 ;
    G_Sfifo_inst_dbuf_2_data <= 16'h0;
    G_Sfifo_inst_dbuf_3_flag <= 1'h0 ;
    G_Sfifo_inst_dbuf_3_data <= 16'h0;
    G_Sfifo_inst_ridx        <= 2'h0 ;
    G_Sfifo_inst_widx        <= 2'h0 ;
  end /// (rst_n == 1'b0)
  else begin /*reg-assignments*/
    if (N_11) begin
      G_Sfifo_inst_dbuf_0_flag <= G_fifo_if_din_flag; //  (S,@) [F5<0>,B0<0>] <0,1> [U1] P1(./SfifoReg.hpp:L35)
      G_Sfifo_inst_dbuf_0_data <= G_fifo_if_din_data; //  (S,@) [F5<0>,B0<0>] <0,65535> [U16] P1(./SfifoReg.hpp:L35)
    end /// (N_11)
    if (N_19) begin
      G_Sfifo_inst_dbuf_1_flag <= G_fifo_if_din_flag; //  (S,@) [F5<0>,B0<0>] <0,1> [U1] P1(./SfifoReg.hpp:L35)
      G_Sfifo_inst_dbuf_1_data <= G_fifo_if_din_data; //  (S,@) [F5<0>,B0<0>] <0,65535> [U16] P1(./SfifoReg.hpp:L35)
    end /// (N_19)
    if (N_27) begin
      G_Sfifo_inst_dbuf_2_flag <= G_fifo_if_din_flag; //  (S,@) [F5<0>,B0<0>] <0,1> [U1] P1(./SfifoReg.hpp:L35)
      G_Sfifo_inst_dbuf_2_data <= G_fifo_if_din_data; //  (S,@) [F5<0>,B0<0>] <0,65535> [U16] P1(./SfifoReg.hpp:L35)
    end /// (N_27)
    if (N_35) begin
      G_Sfifo_inst_dbuf_3_flag <= G_fifo_if_din_flag; //  (S,@) [F5<0>,B0<0>] <0,1> [U1] P1(./SfifoReg.hpp:L35)
      G_Sfifo_inst_dbuf_3_data <= G_fifo_if_din_data; //  (S,@) [F5<0>,B0<0>] <0,65535> [U16] P1(./SfifoReg.hpp:L35)
    end /// (N_35)
    if (CP_run_B2_F1)  G_Sfifo_inst_ridx <= I_run_B3_2; //  (S,@) [F4<0>,B0<0>] <0,3> [U2] P1(./SfifoReg.hpp:L31)
    if (CP_run_B4_F1)  G_Sfifo_inst_widx <= I_run_B6_2; //  (S,@) [F5<0>,B0<0>] <0,3> [U2] P1(./SfifoReg.hpp:L36)
  end /// reg-assignments
  end /// always @ ...

  /*probe assignments*/
  assign _prb_Sfifo_pSetup = Sfifo_pSetup;

endmodule // Sfifo_no_mem

同時に、以下のようなシミュレーション用のCコードが生成されるので、インターフェース構造体を再利用し、この関数をステップ実行することで手軽にシミュレーション出来ます。

void SyncFifoST_RTL (FifoIF& fifo_if)  // same interface as input code
{
SyncFifoST_RTL_Core(fifo_if, &G_SyncFifoDataSt);
}

C2R Gate

C2RTL技術をベースとしたツールC2R Gateが株式会社ユーリカから販売されています。

株式会社ユーリカ