こんにちは、めのんです!
1週間ぶりの命令セットシミュレータです。
ちょっと地味な命令が続きますが、ステータスレジスタの操作は機械語ではすごく大事ですので早い段階でやってしまいますね。
BLD命令の実装
BLD命令というのは、ステータスレジスタの中のTフラグを指定した汎用レジスタの指定したビットにコピーする命令です。
ちょっと難しい書き方をしてしまいましたが、要するにTフラグの状態を取得する命令だと思ってください。
Tフラグはいろんな用途に使うのでこういう命令があるんだと思います。
それでは命令の説明をいつもの「AVR®命令一式手引書」から引用します。
d0~d2の3ビット(図ではb0~b2の部分)で汎用レジスタのどのビットを対象にするかを表しています。
そしてd4~d8の5ビット(図ではd0~d4の部分)でどの汎用レジスタを対象にするかを指定します。
それでは実装を見ていきます。
static void bld(atmega328_t *cpu, uint16_t op)
{
int b = op & 0x7;
int d = (op >> 4) & 0x1f;
if (cpu->sr & flag_T)
cpu->r[d] |= 1 << b;
else
cpu->r[d] &= ~(1 << b);
++cpu->clock;
}
前回までのコードに比べるとかなり複雑になってきました。
最初に、対象ビットを指定するbと対象汎用レジスタを指定するdを取り出しています。
bを求めるには下位3ビットがあればいいので0x7でANDしています。
dを求めるには、まず4ビット右シフトして最下位ビットから始まる状態にした上で5ビットを取り出すために0x1fとANDしています。
次に、Tフラグが1であれば、Rdのb番目のビットに1をセットしています。
Tフラグが0であれば、Rdのb番目のビットを0にしています。
最後にクロックカウンタをインクリメントして終了です。
CPUの動作をシミュレートするには、このようにシフト命令やビット単位のANDやORなどが頻繁に登場します。
苦手な方はこの機会に復習しておいてください。
BST命令の実装
BST命令はBLD命令の逆で、指定した汎用レジスタの対象ビットをTフラグにコピーします。
実装でもちょうどBLD命令の逆のことをやることになります。
static void bst(atmega328_t *cpu, uint16_t op)
{
int b = op & 0x7;
int d = (op >> 4) & 0x1f;
if (cpu->r[d] & (1 << b))
cpu->sr |= flag_T;
else
cpu->sr &= ~flag_T;
++cpu->clock;
}
bとdを求めるところまではBLD命令とまったく同じです。
そのあとは、汎用レジスタRdのb番目のビットが1であれば、Tフラグに1をセットしています。
そうでなければTフラグをクリアしています。
最後はクロックカウンタをインクリメントしています。
op_tableへの登録
では最後にそれぞれの命令をop_tableに登録していきます。
前回と基本的には同じなんですが、2つありますので二重ループにしてあげる必要があります。
for ($b = 0; $b < 8; ++$b)
{
for ($d = 0; $d < 32; ++$d)
{
$opcode_table[0b1111_1000_0000_0000 | $d << 4 | $b] = 'bld';
$opcode_table[0b1111_1010_0000_0000 | $d << 4 | $b] = 'bst';
}
}
bとdで合計8ビットありますので、今日やった2つの命令だけで実際には256通りのオペランドに対応したことになります。
AVRの機械語の命令は16ビットまたは32ビットですので、すごい数があるように思ってしまいますが、このようにオペランドだけが異なるものがたくさんあります。
ですので、実際にはそんなに命令数は多くないと思います。
これでBLD命令とBST命令の実装が終わりました。
それでは次回またお会いしましょう!