こんにちは、めのんです!
今作っている命令セットシミュレータも少しずつ命令が増えています。
でもまだまだで、今までの状態では満足にRAMへの読み書きすらできませんでした。
今回の追加分で、RAMへの最低限の読み書きができるようになります。
LDS命令の実装
最初はLDS命令です。
これはデータメモリから汎用レジスタに1バイトの値を読み込むためのものです。
それで、いつものように「AVR®命令一式手引書」から命令の説明を引用します。
久々の2ワード命令ですね。
LDS命令では、データメモリのアドレスを直接指定して汎用レジスタに値を読み込みます。
前回のLDI命令も含めて、AVRにはロード系の命令がいくつもあります。
AVRに限らず多くのCPUがそんな感じですね。
ところで、上の説明ではRAMPDレジスタ云々の説明がありますが、ATmega328では64KiBを超えるアドレスを扱うことはないのでこの部分は無視します。
また、以前にも書きましたが、この命令セットシミュレータで対象にしているATmega328はAVRe+に相当しますので、実行周期表ではAVReの欄を見ます。
それではコードを見ていきます。
static void lds(atmega328_t *cpu, uint16_t op)
{
uint16_t k = fetch(cpu);
int d = (op >> 4) & 0x1f;
cpu->r[d] = cpu->data[k];
cpu->clock += 2;
}
2ワード命令なので、JMP命令のときと同じように内部でfetch関数を呼び出しています。
あとは目新しい要素はないと思います。
STS命令の実装
STS命令はLDS命令の逆で、汎用レジスタの値をデータメモリに書き込みます。
こちらも「AVR®命令一式手引書」から命令の説明を引用します。
LDS命令同様、RAMPDレジスタのくだりは無視します。
それではコードを見ていきます。
static void sts(atmega328_t *cpu, uint16_t op)
{
uint16_t k = fetch(cpu);
int d = (op >> 4) & 0x1f;
cpu->data[k] = cpu->r[d];
cpu->clock += 2;
}
LDS命令とは5行目の左辺と右辺が逆になっているだけですね。
op_tableへの登録
次に、いつものようにop_tableに登録します。
opcode.phpに次のコードを追加して実行してあげればOKです。
for ($d = 0; $d < 32; ++$d)
{
$opcode_table[0b1001_0000_0000_0000 | $d << 4] = 'lds';
$opcode_table[0b1001_0010_0000_0000 | $d << 4] = 'sts';
}
今回は65,536命令のうち64個が埋まりました。
オペランドの大部分は2ワード目なので、1ワード目には汎用レジスタの番号しか埋め込まれていないからです。
それでは次回またお会いしましょう!