跳轉到內容

6502 彙編

25% developed
來自華夏公益教科書

本書是 6502 組合語言的指南。本書將教授 8 位 6502 處理器的不同記憶體定址模式和指令。

如果你想進行 Atari 2600/8 位系列/5200/7800 程式設計、Commodore PET/VIC/64/128 程式設計、Acorn 8 位程式設計、Apple I/II 程式設計、NES 程式設計超級任天堂程式設計,你可能需要學習 6502 組合語言程式設計。

彙編器的語法會有所不同 - 本書將始終使用以下語法

數字表示
語法 進位制 示例
%00001111 二進位制 LDA #%0001
$FA 十六進位制 LDA #$0E
123 十進位制 LDA #100

暫存器

[編輯 | 編輯原始碼]

暫存器
暫存器 大小(位) 用途
累加器 (A) 8 用於對資料進行計算。
大多數指令可以直接在累加器上操作,而不是花費 CPU 週期訪問記憶體。
X 暫存器 (X) 8 用作某些定址模式中的索引。
Y 暫存器 (Y) 8 用作某些定址模式中的索引。
程式計數器 (PC) 16 指向要執行的下一條指令的地址。
堆疊指標 (S) 8 儲存堆疊索引,下一個堆疊元素將寫入該索引。
該位置的地址為 $0100 + SP。SP 最初設定為 $FD

TSX 和 TXS 是唯一允許你直接修改 S 的指令。

狀態 (P) 8 每一位表示一個狀態標誌。

標誌指示 CPU 的狀態,或有關先前指令結果的資訊。PHP 和 PLP 可以從堆疊中儲存/恢復 P。各種指令可以直接設定或清除 P 中的位:SEC、CLC、SEI、CLI、SED、CLD、CLV。
有關每個標誌的描述,請參見下表。

狀態標誌
符號 名稱 描述
7 N 負數

比較: 如果暫存器的值小於輸入值,則設定。
否則: 如果結果為負數,即結果的第 7 位被設定,則設定。

6 V 溢位

算術運算: 如果在加法或減法期間發生有符號溢位,即結果的符號與輸入和累加器的符號不同,則設定。

BIT: 設定為輸入的第 6 位。

其他: 原始 6502 具有一個名為 "SO" (Set Overflow) 的外部引腳,硬體可以使用它來設定 V 標誌。其目的是比 IRQ 更快地響應硬體事件。大多數常見的 6502 相容平臺沒有使用此功能,或者不使用它。

5 - (未用) 始終設定
4 B[1] 斷點 如果 BRK 指令觸發中斷請求,則設定
3 D 十進位制 十進位制模式[2]: 算術指令將把輸入和輸出視為 "二進位制編碼十進位制" (BCD) 數字。


例如,$09 + $01 = $10 注意: NES 中的 6502 相容 CPU 沒有實現十進位制模式,因此十進位制模式不會改變該 CPU 上的行為,但你仍然可以清除/設定該標誌。

2 I 中斷停用 在設定時停用 IRQ 中斷。NMI 和 RESET 不受影響。
1 Z

比較: 如果暫存器的值等於輸入值,則設定

BIT: 如果將累加器與輸入進行邏輯與運算的結果為 0,則設定。

否則: 如果結果為零,則設定。

注意: 比較 (CMP、CPX、CPY) 指令透過減法來工作,但不保留結果。因此,如果值為 0,則 Z 將被設定,因此這就是為什麼 BEQ 測試 Z 標誌,以及為什麼在 BEQ 之前不必 CMP #0。

0 C 進位 進位/借位標誌用於數學和旋轉操作

算術運算: 如果在加法或減法期間發生無符號溢位,即結果小於初始值 (或等於初始值,如果進位標誌在進入時被設定),則設定。

比較: 如果暫存器的值大於或等於輸入值,則設定。

移位: 設定為輸入的消除位的的值,即左移時為第 7 位,右移時為第 0 位。

記憶體佈局

[編輯 | 編輯原始碼]

16 位的值以小端方式儲存在記憶體中,因此最低有效位元組儲存在最高有效位元組之前。例如,如果地址 $0000 包含 $FF 並且地址 $0001 包含 $00,則從 $0000 讀取兩個位元組的值將得到 $00FF

有符號整數採用二進位制補碼,可以表示從 -128 (%10000000) 到 +127 (%01111111) 的值。如果整數為負數,則第 7 位被設定。

