ウィキペディアによると、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の主なタイプの比較表は次のとおりです。
表からわかるように、MIPSの変数のタイプの選択は、この変数が占有するメモリ量のみに基づいています。 この点に関して、MIPSは符号付き変数と符号なし変数を区別しないことに注意してください。
ラベル(文字)
上記のコードでは、いくつかのラベルを使用しました。
ラベル(これらはシンボルまたはラベルとも呼ばれます)は、メモリ内のアドレスに「名前」を付けるために使用されます。 これらの文字は、データラベル(
.data
セクションにあるグローバル変数のアドレス、この場合は
v:
と命令ラベル(
.text
セクションにある命令のアドレス、たとえば
main:
loop:
2つの大きなクラスに分かれてい
.text
。
.data
セクションのデータは通常、アドレス0x10010000から始まるメモリに保存されます。 命令はアドレス0x00400000から保存されます。 各MIPSアセンブラー命令は正確に32ビットを使用するため、次のラベルアドレステーブルはプログラムに当てはまります。
ラベルの使用は、
.data
グローバル変数やその他のデータを
.data
非常に便利ですが、それについては後で詳しく説明します。
主な指令
いくつかのディレクティブ、つまり
.data
と
.text
をすでに調べました。最初のディレクティブはデータの保存とグローバル変数の宣言を目的としており、2番目のディレクティブはプログラムコード自体に対するものであることは既にわかっています。 残りのMIPSディレクティブを見てみましょう。
.globl sym
.extern sym size
.ascii str
.asciiz str
.byte b1, b2, ..., bn
.half h1, h2, ..., hn
.word w1, w2, ..., wn
.dword dw1, dw2, ..., dwn
.float f1, f2, ..., fn
.double d1, d2, ..., dn
.space n
.align n
最後のディレクティブについて:
.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つのレジスタを使用する必要があります。 各レジスタには、シリアル名と共通名でアクセスできます。 一般的には、もう少し人間が読める形式です。 次のレジスタが利用可能です。
- $ zero($ 0)-値0を常に含み、読み取り専用のレジスタ。
- $ at($ 1)-一時的なプロセッサレジスタ;
- $ v0- $ v1($ 2- $ 3)-関数によって返される結果用。
- $ a0- $ a3($ 4- $ 7)-関数の引数;
- $ t0- $ t9($ 8- $ 15、$ 24- $ 25)-一時データには、好きなように使用できます。
- $ s0- $ s8($ 16- $ 23、$ 30)-定数データの場合、好きなように使用できます。
- $ k0- $ k1($ 26- $ 27)-オペレーティングシステムのカーネル用に予約済み。
- $ gp($ 28)-実際には使用されないグローバル変数のポインター。
- $ sp($ 29)-スタックポインター、その値は常にスタックの先頭アドレスに等しい。
- $ ra($ 31)- 太陽神 、関数が呼び出された命令のアドレス。
- $ f0-関数によって返される浮動小数点の結果。
- $ f4、$ f6、$ f8、$ f10、$ f16、$ f18-浮動小数点を含む一時データ用。
- $ f12、$ f14-浮動小数点関数のパラメーター用
MIPSの手順
ご注意 これから、MIPSプロセッサ、その命令、およびアドオンを、 ここからダウンロードできるMARSと呼ばれるすばらしいMIPSシミュレータの例として見ていきます 。 このシミュレータのMIPS実装は完全に準拠しています。
記事の冒頭のコードで、プログラムのすべての機能部分をすでに特定し、命令、疑似命令をコメント、シンボル(ラベル)、またはディレクティブではないものとして定義しています。 疑似命令はマクロとも呼ばれ、コードの実行中に1つ以上の命令に変換されます。 マクロの例を次に示します。
la rdest, addr
一連の指示に進みます。
lui $at, hi(addr) ori rdest, $at, lo(addr)
ご覧のとおり、MIPSプログラムは常に1行につき1行で記述されます。
指示の種類
MIPSアセンブラー命令には、主に3つのタイプがあります。
- タイプR(登録)。 3つのレジスタがオペランドとして使用されます-宛先レジスタ(略称$ Rd)、最初の引数($ rs)、2番目の引数($ rt)。 そのような命令の例は、3つのレジスタの追加です。
add $t2, $t0, $t1
- タイプI(即時)。 オペランドは2つのレジスタと1つの数字です。 タイプIの命令の例:
addi $t3, $t2, 12
- タイプJ(ジャンプ)。 唯一のオペランドは、行きたい26ビットのアドレスです。 取扱説明書
j 128
.text
のアドレス128に移動し.text
。
コプロセッサー向けの手順もありますが、後で説明します。
シスコール命令
syscall
は最も単純なものの1つですが、同時に最も重要なMIPSアセンブラー命令の1つです。 これはサービス指示であるため、他とは別に考慮されます。
syscall
、プロセッサ自体が実行できないアクションを実行するためにオペレーティングシステムを参照するために使用され
syscall
。 この命令を呼び出す前に、サービスコードをレジスタ$ v0(1〜12の自然数)に入れる必要があります。コードに応じて、オペレーティングシステムは1つまたは別のアクションを実行します。 MARSがサポートするユーティリティコードと対応するオペレーティングシステムアクションのリストを次に示します。
すべての入出力は、MARSコンソールを介して行われます。
算術命令
それでは、いくつかの基本的な算術命令を見てみましょう。 いくつかの略語が使用されます
rs
は結果が書き込まれるレジスタ、
rs
は最初の引数、
rt
は2番目の引数です。
imm16
(16ビット整数)または
imm5
(5ビット整数)も表示される場合があります。
add rd, rs, rt
sub rd, rs, rt
addu rd, rs, rt
subu rd, rs, rt
addi rd, rs, imm16
add
ようadd
、オーバーフローを引き起こす可能性があります。addiu rd, rs, imm16
ところで、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
コメントの代わりにコードを追加します。 これで実行できます。 最初に[実行]-> [アセンブル]を選択します。
16進値のチェックを外してレジスタの10進値を確認し、実行->実行を選択します。
プログラム実行後の$ s0の値は12でなければなりません。
続く
次回の記事では、論理命令と整数の乗算と除算について検討します。 その中で、メモリとスタックを操作しようとします。 それまでの間、MIPSアセンブラでこのコードを書き換えることをお勧めします。
int a = b + c; int d = e + f; int g = a + b; int h = g + d;
ご清聴ありがとうございました!