[risc-v]Cをrisc-vアセンブリに変換
Assembly Languageとは?
アセンブリ言語またはアセンブリ言語は、機械言語に対応するコンピュータプログラミングの低レベル言語である.(wiki)
Sam Blairを紹介する前に、開発者がC言語で作成したソースコードが実際にどのように動作しているかを理解しておきましょう.C言語プログラムは以下の順序で作成し、実行する.
開発者はC言語文法に基づいてプログラムを作成する.
int s = 0;
for (i=0; i<10; i++) {
if (A[i]==0) continue;
s += A[i];
}
コンパイラがコンパイルするCPUのアーキテクチャにマシン言語を生成する.
0x00000000 0x000009B3
0x00000004 0x00000A33
0x00000008 0x10000A97
0x0000000C 0xFF8A8A93
0x00000010 0x00A00E13
0x00000014 0x03CA5063
0x00000018 0x002A1513
0x0000001C 0x01550533
0x00000020 0x00052483
0x00000024 0x00048463
0x00000028 0x009989B3
0x0000002C 0x001A0A13
0x00000030 0xFE0002E3
CPU運転CPUは、生成したマシン言語を順次読み出すことによりプログラムを実行する.
CPUはregister,ALU,MUXなどからなり,入力されたマシン命令セットが下図のように順次取得,復号,実行されるにつれてプログラムが実行される.△この構造については、次の記事で詳しく説明します.
では、ここのコンポーネントは何でしょうか。
アセンブリ言語は、機械言語に対応する低レベルのプログラミング言語である.
したがって,コンパイラがコンパイルしたマシン言語はコンポーネントに一つ一つ対応する.開発者がコンポーネントを介してプログラムを記述する場合、コマンドセットレベルでプログラムの動作を完全に制御できます.
0x00000000 0x000009B3 add x19 x0 x0
0x00000004 0x00000A33 add x20 x0 x0
0x00000008 0x10000A97 auipc x21 65536
0x0000000C 0xFF8A8A93 addi x21 x21 -8
0x00000010 0x00A00E13 addi x28 x0 10
0x00000014 0x03CA5063 bge x20 x28 32
0x00000018 0x002A1513 slli x10 x20 2
0x0000001C 0x01550533 add x10 x10 x21
0x00000020 0x00052483 lw x9 0(x10)
0x00000024 0x00048463 beq x9 x0 8
0x00000028 0x009989B3 add x19 x19 x9
0x0000002C 0x001A0A13 addi x20 x20 1
0x00000030 0xFE0002E3 beq x0 x0 -28
CをRISC-Vコンポーネントに変換
上のcコードの動作を説明すると以下のようになります.
int s = 0;
変数宣言はfor (i=0; i<10; i++) {
if (A[i]==0) continue;
s += A[i];
}
ここで、s変数がx 19、i、x 20、Aのアドレスがx 21のレジスタにそれぞれ格納されていると仮定すると、次のようにコンポーネントコードを記述できます. add x19 x0 x0 // s = 0
add x20 x0 x0 // i = 0
addi x28 x0 10 // x28 = 10
LOOP: bge x28 x20 EXIT // if 10 >= i; GOTO EXIT
slli x10 x20 2 // x10 = i * 4
add x10 x10 x21 // x10 = &A[0] + i*8
lw x9 0(x10) // x9 = A[i]
beq x9 x0 L1 // if A[i] == 0; GOTO L1
add x19 x19 x9 // s = s + A[i]
L1 : addi x20 x20 1 // i = i + 1
beq x0 x0 LOOP // GOTO LOOP
EXIT:
まずsとiを表すレジスタを0(x 0)に初期化する.bgeは定数を比較するのではなく、レジスタに格納されている値を比較するため、x 28という一時レジスタを作成して数字10を格納する.for (i=0; i<10; i++)
は、3行目および3行目によって達成される.32ビットriscvを使用する場合、a[i]の値は以下のようにロードされます.
32ビットriscvは4バイトが1文字です.したがって,インデックスが表す配列の間隔を求めるには,配列のインデックスに4を乗じなければならない.
配列の先頭アドレスに間隔を付けて、実際の値を格納するアドレス値を求めます.
slli x10 x20 2 // x10 = i * 4
add x10 x10 x21 // x10 = &A[0] + i*8
lw x9 0(x10) // x9 = A[i]
シミュレーション
VscodeのRISC−V Venusシミュレータ拡張を用いて記述されたアセンブリコードをシミュレートすることができる.(Venusシミュレータは32ビットriscvをサポートしているのでload wordを使用しています.)
上のコードを実行します.
ループを繰り返すと、x 9、x 19レジスタに適切な値が格納され、所望の瞬間にループが終了することが確保される.
Reference
Reference
この問題について([risc-v]Cをrisc-vアセンブリに変換), 我々は、より多くの情報をここで見つけました https://velog.io/@curiosity806/risc-vC를-risc-v-assembly로-변환하기テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol