【目次に戻る】

3. モジュールkuealuの設計


次は,KUE-CHIP2の算術論理演算命令を処理する回路を,SFLのモジュール kuealuとして設計します.さきほどのkueshiftと同様に, モジュールkuealuは,KUE-CHIP2全体を設計するときに,サブモジュー ルaluとして利用されます.

KUE-CHIP2の算術論理演算命令には,図3 に示すように,加算命令(ADD, ADC),減算命令(SUB, SBC),EOR, OR, AND命令, 比較命令(CMP)があります.まず,EOR, OR, AND命令については,SFLの演算子 @, |, \&を使っ て簡単に処理できます.その他の命令では,8ビッ トの加算あるいは減算を行う必要があります.KUE-CHIP2では負の数を2の補数 で表すことになっていますので,減算は減数の全ビットを反転させて加算を行 うことで実現できます.ただしこの際に,桁上げを考慮しない場合(SUB, CMP) はさらに1を加え,桁上げを考慮する場合(SBC)はさらに桁上げフラグCFの否定 を加えます.従って,加算器さえ用意すればその他の命令は処理できます.

以上の考えに基づき,モジュールkuealuは,加算を行うモジュー ルを,内部にサブモジュールとして用いることにします.階層化設計を行うわ けです.加算を行うモジュールはadd8とします.SFL記述をリスト3.1に示します.これは,大きく分けて3つの部分, すなわち,モジュールadd8の定義部,add8のインタフェー スの宣言部,モジュールkuealuの定義部から成ります.

モジュールadd8の定義部 (3行目から33行目) [TOP]

ここでは,モジュールadd8がどのようなものから構成され,どの ように動作するかが記述されています.

5行目から7行目には,外部端子の定義が行われています.制御入力端子と してはkueshiftと同様にdoを持ち,doの起動で 加算を行うものとします.データ入力端子としては,a<8>, b<8>, ciを持ち,データ出力端子としては,out<8>, co, voを持つも のとします.ここで,outa + b + ciの下位8ビットを, coa + b + ciの8ビッ ト目からの桁上げを出力するもの とします.また,voは桁あふれを示すものですが,a + b + ciの8ビット目からの桁上げと8ビット目への桁上げの排他的論理和を出 力するものとします.

多ビットの加算器の構成法には,桁上げ伝播方式のものや桁上げ先見方式 のものなど,いろいろな種類のものがあります.ここでは,わかりやすいよう に,桁上げ伝播方式で構成しました.これは,1ビットの全加算器を直列につ ないだようなものです.桁上げ伝播加算器は構成は簡単なのですが,直列に計 算を行うので遅延時間が大きくなります.ASICデザインコンテストでは,高速 に計算を行うものに改良してみるのがよいと思われます.

13行目から32行目が,制御入力端子doによる動作の記述です. ここで,c0, ..., c7は各ビットの桁上げを保持するためのデータ内 部端子です.

add8のインタフェースの宣言部 (35行目から42行目) [TOP]

モジュールadd8は,モジュールkuealuの中でサブモジュー ルとして使用されます.そのためには,add8のインタフェースの宣 言を行う必要があります.モジュールの定義部がキーワードmodule で始まるのに対し,インタフェースの宣言部はキーワードdeclareで 始まります.

インタフェースの宣言部では,そのモジュールが外部からどのように見え るかということが記述されます.従って,まず,外部端子の定義を行います. これは,モジュールの定義部のものと同じです.次に,必要であれは,制御入 力端子の仮引数の定義をここで行います.制御入力端子doは加算を 行いますが,そのためにはa<8>, b<8>, ciの値が必要ですので,こ れらを制御入力端子doの仮引数とします.

モジュールkuealuの定義部 (44行目から79行目) [TOP]

以上で,モジュールadd8に関する記述が終わりましたので,モジュー ルkuealuの定義を行います.まずは,外部端子の定義を行います. 制御入力端子doは,kuealuに算術論理演算を依頼するため のものです.データ入力端子としては,算術論理演算の種類を示す mode<3>,被演算データa<8>b<8>,演算前のCF の値ciを用意します.ここで,modeは,8種類の算術論理 演算命令のうちの1つを指定するものですが,表 1図3mmmに対応させること にします.また,データ出力端子としては,演算結果を表すout<8> と,演算後の各フラグを表すco, vo, no, zoを用意します.

