引用http://nicotine.knight.blog.163.com/blog/static/2692611220099251548925/
好多人都是先会高级语言再说汇编的。在学汇编时,学到寻址就搞不明白。
我现在拿CPU6502(就是任天堂红白机用的CPU)来说说寻址与高级代码的关系。
6502资料可以看"图解6502 指令集.pdf"或"6502编程大奥秘.chm(前三章节就够)"。我个人比较喜欢看后者。
下载http://www.uushare.com/user/fogota/files/1648814 或 http://www.uushare.com/user/lzwcsj/files/1009423
6502的寻址有13个。
1。立即寻址
就是一个数(只有一个字节,即8位)直接存放在指令的后面。指令就直接调用这个数值。
例子:
LDA #03 //就是将03传入A寄存器。
STA W //W为一个变量,这里用了“直接寻址”,下面有说明,这一行的作用是将A寄存器的值传到W上。
高级代码 为 W=3;
2。直接寻址
就是一个地址存放在指令的后面。指令就通过这地址调用该地址上的数值。
2.1
例子:
LDA #03
STA W //W为一个变量,W也是一个地址。高级代码不直接写地址而是写成变量。
高级代码 为 W=3;
2.2
如果 W地址就是$0300
那么STA W 写成纯汇编就是 STA $0300
2.3
LDA #03
STA $0300
就是将03这个数值先传到A寄存器,再通过A传到内存地址$0300。CPU是不能直接将数值传到内存上的。
2.4
例如:有2个变量N和W
N=W
写汇编就是
LDA W
STA N
3。零页寻址
这个是6502所特有的,它就是局限在零页,省了高位的数据,用法与"直接寻址"完全相同。
4。累加器寻址
它是说从寄存器A上取值。我可以找到"位移操作"。
位移,例如
LDA W
ASL //操作数就在A中
STA N
写成高级代码
N = W << 1
5。隐含寻址
这个与累加器寻址相近,唯一不同就是它在除寄存器A外的寄存器上取值。在调用子函数或递返时用作入栈出栈。
零页寻址,累加器寻址,隐含寻址这三个都没有可说的,它们与高级代码没有可比较的。
6。直接X变址
这就是拿给出的地址作为基础,并偏移X个量,到达的地址就是所要的。
这个跟数组的使用一样
6.1
例如:一个数组W,它的首地址就是W,即W的第一个元素W(0)的地址就是W
LDX #03
LDA W,X
STA N
高级代码 N=W(3);
6.2
在纯汇编中是不用变量的,如果W地址就是$0300
那么
LDX #03
LDA $0300,X
STA $0200
就是向地址$0200写入在地址$0303上的值
等同
LDA $0303
STA $0200
7。直接Y变址
用法跟“直接X变址”完全相同,一般是X已被占用。才用这个的。
8。零页X变址,这个与“直接X变址”相近,就是局限在零页,省略高位。
9。零页Y变址,这个与“直接Y变址”相近,就是局限在零页,省略高位。
直接Y变址,零页X变址,零页Y变址这三个,只要理解“直接Y变址”就能学会。
10。间接寻址
就是指令后面放了一个指针的地址。
这就好理解了。
例如:P是一个指针,它是由2个字节组成的。地址为P和P+1
JMP (P) //这个不是跳到P地址上,而是跳到P所指向的地址。
这个要说明一下机器码。地址$0300写成机器码是00 03,高低位是反放的。
那么P+1是高位,P是低位。
如果P地址上的值是00 ,P+1地址上的值03
那么JMP (P) 等同 JMP $0300
高级代码绝少这样用,一般是编译器用的。JMP (P) 勉强写成 goto *p
11。先变址X后间接寻址
这样理解"先X变址,之后再间接寻址"
简单说就是分两步做
第一步是先做上面"6。直接X变址"
第二步是做"10。间接寻址"。
理解为一个指针数组
例如:P为一个由指针构成的数组。
ldx #03
lda (P,X)
sta W
写成高级代码
W=*P(3)
12。先间址后变址Y
这样理解"先间接寻址,之后再Y变址"
简单说就是分两步做
第一步是先做上面"10。间接寻址"
第二步是做"7。直接Y变址"。
理解为一个指针,指向一个数组(的首地址)。
例如,一个数组W。W也是数组的首地址,即W(0)的地址
P记录着这个数组的首地址。即P=&W
ldy #03
lda (P),Y
sta N
写成高级代码是
P=&W
...
N=*P(3)
13。相对寻址
这个就是专用在条件跳转上的。意思是相对当前所在地址向前或向后跳一个指定的偏移量。
高级代码中一般不用,而是在代码结构里用上了,是编译器最终写定的。
例如
while....
{...
}
这个while为假时就是要跳过}的,这个是由编译器计算跳多远。
又例如
if .... then ... else ....
这个else就是要跳过then后面的代码,相对多远,编译器计算,then结束后又要跳过else部分,同相。
完
好多人都是先会高级语言再说汇编的。在学汇编时,学到寻址就搞不明白。
我现在拿CPU6502(就是任天堂红白机用的CPU)来说说寻址与高级代码的关系。
6502资料可以看"图解6502 指令集.pdf"或"6502编程大奥秘.chm(前三章节就够)"。我个人比较喜欢看后者。
下载http://www.uushare.com/user/fogota/files/1648814 或 http://www.uushare.com/user/lzwcsj/files/1009423
6502的寻址有13个。
1。立即寻址
就是一个数(只有一个字节,即8位)直接存放在指令的后面。指令就直接调用这个数值。
例子:
LDA #03 //就是将03传入A寄存器。
STA W //W为一个变量,这里用了“直接寻址”,下面有说明,这一行的作用是将A寄存器的值传到W上。
高级代码 为 W=3;
2。直接寻址
就是一个地址存放在指令的后面。指令就通过这地址调用该地址上的数值。
2.1
例子:
LDA #03
STA W //W为一个变量,W也是一个地址。高级代码不直接写地址而是写成变量。
高级代码 为 W=3;
2.2
如果 W地址就是$0300
那么STA W 写成纯汇编就是 STA $0300
2.3
LDA #03
STA $0300
就是将03这个数值先传到A寄存器,再通过A传到内存地址$0300。CPU是不能直接将数值传到内存上的。
2.4
例如:有2个变量N和W
N=W
写汇编就是
LDA W
STA N
3。零页寻址
这个是6502所特有的,它就是局限在零页,省了高位的数据,用法与"直接寻址"完全相同。
4。累加器寻址
它是说从寄存器A上取值。我可以找到"位移操作"。
位移,例如
LDA W
ASL //操作数就在A中
STA N
写成高级代码
N = W << 1
5。隐含寻址
这个与累加器寻址相近,唯一不同就是它在除寄存器A外的寄存器上取值。在调用子函数或递返时用作入栈出栈。
零页寻址,累加器寻址,隐含寻址这三个都没有可说的,它们与高级代码没有可比较的。
6。直接X变址
这就是拿给出的地址作为基础,并偏移X个量,到达的地址就是所要的。
这个跟数组的使用一样
6.1
例如:一个数组W,它的首地址就是W,即W的第一个元素W(0)的地址就是W
LDX #03
LDA W,X
STA N
高级代码 N=W(3);
6.2
在纯汇编中是不用变量的,如果W地址就是$0300
那么
LDX #03
LDA $0300,X
STA $0200
就是向地址$0200写入在地址$0303上的值
等同
LDA $0303
STA $0200
7。直接Y变址
用法跟“直接X变址”完全相同,一般是X已被占用。才用这个的。
8。零页X变址,这个与“直接X变址”相近,就是局限在零页,省略高位。
9。零页Y变址,这个与“直接Y变址”相近,就是局限在零页,省略高位。
直接Y变址,零页X变址,零页Y变址这三个,只要理解“直接Y变址”就能学会。
10。间接寻址
就是指令后面放了一个指针的地址。
这就好理解了。
例如:P是一个指针,它是由2个字节组成的。地址为P和P+1
JMP (P) //这个不是跳到P地址上,而是跳到P所指向的地址。
这个要说明一下机器码。地址$0300写成机器码是00 03,高低位是反放的。
那么P+1是高位,P是低位。
如果P地址上的值是00 ,P+1地址上的值03
那么JMP (P) 等同 JMP $0300
高级代码绝少这样用,一般是编译器用的。JMP (P) 勉强写成 goto *p
11。先变址X后间接寻址
这样理解"先X变址,之后再间接寻址"
简单说就是分两步做
第一步是先做上面"6。直接X变址"
第二步是做"10。间接寻址"。
理解为一个指针数组
例如:P为一个由指针构成的数组。
ldx #03
lda (P,X)
sta W
写成高级代码
W=*P(3)
12。先间址后变址Y
这样理解"先间接寻址,之后再Y变址"
简单说就是分两步做
第一步是先做上面"10。间接寻址"
第二步是做"7。直接Y变址"。
理解为一个指针,指向一个数组(的首地址)。
例如,一个数组W。W也是数组的首地址,即W(0)的地址
P记录着这个数组的首地址。即P=&W
ldy #03
lda (P),Y
sta N
写成高级代码是
P=&W
...
N=*P(3)
13。相对寻址
这个就是专用在条件跳转上的。意思是相对当前所在地址向前或向后跳一个指定的偏移量。
高级代码中一般不用,而是在代码结构里用上了,是编译器最终写定的。
例如
while....
{...
}
这个while为假时就是要跳过}的,这个是由编译器计算跳多远。
又例如
if .... then ... else ....
这个else就是要跳过then后面的代码,相对多远,编译器计算,then结束后又要跳过else部分,同相。
完