PSoC UDB 内 PLD/マクロセルによるアップダウン・カウンタ (3)

PSoC Creator に組み込みの論理合成ソフトウェア「Warp」に関しては、PSoC Creator 付属のドキュメントとしては「小冊子」レベルの "warp_verilog_reference.pdf" しかありませんが、ググっていて Warp のユーザーガイドを見つけました。
Windows 95Windows NT の時代の古いものですが、LPM (Library of Parameterized Modules) モジュールについてのチャプターがあり、madd_sub モジュールについても記述がありました。
その仕様を見ると、やはり Altera の LPM とコンパチのようです。
Altera の lpm_add_sub() メガファンクション相当の madd_sub() の主要なパラメタ/入出力ポートは次のようになっています。 (2016 年 10 月 16 日追記: cin の未接続時の挙動が Altera の lpm_add_sub と異なっていたので修正)

パラメタ 必須 説明
lpm_width Yes dataa[], datab[], result[] ポートのビット幅
lpm_direction No 加算器/減算器あるいは加減算器の指定
lpm_pipeline No 0 なら非パイプライン (組み合わせ回路)、
1 以上ならパイプライン化回路
ポート名 I/O 必須 説明
add_sub IN No 加算/減算切り替え信号
cin IN No キャリー入力
減算モードではボロー入力 (負論理)
未接続時には cin = 0 として扱われる
(加算モードではキャリーなし/減算モードではボローあり)
dataa IN Yes データ入力 (被加数/被減数)
datab IN Yes データ入力 (加数/減数)
result OUT Yes 演算結果
加算: dataa[] + datab[] + cin
減算: dataa[] - datab[] - (~cin)
cout OUT No MSB からのキャリー出力
減算モードではボロー出力 (負論理)
clock IN No パイプライン構成の場合のクロック入力
aclr IN No パイプライン構成の場合の非同期クリア入力

「lpm_direction」パラメタおよび「add_sub」信号の組み合わせにより、単体の加算器、単体の減算器、切り替え可能な加減算器の、3 種のいずれかを選択できます。 その組み合わせは、

  1. 「lpm_direction」パラメタの値が「LPM_ADD」の場合、加算器
  2. 「lpm_direction」パラメタの値が「LPM_SUB」の場合、減算器
  3. 「lpm_direction」パラメタの値が「LPM_NO_TYP」の場合、加減算器となり「add_sub」= 1 の場合に加算、「add_sub」= 0 の場合に減算を行なう

となっています。
1. と 2. の場合は「add_sub」ポートに信号が接続されていても無視されます。 マクロセル消費量は最小 lpm_width、最大 (lpm_width + 2) となります。(非パイプライン構成の場合)
3. の場合で、「add_sub」入力が「1」あるいは「0」の「定数値」の場合は、加減算器とはならずに加算器のみ、あるいは減算器のみになります。
また、3. の場合、計算ロジック部分で加減算切り替え可能となる回路ではなく、キャリー・チェイン加算器のインスタンスひとつと、キャリー・チェイン減算器のインスタンスひとつが生成され、両者の出力を 2-to-1 データセレクタで選択する形式の回路となり、lpm_width の約 3 倍のマクロセルが消費されます。 (非パイプライン構成の場合)
madd_sub() モジュールの呼び出しは、たとえば次のようにします。

`include "lpm.v"

. . . . . <中略> . . . . .

parameter width = 7;
wire [width-1:0] A;
wire [width-1:0] B;
wire [width-1:0] SUM;
wire             CIN;
wire             COUT;

. . . . . <中略> . . . . .

madd_sub #(.lpm_width(width), .lpm_direction(`LPM_ADD))
  add7(.cin(CIN),
       .dataa(A),
       .datab(B),
       .result(SUM),
       .cout(COUT));

LPM_ADD などのマクロは "lpm.v" ファイルの中で定義されているので、シンボル名で指定したい場合にはインクルードする必要があります。
cin / cout ポート両方を使う場合には (width + 2) 個のマクロセルを消費します。
残念なことに、「バグ」か「仕様」か分かりませんが、madd_sub() の cout は、本来の値を反転したものになっているようで、本来の cout の値を得るには width ビット幅の演算を 1 ビット拡張して、(width + 1) ビット幅の演算とし、拡張部分の result ビットを cout として扱い、cout ポートは未使用にします。

madd_sub #(.lpm_width(width+1), .lpm_direction(`LPM_ADD))
  add7(.cin(CIN),
       .dataa({1'b0, A}),
       .datab({1'b0, B}),
       .result({COUT, SUM}));

この記述でも、消費するマクロセル数に変化はありません。
次回は cy_proc3_carry() モジュールを 1 ビット分の「スライス」として、複数個を呼び出して使う方法を説明します。