LC-3学习记录(一)
啥是LC-3?
LC-3是一種簡(jiǎn)單(可能?)的十六位機(jī)器語言,它具有沒什么卵用且可能使您掛科的作用。該語言自發(fā)明以來飽受歡迎,它受歡迎就體現(xiàn)在它受歡迎個(gè)錘子的歡迎,內(nèi)網(wǎng)外網(wǎng)啥資料找不到它受歡迎它受了個(gè)蔡徐坤的歡迎(全惱)。
不知道為啥奧大的計(jì)組要我們學(xué)這種冷門匯編(可能是因?yàn)楹蒙鲜?#xff1f;希望他們是這么想的罷…)…感覺相關(guān)的資源都很少,不會(huì)的地方也找不到人問,學(xué)起來太痛苦了。思前想后,這門匯編內(nèi)容上其實(shí)真的不難,覺得要是后來人學(xué)起這個(gè)因?yàn)橘Y源缺乏再遭罪實(shí)在不值得,故撰此文,希望能幫大家省去一些被知識(shí)的海洋倒灌的時(shí)間和精力。
注:本文假設(shè)您已經(jīng)具有基本的計(jì)算機(jī)組成原理的知識(shí)基礎(chǔ),即理解基本的二進(jìn)制運(yùn)算、機(jī)器語言、寄存器、內(nèi)存尋址的常識(shí)。
二注:本文主要是給小白看的,講得可能特別啰嗦(明明就是因?yàn)槲疫@人本來就比較啰嗦x )
この分割線だ
LC-3的基本指令結(jié)構(gòu)和語法
LC-3是儲(chǔ)存在內(nèi)存中的指令集合,其由十六位二進(jìn)制數(shù)組成,按照內(nèi)存地址的順序運(yùn)行,通過讀寫寄存器并將值存入內(nèi)存的方式運(yùn)作。LC-3假設(shè)有從R0到R7的8個(gè)可調(diào)用的寄存器。
所有LC-3指令都符合 前4位為操作碼,后12位為操作數(shù)的結(jié)構(gòu)。對(duì)于不同的操作碼的操作,后12位的操作數(shù)的具體結(jié)構(gòu)不同。
一行LC-3指令大概長(zhǎng)這樣:
操作碼 操作數(shù) 0000 000000000000如果想在這行執(zhí)行不同的指令,就需要在這行儲(chǔ)存不同的操作碼。
比如,假如我們要在這一行LC-3機(jī)器碼中,對(duì)寄存器R1中的數(shù)+1。
我們首先找到加法操作的語法:
ADD的操作碼是0001。當(dāng)LC-3計(jì)算機(jī)發(fā)現(xiàn)這行代碼由0001打頭時(shí),就會(huì)把后面的部分當(dāng)作ADD操作的操作數(shù)。
Dst指儲(chǔ)存加法運(yùn)算結(jié)果的寄存器。
Src1指儲(chǔ)存運(yùn)算加法的一個(gè)加數(shù)的寄存器。
Imm5指要加的值
因此,我們想要的指令就為:
0001 001 001 1 00001其等價(jià)于
R1 = R1 + 1;0001告訴計(jì)算機(jī)我們進(jìn)行的是加法運(yùn)算(即格式為「Dst = Src1 + Imm5;」的運(yùn)算),而不是別的。
001指計(jì)算的值要儲(chǔ)存在R1寄存器中,只有被指定的寄存器才會(huì)發(fā)生改變。也就是說如果這里指定的是010(R2寄存器),那么經(jīng)管你取出的是R1的值進(jìn)行的運(yùn)算,R1也不會(huì)發(fā)生改變。
就好比:
變的是R2,R1是不變的。(我是不是講太細(xì)了x)
第二個(gè)001指取出R1中的值作為加數(shù)。
1指后面的加數(shù)為常量,如果這里為0,后面的加數(shù)就不是一個(gè)二進(jìn)制常量,而會(huì)被當(dāng)成一個(gè)寄存器了。
00001指加數(shù)常量。
加數(shù)有兩種形式
Dst = Src1 + Imm5;只是其中一種,還有一種為
Dst = Src1 + Src2;機(jī)器語言的語法格式為
可以看見,二者的主要差別在于從右數(shù)的第五位數(shù)。如果計(jì)算機(jī)讀到這行指令由0001開頭,就會(huì)再讀右數(shù)第五位數(shù),如果為1則把最后五位數(shù)作為常數(shù),如果為0則把最后三位數(shù)作為寄存器。
例:
R2 = R1 + R3;可表述為L(zhǎng)C-3指令:
0001 010 001 0 00011看到這這行應(yīng)該用不著多解釋了罷~
LC-3的主要指令
LC-3有著豐富(個(gè)錘子 )且強(qiáng)大(個(gè)屁 )的指令集。
主要包括:
操作指令:ADD, AND, NOT
數(shù)據(jù)遷移指令:LD, LDI, ST, STI, STR, LDR, LEA
程序控制指令:BR, JMP, RTI, TRAP, JSR/JSRR
操作指令
ADD
AND
對(duì)Src1寄存器中的每一位與Src2或一個(gè)常數(shù)中對(duì)應(yīng)的每一位進(jìn)行二進(jìn)制 和操作,并存入Dst寄存器。
NOT
對(duì)Src1寄存器中的每一位進(jìn)行二進(jìn)制非操作,并存入Dst寄存器。
數(shù)據(jù)遷移指令
LD
將內(nèi)存中的內(nèi)容存入Dst寄存器。PCoffset9指PC偏移量。
PC就是現(xiàn)在的指令所在的內(nèi)存地址,offset指偏移量,⑨指笨蛋 ,9指占用9位二進(jìn)制數(shù)。
意思就是把PC + offset9那個(gè)位置的代碼放到指定的Dst寄存器里頭。
比如,假如我們現(xiàn)在的代碼在的地址是3000(PC = 3000),
0010 010 000001111這行代碼就意味著 把地址為3015(3000 + 15)處的內(nèi)容存進(jìn)R2中。
LDI(花里胡哨的)
LDI比LD復(fù)雜一點(diǎn)。它要多套一個(gè)娃。
LD是直接找到PC+offset的內(nèi)容,然后指把這個(gè)內(nèi)容搬進(jìn)Dst。LDI要多一步,它先找到PC+offset,然后把PC+offset的值作為地址,再尋一遍址,然后把這個(gè)地址的內(nèi)容存進(jìn)Dst。(我就感覺到繞)
比如,還是用前面的例子,我們把LD簡(jiǎn)單改成LDI。
1010 010 000001111這行代碼就意味著 把地址為3015(3000 + 15)處的內(nèi)容作為地址 把這個(gè)地址的內(nèi)容 存進(jìn)R2中。
假如3015的內(nèi)容是1500,那么R2的值就會(huì)變成地址為1500的儲(chǔ)存器的值。
ST
ST是LD的逆操作,它將寄存器Src中的值存入PCoffset中的內(nèi)存空間。
LD是把內(nèi)存中的內(nèi)容拿進(jìn)寄存器,ST反過來,把寄存器的內(nèi)容拿進(jìn)內(nèi)存。
STI
同理,STI是LDI的逆操作,把寄存器的指取出來,放進(jìn)PCoffset的地址的內(nèi)容指定的地址里去。
LDR(更加花里胡哨的)
Base其實(shí)就是一個(gè)寄存器。LDR要做的就是把base寄存器中的內(nèi)容取出來作為地址,找到這個(gè)地址后,給它加上offset偏移值,然后把這個(gè)地址中的內(nèi)容存進(jìn)Dst寄存器。
比如,假如R2中的值為1919,地址為1926的內(nèi)存空間中存的值為1145,
0110 001 010 000111這串代碼指的就是把Base中的值(1919)取出來,加上7(變成1926),然后我們以之為地址,找到1926,并把里面的值存入Dst(R1)。然后R1就變成了1145了。
STR
我覺得任何一只貓咪都能輕而易舉地猜到這肯定是LDR是逆操作。
前面的步驟不變,把最后一步反過來(內(nèi)存中的值存進(jìn)寄存器變成寄存器中的值存進(jìn)內(nèi)存)即可。
LEA(好!很直接!)
LEA沒有任何尋址,它僅僅只是把PC+offset的地址的值存進(jìn)寄存器Dst。非常得友好,非常得好理解。事鑒語句。
程序控制指令
BR
這個(gè)屑指令tlld我課件沒看懂百度谷歌查了好長(zhǎng)時(shí)間都沒找到相關(guān)的起碼折騰了我兩三個(gè)小時(shí)氣死我學(xué)tnd屑指令wdnmd
(冷靜下來)BR指令是LC-3中最基礎(chǔ)的跳轉(zhuǎn)指令,作用類似于高級(jí)語言中的while、 for等循環(huán)語句(也可以當(dāng)if用),但是理解起來不那么容易。
這里推薦大家可以移步嗶哩嗶哩大學(xué)參考一下這個(gè)灣灣做的視頻:
BR語句的基本格式如下:
nzp類似于高級(jí)語言中的判斷表達(dá)式(就是C、java里的while語句中圓括號(hào)里的東西),n是negative的意思,意味著判斷上一個(gè)操作的寄存器的值是否小于零,z是zero的意思,意味著判斷上一個(gè)操作的寄存器的值是否等于零,p是positive的意思,意味著判斷上一個(gè)操作的寄存器的值是否大于零。
什么?你問我計(jì)算機(jī)怎么判斷上一個(gè)操作過的寄存器的正負(fù)值?專門取出來判斷一遍嗎?我本來也納悶這個(gè),后來我才知道LC-3的計(jì)算機(jī)里頭專門有三個(gè)bit存上一個(gè)寄存器的值(這個(gè)我查了老半天(怨))。
LC-3的計(jì)算機(jī)中每進(jìn)行一次寄存器操作,LC-3就會(huì)記錄這個(gè)寄存器的正負(fù)值,并存在那三個(gè)bit中。比如我把-1賦值給R1,LC-3中記錄nzp的值的那三個(gè)bit就會(huì)變成100(n為1,指這個(gè)值是負(fù)數(shù))(不可能出現(xiàn)110這樣的,沒有數(shù)既是負(fù)數(shù)又是0)。
而語句中的nzp則用于判斷LC-3中的記錄nzp的三個(gè)bit中的值是否符合語句中的nzp。
比如,語句中的nzp為010,這的含義就是「假如上一個(gè)被操作過的寄存器的值為0,我就把PC (現(xiàn)在的執(zhí)行的指令的地址)設(shè)為PC+offset,否則繼續(xù)按正常順序執(zhí)行指令」。
可以理解為while (Rx(上一個(gè)被操作的寄存器) == 0) {}這樣的語句。
如果語句中的nzp為110,就可以理解為while (Rx(上一個(gè)被操作的寄存器) <= 0) {}這樣的語句。
如果為111,則相當(dāng)于必然跳轉(zhuǎn)。
總結(jié):BR語句的含義就是,如果上一個(gè)操作過的寄存器的值符合指令中的nzp的條件,則對(duì)現(xiàn)有的PC進(jìn)行跳轉(zhuǎn),否則繼續(xù)執(zhí)行下一個(gè)指令。
一般BR在使用時(shí)有兩種用法。
一個(gè)是循環(huán)的實(shí)現(xiàn)。
在BR前面放一個(gè)寄存器運(yùn)算指令。比如R1 = R1 - 1;這樣的。然后在一開始設(shè)定R1位某個(gè)特定正數(shù)值,把br語句的nzp設(shè)定為001(若R1>0)或者011(若R1>=0),則將PC跳轉(zhuǎn)至之前的某一個(gè)位置(offset為負(fù)數(shù)),也就是說重新執(zhí)行一遍前面的一段指令。然后R1不斷減一,直到為零或者小于零。這就是while和for的匯編底層實(shí)現(xiàn)。
另一個(gè)是條件分支判斷,即if的實(shí)現(xiàn)。
和之前不同的地方在于嗎,如果要實(shí)現(xiàn)if,offset值一般設(shè)定為正數(shù),即假如符合條件,就跳過一段指令(不執(zhí)行),不符合就執(zhí)行這段指令。
(如果還沒看明白可以私聊我orz,我語音+畫圖可能理解更清晰一些orz)
JMP
覺得BR用起來麻煩?學(xué)著糟心?看著頭大?來用JMP罷!你用不了上當(dāng)用不了吃虧…
JMP語法很簡(jiǎn)單,啥條件判斷妹有,說跳就跳(無條件跳轉(zhuǎn)),想跳哪就跳哪(與BR使用偏移量跳轉(zhuǎn)不同,它使用的是直接尋址)。
JMP會(huì)讀取Base寄存器中的數(shù)值作為地址,然后直接把PC置為該地址,簡(jiǎn)單粗暴直接,事鑒語句(確信)。
RTI(這個(gè)好像叫RET,沒搞懂到底叫啥)
比JMP更加簡(jiǎn)單粗暴,直接指定一個(gè)常數(shù)作為地址,然后把PC設(shè)為這個(gè)地址。
格式: 1100 + 十二位常數(shù)。
TRAP
t rap,是一種rap ,是trapvector的縮寫,意為陷阱矢量。
它會(huì)先把現(xiàn)在的PC + 1的值給R7,然后把trapvector8中的值作為PC。
我其實(shí)不是很明白有明白的可以來教我一下,…
JSR/JSRR
JSR看起來就是把PC + 1交給R7,然后PC加上常量offset偏移值。(不是很理解這是在干啥x)
JSRR也很粗暴,也是把PC + 1交給R7,然后PC變?yōu)锽ase寄存器中的值。
我在想假如Base寄存器指定為R7會(huì)咋樣()。(可能會(huì)直接執(zhí)行下一行罷)
碼了一上午了有點(diǎn)累,也權(quán)當(dāng)給自己復(fù)習(xí)復(fù)習(xí)。偽代碼和網(wǎng)絡(luò)編程的內(nèi)容咱自己也有一些不明白,所以放到后面寫罷orz,到時(shí)候整點(diǎn)例題來給大家看看
大家如果有什么問題或者建議可以加咱的QQ306168645來交流。來閑聊也星233333,咱超話癆的,雖說咱未必有時(shí)間orz
大家學(xué)習(xí)順利愉快w
總結(jié)
以上是生活随笔為你收集整理的LC-3学习记录(一)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python 爬虫斗图吧 多页图片
- 下一篇: ESP32|基于ESP32制作的低成本、