FPGA開発日記

カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages , English Version https://fpgadevdiary.hatenadiary.com/

MicroPython試行(3. RISC-V移植環境の調査 → Spikeでの動作)

MicroPythonをRISC-Vのプラットフォームで動作させたくて、調査している。

MicroPythonはQEMUの環境も用意されていて、ARMやXtensaなどの環境も用意されている。これらを参考にしながら、実装を進めていこう。

RISC-V用に用意しなければならないのは、

  • nlr_push()
  • nlr_jump()

の関数だ。これらについて日本語の資料を探したのだが見つからないので、とりあえずARM版、Xtensa版を見ながら見様見真似で進めている。

どうやら、Calling Conventionに基づいてレジスタの情報をバッファに突っ込むような作業が必要になる。

などを保管しておく必要があるが、基本的にCalling ConventionにおけるCallee側を保存して置けばよいという理解だ。

// We only need the functions here if we are on arm/thumb, and we are not
// using setjmp/longjmp.
//
// For reference, arm/thumb callee save regs are:
//      r4-r11, r13=sp

なるほど、つまりRISC-Vであれば、Callee Save側のレジスタを保存すればよいのかしら。ここらへん実際にアプリがどのように動くのか、さっぱりわからん。

f:id:msyksphinz:20171102014057p:plain

というわけで一生懸命アセンブリを書いた。しかも、あとでよく見てみるとCaller Save側のReturn Addressも保存しなければならないのか。

unsigned int nlr_push(nlr_buf_t *nlr) {

    __asm volatile (
    "sw  x2,  8 (x10) \n" // save regs...
    "sw  x8,  12(x10) \n"
    "sw  x9,  16(x10) \n"
    "sw  x18, 20(x10) \n"
    "sw  x19, 24(x10) \n"
    "sw  x20, 28(x10) \n"
    "sw  x21, 32(x10) \n"
    "sw  x22, 36(x10) \n"
    "sw  x23, 40(x10) \n"
    "sw  x24, 44(x10) \n"
    "sw  x25, 48(x10) \n"
    "sw  x26, 52(x10) \n"
    "sw  x27, 56(x10) \n"
    "sw  ra,  60(x10) \n"
    "j   nlr_push_tail \n" // do the rest in C
    );

    return 0; // needed to silence compiler warning
}

...

NORETURN void nlr_jump(void *val) {
    nlr_buf_t **top_ptr = &MP_STATE_THREAD(nlr_top);
    nlr_buf_t *top = *top_ptr;
    if (top == NULL) {
        nlr_jump_fail(val);
    }

    top->ret_val = val;
    *top_ptr = top->prev;

    __asm volatile (
    "lw  sp,  8 (%0) \n" // restore regs...
    "lw  s0,  12(%0) \n"
    "lw  s1,  16(%0) \n"
    "lw  s2,  20(%0) \n"
    "lw  s3,  24(%0) \n"
    "lw  s4,  28(%0) \n"
    "lw  s5,  32(%0) \n"
    "lw  s6,  36(%0) \n"
    "lw  s7,  40(%0) \n"
    "lw  s8,  44(%0) \n"
    "lw  s9,  48(%0) \n"
    "lw  s10, 52(%0) \n"
    "lw  s11, 56(%0) \n"
    "lw  ra,  60(%0) \n"
    "li  a0, 1       \n" // return 1, non-local return
    "ret             \n" // return
    :                               // output operands
    : "r"(top)                      // input operands
    :                               // clobbered registers
    );

    for (;;); // needed to silence compiler warning
}

これで動かしてみる。やってみるのはSpikeシミュレータでの動作だ。とりあえずこれで動作を確認したい。

f:id:msyksphinz:20171102013920p:plain

やった!動作した。とりあえず方針としては合っているようだ。 次は、これをRocket Chipとか、HiFive1で動かしてみたいな。

msyksphinz.hatenablog.com

msyksphinz.hatenablog.com