在匯編中,大部分指令都是和CPU與內存相關的
內存
- 內存空間的大小受CPU地址總線寬度的限制。8086的內存地址范圍為0x00000~0xFFFFF
- 0x00000 ~ 0x9FFFF:主存儲器。可讀可寫
- 0xA0000 ~ 0xBFFFF:顯存地址空間。可讀可寫
- 0xCFFFF ~ 0x FFFFF:存儲各種硬件系統信息。只讀
CPU
總線
- 地址總線
- 數據總線
- 控制總線
地址總線
它決定了CPU的尋址能力
-
8086的地址總線寬度是20,尋址能力是1M
一根總線可以傳的 2^1 個值(0,1).所以20根地址總線可以傳遞 2^20 個值。內存中一個內存單元保存一個字節,所以8086的尋址能力是1M
數據總線
它決定CPU的傳輸能力
-
8086的數據總線寬度是16,每次可以傳輸2個字節
數據總線傳遞的是數據,16根同時放電,一次可以傳輸16個bit位,為2個Byte
控制總線
- CPU對其它控件的控制,通過其傳輸
寄存器
不同的CPU,寄存器的個數、結構是不同的(8086是16位結構的CPU)
-
8086有14個寄存器
- 都是16位的寄存器
-
可以存放2個字節
image.png
通用寄存器
數據寄存器
- 通常,CPU會先將內存中的數據存儲到通用寄存器,然后再對通用寄存器中的數據進行運算
- AX、BX、CX、DX:可以存放兩個字節 *H、 *L ( * = A/B/C/D )。
尋址方式
物理地址 = 基地址 + 偏移地址
* 8086的地址總線是20根,可以尋址的范圍為0x00000 ~ 0xFFFFF。CPU是16位,計算出來的地址范圍是0x0000 ~ 0xFFFF。為了滿足地址總線的尋址范圍,采用基地址+偏移地址的方法,通過CPU中的地址加法器計算出物理地址,再由地址總線傳給內存,尋找物理地址。
* 基地址必須是16的倍數
* 偏移地址的尋址范圍為64kb(0x0000 ~ 0xFFFF)
* 8086內存最大可以分成16段。2^20 / 2 ^ 16 = 2^4
段寄存器
8086有四個段寄存器:CS、DS、SS、ES,當CPU需要訪問內存時由這4個段寄存器提供內存單元的段地址
* CS (Code Segment):代碼段寄存器
* DS (Data Segment):數據段寄存器
* SS (Stack Segment):堆棧段寄存器
* ES (Extra Segment):附加段寄存器
CS和IP
- CS為代碼段寄存器,IP為指令指針寄存器,它們指示了CPU當前要讀取指令的地址
分析CS和IP的工作流程
2990730-69f1503975cf6889.png
- 程序啟動時CS指向2000H,IP指向0000H
地址加法器計算CPU需要在內存中尋找的地址單元 20000H
地址加法器計算的20位地址結果傳入輸入輸出控制電路
輸入輸出控制電路通過地址總線將地址傳入內存
在內存中找到20000H地址單元,讀取指令
指令通過數據總線傳回輸入輸出控制電路
將指令放入指令緩沖器
修改IP中0000H的值
-
執行控制器
注意: 指令一旦放入指令緩沖器,立即修改IP的值,然后才會執行指令 補充: * 在內存中讀數據時,讀多少個字節由匯編指令決定 * 指令通過數據總線傳回時,一次傳多少字節由數據總線決定 * 8086CPU啟動時CS和IP分別被設置為CS=0xFFFFH,IP=0000H
指令和數據
內存或磁盤上,指令和數據沒有任何區別
同樣的信息既可以被CPU認為指令,又可以被認為數據
-
通過CS:IP指向的時候被認為指令,通過DS指向時被認為數據
注意: 如果內存中的內容曾被CPU執行過,那么它所在的內存單元必然被CS:IP指向過
jmp指令
- CPU從何處執行指令由CS,IP中的內容決定,所以可以通過修改CS,IP中的來控制CPU執行的目標指令
- 8086提供mov指定,它可以修改大部分寄存器的值,但是不能修改CS,IP中的值。
- 8086提供額外的指令來修改CS,IP,最簡單的是jmp指令
jmp用法:
- jmp CS:IP 該指令執行后CPU直接從修改后的CS:IP執行指令
- jmp 數據寄存器,該指令將數據寄存器中的值,賦值給IP。適合CS不變的情況下使用
DS和[address]
DS,通常存放要訪問數據的段地址
DS不能直接由mov ds,10000H賦值,需要數據寄存器間接
-
【address】表示內存單元地址
向ds中存入地址 mov bx,1000H mov ds,bx mov al,[0]
大小端
大端模式,是指數據的高字節保存在內存的低地址中,而數據的低字節保存在內存的高地址中(高低\低高)
-
小端模式,是指數據的高字節保存在內存的高地址中,而數據的低字節保存在內存的低地址中(高高\低低)
注意: ARM既可以工作在大端模式,也可以工作在小端模式
棧
- 棧:是一種具有特殊訪問方式的存儲空間
- 8086將SS作為棧段的段地址,任意時刻,SS:SP指向棧頂元素
- 8086提供PUSH和POP指令操作棧段的數據
PUSH
-
push ax 將ax中的數據入棧
入棧過程: SP = SP - 2,SS:SP 指向當前棧頂前面的單元,以當前棧頂前面的單元為新的棧頂; 將ax中的內容送入 SS:SP 指向的內存單元處,SS:SP此時指向新棧頂
POP
-
pop ax 將棧中數據存放到ax中
出棧過程: 將SS:SP指向的內存單元處的數據送入ax中; SP=SP + 2,SS:SP 指向當前棧頂下面的單元,以當前棧頂下面的單元為新的棧頂 如果將10000H 到 1000FH 這段空間當做棧,初始狀態棧是空的,此時,SS=1000H,SP=10H
棧頂超界
當棧滿的時候再使用push指令入棧,或棧空的時候再使用pop指令出棧,都將發生棧頂超界問題
棧頂超界是非常危險的,因為棧空間之外可能存放其他有用的數據、代碼等。棧頂超界會覆蓋這個數據、代碼
注意:
在8086中,push、pop操作的數據都是2個字節的
棧段
- 對于8086來說,在編程時,可以根據需要,將一組內存單元定義為一個段
- 我們可以將一組長度為N(N<=64KB)、地址連續、起始地址為16倍數的內存單元,當做棧空間來使用,稱為棧段。比如用 10010H~1001FH 這段內存空間當做棧來使用,我們就可以認為 10010H~1001FH 是一個棧段,它的段地址為1001H,長度為16字節
- 如何使用push、pop等棧操作指令訪問我們定義的棧段?
- 用SS存放棧段的段地址,用SP存放棧頂的偏移地址