Open8
[WIP] Xtensa 調査メモ
Xtensa とは
ESP32 などのマイコンに搭載されている RISC 命令セットアーキテクチャ。
小規模、省電力が特長。
基本情報
標準的な Xtensa の命令は 24bit で表現。Code density(コード縮小)オプションを有効化すると 16bit で表現。
Xtensa プロセッサはハーバード・アーキテクチャを採用。
基本的なレジスタ
ニーモニック | 名前 | 数 | ビット幅 | 説明 |
---|---|---|---|---|
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
というレジスタで制御。
具体的には WindowBase
に 4
を掛け算した値を開始位置として16個のレジスタをマッピング。
神記事
ABI
Window Register ABI
AR
からマッピングされた a0
~ a15
の ABI は以下のように定義。
レジスタ | 用途 |
---|---|
a0 |
リターンアドレス |
a1 |
スタックポインタ |
a2 ~ a7
|
受け取った引数 |
引数は最初の6個は a2
~ a7
に渡され、残りはスタックに保持。
Xtensa の関数呼び出しはサブルーチンと表現される。サブルーチンの呼び出しには CALLn
命令と CALLXn
命令を利用。
n
はレジスタウィンドウを回転させる量。また n
は 4, 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 |
as と at の和(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