【目次に戻る】

4. KUE-CHIP2のSFL記述


いよいよKUE-CHIP2全体を,SFLのモジュールkuechip2として記述します. リスト4.1 に一例を示します.

他のファイルのインクルード (3行目から5行目) [TOP]

モジュールkuechip2では,これまでに設計したモジュールkueshiftと kuealuをサブモジュールとして用います.それらのSFL記述は,必ずしもここ にインクルードする必要はないのですが,インクルードすると論理合成の際に 便利です.%iに続けて"と"でファイル名を囲むことで,カレントディレクトリ から見たパス名のファイルをインクルードします.

図1.1 のブロック図には,INCという8ビットのインクリメンタがあります.8ビット のインクリメンタはまだ設計していないのですが,PARTHENON標準ライブラリ の中にinc8という8ビットのインクリメンタが存在しますので,これを用いる ことにします.PARTHENON標準ライブラリは,$PARTHENON/sfl_lib.dirという ディレクトリに,多くのファイルとして格納されていますが,%iに続けて< と>でファイル名を囲むことで,このディレクトリにあるファイルをインク ルードします.inc8.hというファイルの中身は, リスト4.2 のようになっています.inc8は,機能回路として定義されています.機能回路 はモジュールのようなものですが,論理合成されない,使える演算子と構成要 素が拡張されているなどという点でモジュールと異なっています.機能回路の 記述は,circuit_typeあるいはcircuit_classで始めます.inc8などの PARTHENON標準ライブラリは,すでに論理合成されてそのネットリストが用意 されていますので,機能回路で定義されているわけです.

マクロ定義 (7行目から20行目) [TOP]

SFLでは,%dを用いてマクロ定義を行います.たとえば,NOPという文字列 は,(ir<7:3> == 0b00000)という文字列に置き換えられます.ここでは マクロ定義を用いて, 表1.1 に従って命令の分類を行っています.

サブモジュールタイプの定義 (22行目から38行目) [TOP]

モジュールkuechip2では,これまでに設計したモジュールkueshift, kuealuを,それぞれサブモジュールshifter, aluとして用います.そのために は,サブモジュールタイプの定義が必要ですので,ここで行っています. kueshiftの制御入力端子doの仮引数と,kuealuの制御入力端子doの仮引数は, ともに,すべてのデータ入力端子とします.

外部端子の定義 (41行目から47行目) [TOP]

ここからは,モジュールkuechip2の定義部の記述となります.まずは,外 部端子を記述します.KUE-CHIP2の外部端子はすでに規定されているので,こ こにはそれらを書き下せばよいのですが,どれを制御端子にしてどれをデータ 端子にするかということを決める必要があります.

まず入力端子に関してですが,メモリやIBUFの値を読み込むためのdbi, IBUF_FLAG, OBUF_FLAGを読み込むためのibuf_flg_in, obuf_flg_inはすべてデー タ入力端子とします.出力端子に関しては,メモリの値の読み出しを依頼する mem_re,メモリへ値の書き込みを依頼するmem_we,IBUFの値の読み出しを依頼 するibuf_re,IBUF_FLAGを0にするibuf_flg_clr,OBUFへ値の書き込みを依頼 するobuf_weは制御出力端子にします.そして,メモリやOBUFに値を書き込む ためのdbo<8>,メモリのアドレスを指定するためのab<9>はデー タ出力端子とします.

その他に,デザインコンテストでは規定されていませんが,kuechip2を起 動するための制御入力端子startを持つものとします.

構成要素の定義 (49行目から58行目) [TOP]

次はkuechip2の構成要素を記述します.まずレジスタに関しては, 図1.1 に示したように,acc, ix, cf, vf, nf, zf, pc, ir, marを用意します. KUE-CHIP2のレジスタはリセット信号でリセットされるので,レジスタとして はreg_wr (register with reset)を用いることにします.そのほかに,図1.1 に示されているものとしては,モジュールkueshift, kuealuを,それぞれサブ モジュールshifter, aluとして用い,PARTHENON標準ライブラリのinc8を,サ ブモジュールincとして用います.また,データ内部端子として,sel_bを用意 します.

そのほかに,図1.1にはありませんが,SFL記述を簡潔にするためのいくつ かの構成要素を定義します.bcond_calc, bcond_statusは,BRANCH命令を処理 するために設けた制御内部端子です.exec_aluは,aluを用いて算術論理演算 命令を処理するための制御内部端子です.制御内部端子は,制御入力端子や制 御出力端子と同様に,起動されなければその値は0で,起動されるとその値が1 になります.また,動作を関連づけることもできます.これらの働きについて はもう少し後で説明します.

