【目次に戻る】

3. モジュールkuealuの設計


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

KUE-CHIP2の算術論理演算命令には, 規定課題の資料 に示すように,加算命令(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行目から6行目には,外部端子の定義が行われています.制御入力端子と してはkueshiftと同様にdoを持ち,doの起動で加算を行うものとします.デー タ入力端子としては,a<8>, <8>, ciを持ち,データ出力端子と しては,out<8>, co, voを持つものとします.ここで,outはa + b + ciの下位8ビットを,coはa + b + ciの8ビット目からの桁上げを出力するもの とします.また,voは桁あふれを示すものですが,a + b + ciの8ビット目か らの桁上げと8ビット目への桁上げの排他的論理和を出力するものとします.

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

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

add8のサブモジュールタイプ宣言部 (35行目から42行目) [TOP]

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

サブモジュールタイプ宣言部では,そのモジュールが外部からどのように 見えるかということが記述されます.従って,まず,外部端子の定義を行いま す.これは,モジュールの定義部のものと同じです.次に,必要であれは,制 御入力端子の仮引数の定義をここで行います.制御入力端子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.1 のmmm,すなわち.KUE-CHIP2の命令コードの7ビット目から5ビット目に対応さ せることにします.また,データ出力端子としては,演算結果を表す out<8>と,演算後の各フラグを表すco, vo, no, zoを用意します.

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

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

56行目などでは,サブモジュールaddの制御入力端子doが起動されていま す.SFLでは,制御入力端子は,()をそのあとに書くことで起動します.引数 があれば,()の中に書きます.モジュールadd8のdoは,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: submod_type 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 {
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 {
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 {
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)
# simulation data for kuealu

sflread kuealu.sfl
autoinstall kuealu

rpt_add ext \
"do=%B mode=%B a=%X b=%X ci=%B out=%X cvnz=%B%B%B%B  " \
do mode a b ci out co vo no zo

rpt_add add \
"add[do=%B a=%X b=%X ci=%B cv=%B%B]\n" \
add.do add.a add.b add.ci add.co add.vo

# execute
set do 1

# xor, or, and
set mode 100; set a X33; set b X07; set ci 0; report do
set mode 101; set a X33; set b X07; set ci 0; report do
set mode 110; set a X33; set b X07; set ci 0; report do

# sub, add
set mode 010; set a X33; set b X07; set ci 0; report do
set mode 010; set a X07; set b X33; set ci 1; report do
set mode 011; set a X33; set b X07; set ci 0; report do
set mode 011; set a X07; set b X33; set ci 1; report do

# sbc, adc
set mode 000; set a X33; set b X07; set ci 0; report do
set mode 000; set a X07; set b X33; set ci 1; report do
set mode 001; set a X33; set b X07; set ci 0; report do
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]