[英]Specifying one argument for sw MIPS assembly instruction?
我正在學習計算機體系結構課程的MIPS匯編。 本課程使用MARS。 在接受10個數字放入數組進行分配時,我決定測試一些東西。 我想看看是否可以創建一個自動將用戶輸入的整數推送到堆棧的循環。 到目前為止,這是我的代碼:
# For loop initialization
li $s0, 0 # Set $s0 equal to zero.
li $sp, -40 # Reserve space for 10 integers on the stack.
li $t0, 0 # temp var to increment stack offset.
# Stores ten user inputted numbers onto the stack.
stackLoop:
beq $s0, 10, doneStack
li $v0, 51
la $a0, prompt
syscall
sw $t0($sp)
# Print out stack values.
li $v0, 1
lw $0($sp)
syscall
addi $t0, $t0, 4
addi $s0, $s0, 1
j stackLoop
doneStack:
當我得到sw指令時遇到了問題,當我指定兩個參數時因為$ t0($ sp)無效而引發了錯誤。 但是,如上所示,僅指定一個參數似乎有效。 在開始這項工作之前,我曾向我的教授詢問過這個問題,他說這是不可能做到的。 為什么只使用一個參數? 我的結論是sw必須默認存儲$ v0。 但是,這並不能成為語法的借口。 例如,鍵入sw $ v0,$ t0($ sp)會在編譯時拋出錯誤。
同樣,當使用$ 0($ sp)時,為什么lw工作? 我猜lw默認加載到$ a0,這可以解釋為什么li $ v0,1可行。 但是,如果是這種情況,為什么lw $ a0,0($ sp)產生增量4,一個字中的字節數? 它不會引用0($ sp)處的數據,這是在每次迭代時從堆棧中彈出的嗎?
我查看了一些文檔,但所有文檔都使用了sw和lw的兩個參數。 我班上的教科書甚至沒有提到我上面所做的事情是可能的。 對於中篇小說風格的帖子表示道歉,但我的好奇心被激怒了。
MARS使用一個非常簡單的解析器,甚至更簡單的tokenizer。
在分布式JAR中,源文件可用,如果您想哭,可以查看Java類mars.mips.instructions.InstructionSet
。
由於MARS的本質,這是完全可以接受的: 教育模擬器。
標記生成器將文本分成空格上的標記(但輸入首先分為行),逗號和括號。
因此,這些語法都是等價的:
sw $t0($sp)
sw $t0 ($sp)
sw $t0, ($sp)
MIPS ISA中沒有帶sw
和lw
(或任何其他指令)的默認寄存器。
對於每條指令都是如此,但是,尊重RISC心態,只有lw
和sw
(和兄弟姐妹)可以有括號(因為它們表示尋址模式),從而緩解問題(仍然可以使用or $t0 $t0 $t1
) 。
最后, sw $v0, $t0($sp)
在MIPS中無法編碼。
sw
它是一個I型指令 ,從而它具有一個源寄存器(t)的一個基址寄存器(一個或多個)和一個16位立即位移(I):
101011 ttttt sssss iiiiiiiiiiiiiiii
TL; DR : sw $t0($sp)
只是一個MARS工件。
匯編不是像C,Java等編程語言...... - 你有一些自由語法來編寫單個表達式。
裝配更像是機器指令的“助記符”(名稱),它們在CPU中硬連線,通過CPU的創建者如何設計芯片上的晶體管布局,以及它如何連接到計算機的其他部分。 因此,如果CPU被設計為具有指令ori $3, $3, 0x25
,那么您可以在源代碼中編寫它,並且匯編器將其轉換為機器代碼,對於MIPS CPU,該代碼為0x34630025
。 當MIPS在地址pc
(程序計數器)的內存中遇到這個特定字時,它將執行ori $3, $3, 0x25
執行任何其他操作。
你不能編碼ori $3, $3, 0x25 + 0x33
(在將它組裝成簡單的0x58
之前沒有預先計算常量),沒有機器操作碼允許將0x25 + 0x33編碼為應在運行時添加的兩個值。 一個聰明的匯編程序會讓你寫這個,並編譯為ori $3, $3, 0x58
(IIRC MARS並不聰明)。
因此,您不能學習某種語法並構建相關的指令,您必須學習CPU供應商定義的指令,並記住可能的和不可的。 匯編是從可讀助記符到二進制機器代碼的1:1翻譯(盡管MARS匯編器有許多“偽指令”,它們不會轉換為單個本機操作碼,而是轉換為本機操作碼鏈(通常為2-3個),模擬偽指令行為,所以它是一種編譯器,雖然非常原始,所有可能的偽指令都有記錄)。
這就是為什么可能的指令是有限的,你直接使用芯片上的硬件晶體管,你只有CPU設計人員已經投入到設計中。 如果你想創建一些新的指令,你就不熟悉固定的CPU(盡管你可以使用其中一個FPGA芯片來創建自己的內部邏輯,但那是完全不同的主題)。
關於lw $0($sp)
- 這是無效的語法,它會編譯,因為MARS匯編程序不是太陽下最大的SW,所以在我希望它更聰明的情況下它會失敗(如li $t1,123+34
不起作用),並且在停止和報告錯誤會好得多的情況下,它實際上會產生一些東西。
你的lw $0($sp)
組裝為lw $0, 0($sp)
,即它會猜測是否缺少昏迷,並且缺少位移,整個指令只是空間填充,因為你可以存儲到$0
即$zero
任何東西你想要(就像那個lw
),但你會回讀總是零。
運行MARS,打開幫助F1並檢查選項卡“基本指令”和“擴展(偽)指令”,這些都是您可以使用的。 不幸的是,用於描述它們的語法是example-ish one,而不是math-ish,所以它有時看起來像是可用的東西,直到你發現它不是,很難。
現在關於lw
...幫助說lw $t1,-100($t2)
。 如果你是經驗豐富的asm開發人員,他知道幾個其他CPU的匯編,以及幾個不同匯編器的語法,這是非常明顯的。 如果你不熟悉裝配,我可以看到這是非常難以理解的。 長篇描述也沒有多大幫助。
但是招的部分是檢查綠色區域上方的標簽,以“操作數的關鍵為例說明”,讓試圖利用此為lw
...
$t1, $t2, $t3
任何整數寄存器
-100簽名的16位整數(-32768到32767)加載和存儲尋址模式-100($ t2)符號擴展的16位整數添加到$ t2的內容
如你所見,沒有lw $t1,$t3($t2)
(這意味着你可以在位移位置使用寄存器)。
那么如何解釋這個幫助: lw
是“加載詞”,它是一個基本指令,它有兩個操作數。
左操作數是目標寄存器(可以是32個GPR(通用寄存器)中的任何一個,即$0
到$31
,或者它們的別名如$at
, $t0
等... - 這是從內存中取出的字值將被存儲。
右操作數的形式為“displacement_constant($ GPR)”,用於將內存計算作為GPR的內容與displacement_constant一起添加。 即-100($sp)
將在寄存器$sp
取值並從中減去100
,並將其用作存儲器地址以接觸存儲器芯片,並從那里獲取字值。
這意味着在MIPS上,你只能通過單個寄存器間接尋址lw
內存,不允許使用$t0 + $t2
這樣的數學表達式。 要做到這一點,你必須首先計算,如:
add $at, $t0, $t2 # don't use $at unless you know what you are doing
lw $a0,0($at) # as 99% of pseudo ins. will use $at for their temporaries
實際上在你編譯代碼之后,你可以在MARS中看到反匯編的機器代碼(這就是我如何計算出ori
示例使用的操作碼,以及MARS從無效的lw $0($sp)
產生什么樣的憎惡) - 在“執行”選項卡中(我只是不確定我是否必須稍微配置它以顯示所有內容,包括偽指令如何轉換為基本指令,但在設置中找不到任何關於它的內容,所以讓我們希望該視圖是默認的)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.