//addr :代表8位地址 addr16:代表16位地址 data :立即数
[算术运算指令]
1. ADC--累加器,存储器,进位标志C相加,结果送累加器A A+M+C→A
符号码格式 | 指令操作码 | 寻址方式 周期 |
ADC ($addr,X) | 61 | 先变址X后间址 |
ADC $addr | 65 | 零页寻址 |
ADC #$data | 69 | 立即寻址 |
ADC $addr16 | 6D | 绝对寻址 |
ADC ($addr),Y | 71 | 后变址Y间址 |
ADC $addr,X | 75 | 零页X变址 |
ADC $addr16,Y | 79 | 绝对Y变址 |
ADC $addr16,X | 7D | 绝对X变址 |
注意:由于进位标志C页会参加运算,所以在做加法运算时,一般要在前面加指令 CLC,清除进位标志
例1: //两个8位数加法运算演示,目的是将寄存器A的内容加上地址2100的内容,结果送寄存器A
2000:LDA #$20 //立即数21送寄存器A
2002:STA $2100 //地址2100的内容为20
2005:LDA #$21 //寄存器A的内容为21
2007:CLC //清除进位标志C,注意:在做加法运算前一定要加该指令
2008:ADC $2100 //寄存器A的内容和地址2100的内容相加
200B:RTS
大家可以进入NCTOOLS,输入 A 2000,然后输入上面代码,然后 输入 G 2000,然后按R看寄存器A的值,是不是等于41呢?
例2://两个16位数加法运算,这里是将0194+01BA,大家注意看看程序与上面有什么不同.
在这个程序里,先将要相加的数分别放地址2100,2101,2102,2103,具体是这样的:2100:94 01 BA 01
然后先将地址2100的内容+地址2102的内容,结果送地址2104
再将地址2101的内+地址2103的内容,结果送地址2105
那么地址2104,2105的结果,就是两个16位数相加的结果,这里是034E
2000:LDA #$94 //立即数94送寄存器A
2002:STA $2100 //寄存器A的内容送地址2100
2005:LDA #$01 //立即数01送寄存器A
2007:STA $2101 //寄存器A的内容送地址2101
200A:LDA #$BA //立即数BA送寄存器A
200C:STA $2102 //寄存器A的内容送地址2102
200F:LDA #$01 //立即数01送寄存器A
2011:STA $2103 //寄存器A的内容送地址2103
2014:CLC //清除进位标志,注意,开始做加法程序前,一定要清除进位标志
2015:LDA $2100 //地址2100的值送寄存器A
2018:ADC $2102 //寄存器A的内容 + 地址2102的内容 + C → A,这里C=0
201B:STA $2104 //寄存器A的内容送地址2104
201E:LDA $2101 //地址2101的内容送寄存器A
2021:ADC $2103 //寄存器A的内容 + 地址2103的内容 + C → A,这里C=1,请注意,这里没有用CLC指令
2024:STA $2105 //寄存器A的内容送地址2105
2027:RTS //程序结束
在这个程序里,最重要的就是为什么后面的加法指令前面没有用CLC指令,不是说在做加法前要用CLC指令吗?
但这里就不一样,由于在前面已经用了CLC指令,将C=0,做了一次加法运算后,会影响标志位C
如果做完第一次加法运算后,C=0,那么说明没有产生进位,C还是等于0,所以没有必要再用CLC指令
如果做完第一次加法运算后,C=1,那么说明产生了进位,如果再做第二次加法运算前,还使用CLC指令,那么计算的结果
就是错误的,我们来看 第一次运算后,(2104)=4E,如果第二次运算前使用CLC指令,那么01+01+00=02,最后的结果是这样的
(2104)=4E,(2105)=02,那么说明 0194+01BA=024E,我们口算都能知道这个结果是错误的,实际上由于第一次运算后,产生了进位
所以我们要把进位保留即01+01+(C)=01+01+01=03,所以实际的结果是(2104)=4E,(2105)=03
2. SBC--从累加器减去存储器和进位标志C,结果送累加器 A-M-C→A
符号码格式 | 指令操作码 | 寻址方式 |
SBC ($addr,X) | E1 | 先变址X后间址 |
SBC $addr | E5 | 零页寻址 |
SBC #$data | E9 | 立即寻址 |
SBC $addr16 | ED | 绝对寻址 |
SBC ($addr),Y | F1 | 后变址Y间址 |
SBC $addr,X | F5 | 零页X变址 |
SBC $addr16,Y | F9 | 绝对Y变址 |
SBC $addr16,X | FD | 绝对X变址 |
注意:由于在做减法运算时,进位标志C会参与运算,所以在做减法前要先加指令 SEC,置进位标志
例: //减法指令演示,目的是将寄存器A的内容减去地址2100的内容,结果送寄存器A
2000: LDA #$21 //立即数21送寄存器A
2002:STA $2100 //寄存器A的内容送地址2100
2005: LDA #$22 //立即数22送寄存器A
2007:SEC //置位标志位C,注意:在做减法运算前一定要加该指令
2008:SBC $2100 //寄存器A的内容减去地址2100的内容
200B: RTS
大家可以进入NCTOOLS,输入 A 2000,然后输入上面代码,然后 输入 G 2000,然后按R看寄存器A的值,是不是等于01呢?
例2: //求二进制数的平方根
程序目的:将地址2100的内容求得其平方根后,结果送地址2101,为方便计算,这里假设地址2100的内容为整数,方根也取整数
例如 若(2100)=19 (十进制的25)
结果(2101)=05
若(2101)=65 (十进制的101)
结果(2101)=0A
求方根方法:我们知道任何整数都有如下性质:
1 * 1 = 1
2 * 2 = 1 + 3
3 * 3 = 1 + 3 + 5
4 * 4 = 1 + 3 + 5 + 7
......
N * N=1 + 3 + 5 + ...... + (2N-1)
那么,我们可以把一个正整数X = N * N连续减去奇数 1, 3, 5, 7......(2N-1)直到结果为0或者不够减为止,所减去奇数的个数
就是这个正整数的整数平方根.
在下面的程序里,我们将目标数连续减去地址F0的内容
2000:LDA#$00 //初始化地址F0的内容为00
2002:STA $F0
2004:LDA $2100 //取目标数到寄存器A中
2007:SEC
2008:SBC $F0 //目标数减去地址F0的内容
200A:BCC $2016 //不够减转结束,结果在地址F0中
200C:INC $F0 //地址F0的内容加1,(06)为已减的奇数个数
200E:SBC $F0 //和前面的减法指令合起来正好减去了奇整数
2010:BEQ $2016 //减结果为0,转结束,结果在地址F0中
2012:BCS $2008 //减结果>0,继续减
2014:DEC $F0 //减结果<0,则从结果中扣除1
2016:LDA $F0
2018:STA $2101 //把最后结果送地址2101
201B:RTS
3. INC--存储器单元内容增1 M+1→M
符号码格式 | 指令操作码 | 寻址方式 |
INC $addr | E6 | 零页寻址 |
INC $addr16 | EE | 绝对寻址 |
INC $addr,X | F6 | 零页X变址 |
INC $addr16,X | FE | 绝对X变址 |
这个指令应该很好理解吧,就是把某个地址的内容加1,当然我们也可以用加法指令把某个地址加1,但大家可以看到,这里的指令所占用字节少
执行速度也较快.请看下面的比较:
用加法指令把地址2100的内容加1
2000:LDA $2100
2003:CLC
2004:ADC #$01
2006:STA $2100
2009:RTS
所占字节数:10个
用上面的指令把地址2100的内容加1
2000:INC $2100
2003:RTS
所占字节数:4个
一比较,大家就能发现谁占了上风吧!在对某个地址进行加1运算时,应该用INC指令.
4. DEC--存储器单元内容减1 M-1→M
符号码格式 | 指令操作码 | 寻址方式 |
DEC $addr | C6 | 零页寻址 |
DEC $addr16 | CE | 绝对寻址 |
DEC $addr,X | D6 | 零页X变址 |
DEC $addr16,X | DE | 绝对X变址 |
5. 寄存器X,Y加1减1
符号码格式 | 指令操作码 | 寻址方式 |
INX | E8 | 隐含寻址 |
DEX | CA | 隐含寻址 |
INY | C8 | 隐含寻址 |
DEY | 88 | 隐含寻址 |