6502 的程式計數器是 16 位寬,因此可以定址高達 2^16 (65536) 位元組的記憶體。某些記憶體區域專用於特定用途

記憶體區域
區域 內容 描述
$0000 - $00FF 零頁記憶體的第一頁,訪問速度比其他頁快。
指令可以用單個位元組而不是兩個位元組來指定零頁內的地址,因此使用零頁而不是其他任何頁的指令執行時只需要少一個 CPU 週期
$0100 - $01FF 堆疊後進先出資料結構。從 $01FF$0100 向後增長。
由一些傳輸堆疊子程式指令使用
$0200 - $FFFF 通用可以用於任何所需用途的記憶體。
使用 6502 處理器的裝置可以選擇保留子區域用於其他用途,例如 記憶體對映 I/O

記憶體定址模式

[編輯 | 編輯原始碼]

每條指令使用十三種記憶體定址模式中的一種,這決定了指令的運算元。每個模式都提供了一個示例。

累加器: A

[編輯 | 編輯原始碼]

累加器被隱式地用作運算元,因此不需要指定地址。

示例

使用沒有運算元的 ASL (算術左移) 指令時,累加器始終是左移的值。

ASL

隱式: i

[編輯 | 編輯原始碼]

運算元是隱式的,因此不需要指定它。

示例

這裡隱式的運算元是 X,即傳輸的源,和 A,即傳輸的目標。

TXA

立即數: #

[編輯 | 編輯原始碼]

運算元直接用於執行計算。

示例

將值 $22 載入到累加器中。

LDA #$22

絕對地址: a

[編輯 | 編輯原始碼]

指定完整的 16 位地址,並使用該地址處的位元組執行計算。

示例

將地址 $D010 處的數值 $24 載入到 X 暫存器中。

LDX $D010

零頁:zp

[編輯 | 編輯原始碼]

單個位元組指定記憶體第一頁($00xx)中的地址,也稱為零頁,並使用該地址處的位元組執行計算。

示例

將地址 $0002 處的數值載入到 Y 暫存器中。

LDY $02

相對:r

[編輯 | 編輯原始碼]

指定的偏移量將加到程式計數器 (PC) 中儲存的當前地址上。偏移量範圍為 -128 到 +127。

示例

將偏移量 $2D 加到程式計數器 (例如 $C100) 中的地址。分支 (如果執行) 的目標地址將為 $C12D

BPL $2D

絕對間接: (a)

[編輯 | 編輯原始碼]

使用指定地址處儲存的低位元組序的 2 位元組數值執行計算。僅用於 JMP 指令。

示例

讀取地址 $A001$A002,分別返回 $FF$00。然後跳轉到地址 $00FF

JMP ($A001)

帶 X 索引的絕對:a,x

[編輯 | 編輯原始碼]

X 中的數值加到指定的地址,得到一個和地址。使用和地址處的數值執行計算。

示例

X 中的數值 $02 加到 $C001,得到和 $C003。使用地址 $C003 處的數值 $5A 執行帶進位加 (ADC) 操作。

ADC $C001,X

帶 Y 索引的絕對:a,y

[編輯 | 編輯原始碼]

Y 中的數值加到指定的地址,得到一個和地址。使用和地址處的數值執行計算。

示例

Y 中的數值 $03 加到 $F001,得到和 $F004。將地址 $F004 處的數值 $EF 加 1 (INC) 並將 $F0 寫回 $F004

INC $F001,Y

帶 X 索引的零頁:zp,x

[編輯 | 編輯原始碼]

X 中的數值加到指定的零頁地址,得到一個和地址。使用和地址處的數值執行計算。

示例

X 中的數值 $02 加到 $01,得到和 $03。將地址 $0003 處的數值 $A5 載入到累加器中。

LDA $01,X

帶 Y 索引的零頁:zp,y

[編輯 | 編輯原始碼]

Y 中的數值加到指定的零頁地址,得到一個和地址。使用和地址處的數值執行計算。

示例

Y 中的數值 $03 加到 $01,得到和 $04。將地址 $0004 處的數值 $E3 載入到累加器中。

LDA $01,Y

帶 X 索引的零頁間接: (zp,x)

[編輯 | 編輯原始碼]

X 中的數值加到指定的零頁地址,得到一個和地址。載入和地址 (LSB) 和和地址加 1 (MSB) 處的 2 位元組對中儲存的低位元組序地址,並使用該地址處的數值執行計算。

