MIPSアセンブラーの学習





ウィキペディアによると、MIPSはMIPS Computer Systems(現在のMIPS Technologies)によって開発され、1985年に最初に実装されたマイクロプロセッサです。 このアーキテクチャには、3Dモデリング、浮動小数点数の高速処理、マルチスレッド計算用に特別に作成された多数の修正があります。 これらのプロセッサのさまざまなバージョンが、CiscoおよびMikrotikのルーター、スマートフォン、タブレット、ゲームコンソールで使用されています。



MIPS命令は理解するのに十分なほど単純であり、それから、アセンブラーの学習を開始することが推奨されます。 実際、今何をしますか。



MIPSアセンブラーのプログラム構造



これは、古典的なMIPSアセンブラプログラムの外観です。

ポイントから始まるものはすべてディレクティブです。 .data



ディレクティブは、データセグメントの始まり、 .data



コードセグメントの始まりを意味します。

コロンが続くものはすべてラベルv:



main:



loop:



およびendloop:



です。

#



記号に続くテキストはすべてコメントです。

そして実際に残っているのは、 命令疑似 命令 (マクロ)です。



 .data v: .word -1, -2, -3, -4, -5, -6, -7, -8, -9, -10 .text .globl main main: li $t0, 0 # $t0 = 0 (variable a) li $t1, 0 # $t1 = 0 (counter i) li $t2, 10 # $t2 = 10 (count limit l) loop: slt $t3, $t1, $t2 beq $t3, $zero, endloop la $t3, V sll $t4, $t1, 2 addu $t3, $t3, $t4 lw $t3, 0($t3) addu $t0, $t0, $t3 addiu $t1, $t1, 1 b loop endloop:
      
      







MIPSアセンブラーのタイプ



C ++とMIPSの主なタイプの比較表は次のとおりです。

C ++およびMIPSの型比較チャート

表からわかるように、MIPSの変数のタイプの選択は、この変数が占有するメモリ量のみに基づいています。 この点に関して、MIPSは符号付き変数と符号なし変数を区別しないことに注意してください。



ラベル(文字)



上記のコードでは、いくつかのラベルを使用しました。

