Open8

[WIP] Xtensa 調査メモ

ほたほた

Xtensa とは

ESP32 などのマイコンに搭載されている RISC 命令セットアーキテクチャ。
小規模、省電力が特長。

ほたほた

基本的なレジスタ

ニーモニック 名前 ビット幅 説明
PC Program counter 1 32 実行中の命令のアドレスを保持。
AR[n] Address registers 32 or 64 32 物理汎用レジスタ。
a0 ~ a15 Architectual registers 16 32 AR からマッピング。

Xtensa のコアが直接アクセス出来るのは a0 ~ a15 のレジスタ。
Windowed register オプションを有効化することで AR[i..i+15]a0 ~ a15 にマッピング。

Windowed Register

AR から a0 ~ a15 へのマッピング範囲は WindowBase というレジスタで制御。
具体的には WindowBase4 を掛け算した値を開始位置として16個のレジスタをマッピング。

ほたほた

ABI

Window Register ABI

AR からマッピングされた a0 ~ a15 の ABI は以下のように定義。

レジスタ 用途
a0 リターンアドレス
a1 スタックポインタ
a2 ~ a7 受け取った引数

引数は最初の6個は a2 ~ a7 に渡され、残りはスタックに保持。

Xtensa の関数呼び出しはサブルーチンと表現される。サブルーチンの呼び出しには CALLn 命令と CALLXn 命令を利用。
n はレジスタウィンドウを回転させる量。また n4, 8, 12 に等しく、CALLn 命令は CALL4, CALL8, CALL12 のように表される。CALLXn 命令も同様。

ほたほた

Instruction Formats

Instruction Fields

  • op0, op1, op2
    • 4bit opcode フィールド
  • r, s, t
    • 4bit オペランドフィールド

Format descriptions

TODO

ほたほた

命令早見表

Assembler expressions 説明
ar AR[r] に対応。
as AR[s] に対応。
at AR[t] に対応。
sr スペシャルレジスタネーム

WIP

命令 アセンブリ 説明
ABS abs ar, at at の絶対値を計算し ar に書き込む。
ADD add ar, as, at asat の和(32bit)を計算し ar に書き込む。
ADDX2 addx2 ar, as, at ar = as + (at * 2)
MOV mov.n ar, at ar = at
S32I s32i at, as, imm as(offset imm)at をストア。
L32I l32i at, as, imm as(offset imm)at にロード。
ほたほた

コンパイラが出力するアセンブリの観察

Compiler Explorer で gcc が出力する Xtensa アセンブリを観察する。
コンパイラ:Xtensa gcc 12.2.0
オプション:-O0

比較演算子

Less than

main.c
int main() {
    int a = 1;
    int b = 2;
    int c = a < b;

    return 0;
}
コンパイル結果
main:
        entry   sp, 48
        mov.n   a7, sp
        movi.n  a2, 1         # int a = 1;
        s32i.n  a2, a7, 0
        movi.n  a2, 2         # int b = 2;
        s32i.n  a2, a7, 4
        movi.n  a2, 1          # a2 は a < b の演算結果(最初は 1(true) がセットされる)
        l32i.n  a4, a7, 0      # a4 = a;
        l32i.n  a3, a7, 4      # a3 = b;
        blt     a4, a3, .L2    # もし a < b なら .L2 へジャンプ(a2 は 1(true) のまま)
        movi.n  a2, 0         # blt でジャンプが起きなかった場合は a2 に 0(false) がセットされる
.L2:
        extui   a2, a2, 0, 8  # a2 から 8bit 抽出して a2 に格納(なんでやってるのか分からん)
        s32i.n  a2, a7, 8     # c = a2;
        movi.n  a2, 0          # return 0;
        retw.n