在6502上进行减法操作(sbc汇编指令)期间如何借位?

3

当NES使用的6502进行减法操作(sbc asm指令)时,借位(即进位标志被清除)是在什么情况下发生的?是每当结果为负数(-1到-128)时都会发生吗?

非常感谢! 谢谢 STeN


进位适用于无符号数。 - Jester
3个回答

6
在6502上,SBC n 操作与 ADC (n EOR $FF) 完全相同 —— 这是一种补码反码。因此,当 A + (operand ^ 0xff) + existing carry 小于256 时,进位标志被清除。
编辑:如果进位标志已设置,则执行减法操作时不使用借位。如果进位标志未设置,则执行减法操作时使用借位。因此,如果在减法操作后进位标志被设置,则没有发生借位。如果进位标志未设置,则发生了借位。
如果要测试结果是否为负数,则可以通过 BMI 或者 BPL 隐式地检查符号位。
在普通的6502十进制模式下,情况比这还要稍微复杂一些,但NES变种没有十进制模式,因此请忽略任何关于它的信息。
澄清以下评论:如果您将数字视为有符号数,则 127+127128-128,以此类推。这是常规的二进制补码表示法,没有什么特别之处。
LDA #-63    ; i.e. 1100 0001
SEC
SBC #65     ; i.e. 0100 0001
; result in accumulator is now -128, i.e. 1000 0000,
; and carry remains set because there was no borrow

BPL somewhere     ; wouldn't jump, because -128 is negative
BMI somewhereElse ; would jump, because -128 is negative

以下代码在内部工作方面完全等效:
```html

以下代码在内部工作方面完全等效:

```
LDA #-63    ; i.e. 1100 0001
SEC         ; ... everything the same up until here ...
ADC #65     ; i.e. 1011 1110 (the complement of 0100 0001)

; result = 1100 0001 + 1011 1110 + 1 = [1] 0111 1111 + 1 = [1] 1000 0000
;                                       ^
;                                       |
;                                     carry
; = -128

因此,如上所述,将“结果”定义为6502手册和“累加器中的东西”的普通编程含义,您可以按照上述方法测试结果是否为正或负,例如:
SBC $23
BMI resultWasNegative
resultWasPositive: ...

如果您想知道完整结果是否为负数(即是否适合累加器),则可以检查溢出标志。如果设置了溢出,则表示由于8位限制,累加器中的内容具有错误的符号。因此,您可以在溢出和符号之间执行异或运算的等效操作:
SBC $23

BVC signIsTheOpposite
BMI resultWasNegative
JMP resultWasPositive

signIsTheOpposite:
BPL resultWasNegative
JMP resultWasPositive

2
如果您想测试结果是否为负数,请通过BMI或BPL隐式地检查符号位。这是错误的!例如,(-128)减1仍然是负数,但在累加器中,您将得到正的字节宽值+127。在这种情况下,应检查溢出标志,如果设置了该标志,则符号(负)标志的值是不正确的(即被反转)。 - lvd
1
@lvd我不同意你的评估,也不喜欢你的脾气。这就像争论任何用C语言写作并说10/7的结果是0的人是“INCORRECT!”一样荒唐可笑。按照6502数据表和手册以及所有常识所定义的,结果就是累加器中的东西。我已经对溢出进行了扩展回答,以防你会感到高兴,但是,老实说,在你幼稚的喊叫声中,你只是在纠结于琐事。固定大小算术的一个简单事实是溢出和下溢可能会改变符号,但符号已经改变了。 - Tommy
(根据编辑历史记录,我最初误读了lvd的评论;希望我已经纠正我的错误) - Tommy
1
所提出的问题显然是由新手提出的。聚焦于诸如有符号计算中的溢出等细节是明智的。否则,第一次尝试汇编语言的人可能会以更加不愉快的方式获得相同的经验。 - lvd
检查我的编辑历史,你会发现尽管我自认为能回答这个问题,但在你的评论中还是被绊倒了。所以我认为你是正确的。 - Tommy

1
Tommy的答案是正确的,但我有一个更简单的看法。
6502的ALU中的运算都是8位的,因此您可以这样考虑减法(对于$65和$64):
 01100101
-01100100
 ========
 00000001

我的做法是将减法想象成一个9位(无符号)操作,累加器的第9位设为1,因此$65-$64看起来像这样:

 1 01100101
-  01100100
 ==========
 1 00000001 

而 $64 - $65 会看起来像这样

 1 01100100
-  01100101
 ==========
 0 11111111

新的进位位是结果的虚拟第9位。
本质上,当将运算数解释为无符号数字时,如果它比累加器解释为无符号数字大,那么进位就会被设置。或者更严谨地说,当...
 A < operand - 1 + oldcarry

0

不,结果也可能是正数。

例如:

lda #$10
sec
sbc #$f0

执行完后,Carry 标志将被清除,Accumulator 将为 $20。

在减法后测试正/负值,请使用状态寄存器的 N(Negative)标志和评估它的分支(BMI/BPL)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接