
ロードあればストアあり。前回、前々回と浮動小数とSIMD(スカラー)のロード命令(LDR)を練習してみました。今回は対になるストア命令(STR)の練習です。ほぼ同様なアドレシングモードが使用できますが、唯一PC相対だけはありません。PC相対で指定できるのは”.TEXT”セグメントと解釈されるのでストアは対象外っと。
※「ぐだぐだ低レベルプログラミング」投稿順indexはこちら
※実機動作確認には以下を使用しております。
-
- Raspberry Pi 4 model B、Cortex-A72コア(ARMv8-A)
- Raspberry Pi OS (64bit) bullseye
- gcc (Debian 10.2.1-6) 10.2.1 20210110
ARMv8もいろいろレベルがあり、Arm Cortex-A72はARMv8の中でもベーシックな(命令数の少ない)ARMv8p0です。
※A64の最新のマニュアルは以下でダウンロード可能です。
Arm Architecture Reference Manual for A-profile architecture
STR命令
前回、前々回と練習したLDR命令と対になるストア命令はSTRというニーモニックです。整数型のロード、ストアとニーモニック共通なので、ロード、ストアの対象になるレジスタ指定で整数なのか浮動小数(SIMDスカラ)か判定することになります。
LDRとSTRは「代表的な」ロード/ストア命令ですが、他にもいろいろあるのは以前にやったとおりです。RISCといいつつ命令多すぎA64です。今回は、前回、前々回と練習したLDRのほぼほぼ同じアドレシングのSTRを見ていきたいと思います。SIMDスカラまでいれるとストアできるビット幅はいろいろなのですが、例によってFloat(単精度浮動小数)だけにしてます。手抜き。
今回実験のアセンブリ言語関数
「いつものように手抜きな」関数プロローグもエピローグもない被テスト関数ですが、いつもと違って実質2命令です。ストアするからにはストアするデータがレジスタに載っていないとならないのですが、今回は引数でデータを与えるのでなく、唯一STRでおよびがかからないPC相対アドレシングで .TEXT セグメント中の定数をロードしたものをストアするようにしてます。
.globl fstrSImmPost, fstrSImmPre, fstrSImmU, fstrSRegLSL0, fstrSRegLSL2, fstrSRegUXTW0, fstrSRegUXTW2
.text
.balign 4
fstrSImmPost:
ldr s0, dlabel1
str s0, [x0], #4
ret
fstrSImmPre:
ldr s0, dlabel2
str s0, [x0, #4]!
ret
fstrSImmU:
ldr s0, dlabel3
str s0, [x0, #8]
ret
fstrSRegLSL0:
ldr s0, dlabel4
str s0, [x0, x1]
ret
fstrSRegLSL2:
ldr s0, dlabel5
str s0, [x0, x1, LSL #2]
ret
fstrSRegUXTW0:
ldr s0, dlabel6
str s0, [x0, w1, UXTW]
ret
fstrSRegUXTW2:
ldr s0, dlabel7
str s0, [x0, w1, UXTW #2]
ret
.balign 4
dlabel1:
.single 1.2345e3
dlabel2:
.single 2.2345e3
dlabel3:
.single 3.2345e3
dlabel4:
.single 4.2345e3
dlabel5:
.single 5.2345e3
dlabel6:
.single 6.2345e3
dlabel7:
.single 7.2345e3
C言語記述のmain関数
「通り一遍さわるだけの手抜きな」C言語記述のテスト駆動部です。被テスト関数は格納先のアドレスへのポインタ、およびインデックスを受け入れ、Float型の定数を所定メモリにストアします。ストア先としては配列を用意しておきます。Pre、Postインデックスアドレシングをテストする場合には、更新後のポインタを戻り値として受け取ります。他のケースでは処理結果は配列に入っているハズなので戻り値はvoidです。
#include <stdio.h>
#include <stdint.h>
extern uint64_t fstrSImmPost(float *);
extern uint64_t fstrSImmPre(float *);
extern void fstrSImmU(float *);
extern void fstrSRegLSL0(float *, uint64_t);
extern void fstrSRegLSL2(float *, uint64_t);
extern void fstrSRegUXTW0(float *, uint32_t);
extern void fstrSRegUXTW2(float *, uint32_t);
#define MAXMEM (10)
float TargetMEM[MAXMEM];
void initTGT() {
for (int i=0; i < MAXMEM; i++) {
TargetMEM[i] = 0.0f;
}
}
int main(void) {
uint64_t resultA;
initTGT();
printf ("TargetMEM-A : 0x%lx\n", TargetMEM);
resultA =fstrSImmPost(TargetMEM);
printf ("fstrSImmPost-A: 0x%lx\n", resultA);
resultA =fstrSImmPre(TargetMEM);
printf ("fstrSImmPre-A : 0x%lx\n", resultA);
fstrSImmU(TargetMEM);
fstrSRegLSL0(TargetMEM, 12);
fstrSRegLSL2(TargetMEM, 4);
fstrSRegUXTW0(TargetMEM, 20);
fstrSRegUXTW2(TargetMEM, 6);
for (int i=0; i < MAXMEM; i++) {
printf("%d : %e \n", i, TargetMEM[i]);
}
return 0;
}
ビルドして実行
ちゃんと期待通りの結果がメモリに格納されたようです。目出度し目出度し。といってまだロード、ストア続くんじゃが。ほんと命令多いなA64。