制御端子の仮引数の定義 (60行目から64行目) [TOP]

制御端子のうち,制御出力端子と制御内部端子の仮引数の定義は,モジュー ルの定義部で行います.制御出力端子と制御内部端子を起動するのは,これら を持つモジュールだからです.

mem_reはabを仮引数として持つものとします.メモリの内容を読みだすた めには,アドレスを与えなければならないからです.mem_weについては,アド レスだけではなく,メモリに書き込むべきデータの値も与えなければなりませ んので,abとdboを仮引数とします.obuf_weについては,書き込むべきデータ の値だけを与えれば良いので,dboを仮引数とします.

exec_aluはsel_bを仮引数として持つものとします. 図1.1 に示すように,sel_bはaluの入力の1つとなるからです.

ステージとタスクと仮引数の定義 (66行目から67行目) [TOP]

SFLには,ステージという概念があります.制御端子は1クロックで終了す る動作を行うのに対し,ステージは複数クロックにまたがる一連の動作を行い ます.すなわち,ステージは状態を持ちますが,制御端子は状態を持ちません.

ステージを複数個用意すると,並列動作をうまく記述することができます. しかし,ここではステージを一つだけ用意し,その唯一のステージの名前を allとします.ステージallは, 表1.1 に示されたフェーズ表に従って,各命令の動作を制御するものとします.

ステージにはタスクというものが存在し,これが起動されることでステー ジが動作すると考えられています.ステージallにもタスクが必要です.tとい う名前のタスクを用意します.

制御端子による動作 (69行目から99行目) [TOP]

次に,制御端子による動作を記述します.制御端子のうち,制御入力端子 と制御内部端子による動作の定義は,これらを持つモジュールの定義部で行わ れます.一方,制御出力端子による動作の定義は,その制御出力端子を持つモ ジュールの外,つまりそのモジュールをサブモジュールとして使用するモジュー ルで行われます.従って,ここでは行われません.

制御入力端子startが起動されると,ステージ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以外).

ステージの動作 (101行目から199行目) [TOP]

最後に,ステージallの動作を記述します.SFLのステージは,generateと いうキーワードで起動され,起動された次のクロックから動作を開始し, finishというキーワードで動作を終了します.したがって,allは,制御入力 端子startによって動作を開始し,HLT命令により動作を終了します.

ステージallは3つの状態を持つものとし, 表1.1 に示した3つのフェーズp1, p2, p3をそれぞれの状態に対応させます.状態p1 では,命令の種類によらず動作は一定ですが,状態p2, p3での動作は命令の種 類によって様々なものとなります.状態を持つステージでは,どれかの1つの 状態のみが有効になっています.ステージが動作中であっても,有効でない状 態の動作は行われません.初めに有効な状態(初期状態)は,キーワード first_stateで指定します.有効な状態の変更(状態遷移)は,キーワード gotoによって行います.

表1.1とこのSFL記述を見比べることで,SFL記述の意味がわかりやすくなる と思います.

制御端子の起動 [TOP]

制御端子による動作とステージの動作の記述には,制御端子の起動がたく さん現れています.制御端子は,その後に()を付けることで起動します.制御 端子は,制御入力端子,制御出力端子,制御内部端子に分けられますが,ここ では,それぞれの起動について説明します.

まず,制御入力端子ですが,あるモジュールから起動するのは,そこで使 用しているサブモジュールの制御入力端子であることに注意してください.例 えば140行目では,サブモジュールshifterの制御入力端子doを, ir<2:0>, ix, cfを引数として起動しています.これにより,kueshift のdoの仮引数の定義(28行目)に従って,shifterのデータ入力端子mode, in, ciに,それぞれ,ir<2:0>, ix, cfの値が転送されます.また,shifter のdoが1になり,それに対応づけられた動作が行われます.この動作は,モジュー ルkueshiftの定義部に記述されています.このように,制御入力端子を用いて, あるモジュールからそこで使用しているサブモジュールに仕事を依頼します.

次に,制御出力端子について見てみます.例えば106行目では,制御出力端 子mem_reを,0b0 || pcを引数として起動しています.これにより,61行目の 仮引数の定義に従って,データ出力端子abに0b0 || pcの値が転送されます. また,mem_reが1になり,それに対応づけられた動作が行われます.この動作 とは,メモリのab番地の内容をdbiに転送することですが,これはモジュール kuechip2の外側で規定されます.このように,制御出力端子を用いて,あるモ ジュールから外側のモジュールに仕事を依頼します.

