PSoC Creator の Verilog-HDL のリダクション演算の不具合 (1)

 PSoC Creator のユーザ・コンポーネントとして、(LS)TTL / HCMOS の 4 ビット ALU である 74181 の内部回路を Verilog-HDL で書いていて、「リダクション演算」に関する不具合があることに気が付きました。
 回避する方法も判明しているので、実用上は問題ありません。
 74181 は 4 ビット ALU (Arithmetic Logic Unit) で、算術演算で 16 種類、論理演算で 16 種類の演算を実現することができます。内部に「Carry Look Ahead」(以下「CLA」と略す) 回路を内蔵していて、「リプル・キャリー」方式より高速に結果が得られます。
 CLA 回路は上位ビットになるほど回路が複雑になります。
 最も複雑なのは、74181 を複数個使用してビット幅を拡大するための \overline{\rm P}\overline{\rm G} 出力やリプルキャリー出力の {\rm C}_{\rm n+4} 出力ですが、ここでは中程度の複雑さの 3 ビット目への内部 CLA 回路を例にあげます。
 内部 CLA 回路部分のみを示します。

 TTL (Transistor-Transistor-Logic) では「AND-OR-INVERT」構成にすると回路が節約でき、上記の回路でも AND-OR-INVERT 構成になっています。
 「M」入力は arithmetic / logic モードの切り替えで、M = L で算術演算モード、M = H で論理演算モードになります。
 M = H の論理モードでは、CLA 出力値を固定して隣の桁への「桁上がり」を防止しています。
 この回路を Verilog-HDL 言語で、ひとつの式として素直に書き下すと次のようになります。

  assign cla[3] = ~( (g[2] & (~m)) | ((~m) & p[2] & g[1])
                   | ((~m) & p[2] & p[1] & g[0])
                   | ((~m) & p[2] & p[1] & p[0] & cn));

 「AND」部分は 2 項演算子の「&」、「OR」部分は 2 項演算子の「|」を使っています。
 これを PSoC Creator で論理合成し、「.rpt」ファイルから結果を抜き出すと次のようになります。
 (2020 年 3 月 28 日追記: PSoC Creator のバージョンは、「3.0 sp 2」および「4.0 update 1」について試しており、両者とも使われている論理合成ソフトウェアは Cypress 製の Warp V6.3 IR41 です。 )

   MacroCell: Name=cla_3, Mode=(Combinatorial)
        Total # of inputs        : 8
        Total # of product terms : 4
            Clock Enable: True
        Main Equation            : 4 pterms
        !(
              g_2 * !m
            + !m * p_2 * g_1
            + !m * p_2 * p_1 * g_0
            + !m * p_2 * p_1 * p_0 * cn
        );
        Output = cla_3 (fanout=1)

 PSoC3/4/5LP の UDB (Universal Digital Block) の PLD 部分は FPGA などの SRAM ベースの LUT (LookUp Table) 方式とは違って、従来の PLD と同様に AND-OR-(INVERT) 形式で実現されているので、Verilog ソースの記述通りに合成されています。
 「AND」部分を Verilog 機能の単項リダクション演算子 (reduction operator) に書き換えると次のようになります。

  assign cla[3] = ~( (&{(~m), g[2]}) | (&{(~m), p[2], g[1]})
                   | (&{(~m), p[2:1], g[0]})
                   | (&{(~m), p[2:0], cn}));

 これを PSoC Creator で論理合成し、「.rpt」ファイルから結果を抜き出すと次のようになります。

   MacroCell: Name=cla_3, Mode=(Combinatorial)
        Total # of inputs        : 5
        Total # of product terms : 1
            Clock Enable: True
        Main Equation            : 1 pterm
        !(
              !m * p_2 * p_1 * p_0 * cn
        );
        Output = cla_3 (fanout=1)

 本来、4 項あるべきプロダクト・タームが最後の 1 項しかなく、この結果は正しくありません。
 「Altera Quartus II 11.0sp1 web edition」で Cyclone をターゲットに論理合成した結果を「Mentor ModelSim-ASE 6.6d」でゲートレベル・シミュレーションすると、正しい結果が得られ、上記の表現が問題ないことが確認できました。
 徹底的に調べたわけではないのですが、2 項演算と単項リダクション演算を混ぜていろいろと記述してみた結果、PSoC Creator では 2 項演算の項はすべて正しく変換され、単項リダクション演算の項が 2 個以上あると最後の項のみが変換されるようです。
 下のように、AND 出力と OR 入力の間のワイヤを定義し、式を分割して、各 assign 文には単項リダクション演算は 1 項しか存在しないようにすると、PSoC Creator でも正しい変換結果が得られました。

  assign cla30  = &{(~m),         g[2]};
  assign cla31  = &{(~m), p[2],   g[1]};
  assign cla32  = &{(~m), p[2:1], g[0]};
  assign cla33  = &{(~m), p[2:0], cn};
  assign cla[3] = ~|{cla30, cla31, cla32, cla33};

 ここでは、NOR 部分もリダクション演算で記述しています。
 assign 文の行数としては増えていますが、回路の可読性としては向上していると思います。