SystemVerilogのStream演算について、念のためVerilatorでどのように生成されているのか確認しておこうと思った。
まず、簡単な構成として以下のようなStream演算をコンパイルしてみた。
initial begin static bit [7:0] value_a = 8'h8C; static bit [7:0] value_b = {<<{value_a}}; $display("value_b = 0x%h", value_b); end
C++に変換された結果を見てみると、単純に定数が生成されていた。あ、そうですか...
// Body vlSelf->streaming__DOT__unnamedblk1__DOT__value_a = 0x8cU; vlSelf->streaming__DOT__unnamedblk1__DOT__value_b = 0x31U; VL_WRITEF("value_b = 0x31\n");
次に、入出力を付けてモジュール宣言してみた。
module streaming ( input logic [ 7: 0] in, output logic [ 7: 0] out ); assign out = {<<{in}};
生成されたC++を確認してみると、マクロが埋め込まれているようだった。
VL_INLINE_OPT void Vstreaming___024root___combo__TOP__2(Vstreaming___024root* vlSelf) { if (false && vlSelf) {} // Prevent unused Vstreaming__Syms* const __restrict vlSymsp VL_ATTR_UNUSED = vlSelf->vlSymsp; VL_DEBUG_IF(VL_DBG_MSGF("+ Vstreaming___024root___combo__TOP__2\n"); ); // Body vlSelf->out = VL_STREAML_FAST_III(8,8,32,(IData)(vlSelf->in), 0); }
マクロの定義を確認してみる。意外とよく見るビット反転のプログラムで構成されていた。
switch (rd_log2) { case 0: ret = ((ret >> 1) & VL_UL(0x55555555)) | ((ret & VL_UL(0x55555555)) << 1); // FALLTHRU case 1: ret = ((ret >> 2) & VL_UL(0x33333333)) | ((ret & VL_UL(0x33333333)) << 2); // FALLTHRU case 2: ret = ((ret >> 4) & VL_UL(0x0f0f0f0f)) | ((ret & VL_UL(0x0f0f0f0f)) << 4); // FALLTHRU case 3: ret = ((ret >> 8) & VL_UL(0x00ff00ff)) | ((ret & VL_UL(0x00ff00ff)) << 8); // FALLTHRU case 4: ret = ((ret >> 16) | (ret << 16)); }