最後に,制御内部端子について見てみます.例えば156行目では,制御内部 端子exec_aluを,ixを引数として起動しています.これにより,64行目の仮引 数の定義に従って,データ内部端子sel_bにixの値が転送されます.また, exec_aluが1になり,それに対応づけられた動作が行われます.この動作は, 89行目から99行目に書かれています.制御内部端子は,制御入力端子や制御出 力端子のように別のモジュールに仕事を依頼するものではなく,一連のまとまっ た動作を記述するためのものです.従って,必ずしもこのように記述する必要 はないのですが,制御入力端子を利用することで,SFL記述を簡潔にすること ができます.

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

[リスト 4.1] SFL記述 (kuechip2.sfl) [TOP]
  1: /** kuechip2 : The main module for KUE-CHIP2 **/
  2: 
  3: %i "kueshift.sfl"
  4: %i "kuealu.sfl"
  5: %i <inc8.h>
  6: 
  7: %d NOP    (ir<7:3> == 0b00000)
  8: %d HLT    ((ir<7:3> == 0b00001) | (ir<7:4> == 0b0101))
  9: %d OUT    (ir<7:3> == 0b00010)
 10: %d IN     (ir<7:3> == 0b00011)
 11: %d SRCF   (ir<7:4> == 0b0010)
 12: %d BRANCH (ir<7:4> == 0b0011)
 13: %d SHIFT  (ir<7:4> == 0b0100)
 14: %d LD_REG ((ir<7:4> == 0b0110) & (ir<2:1> == 0b00))
 15: %d AL_REG ((ir<7> == 0b1)      & (ir<2:1> == 0b00))
 16: %d LD_IMM ((ir<7:4> == 0b0110) & (ir<2:1> == 0b01))
 17: %d AL_IMM ((ir<7> == 0b1)      & (ir<2:1> == 0b01))
 18: %d LD_MA  ((ir<7:4> == 0b0110) & (ir<2> == 0b1))
 19: %d ST_MA  ((ir<7:4> == 0b0111) & (ir<2> == 0b1))
 20: %d AL_MA  ((ir<7> == 0b1)      & (ir<2> == 0b1))
 21: 
 22: submod_type kueshift {
 23:     /** external pins **/
 24:     instrin     do;
 25:     input       mode<3>, in<8>, ci;
 26:     output      out<8>, co, vo, no, zo;
 27:     /** arguments of instrin **/
 28:     instr_arg   do(mode, in, ci);
 29: }
 30: 
 31: submod_type kuealu {
 32:     /** external pins **/
 33:     instrin     do;
 34:     input       mode<3>, a<8>, b<8>, ci;
 35:     output      out<8>, co, vo, no, zo;
 36:     /** arguments of instrin **/
 37:     instr_arg   do(mode, a, b, ci);
 38: }
 39: 
 40: module kuechip2 {
 41:     /** external pins **/
 42:     instrin     start;
 43:     input       dbi<8>;
 44:     input       ibuf_flg_in, obuf_flg_in;
 45:     instrout    mem_we, mem_re;
 46:     instrout    ibuf_re, ibuf_flg_clr, obuf_we;
 47:     output      dbo<8>, ab<9>;
 48: 
 49:     /** elements **/
 50:     reg_wr      acc<8>, ix<8>;
 51:     reg_wr      cf, vf, nf, zf;
 52:     reg_wr      pc<8>, ir<8>, mar<8>;
 53:     inc8        inc;
 54:     kuealu      alu;
 55:     kueshift    shifter;
 56:     sel         sel_b<8>;
 57:     instrself   bcond_calc, bcond_status;
 58:     instrself   exec_alu;
 59: 
 60:     /** arguments of instrout and instrself **/
 61:     instr_arg   mem_re(ab);
 62:     instr_arg   mem_we(ab, dbo);
 63:     instr_arg   obuf_we(dbo);
 64:     instr_arg   exec_alu(sel_b);
 65: 
 66:     /** stages and tasks and their arguments **/
 67:     stage_name  all { task t(); }
 68: 
 69:     /** operations of instrin and instrself **/
 70:     instruct start generate all.t();
 71:     instruct bcond_calc if (
 72:         ( ir<3:0> == 0b0000 ) |
 73:         ( ( ir<3:0> == 0b1000 ) & vf ) |
 74:         ( ( ir<3:0> == 0b0001 ) & ^zf ) |
 75:         ( ( ir<3:0> == 0b1001 ) & zf ) |
 76:         ( ( ir<3:0> == 0b0010 ) & ^nf ) |
 77:         ( ( ir<3:0> == 0b1010 ) & nf ) |
 78:         ( ( ir<3:0> == 0b0011 ) & ^(nf | zf) ) |
 79:         ( ( ir<3:0> == 0b1011 ) & nf | zf ) |
 80:         ( ( ir<3:0> == 0b0100 ) & ^ibuf_flg_in ) |
 81:         ( ( ir<3:0> == 0b1100 ) & obuf_flg_in ) |
 82:         ( ( ir<3:0> == 0b0101 ) & ^cf ) |
 83:         ( ( ir<3:0> == 0b1101 ) & cf ) |
 84:         ( ( ir<3:0> == 0b0110 ) & ^(vf @ nf) ) |
 85:         ( ( ir<3:0> == 0b1110 ) & vf @ nf ) |
 86:         ( ( ir<3:0> == 0b0111 ) & ^((vf @ nf) | zf) ) |
 87:         ( ( ir<3:0> == 0b1111 ) & (vf @ nf) | zf )
 88:                             ) bcond_status();
 89:     instruct exec_alu par {
 90:         any {
 91:             ir<3> : alu.do(ir<6:4>, ix, sel_b, cf);
 92:             else : alu.do(ir<6:4>, acc, sel_b, cf);
 93:         }
 94:         if ( ^(ir<6:4> == 0b111) ) any { /* except CMP */
 95:             ir<3> : ix := alu.out;
 96:             else : acc := alu.out;
 97:         }
 98:         cf := alu.co; vf := alu.vo; nf := alu.no; zf := alu.zo;
 99:     }
100: 
101:     /** operations of stages **/
102:     stage all {
103:         state_name p1, p2, p3;
104:         first_state p1;
105:         state p1 par {
106:             ir := mem_re(0b0 || pc).dbi;
107:             pc := inc.do(pc).out;
108:             goto p2;
109:         }
110:         state p2 any {
111:             NOP : goto p1;
112:             HLT : par {
113:                 goto p1;
114:                 finish;
115:             }
116:             OUT : par {
117:                 obuf_we(acc);
118:                 goto p1;
119:             }
120:             IN : par {
121:                 acc := ibuf_re().dbi;
122:                 goto p3;
123:             }
124:             SRCF : par {
125:                 cf := ir<3>;
126:                 goto p1;
127:             }
128:             BRANCH : par {
129:                 bcond_calc();
130:                 mem_re(0b0 || pc);
131:                 inc.do(pc);
132:                 any {
133:                     bcond_status : pc := dbi;
134:                     else : pc := inc.out;
135:                 }
136:                 goto p1;
137:             }
138:             SHIFT : par {
139:                 any {
140:                     ir<3> : ix := shifter.do(ir<2:0>, ix, cf).out;
141:                     else : acc := shifter.do(ir<2:0>, acc, cf).out;
142:                 }
143:                 cf := shifter.co; vf := shifter.vo;
144:                 nf := shifter.no; zf := shifter.zo;
145:                 goto p1;
146:             }
147:             LD_REG : par {
148:                 any {
149:                     ir<0> & ^ir<3> : acc := ix;
150:                     ^ir<0> & ir<3> : ix := acc;
151:                 }
152:                 goto p1;
153:             }
154:             AL_REG : par {
155:                 any {
156:                     ir<0> : exec_alu(ix);
157:                     else : exec_alu(acc);
158:                 }
159:                 goto p1;
160:             }
161:             LD_IMM : par {
162:                 any {
163:                     ir<3> : ix := mem_re(0b0 || pc).dbi;
164:                     else : acc := mem_re(0b0 || pc).dbi;
165:                 }
166:                 pc := inc.do(pc).out;
167:                 goto p1;
168:             }
169:             AL_IMM : par {
170:                 exec_alu(mem_re(0b0 || pc).dbi);
171:                 pc := inc.do(pc).out;
172:                 goto p1;
173:             }
174:             LD_MA | ST_MA | AL_MA : par {
175:                 mem_re(0b0 || pc);
176:                 any {
177:                     ir<1> : mar := alu.do(0b011, ix, dbi, 0b0).out;
178:                     else : mar := dbi;
179:                 }
180:                 pc := inc.do(pc).out;
181:                 goto p3;
182:             }
183:         }
184:         state p3 par {
185:             any {
186:                 IN : ibuf_flg_clr();
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: }

[リスト 4.2] inc8.h [TOP]
 1: /******************************************
 2: * (C)Copyright by N.T.T 1993(unpublished) *
 3: * All rights are reserved.     by K.Oguri *
 4: ******************************************/
 5: circuit_class inc8 {
 6:     input       in<8> ;
 7:     output      out<8> ;
 8:     instrin     do ;
 9:     instr_arg do(in) ;
10:     instruct do out = in + 0b1 ;
11: }