示例

X 中的數值 $02 加到 $15,得到和 $17。地址 $0017$0018 處的地址 $D010 將是累加器中數值 $0F 儲存的位置。

STA ($15,X)

帶 Y 索引的零頁間接: (zp),y

[編輯 | 編輯原始碼]

Y 中的數值加到指定地址 (LSB) 和指定地址加 1 (MSB) 處的 2 位元組對中儲存的低位元組序地址處的地址。使用和地址處的數值執行計算。實際上,定址模式實際上重複了累加器暫存器的數字。

示例

Y 中的數值 $03 加到地址 $002A$002B 處的地址 $C235,得到和 $C238。然後,將累加器與 $C238 處的數值 $2F 進行異或運算。

EOR ($2A),Y

這些是 6502 處理器的指令,包括 ASCII 視覺化、受影響標誌的列表以及可接受定址模式的操作碼錶。

載入和儲存

[編輯 | 編輯原始碼]
將記憶體載入到累加器: LDA    將記憶體載入到索引 X: LDX    將記憶體載入到索引 Y: LDY   

M -> A

標誌:N,Z

M -> X

標誌:N,Z

M -> Y

標誌:N,Z

定址模式 操作碼
a AD
a,x BD
a,y B9
# A9
zp A5
(zp,x) A1
zp,x B5
(zp),y B1
定址模式 操作碼
a AE
a,y BE
# A2
zp A6
zp,y B6
定址模式 操作碼
a AC
a,x BC
# A0
zp A4
zp,x B4
將累加器儲存到記憶體: STA    將索引 X 儲存到記憶體: STX    將索引 Y 儲存到記憶體: STY   

A -> M

標誌:無

X -> M

標誌:無

Y -> M

標誌:無

定址模式 操作碼
a 8D
a,x 9D
a,y 99
zp 85
(zp,x) 81
zp,x 95
(zp),y 91
定址模式 操作碼
a 8E
zp 86
zp,y 96
定址模式 操作碼
a 8C
zp 84
zp,x 94
將記憶體加到累加器並帶進位: ADC    將記憶體從累加器中減去並帶借位: SBC   

A + M + C -> A

標誌:N,V,Z,C

A - M - ~C -> A

標誌:N,V,Z,C

定址模式 操作碼
a 6D
a,x 7D
a,y 79
# 69
zp 65
(zp,x) 61
zp,x 75
(zp),y 71
定址模式 操作碼
a ED
a,x FD
a,y F9
# E9
zp E5
(zp,x) E1
zp,x F5
(zp),y F1

遞增和遞減

[編輯 | 編輯原始碼]
將記憶體加 1: INC    將索引 X 加 1: INX    將索引 Y 加 1: INY   

M + 1 -> M

標誌:N,Z

X + 1 -> X

標誌:N,Z

Y + 1 -> Y

標誌:N,Z

定址模式 操作碼
a EE
a,x FE
zp E6
zp,x F6
定址模式 操作碼
i E8
定址模式 操作碼
i C8
將記憶體減 1: DEC    將索引 X 減 1: DEX    將索引 Y 減 1: DEY   

M - 1 -> M

標誌:N,Z

X - 1 -> X

標誌:N,Z

Y - 1 -> Y

標誌:N,Z

定址模式 操作碼
a CE
a,x DE
zp C6
zp,x D6
定址模式 操作碼
i CA
定址模式 操作碼
i 88

移位和旋轉

[編輯 | 編輯原始碼]
算術左移一位:ASL    邏輯右移一位:LSR   

C <- 7 6 5 4 3 2 1 0 <- 0

標誌:N,Z,C

0 -> 7 6 5 4 3 2 1 0 -> C

標誌:N,Z,C

定址模式 操作碼
a 0E
a,x 1E
A 0A
zp 06
zp,x 16
定址模式 操作碼
a 4E
a,x 5E
A 4A
zp 46
zp,x 56
迴圈左移一位:ROL    迴圈右移一位:ROR   

C <- 7 6 5 4 3 2 1 0 <- C

標誌:N,Z,C

C -> 7 6 5 4 3 2 1 0 -> C

標誌:N,Z,C

定址模式 操作碼
a 2E
a,x 3E
A 2A
zp 26
zp,x 36
定址模式 操作碼
a 6E
a,x 7E
A 6A
zp 66
zp,x 76
累加器與記憶體執行與運算:AND    累加器與記憶體執行或運算:ORA    累加器與記憶體執行異或運算:EOR   

