20 |
BSVの設計トライアル (10) |
スタック操作のBSV記述
共通シーケンスをコールする場合、これまで見てきたように、スタック操作をする必要がありますが、煩雑なのでこれを隠蔽することを考えます。と言ってもソフトウェアでやるように、push, pop, call, return等の概念を使います。また、これまでハードウェアという意識から「共通シーケンス」と称してきた概念を、ソフトウエアに合わせてサブルーチンと呼びます。
対象となる検証用FSMのステート定義を示します。例として4レベルのFSMを考えます。state変数は構造体で定義しています。
typedef enum { L1, L2, L3, L4 } Function_t deriving(Bits,Eq);
typedef enum { S0, S1, S2, S3, S4 } Step_t deriving(Bits,Eq);
typedef struct {
Function_t func;
Step_t step;
} State_t deriving(Bits,Eq);
rsはリターンスタック配列で、BSVでの実装例として、今回はRegFileで構成します。spはスタックポインタで配列インデックスです。Verilogにおける配列のdata変数への読み出し
data <= rs[sp]
は、この実装では、
data <=rs.sub(sp)
となり、逆にVerilogにおける配列へのdataの書き込み
rs[sp] <= data
は、この実装では
rs.upd(sp, data)
となります。
マクロ命令定義
これらを用いて作成したマクロ命令の定義文のコードです。
`define pushRet rs.upd(sp, ret); sp <= sp + 1
`define popRet state <= rs.sub(sp-1); sp <= sp - 1
`define call(SUB) `_saveNext; state <= State_t {func:SUB, step:S0}
`define _saveNext ret <= State_t {func:state.func, step:nextStep()}
`define return state <= ret
`define next state.step <= nextStep()
その説明を表243.1に示します。
マクロ命令名 | 説明 |
---|---|
pushRet | 非リーフルーチン中で、他のルーチンを呼ぶ際に破壊されるretをスタックにプッシュするマクロ命令で、必ず先頭でpushするものとします。 |
popRet | 非リーフ内で呼び出し元に戻るためのマクロ命令で、retを回復せずに、スタック中の戻りステートに直接戻るマクロ命令です。 |
call(SUB) | サブルーチンコールです。次のステートをretに入れ、コール先にジャンプします。 |
_saveNext | callに使用されており、次のステートをretに入れる内部マクロ命令です。後述のnextStep()関数を使用しています。ユーザが陽に使う必要は無いため、アンダースコアを付けています。 |
return | リーフ内で呼び出し元に戻るためのマクロ命令です。 |
next | 次のステートに進めるためのマクロ命令です。後述のnextStep()関数を使用しています。 |