PSoC UDB 内 PLD/マクロセルによるアップダウン・カウンタ (3)
PSoC Creator に組み込みの論理合成ソフトウェア「Warp」に関しては、PSoC Creator 付属のドキュメントとしては「小冊子」レベルの "warp_verilog_reference.pdf" しかありませんが、ググっていて Warp のユーザーガイドを見つけました。
Windows 95 や Windows 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 種のいずれかを選択できます。 その組み合わせは、
- 「lpm_direction」パラメタの値が「LPM_ADD」の場合、加算器
- 「lpm_direction」パラメタの値が「LPM_SUB」の場合、減算器
- 「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 ビット分の「スライス」として、複数個を呼び出して使う方法を説明します。