A & M -> A

標誌:N,Z

A | M -> A

標誌:N,Z

A ^ M -> A

標誌:N,Z

定址模式 操作碼
a 2D
a,x 3D
a,y 39
# 29
zp 25
(zp,x) 21
zp,x 35
(zp),y 31
定址模式 操作碼
a 0D
a,x 1D
a,y 19
# 09
zp 05
(zp,x) 01
zp,x 15
(zp),y 11
定址模式 操作碼
a 4D
a,x 5D
a,y 59
# 49
zp 45
(zp,x) 41
zp,x 55
(zp),y 51

比較和測試位

[編輯 | 編輯原始碼]

負號 (N)、零 (Z) 和進位 (C) 狀態標誌 用於條件 (分支) 指令。

所有比較指令都以相同的方式影響標誌。

條件 N Z C
暫存器 < 記憶體 1 0 0
暫存器 = 記憶體 0 1 1
暫存器 > 記憶體 0 0 1
比較記憶體和累加器:CMP    比較記憶體和索引 X:CPX    比較記憶體和索引 Y:CPY   

A - M

標誌:N,Z,C

X - M

標誌:N,Z,C

Y - M

標誌:N,Z,C

定址模式 操作碼
a CD
a,x DD
a,y D9
# C9
zp C5
(zp,x) C1
zp,x D5
(zp),y D1
定址模式 操作碼
a EC
# E0
zp E4
定址模式 操作碼
a CC
# C0
zp C4

測試記憶體中的位與累加器:BIT

A & M

標誌:N = M7,V = M6,Z

定址模式 操作碼
a 2C
# 89
zp 24
當進位位為 0 時分支:BCC    當進位位為 1 時分支:BCS   

當 C = 0 時分支

標誌:無

當 C = 1 時分支

標誌:無

定址模式 操作碼
r 90
定址模式 操作碼
r B0
當結果不為 0 時分支:BNE    當結果為 0 時分支:BEQ   

當 Z = 0 時分支

標誌:無

當 Z = 1 時分支

標誌:無

定址模式 操作碼
r D0
定址模式 操作碼
r F0
當結果為正時分支:BPL    當結果為負時分支:BMI   

當 N = 0 時分支

標誌:無

當 N = 1 時分支

標誌:無

定址模式 操作碼
r 10
定址模式 操作碼
r 30
當溢位位為 0 時分支:BVC    當溢位位為 1 時分支:BVS   

當 V = 0 時分支

標誌:無

當 V = 1 時分支

標誌:無

定址模式 操作碼
r 50
定址模式 操作碼
r 70
將累加器傳輸到索引 X:TAX    將索引 X 傳輸到累加器:TXA   

A -> X

標誌:N,Z

X -> A

標誌:N,Z

定址模式 操作碼
i AA
定址模式 操作碼
i 8A
將累加器傳輸到索引 Y:TAY    將索引 Y 傳輸到累加器:TYA   

A -> Y

標誌:N,Z

Y -> A

標誌:N,Z

定址模式 操作碼
i A8
定址模式 操作碼
i 98
將堆疊指標傳輸到索引 X:TSX    將索引 X 傳輸到堆疊指標:TXS   

S -> X

標誌:N,Z

X -> S

標誌:無

定址模式 操作碼
i BA
定址模式 操作碼
i 9A
將累加器壓入堆疊:PHA    從堆疊中拉出累加器:PLA   

A -> S

標誌:無

S -> A

標誌:N,Z

定址模式 操作碼
i 48
定址模式 操作碼
i 68
將處理器狀態壓入堆疊:PHP    從堆疊中拉出處理器狀態:PLP   

P -> S

標誌:無

S -> P

標誌:全部

定址模式 操作碼
i 08
定址模式 操作碼
i 28

處理器狀態儲存為一個位元組,從高到低位的標誌位如下:NV--DIZC。

子程式和跳轉

[編輯 | 編輯原始碼]

跳轉到新位置:JMP

透過更改程式計數器的值跳轉到新位置。

警告: 當與 絕對間接 地址模式一起使用時,當指定地址為 $xxFF 時,硬體錯誤會導致意外行為。
例如,JMP ($11FF) 將從 $11FF 讀取低位元組,從 $1100 讀取高位元組,而不是從 $1200 讀取高位元組,正如人們預期的那樣。這是由於間接地址的低位元組溢位沒有進位到高位元組。

