次は,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がどのようなものから構成され,どの ように動作するかが記述されています.
5行目から7行目には,外部端子の定義が行われています.制御入力端子と してはkueshiftと同様にdoを持ち,doの起動で 加算を行うものとします.データ入力端子としては,a<8>, b<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は,モジュールkuealuの中でサブモジュー ルとして使用されます.そのためには,add8のインタフェースの宣 言を行う必要があります.モジュールの定義部がキーワードmodule で始まるのに対し,インタフェースの宣言部はキーワードdeclareで 始まります.
インタフェースの宣言部では,そのモジュールが外部からどのように見え るかということが記述されます.従って,まず,外部端子の定義を行います. これは,モジュールの定義部のものと同じです.次に,必要であれは,制御入 力端子の仮引数の定義をここで行います.制御入力端子doは加算を 行いますが,そのためにはa<8>, b<8>, ciの値が必要ですので,こ れらを制御入力端子doの仮引数とします.
以上で,モジュールadd8に関する記述が終わりましたので,モジュー ルkuealuの定義を行います.まずは,外部端子の定義を行います. 制御入力端子doは,kuealuに算術論理演算を依頼するため のものです.データ入力端子としては,算術論理演算の種類を示す mode<3>,被演算データa<8>とb<8>,演算前のCF の値ciを用意します.ここで,modeは,8種類の算術論理 演算命令のうちの1つを指定するものですが,表 1や図3のmmmに対応させること にします.また,データ出力端子としては,演算結果を表すout<8> と,演算後の各フラグを表すco, vo, no, zoを用意します.
次に,51行目では,さきほどの設計したモジュールadd8をサブモ ジュール名addとして用いることを宣言しています.
54行目から78行目が,制御入力端子doによる動作の記述です. modeの値により,動作が異なっています.サブモジュールの外部端 子は,“サブモジュール名.外部端子名”で参照します.例えば,66行目の add.coは,サブモジュールaddのデータ出力端子 coを示します.
56行目などでは,サブモジュールaddの制御入力端子 doが起動されています.制御入力端子は,()をそのあとに 書くことで起動されます.引数があれば,()の中に書きます.モジュー ル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 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 }
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]