いよいよKUE-CHIP2全体を,SFLのモジュールkuechip2として記述し ます.リスト4.1に一例を示します.
モジュールkuechip2では,これまでに設計したモジュール kueshiftとkuealuをサブモジュールとして用います.それ らのSFL記述は,必ずしもここにインクルードする必要はないのですが,イン クルードすると論理合成の際に便利です.%iと空白に続けて "と"でファイル名を囲むことで,カレントディレクトリか ら見たパス名のファイルをインクルードします.
図1のブロック図には,INCという8ビット のインクリメンタがあります.8ビットのインクリメンタはまだ設計していな いのですが,PARTHENON標準ライブラリの中にinc8という8ビットの インクリメンタが存在しますので,これを用いることにします.PARTHENON標 準ライブラリは,$PARTHENON/sfl_lib.dirというディレクトリに,多くのファ イルとして格納されていますが,%iと空白に続けて<と >でファイル名を囲むことで,このディレクトリにあるファイル をインクルードします.
inc8.cirというファイルの中身は,リスト4.2の ようになっています.inc8は,機能回路として定義されています. 機能回路はモジュールのようなものですが,論理合成されない,使える演算子 と構成要素が拡張されているなどという点でモジュールと異なっています.機 能回路の記述は,circuitで始めます.inc8などの PARTHENON標準ライブラリは,すでに論理合成されてそのネットリストが用意 されていますので,機能回路で定義されているわけです.
モジュールkuechip2では,これまでに設計したモジュール kueshift, kuealuやPARTHENON標準ライブラリのinc8を, それぞれサブモジュールshifter, alu, incとして用います.そのた めには,インタフェースの宣言が必要ですので,ここで行っています. inc8のインタフェースの宣言は,inc8.hというファイル(リスト4.3)にあります.kueshiftの制御入力 端子doの仮引数と,kuealuの制御入力端子doの 仮引数は,ともに,すべてのデータ入力端子とします.
SFLでは,%dを用いてマクロ定義を行います.たとえば,NOP という文字列は,(ir<7:3> == 0b00000)という文字列に置き換えられま す. ここではマクロ定義を用いて,表1に 従って命令の分類を行っています.
ここからは,モジュールkuechip2の定義部の記述となります.ま ずは,外部端子を記述します.KUE-CHIP2の外部端子はすでに規定されている ので,ここにはそれらを書き下せばよいのですが,どれを制御端子にしてどれ をデータ端子にするかということを決める必要があります.
まず入力端子に関してですが,kuechip2を起動するための startを制御入力端子とし,メモリやIBUFの値を読み込むための dbi<8>,IBUF_FLAG, OBUF_FLAGを読み込むためのibuf_flg_in, obuf_flg_inをデータ入力端子とします.出力端子に関しては,メモリの 値の読み出しを依頼するmem_re,メモリへ値の書き込みを依頼する mem_we,IBUFの値の読み出しを依頼するibuf_re,OBUFへ 値の書き込みを依頼するobuf_weは制御出力端子にします.そして, メモリやOBUFに値を書き込むためのdbo<8>,メモリのアドレスを指 定するためのab<9>はデータ出力端子とします.
次はkuechip2の構成要素を記述します.まずレジスタに関しては, 図1に示したように,acc, ix, cf, vf, nf, zf, pc, ir, marを用意します.KUE-CHIP2のレジスタはリセット信 号でリセットされるので,レジスタとしてはreg_wr (register with reset)を用いることにします.そのほかに,図1に示されているものとしては, モジュールkueshift, kuealuを,それぞれサブモジュール shifter, aluとして用い,PARTHENON標準ライブラリのinc8を, サブモジュールincとして用います.また,データ内部端子として, sel_bを用意します.
そのほかに,図1にはありませんが,SFL記述を簡潔にするためのいくつか の構成要素を定義します.bcond_calc, bcond_statusは,BRANCH命 令を処理するために設けた制御内部端子です.exec_aluは, aluを用いて算術論理演算命令を処理するための制御内部端子です. 制御内部端子は,制御入力端子や制御出力端子と同様に,起動されなければそ の値は0で,起動されるとその値が1になります.また,動作を関連づけること もできます.これらの働きについてはもう少し後で説明します.
制御端子のうち,制御出力端子と制御内部端子の仮引数の定義は,モジュー ルの定義部で行います.制御出力端子と制御内部端子は,これらを持つモジュー ルによって起動されるからです.
mem_reはabを仮引数として持つものとします.メモリ の内容を読みだすためには,アドレスを与えなければならないからです. mem_weについては,アドレスだけではなく,メモリに書き込むべき データの値も与えなければならないので,abとdboを仮引 数とします.obuf_weについては,書き込むべきデータの値だけを与 えれば良いので,dboを仮引数とします.
exec_aluはsel_bを仮引数として持つものとします. 図1に示すように,sel_bは aluの入力の1つとなるからです.
SFLには,ステージという概念があります.制御端子は1クロックで終了す る動作を行うのに対し,ステージは複数クロックにまたがる一連の動作を行い ます. すなわち,ステージは状態を持ちますが,制御端子は状態を持ちませ ん.
ステージを複数個用意すると,並列動作をうまく記述することができます. しかし,ここではステージを一つだけ用意し,その唯一のステージの名前を allとします.ステージallは,表1に示されたフェーズ表に従って,各命令の 動作を制御するものとします.
ステージにはタスクというものが存在し,これが起動されることでステー ジが動作すると考えられています.ステージallにもタスクが必要で す.tという名前のタスクを用意します.
次に,制御端子による動作を記述します.制御端子のうち,制御入力端子 と制御内部端子による動作の定義は,これらを持つモジュールの定義部で行わ れます.一方,制御出力端子による動作の定義は,その制御出力端子を持つモ ジュールの外,つまりそのモジュールをサブモジュールとして使用するモジュー ルで行われます.従って,ここでは行われません.
制御入力端子startが起動されると,generateという SFLのキーワードにより,ステージallのタスクtが起動さ れ,KUE-CHIP2が動き出します.
制御内部端子bcond_calcは,命令コードとフラグの値に従って, BRANCH命令の分岐条件を判定します.分岐条件の詳細については,規定課題の 資料を見てください.もし条件が成り立てば,制御内部端子 bcond_statusを起動して1にします.条件が成り立たなければ, bcond_statusは0のままです.
制御内部端子exec_aluは,aluを用いて算術論理演算命 令を行い,フラグを更新します.算術論理演算命令の第1オペランドは, ir<3>が1か0かで,ixかaccとなります.命令の 第2オペランドは,exec_aluの仮引数sel_bに与えられた値 となります.演算結果は,ir<3>が1か0かで,ixか accに格納されます(比較命令CMP以外).
最後に,ステージallの動作を記述します.ステージは generateで起動され,起動された次のクロックから動作を開始し, finishというキーワードで動作を終了します.したがって,ステー ジallは制御入力端子startによって動作を開始し,HLT命 令により動作を終了します.
ステージallは3つの状態を持つものとし,表1に示した3つのフェーズp1, p2, p3をそれぞ れの状態に対応させます.状態p1では,命令の種類によらず動作は一定 ですが,状態p2, p3での動作は命令の種類によって異ってきます.状態 を持つステージでは,どれかの1つの状態のみが有効になっています.ステー ジが動作中であっても,有効でない状態の動作は行われません.初めに有効な 状態(初期状態)は,キーワードfirst_stateで指定します.有効な状 態の変更(状態遷移)は,キーワードgotoによって行います.
表1とこのSFL記述を見比べることで,SFL記述の意味がわか りやすくなると思います.
kuechip2のSFL記述には,制御端子の起動がたくさん現れています.制 御端子は,その後に()を付けることで起動します.制御端子は,制御入 力端子,制御出力端子,制御内部端子に分けられますが,ここでは,それぞれ の起動について説明します.
まず,制御入力端子についてですが,サブモジュールの制御入力端子は, これを使用している外側のモジュールが起動します.例えば141行目では,サ ブモジュールshifterの制御入力端子doを,ir<2:0>, ix, cfを引数として起動しています.これにより,kueshiftのdoの 仮引数の定義(14行目)に従って,shifterのデータ入力端子mode, in, ciに,それぞれ,ir<2:0>, ix, cfの値が転送されます.ま た,shifterのdoが1になり,それに対応づけられた動作が行われ ます.この動作は,モジュールkueshiftの定義部に記述されています. このように,制御入力端子を用いて,あるモジュールからそこで使用している サブモジュールに仕事を依頼します.
次に,制御出力端子について見てみます.例えば107行目では,制御出力端 子mem_reを,0b0 || pcを引数として起動しています.こ れにより,62行目の仮引数の定義に従って,データ出力端子abに 0b0 || pcの値が転送されます.また,mem_reが1になり, それに対応づけられた動作が行われます.この動作とは,メモリの ab番地の内容をdbiに転送することですが,これはモジュー ルkuechip2の外側で規定されます.このように,制御出力端子を用 いて,あるモジュールから外側のモジュールに仕事を依頼します.
最後に制御内部端子について見てみます.例えば157行目では, ixを引数として制御内部端子exec_aluを起動しています. これにより,65行目の仮引数の定義に従って,データ内部端子sel_b にixの値が転送されます.また,exec_aluが1になり,そ れに対応づけられた動作が行われます.この動作は90行目から100行目に書か れています.制御内部端子は,制御入力端子や制御出力端子のように別のモジュー ルに仕事を依頼するものではなく,一連のまとまった動作を記述するためのも のです.これを用いることでSFL記述を簡潔にすることができます.
以上で,リスト4.1の説明は終わりです.リスト4.1のSFL記述は, kuechip2.sflというファイルに格納するものとします.
リスト4.1: SFL記述 (kuechip2.sfl) [TOP]1 /** kuechip2 : The main module of KUE-CHIP2 **/ 2 3 %i "kueshift.sfl" 4 %i "kuealu.sfl" 5 %i6 %i 7 8 declare kueshift { 9 /** external pins **/ 10 instrin do; 11 input mode<3>, in<8>, ci; 12 output out<8>, co, vo, no, zo; 13 /** arguments of instrin **/ 14 instr_arg do(mode, in, ci); 15 } 16 17 declare kuealu { 18 /** external pins **/ 19 instrin do; 20 input mode<3>, a<8>, b<8>, ci; 21 output out<8>, co, vo, no, zo; 22 /** arguments of instrin **/ 23 instr_arg do(mode, a, b, ci); 24 } 25 26 %d NOP (ir<7:3> == 0b00000) 27 %d HLT ((ir<7:3> == 0b00001) | (ir<7:4> == 0b0101)) 28 %d OUT (ir<7:3> == 0b00010) 29 %d IN (ir<7:3> == 0b00011) 30 %d SRCF (ir<7:4> == 0b0010) 31 %d BRANCH (ir<7:4> == 0b0011) 32 %d SHIFT (ir<7:4> == 0b0100) 33 %d LD_REG ((ir<7:4> == 0b0110) & (ir<2:1> == 0b00)) 34 %d AL_REG ((ir<7> == 0b1) & (ir<2:1> == 0b00)) 35 %d LD_IMM ((ir<7:4> == 0b0110) & (ir<2:1> == 0b01)) 36 %d AL_IMM ((ir<7> == 0b1) & (ir<2:1> == 0b01)) 37 %d LD_MA ((ir<7:4> == 0b0110) & (ir<2> == 0b1)) 38 %d ST_MA ((ir<7:4> == 0b0111) & (ir<2> == 0b1)) 39 %d AL_MA ((ir<7> == 0b1) & (ir<2> == 0b1)) 40 41 module kuechip2 { 42 /** external pins **/ 43 instrin start; 44 input dbi<8>; 45 input ibuf_flg_in, obuf_flg_in; 46 instrout mem_we, mem_re; 47 instrout ibuf_re, obuf_we; 48 output dbo<8>, ab<9>; 49 50 /** elements **/ 51 reg_wr acc<8>, ix<8>; 52 reg_wr cf, vf, nf, zf; 53 reg_wr pc<8>, ir<8>, mar<8>; 54 kuealu alu; 55 kueshift shifter; 56 inc8 inc; 57 sel sel_b<8>; 58 instrself bcond_calc, bcond_status; 59 instrself exec_alu; 60 61 /** arguments of instrout and instrself **/ 62 instr_arg mem_re(ab); 63 instr_arg mem_we(ab, dbo); 64 instr_arg obuf_we(dbo); 65 instr_arg exec_alu(sel_b); 66 67 /** stages and tasks and their arguments **/ 68 stage_name all { task t(); } 69 70 /** operations of instrin and instrself **/ 71 instruct start generate all.t(); 72 instruct bcond_calc if ( 73 ( ir<3:0> == 0b0000 ) | 74 ( ( ir<3:0> == 0b1000 ) & vf ) | 75 ( ( ir<3:0> == 0b0001 ) & ^zf ) | 76 ( ( ir<3:0> == 0b1001 ) & zf ) | 77 ( ( ir<3:0> == 0b0010 ) & ^nf ) | 78 ( ( ir<3:0> == 0b1010 ) & nf ) | 79 ( ( ir<3:0> == 0b0011 ) & ^(nf | zf) ) | 80 ( ( ir<3:0> == 0b1011 ) & nf | zf ) | 81 ( ( ir<3:0> == 0b0100 ) & ^ibuf_flg_in ) | 82 ( ( ir<3:0> == 0b1100 ) & obuf_flg_in ) | 83 ( ( ir<3:0> == 0b0101 ) & ^cf ) | 84 ( ( ir<3:0> == 0b1101 ) & cf ) | 85 ( ( ir<3:0> == 0b0110 ) & ^(vf @ nf) ) | 86 ( ( ir<3:0> == 0b1110 ) & vf @ nf ) | 87 ( ( ir<3:0> == 0b0111 ) & ^((vf @ nf) | zf) ) | 88 ( ( ir<3:0> == 0b1111 ) & (vf @ nf) | zf ) 89 ) bcond_status(); 90 instruct exec_alu par { 91 any { 92 ir<3> : alu.do(ir<6:4>, ix, sel_b, cf); 93 else : alu.do(ir<6:4>, acc, sel_b, cf); 94 } 95 if ( ^(ir<6:4> == 0b111) ) any { /* except CMP */ 96 ir<3> : ix := alu.out; 97 else : acc := alu.out; 98 } 99 cf := alu.co; vf := alu.vo; nf := alu.no; zf := alu.zo; 100 } 101 102 /** operations of stages **/ 103 stage all { 104 state_name p1, p2, p3; 105 first_state p1; 106 state p1 par { 107 ir := mem_re(0b0 || pc).dbi; 108 pc := inc.do(pc).out; 109 goto p2; 110 } 111 state p2 any { 112 NOP : goto p1; 113 HLT : par { 114 goto p1; 115 finish; 116 } 117 OUT : par { 118 obuf_we(acc); 119 goto p1; 120 } 121 IN : par { 122 acc := ibuf_re().dbi; 123 goto p3; 124 } 125 SRCF : par { 126 cf := ir<3>; 127 goto p1; 128 } 129 BRANCH : par { 130 bcond_calc(); 131 mem_re(0b0 || pc); 132 inc.do(pc); 133 any { 134 bcond_status : pc := dbi; 135 else : pc := inc.out; 136 } 137 goto p1; 138 } 139 SHIFT : par { 140 any { 141 ir<3> : ix := shifter.do(ir<2:0>, ix, cf).out; 142 else : acc := shifter.do(ir<2:0>, acc, cf).out; 143 } 144 cf := shifter.co; vf := shifter.vo; 145 nf := shifter.no; zf := shifter.zo; 146 goto p1; 147 } 148 LD_REG : par { 149 any { 150 ir<0> & ^ir<3> : acc := ix; 151 ^ir<0> & ir<3> : ix := acc; 152 } 153 goto p1; 154 } 155 AL_REG : par { 156 any { 157 ir<0> : exec_alu(ix); 158 else : exec_alu(acc); 159 } 160 goto p1; 161 } 162 LD_IMM : par { 163 any { 164 ir<3> : ix := mem_re(0b0 || pc).dbi; 165 else : acc := mem_re(0b0 || pc).dbi; 166 } 167 pc := inc.do(pc).out; 168 goto p1; 169 } 170 AL_IMM : par { 171 exec_alu(mem_re(0b0 || pc).dbi); 172 pc := inc.do(pc).out; 173 goto p1; 174 } 175 LD_MA | ST_MA | AL_MA : par { 176 mem_re(0b0 || pc); 177 any { 178 ir<1> : mar := alu.do(0b011, ix, dbi, 0b0).out; 179 else : mar := dbi; 180 } 181 pc := inc.do(pc).out; 182 goto p3; 183 } 184 } 185 state p3 par { 186 any { 187 LD_MA : any { 188 ir<3> : ix := mem_re(ir<0> || mar).dbi; 189 else : acc := mem_re(ir<0> || mar).dbi; 190 } 191 ST_MA : any { 192 ir<3> : mem_we(ir<0> || mar, ix); 193 else : mem_we(ir<0> || mar, acc); 194 } 195 AL_MA : exec_alu(mem_re(ir<0> || mar).dbi); 196 } 197 goto p1; 198 } 199 } 200 }
1 /****************************************** 2 * (C)Copyright by N.T.T 1993(unpublished) * 3 * All rights are reserved. * 4 ******************************************/ 5 circuit inc8 { 6 input in<8> ; 7 output out<8> ; 8 instrin do ; 9 instruct do out = in + 0b1 ; 10 }
1 /****************************************** 2 * (C)Copyright by N.T.T 1993(unpublished) * 3 * All rights are reserved. * 4 ******************************************/ 5 declare inc8 { 6 input in<8> ; 7 output out<8> ; 8 instrin do ; 9 instr_arg do(in) ; 10 }