2017-10-05 214 views
0

我想以小時:分鐘:秒的格式獲取MIPS中的當前時間。我知道使用syscall 30會將自1970年1月1日以來的總毫秒數放到寄存器$ a1和$ a0中,但我不知道如何將寄存器加在一起併除以1000來獲得總秒數。我相信其餘的應該很容易。如何在MIPS彙編語言中以秒爲單位獲得當前時間?

謝謝!

+0

相關:https://stackoverflow.com/questions/16050338/mips-integer-multiplication-and-division。您可以使用硬件32b/32b => 32b除法指令構建1000倍的擴展精度除法,也可以使用定點乘法逆。你必須從32位乘法中構建一個64b x 1000 => 128b的乘法,但是在硬件上乘以* *的速度比劃分速度要快得多。 (gcc只是爲'int div_by_1000(long long millis){return millis/1000; }':https://godbolt.org/g/MR6h6d調用一個libgcc.a幫助函數;你可以看看它的src。) –

回答

3

除以64位數字

MIPS以來,火星上的仿真,不支持64÷32⇒64個師我們需要實現我們自己的多字師。
該書黑客喜悅作爲chapter就可以了,主要基於Knuth編寫的計算機編程藝術

的想法是在原理上非常簡單:考慮一個64位數字作爲兩個數字編號,每個數字是32位(這樣該數的底爲2 ),並執行等級校逐位分割。

讓我們解決這一想法下與鹼10例如:考慮53/2
我們可以通過將5×2,得到的結果米和餘- [R計算結果 1.
是結果(最顯著一種)的第一個數字。
然後,我們在53 「滴」 的3得到13號,這是- [R 1 * 10 + 3
我們再次做13/2來獲得 = 6和r = 1.
結果是26(餘1)。

我們採用同樣的方法,唯一的區別是,我們處理範圍從0到2 位數 - 1
因此,一個64位的號碼,就像時間的系統調用返回的一個,是看作是一個兩位數的數字:最少的一個(最右邊)在$a0,另一個在$a1
例如,數0x15EF18933B1被視爲

Digit 1 Digit 0 
0x15E 0xF18933B1 

我們正在尋找的是,不只是一個循環,我們的「添加」最後剩餘的當前數字的算法,我們除以除數得到結果的當前數字和剩餘部分用於下一步。
注意,通過「添加」,我們的意思是「與重量增加」,其餘[R 不添加到當前數字ň,它是由基本縮放,然後加入(這正是我們之前做的,我們做了1 * 10 + 3,而不是1 + 3)。 我不會深入解釋算法,因爲它可以在線獲得。

一個非常重要的事情要注意的是,我們實際上並沒有到達任何地方。
由於當前餘數的縮放,我們仍然需要執行64÷32⇒64除法(對於小數點情況,13/2不會比53/2更容易!)。
區別在於我們知道該數字最多爲兩位數。

爲了解開這個循環論證,我們需要縮小到一個32÷16⇒32除法。
MIPS支持32÷32⇒32,通過將我們的除數限制爲至多65535,我們得到我們想要的。
所以該算法的工作原理是16位半字,64位數字被視爲4位數字。

該代碼是

#Input 
# a0:a1 = N = DCBA 
# a2 = K (16-bit) 

#Output 
# a0:a1 = quotient 
# hi = reminder 
div64x16: 
subu $sp, $sp, 16 

sw $a0, ($sp) 
sw $a1, 4($sp) 

add $t0, $sp, 8  # Pointer to digits (N) 
add $t3, $sp, 16 # Pointer to result (M) 
xor $t1, $t1, $t1 # Remainder 

loop: 
    subu $t3, $t3, 2 
    subu $t0, $t0, 2 

    sll $t1, $t1, 16 # t1 = R * 65536 
    lhu $t2, ($t0)  # t2 = N[i] 
    addu $t2, $t2, $t1 # t2 = N[i] + R * 65536 

    div $t2, $a2 

    mflo $t1   # t1 = (N[i] + R * 65536)/K 
    sh $t1, ($t3)  # M[i] = (N[i] + R * 65536)/K 

    mfhi $t1   # t1 = (N[i] + R * 65536) % K 

bne $t0, $sp, loop 

mthi $t1 

lw $a0, 8($sp) 
lw $a1, 12($sp) 

addu $sp, $sp, 16 
jr $ra 

的輸入參數是在a0:a1(64位被除數,低位字中a0)和a2(除數)。
結果在a0:a1(商)和hi(餘數)中。

注意對除數有限制:它必須是16位大小。
這簡化了除法算法,但在計算一天的時間時需要一些解決方法。

計算

的考慮從Unix紀元(1970年1月1日)的毫秒時間去一天的時間一個除以1000 * 3600 * 24,並採取了剩餘部分。
但是,1000 * 3600 * 24不適合16位。我們可以用三個部門來完成,但是我們需要結合剩餘部分。

有一個更簡單,更直觀的方法。
首先,我們擺脫了ms。我們在一天中的時間內不需要精確度,所以我們可以完全放棄剩下的部分。

li $v0, 30 
syscall 

#a0:a1 = ms since epoch 

li $a2, 1000 
jal div64x16 

#a0:a1 = seconds since epoch 

現在我們需要3600 * 24 = 86400分,但我們不能。
一個很好的技巧是除以3600 * 12 = 43200(即適合16位),這給了我們半天(我們稱之爲hh)的數量,其餘的給我們第二遠進入半天(稱之爲hs)。
由於在半天時間裏有43200秒,時間最多可以是11:59:59。
我們不知道如果2:0:0是2pm還是2am,我們需要檢查是否hh是奇數還是要知道,如果hh是偶然我們是在前半天一天和時間是正確的,否則我們在第二個半天,並且我們增加43200(半天的秒)到hs
這會在將半天中的秒數轉換爲秒。

#a0:a1 = seconds since epoch 

li $a2, 43200 
jal div64x16 

#a0:a1 = half-days since epoch 
#hi = seconds in half-day 

mfhi $s0    #Seconds in the half-day 

andi $a0, $a0, 1  #a1 = 1 if odd half-day number (otherwise 0) 
ror $a0, $a0, 1  #a1 < 0 if odd half-day number (otherwise 0) 
sra $a0, $a0, 31  #a1 = 0xffffffff if odd half-day number (otherwise 0) 
andi $a0, $a0, 43200 #a1 = 43200 if odd half-day number (otherwise 0) 

add $s0, $s0, $a0  #s0 = seconds in the day 

一旦有人在當天秒數(一個32位數字)其餘很容易。

li $t0, 3600 
div $s0, $t0   
mflo $s0    #s0 = Hour 

mfhi $t1 
li $t0, 60 
div $t1, $t0 
mflo $s1    #s1 = Minute 
mfhi $s2    #s2 = Second 

#Print the time 
li $v0, 1 
move $a0, $s0 
syscall 

li $v0, 4 
la $a0, sep 
syscall 

li $v0, 1 
move $a0, $s1 
syscall 

li $v0, 4 
la $a0, sep 
syscall 

li $v0, 1 
move $a0, $s2 
syscall 


#Exit 
li $v0, 10 
syscall 

注意的時間系統調用使用Java new Date().getTime()值,這是在GMT時區的當前時間。除非你住在那個時區,否則時間會有所不同。


此符號代表一個64位被除數,一個32位除數和一個64位的結果。

相關問題