ESP32でULPを使ったBlink その2と逆アセンブラ

コードの内容を見直しと、なぜか逆アセンブラを作ってみました。最新情報はM5StickC非公式日本語リファレンスをみてください。

サンプルコード

#include "esp32/ulp.h"
#include "driver/rtc_io.h"
#include "ulputil.h"
// スローメモリー変数割当
enum {
  SLOW_BLINK_STATE,     // Blinkの状態保持
  SLOW_PROG_ADDR        // プログラムの先頭アドレス
};
void ULP_BLINK(uint32_t us) {
  // ULPの起動間隔を設定
  ulp_set_wakeup_period(0, us);
  // メモリ初期化
  memset(RTC_SLOW_MEM, 0, 8000);
  // 変数初期化
  RTC_SLOW_MEM[SLOW_BLINK_STATE] = 0;
  // ブリンクするPIN(14bitオフセットして指定する)
  const int pin_blink_bit = RTCIO_GPIO26_CHANNEL + 14;
  const gpio_num_t pin_blink = GPIO_NUM_26;
  // GPIO26の初期化(出力に設定して初期値0)
  rtc_gpio_init(pin_blink);
  rtc_gpio_set_direction(pin_blink, RTC_GPIO_MODE_OUTPUT_ONLY);
  rtc_gpio_set_level(pin_blink, 0);
  // ULPプログラム
  const ulp_insn_t  ulp_prog[] = {
    I_MOVI(R3, SLOW_BLINK_STATE),           // R3 = SLOW_BLINK_STATE
    I_LD(R0, R3, 0),                        // R0 = RTC_SLOW_MEM[R3(SLOW_BLINK_STATE)]
    M_BL(1, 1),                             // IF R0 < 1 THAN GOTO M_LABEL(1)
    // R0 => 1の時実行
    I_WR_REG(RTC_GPIO_OUT_REG, pin_blink_bit, pin_blink_bit, 1), // pin_blink_bit = 1
    I_MOVI(R0, 0),                          // R0 = 0
    I_ST(R0, R3, 0),                        // RTC_SLOW_MEM[R3(SLOW_BLINK_STATE)] = R0
    M_BX(2),                                // GOTO M_LABEL(2)
    // R0 < 1の時実行
    M_LABEL(1),                             // M_LABEL(1)
    I_WR_REG(RTC_GPIO_OUT_REG, pin_blink_bit, pin_blink_bit, 0),// pin_blink_bit = 0
    I_MOVI(R0, 1),                          // R0 = 1
    I_ST(R0, R3, 0),                        // RTC_SLOW_MEM[R3(SLOW_BLINK_STATE)] = R0
    M_LABEL(2),                             // M_LABEL(2)
    I_HALT()                                // プログラム停止
  };
  // 変数の分プログラムを後ろにずらして実行
  size_t size = sizeof(ulp_prog) / sizeof(ulp_insn_t);
  ulp_process_macros_and_load(SLOW_PROG_ADDR, ulp_prog, &size);
  ulp_run(SLOW_PROG_ADDR);
}
void setup() {
  // デバッグ出力用
  Serial.begin(115200);
  // 300ms間隔でULPプログラムを実行
  ULP_BLINK(300000);
}
void loop() {
  // デバッグ出力
  ulpDump(0, 20, SLOW_PROG_ADDR);
  delay(1000);
}

元にしたソースはesp32 ulp programmingですが、デクリメントとかインクリメントとかしていましたが、コストを調べると直値のMOVEと同じだったので、0と1を直接代入するように買えています。

変数もenumで最初に定義して、プログラムのロード場所と実行開始のアドレスを指定しています。

デバッグしていて、なぜか逆アセンブラも作っていました。

0000 : 00C30000 DATA     0                              // ST ADDR:0x0006
0001 : 72800003 PROG MOVE   R3,   0                     // R3 = 0
0002 : D000000C PROG LD     R0, R3,   0                 // R0 = MEM[R3+0]
0003 : 820A0001 PROG JUMPR  +  5,   1, LT               // IF R0 < 1 THAN GOTO 0x0008
0004 : 1AD40500 PROG REG_WR 0x0000,  21,  21,   1       // RTC_IO[21:21] = 1
0005 : 72800000 PROG MOVE   R0,   0                     // R0 = 0
0006 : 6800000C PROG ST     R0, R3,   0                 // MEM[R3+0] = R0
0007 : 8000002C PROG JUMP   0x000B                      // GOTO 0x000B
0008 : 1AD40100 PROG REG_WR 0x0000,  21,  21,   0       // RTC_IO[21:21] = 0
0009 : 72800010 PROG MOVE   R0,   1                     // R0 = 1
000A : 6800000C PROG ST     R0, R3,   0                 // MEM[R3+0] = R0
000B : B0000000 PROG HALT                               // HALT
000C : 00000000 PROG NOP                                // NOP
000D : 00000000 PROG NOP                                // NOP
000E : 00000000 PROG NOP                                // NOP
000F : 00000000 PROG NOP                                // NOP
0010 : 00000000 PROG NOP                                // NOP
0011 : 00000000 PROG NOP                                // NOP
0012 : 00000000 PROG NOP                                // NOP
0013 : 00000000 PROG NOP                                // NOP

こんな感じの出力がシリアルにでます。一番先頭の変数は書き込まれる場所が2箇所あって、上位16ビットでどこから書き込まれたのかがわかります。上記の場合には0x0006で0(消灯)に設定した状態の出力です。

0000 : 01430001 DATA     1                              // ST ADDR:0x000A

もう一箇所はADDR:0x000Aで1(点灯)に設定しています。

まだ使っている命令だけしかキレイにしていないので、もうちょっと手を入れたらライブラリとして公開しようかな。

まとめ

いろいろ中を見ていました、Arduinoから使えるマクロだと、全命令をサポートしていないですね。ステージカウントレジスタを使っている命令が全滅でした。ループのカウンターで使うと便利そうなのですが、まあなくても他のレジスタ使えばなんとかなるはずです。

コメント