標誌:無

定址模式 操作碼
a 4C
(a) 6C

跳轉到新位置並儲存返回地址:JSR

跳轉到子程式。

下一個指令之前的地址 (PC - 1) 被壓入堆疊:首先是高位元組,然後是低位元組。由於堆疊向後增長,因此返回地址在記憶體中儲存為小端數。
PC 被設定為目標地址。

標誌:無

定址模式 操作碼
a 20

從子程式返回:RTS

從子程式返回到呼叫它的 JSR 的位置。

返回地址從堆疊中彈出 (先彈出低位元組,然後彈出高位元組)。
返回地址遞增並存儲在 PC 中。

標誌:無

定址模式 操作碼
i 60

從中斷返回:RTI

從中斷返回。

P 從堆疊中彈出。
PC 從堆疊中彈出。

標誌:全部

定址模式 操作碼
i 40

設定和清除

[編輯 | 編輯原始碼]
清除進位位:CLC    設定進位位:SEC   

0 -> C

標誌:C = 0

1 -> C

標誌:C = 1

定址模式 操作碼
i 18
定址模式 操作碼
i 38
清除十進位制模式:CLD    設定十進位制模式:SED   

0 -> D

標誌:D = 0

1 -> D

標誌:D = 1

定址模式 操作碼
i D8
定址模式 操作碼
i F8
清除中斷停用狀態:CLI    設定中斷停用狀態:SEI   

0 -> I

標誌:I = 0

1 -> I

標誌:I = 1

定址模式 操作碼
i 58
定址模式 操作碼
i 78
清除溢位位:CLV   

0 -> V

標誌:V = 0

定址模式 操作碼
i B8

中斷:BRK   

強制中斷

標誌:B = 1,I = 1

定址模式 操作碼
i 00

無操作:NOP   

無操作

標誌:無

定址模式 操作碼
i EA

指令表

[編輯 | 編輯原始碼]
指令表
高半位元組 低半位元組
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
00 BRK i ORA (zp,x) ORA zp ASL zp PHP i ORA # ASL A ORA a ASL a
10 BPL r ORA (zp),y ORA zp,x ASL zp,x CLC i ORA a,y ORA a,x ASL a,x
20 JSR a AND (zp,x) BIT zp AND zp ROL zp PLP i AND # ROL A BIT a AND a ROL a
30 BMI r AND (zp),y AND zp,x ROL zp,x SEC i AND a,y AND a,x ROL a,x
40 RTI i EOR (zp,x) EOR zp LSR zp PHA i EOR # LSR A JMP a EOR a LSR a
50 BVC r EOR (zp),y EOR zp,x LSR zp,x CLI i EOR a,y EOR a,x LSR a,x
60 RTS i ADC (zp,x) ADC zp ROR zp PLA i ADC # ROR A JMP (a) ADC a ROR a
70 BVS r ADC (zp),y ADC zp,x ROR zp,x SEI i ADC a,y ADC a,x ROR a,x
80 STA (zp,x) STY zp STA zp STX zp DEY i BIT # TXA i STY a STA a STX a
90 BCC r STA (zp),y STY zp,x STA zp,x STX zp,y TYA i STA a,y TXS i STA a,x
A0 LDY # LDA (zp,x) LDX # LDY zp LDA zp LDX zp TAY i LDA # TAX i LDY a LDA a LDX a
B0 BCS r LDA (zp),y LDY zp,x LDA zp,x LDX zp,y CLV i LDA a,y TSX i LDY a,x LDA a,x LDX a,y
C0 CPY # CMP (zp,x) CPY zp CMP zp DEC zp INY i CMP # DEX i CPY a CMP a DEC a
D0 BNE r CMP (zp),y CMP zp,x DEC zp,x CLD i CMP a,y CMP a,x DEC a,x
E0 CPX # SBC (zp,x) CPX zp SBC zp INC zp INX i SBC # NOP i CPX a SBC a INC a
F0 BEQ r SBC (zp),y SBC zp,x INC zp,x SED i SBC a,y SBC a,x INC a,x

參考資料

[編輯 | 編輯原始碼]
  1. [1],B標誌位不代表實際的CPU暫存器
[編輯 | 編輯原始碼]

進一步閱讀

[編輯 | 編輯原始碼]
華夏公益教科書