これまでインラインアセンブラやバイナリ手打ちをしてきましたが、ふと気づいたことがあります。
書き込み時にシリアル通信という高レベルなことを使うなんてけしからん!!
というわけで
一番理解している ARM マイコンでパチパチマイコンを作ることにしました。
パチパチマイコンとは、機械語を手打ちで入力していくマイコンのことで、ネットを調べると Z80 マイコンがよく出てきます。僕自身、この Z80 の例を見て作ろうと決心しました。
仕様
STM32 は RAM に書き込まれたプログラムを実行することが可能です。なので、配列としてプログラムデータを書いてそれを実行できます。 以下が例です。
using hword_t = uint16_t;
#define _assign_32bit(x) _low(x), _high(x)
__attribute__((aligned(4))) hword_t programBuffer[512] = {
0x4800 | ((0xff & 4) >> 2), // 00: ldr r0, [pc, #4]
0x2101, // 02: mov r1, #1
0x6001, // 04: str r1, [r0, #0]
0x4770, // 06: bx lr
_assign_32bit(&GPIOF->ODR), // 08: Imm32
};
こんな感じでオペコードを書けば良さそうです。今回はマイコンに搭載されている ARM 命令のサブセット、Thumb2 のみをサポートすることにしました。また、ハードウェアは秋月で売られている STM32F042K6T6 を使うこととします。
では実際に実行する方法ですが、ひとまずプログラムカウンタにジャンプ先アドレスを記載すれば良いのです。そこで以下のようなアセンブリを書きました。
.section .text
.type execute, %function
.global execute
execute:
mov pc, r0
やっていることは簡単、pc
に第1引数 r0
の値を代入しているだけです。これだけで、次のクロックで指定したアドレスに強制ジャンプします。呼び出し方は
void execute(hword_t *addr);
execute(programBuffer);
と言った感じです。簡単ですね。上の programBuffer
には「PF0 の LED をつけよ」と命令しているので、予め設定をしておけばいいですね。
void allInit() {
RCC->AHBENR |= RCC_AHBENR_GPIOFEN;
GPIOF->MODER &= ~GPIO_MODER_MODER0_Msk;
GPIOF->MODER |= (GPIO_MODE_OUTPUT_PP << GPIO_MODER_MODER0_Pos);
GPIOF->ODR = 0;
}
とりあえずこれでいいようです。
実行テスト
あとはこんな感じで実行します。
int main() {
allInit();
while(1) {
execute(programBuffer);
}
}
これで PF0 の LED がつくと思います。いい感じに動いていますね。以上、仕様と実行のテストでした。次回に続く。