次に,51行目では,さきほどの設計したモジュールadd8をサブモ ジュール名addとして用いることを宣言しています.

54行目から78行目が,制御入力端子doによる動作の記述です. modeの値により,動作が異なっています.サブモジュールの外部端 子は,“サブモジュール名.外部端子名”で参照します.例えば,66行目の add.coは,サブモジュールaddのデータ出力端子 coを示します.

56行目などでは,サブモジュールaddの制御入力端子 doが起動されています.制御入力端子は,()をそのあとに 書くことで起動されます.引数があれば,()の中に書きます.モジュー ルadd8doは,41行目に示すような仮引数を持ちますので, 例えば,add.do(a, ^b, ^ci)という記述は,

add.a = a; add.b = ^b; add.ci = ^ci; add.do();
ということを意味します.なお,add.do(a, ^b, ^ci).outという表 現は,制御入力端子の起動とサブモジュールの外部端子の参照を1文にまとめ たものです.

以上で,リスト3.1の説明は終わりです.リスト3.1のSFL記述は, kuealu.sflというファイルに格納することにします.

リスト3.1: SFL記述 (kuealu.sfl) [TOP]
 1  /** kuealu : ALU for KUE-CHIP2 **/
 2  
 3  module add8 {
 4      /** external pins **/
 5      instrin     do;
 6      input       a<8>, b<8>, ci;
 7      output      out<8>, co, vo;
 8  
 9      /** elements **/
10      sel         c0, c1, c2, c3, c4, c5, c6, c7;
11  
12      /** operations of instrin **/
13      instruct do par {
14          c0 = (a<0> & b<0>) | (b<0> & ci) | (ci & a<0>);
15          c1 = (a<1> & b<1>) | (b<1> & c0) | (c0 & a<1>);
16          c2 = (a<2> & b<2>) | (b<2> & c1) | (c1 & a<2>);
17          c3 = (a<3> & b<3>) | (b<3> & c2) | (c2 & a<3>);
18          c4 = (a<4> & b<4>) | (b<4> & c3) | (c3 & a<4>);
19          c5 = (a<5> & b<5>) | (b<5> & c4) | (c4 & a<5>);
20          c6 = (a<6> & b<6>) | (b<6> & c5) | (c5 & a<6>);
21          c7 = (a<7> & b<7>) | (b<7> & c6) | (c6 & a<7>);
22          out = (a<7> @ b<7> @ c6) ||
23                (a<6> @ b<6> @ c5) ||
24                (a<5> @ b<5> @ c4) ||
25                (a<4> @ b<4> @ c3) ||
26                (a<3> @ b<3> @ c2) ||
27                (a<2> @ b<2> @ c1) ||
28                (a<1> @ b<1> @ c0) ||
29                (a<0> @ b<0> @ ci);
30          co = c7;
31          vo = c7 @ c6;
32      }
33  }
34  
35  declare add8 {
36      /** external pins **/
37      instrin     do;
38      input       a<8>, b<8>, ci;
39      output      out<8>, co, vo;
40      /** arguments of instrin **/
41      instr_arg   do(a, b, ci);
42  }
43  
44  module kuealu {
45      /** external pins **/
46      instrin     do;
47      input       mode<3>, a<8>, b<8>, ci;
48      output      out<8>, co, vo, no, zo;
49      
50      /** elements **/
51      add8        add;
52  
53      /** operations of instrin **/
54      instruct do par {
55          any { /* out */
56              mode == 0b000 : out = add.do(a, ^b, ^ci).out; /* SBC */
57              mode == 0b001 : out = add.do(a, b, ci).out;   /* ADC */
58              mode == 0b010 : out = add.do(a, ^b, 0b1).out; /* SUB */
59              mode == 0b011 : out = add.do(a, b, 0b0).out;  /* ADD */
60              mode == 0b100 : out = a @ b;                  /* EOR */
61              mode == 0b101 : out = a | b;                  /* OR  */
62              mode == 0b110 : out = a & b;                  /* AND */
63              mode == 0b111 : out = add.do(a, ^b, 0b1).out; /* CMP */
64          }
65          any { /* co */
66              mode == 0b000 : co = ^add.co; /* SBC */
67              mode == 0b001 : co = add.co;  /* ADC */
68              else : co = ci; /* SUB, ADD, EOR, OR, AND, CMP */
69          }
70          any { /* vo */
71              mode == 0b100 : vo =0b0; /* EOR */
72              mode == 0b101 : vo =0b0; /* OR  */
73              mode == 0b110 : vo =0b0; /* AND */
74              else : vo = add.vo; /* SBC, ADC, SUB, ADD, CMP */
75          }
76          no = out<7>;
77          zo = ^(/| out);
78      }
79  }