ラベル(これらはシンボルまたはラベルとも呼ばれます)は、メモリ内のアドレスに「名前」を付けるために使用されます。 これらの文字は、データラベル( .data



セクションにあるグローバル変数のアドレス、この場合はv:



と命令ラベル( .text



セクションにある命令のアドレス、たとえばmain:



loop:



2つの大きなクラスに分かれてい.text





.data



セクションのデータは通常、アドレス0x10010000から始まるメモリに保存されます。 命令はアドレス0x00400000から保存されます。 各MIPSアセンブラー命令は正確に32ビットを使用するため、次のラベルアドレステーブルはプログラムに当てはまります。

テーブル"ラベルアドレス"

ラベルの使用は、 .data



グローバル変数やその他のデータを.data



非常に便利ですが、それについては後で詳しく説明します。



主な指令



いくつかのディレクティブ、つまり.data



.text



をすでに調べました。最初のディレクティブはデータの保存とグローバル変数の宣言を目的としており、2番目のディレクティブはプログラムコード自体に対するものであることは既にわかっています。 残りのMIPSディレクティブを見てみましょう。



最後のディレクティブについて: .data



.align 1



.data



としましょう。 この場合、たとえばサイズ0バイトのアドレス0x10010000にメモリに書き込む場合でも、次のバイトは空のままになり、メモリに別のバイトを書き込む場合は、アドレス0x10010002を既に受け取ります。 MIPSはデフォルトでデータアライメントを自動的に有効にします。したがって、偶数のメモリアドレス(0x10010000、0x10010002、0x10010003ではなく)にのみ16ビット値( .half



)、4の倍数、64のアドレスにのみ32ビット値を書き込むことができます。 -bit-8の倍数のアドレスのみ



.data



データ形式



.data



データは、かなり自由な方法で書き込まれます。 ラベル、データ型、値を指定するだけです。 このコードには、正しいデータ記録のいくつかの例が含まれています。



 .data var1: .byte 'A', 0xF3, 127, -1, '\n' var2: .half -10, 0xffff var3: .word 0x12345678 var4: .float 12.3, -0.1 var5: .double 1.5e-10 var6: .dword 0x1234567812345678 str1: .ascii “i love mips\n" str2: .asciiz “zero-finished string" array: .space 100
      
      







コードで使用されているデータ型をもう少し詳しく見ていきます。



登録



MIPSプロセッサの主要部分の1つはレジスタです。 標準のMIPSプロセッサには、最初のコプロセッサに32個のメインレジスタがあり、さらに32個があります。これは、浮動小数点計算に使用されるモジュールです。 各レジスタのサイズはそれぞれ32ビットで、 int



型の単一の値が完全に配置されます。 long



型の変数を格納するには、一度に2つのレジスタを使用する必要があります。 各レジスタには、シリアル名と共通名でアクセスできます。 一般的には、もう少し人間が読める形式です。 次のレジスタが利用可能です。





MIPSの手順



ご注意 これから、MIPSプロセッサ、その命令、およびアドオンを、 ここからダウンロードできるMARSと呼ばれるすばらしいMIPSシミュレータの例として見ていきます 。 このシミュレータのMIPS実装は完全に準拠しています。



記事の冒頭のコードで、プログラムのすべての機能部分をすでに特定し、命令、疑似命令をコメント、シンボル(ラベル)、またはディレクティブではないものとして定義しています。 疑似命令はマクロとも呼ばれ、コードの実行中に1つ以上の命令に変換されます。 マクロの例を次に示します。



 la rdest, addr
      
      



一連の指示に進みます。



 lui $at, hi(addr) ori rdest, $at, lo(addr)
      
      







ご覧のとおり、MIPSプログラムは常に1行につき1行で記述されます。



指示の種類



MIPSアセンブラー命令には、主に3つのタイプがあります。





コプロセッサー向けの手順もありますが、後で説明します。



シスコール命令



syscall



は最も単純なものの1つですが、同時に最も重要なMIPSアセンブラー命令の1つです。 これはサービス指示であるため、他とは別に考慮されます。 syscall



、プロセッサ自体が実行できないアクションを実行するためにオペレーティングシステムを参照するために使用されsyscall



。 この命令を呼び出す前に、サービスコードをレジスタ$ v0(1〜12の自然数)に入れる必要があります。コードに応じて、オペレーティングシステムは1つまたは別のアクションを実行します。 MARSがサポートするユーティリティコードと対応するオペレーティングシステムアクションのリストを次に示します。



シスコール表



すべての入出力は、MARSコンソールを介して行われます。



算術命令



それでは、いくつかの基本的な算術命令を見てみましょう。 いくつかの略語が使用されますrs



は結果が書き込まれるレジスタ、 rs



は最初の引数、 rt



は2番目の引数です。 imm16



(16ビット整数)またはimm5



(5ビット整数)も表示される場合があります。





ところで、imm16はデフォルトで正と解釈されます。 例:

 addiu $s1, $zero, 0xFFFF # $s1 = 0x0000FFFF ( )
      
      





負の値を追加する必要がある場合、これを明示的に示す必要があります。

 addiu $s1, $zero, -0xFFFF # $s1 = 0xFFFF0001 (     2)
      
      







これらの手順を使用して実際の計算を見てみましょう。 たとえば、次のコード(C ++)を使用します。

int f = (g+h) - (ij);





そして、このコードをMIPS命令に変換します。 最初に、「=」記号の右側の値を計算してから、変数fに割り当てる必要があります。 変数fがレジスタ$ s0、g-$ s1、h-$ s2、i-$ s3、j-$ s4にあるとします。 結果は次のとおりです。



 addu $t0, $s1, $s2 # t0 = s1 + s2 = g + h subu $t1, $s3, $s4 # t1 = s3 - s4 = i - j subu $s0, $t0, $t1 # s0 = f = t0 - t1 = (g+h) - (ij)
      
      







そして、結果のコードをMARSでテストできるようになりました。 ここからドラフトダウンロードして、MARSで開きます。

 java -jar Mars_4_2.jar
      
      





コメントの代わりにコードを追加します。 これで実行できます。 最初に[実行]-> [アセンブル]を選択します。



MARSアセンブル操作



16進値のチェックを外してレジスタの10進値を確認し、実行->実行を選択します。



MARS Run操作



プログラム実行後の$ s0の値は12でなければなりません。



実行後の登録



続く



次回の記事では、論理命令と整数の乗算と除算について検討します。 その中で、メモリとスタックを操作しようとします。 それまでの間、MIPSアセンブラでこのコードを書き換えることをお勧めします。

 int a = b + c; int d = e + f; int g = a + b; int h = g + d;
      
      





ご清聴ありがとうございました!



All Articles