ロードあればストアあり。前回、前々回と浮動小数と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。