SECONDSを用いてシミュレーション [TOP]

kuealuの記述が完成したら,SECONDSを用いてその動作を確かめ てみます.リスト3.2に,そのためのSECONDSのコマンド列を用意しましたので, これを利用してください.

リスト3.2: SECONDSへのコマンド列(kuealu.sec)
 1  # simulation data for kuealu
 2  
 3  sflread kuealu.sfl
 4  autoinstall kuealu
 5  
 6  rpt_add ext \
 7  "do=%B mode=%B a=%X b=%X ci=%B out=%X cvnz=%B%B%B%B  " \
 8  do mode a b ci out co vo no zo
 9  
10  rpt_add add \
11  "add[do=%B a=%X b=%X ci=%B cv=%B%B]\n" \
12  add.do add.a add.b add.ci add.co add.vo
13  
14  # execute
15  set do 1
16  
17  # xor, or, and
18  set mode 100; set a X33; set b X07; set ci 0; report do
19  set mode 101; set a X33; set b X07; set ci 0; report do
20  set mode 110; set a X33; set b X07; set ci 0; report do
21  
22  # sub, add
23  set mode 010; set a X33; set b X07; set ci 0; report do
24  set mode 010; set a X07; set b X33; set ci 1; report do
25  set mode 011; set a X33; set b X07; set ci 0; report do
26  set mode 011; set a X07; set b X33; set ci 1; report do
27  
28  # sbc, adc
29  set mode 000; set a X33; set b X07; set ci 0; report do
30  set mode 000; set a X07; set b X33; set ci 1; report do
31  set mode 001; set a X33; set b X07; set ci 0; report do
32  set mode 001; set a X07; set b X33; set ci 1; report do

リスト3.2の内容を,kuealu.secというファイルに保存して,コマンドプロ ンプトで,

% seconds < kuealu.sec
としてみてください.SFL記述が正しければ,リスト3.3のような結果となるは ずです.ここには,kuealuの外部端子だけではなく,add の外部端子の値も表示しています.命令の種類がEOR, OR, ANDの時は,加算を 行う必要がないため,addが動作していないことがわかります.また, 加算器addで減算を行っているとき,add.bの値や桁上げフ ラグの値がどうなっているかに着目してください.

リスト3.2を適当に変更して,いろいろな値で動作を確認してみてください.

リスト3.3: SECONDSの実行結果
do=1 mode=100 a=33 b=07 ci=0 out=34 cvnz=0000  add[do=0 a=zz b=zz ci=z cv=zz]
do=1 mode=101 a=33 b=07 ci=0 out=37 cvnz=0000  add[do=0 a=zz b=zz ci=z cv=zz]
do=1 mode=110 a=33 b=07 ci=0 out=03 cvnz=0000  add[do=0 a=zz b=zz ci=z cv=zz]
do=1 mode=010 a=33 b=07 ci=0 out=2c cvnz=0000  add[do=1 a=33 b=f8 ci=1 cv=10]
do=1 mode=010 a=07 b=33 ci=1 out=d4 cvnz=1010  add[do=1 a=07 b=cc ci=1 cv=00]
do=1 mode=011 a=33 b=07 ci=0 out=3a cvnz=0000  add[do=1 a=33 b=07 ci=0 cv=00]
do=1 mode=011 a=07 b=33 ci=1 out=3a cvnz=1000  add[do=1 a=07 b=33 ci=0 cv=00]
do=1 mode=000 a=33 b=07 ci=0 out=2c cvnz=0000  add[do=1 a=33 b=f8 ci=1 cv=10]
do=1 mode=000 a=07 b=33 ci=1 out=d3 cvnz=1010  add[do=1 a=07 b=cc ci=0 cv=00]
do=1 mode=001 a=33 b=07 ci=0 out=3a cvnz=0000  add[do=1 a=33 b=07 ci=0 cv=00]
do=1 mode=001 a=07 b=33 ci=1 out=3b cvnz=0000  add[do=1 a=07 b=33 ci=1 cv=00]