次は,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がどのようなものから構成され,どのように動 作するかが記述されています.
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は,モジュールkuealuにサブモジュールとして使用されま す.そのためには,add8のサブモジュールタイプ宣言を行う必要があります. モジュールの定義部がキーワードmoduleで始まるのに対し,サブモジュールタ イプの宣言部はキーワードsubmod_typeあるいはsubmod_classで始まります.
サブモジュールタイプ宣言部では,そのモジュールが外部からどのように 見えるかということが記述されます.従って,まず,外部端子の定義を行いま す.これは,モジュールの定義部のものと同じです.次に,必要であれは,制 御入力端子の仮引数の定義をここで行います.制御入力端子doは加算を行いま すが,そのためにはa<8>, b<8>, ciの値が必要ですので,これら を制御入力端子doの仮引数とします.
以上で,モジュール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: }
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]