6502 汇编:16 位减法中的进位结果

问题描述

我恢复了一个旧的 6502 模拟器,我多年前做了一些新功能。在测试过程中,我发现了一些错误,肯定是由于我的实现错误
我必须循环执行 16 位减法,直到结果为负:很简单,不是吗?下面是一个例子:

V1 equ $90  
V2 equ $01  
Label:
 sec  
 lda V2  
 sbc #2  
 sta V2  
 lda V1  
 sbc #10  
 sta V1   
 "Branch" to Label if result is >0,otherwise exit  
 rts  

现在,问题是确定选择哪个分支或找到不同的解决方案。 如果 V2 减法清除进位,则 BCS 无效。
如果 V1 为“负”(>$80),则 BPL 无效。
这应该很容易,但是...

编辑
我没有在答案中找到真正的解决方案。
让我尝试遵循逻辑,首先使用代码中的原始值。

  1. 进位由SEC
  2. 设置
  3. 拳头子 (1-2) 清除进位。 V1 = $FF
  4. 第二个子项($90-$0A-1(非借))结果为 V2=$85
  5. 进位清零;结果 ($85FF) 仍然是负数)
    我无法使用 BCS跳转标签)或 BMI 测试结果,因为 V2 为负值。
    那么?

使用不同的集合,即 V1=$1 和 V2=$0A 我将得到 有什么建议吗?

解决方法

通常,这样的序列(我稍微修改了您问题中的代码以使其更加独立)

V1 equ $91  
V2 equ $90  
 lda #00
 sta V2
 lda #20
 sta V1 
Label:
 sec  
 lda V2  
 sbc #2  
 sta V2  
 lda V1  
 sbc #10  
 sta V1   

将按预期工作。使用代码中使用的值,在第一次减法后将清除进位,并在第二次减法后再次设置。如果不是,那么最可能的原因是模拟器中的错误。我已经在在线 6502 仿真中运行了它,并且在到达最终 sta V1 时设置了进位。我也在 visual6502 中运行它,这是跟踪输出:


cycle ab    db  rw  Fetch   pc      a   x   y   s   p
0   0000    a9  1   LDA #   0000    aa  00  00  fd  nv‑BdIZc
0   0000    a9  1   LDA #   0000    aa  00  00  fd  nv‑BdIZc
2   0002    85  1   STA zp  0002    00  00  00  fd  nv‑BdIZc
4   0090    00  0           0004    00  00  00  fd  nv‑BdIZc
5   0004    a9  1   LDA #   0004    00  00  00  fd  nv‑BdIZc
7   0006    85  1   STA zp  0006    14  00  00  fd  nv‑BdIzc
9   0091    14  0           0008    14  00  00  fd  nv‑BdIzc
10  0008    38  1   SEC     0008    14  00  00  fd  nv‑BdIzc
12  0009    a5  1   LDA zp  0009    14  00  00  fd  nv‑BdIzC
15  000b    e9  1   SBC #   000b    00  00  00  fd  nv‑BdIZC
17  000d    85  1   STA zp  000d    00  00  00  fd  nv‑BdIZC
19  0090    fe  0           000f    fe  00  00  fd  Nv‑BdIzc
20  000f    a5  1   LDA zp  000f    fe  00  00  fd  Nv‑BdIzc
23  0011    e9  1   SBC #   0011    14  00  00  fd  nv‑BdIzc
25  0013    85  1   STA zp  0013    14  00  00  fd  nv‑BdIzc
27  0091    09  0           0015    09  00  00  fd  nv‑BdIzC

正如你在最后看到的,进位被设置(用大写 C 表示)。

顺便说一下,您的代码还有一个问题。如果您有 2000(十进制),那么要将其加载到两个位置,您需要先将其转换为十六进制,然后再将其切成两个字节。如果您将 0 加载到零页位置并将 20 位小数加载到其后继位置,则您实际上加载了 20 * 256 = 5120。2000 的十六进制为 $07d0


遵循对问题的最新编辑。这是一段简化的代码,它通过进位清除从 $0a 中减去 $90

clc
lda #$90
sbc #$0a

这是 Visual 6502 跟踪

cycle ab    db  rw  Fetch   pc      a   x   y   s   p
0   0000    18  1   CLC     0000    aa  00  00  fd  nv‑BdIZc
0   0000    18  1   CLC     0000    aa  00  00  fd  nv‑BdIZc
2   0001    a9  1   LDA #   0001    aa  00  00  fd  nv‑BdIZc
4   0003    e9  1   SBC #   0003    90  00  00  fd  Nv‑BdIzc
6   0005    ea  1   NOP     0005    90  00  00  fd  Nv‑BdIzc
8   0006    ea  1   NOP     0006    85  00  00  fd  Nv‑BdIzC

如果您的模拟器在这种情况下未设置进位,则您的模拟器存在错误。

,

循环执行 16 位减法,直到结果为负

如果结果 >0,则“分支”到标签,

您是否发现这些描述相互矛盾?
第一个在0继续,第二个在0停止
只有你能决定哪一个是正确的!


来自评论:

此代码是 Bin 到 Ascii 转换的一部分,由十次幂减法制成。 bin 值可能大于 8000 美元,因此它是“负数”,但这并不重要。在第一次迭代中,我每个循环减 10000,直到结果“低于 0”,然后我恢复以前的值并继续余数。问题是如何检测帖子中所说的“低于 0”条件

Do ... Loop While GE 0

下一个示例从存储在零页地址 $90 的无符号字中减去 10000 ($2710)。低字节为 90 美元,高字节为 91 美元(小端)。

Lo equ $90       ; The 16-bit bin is stored at zero page address $90
Hi equ $91
      sec        ; Because SBC subtracts the complement of C
      ldx #-1
Label inx
      lda Lo     ; Load from a zero page address
      sbc #$10   ; Subtracting immediate $10
      sta Lo     ; Store to a zero page address
      lda Hi     ; Load from a zero page address
      sbc #$27   ; Subtracting immediate $27
      sta Hi     ; Store to a zero page address
      bcs Label  ; Result GE 0 (greater or equal)
      rts

X 寄存器现在包含原始数字中 10000 的次数。


Do ... Loop While GT 0

您可以添加 ora 指令以查看生成的单词是否已变为否定。然后根据 Z 中的 ora 和(最后一个)C 中的 sbc 进行分支。

Lo equ $90       ; The 16-bit bin is stored at zero page address $90
Hi equ $91
      sec        ; Because SBC subtracts the complement of C
Label lda Lo     ; Load from a zero page address
      sbc #$10   ; Subtracting immediate $10
      sta Lo     ; Store to a zero page address
      lda Hi     ; Load from a zero page address
      sbc #$27   ; Subtracting immediate $27
      sta Hi     ; Store to a zero page address
      ora Lo     ; To define Z for the whole word
      beq Done   ; Result EQ 0 (equal)
      bcs Label  ; Result GT 0 (greater)
Done  rts

我的 6502 手册说:“最重要的是,请记住比较是通过 BCSBCC不是 BPLBMI)完成的.

,

我找到了一个解决方案,既麻烦又不优雅,但有效:

           LDY #0
_B2D161    INY  
           PHA  
           TXA  
           SEC  
           SBC  #$10
           TAX  
           PLA
;----------------------  
           BCS  _BD1  ;normal flow
           SEC  ;set carry for the next sub
           SBC  #$28  ;the carry=0 would have incremented the minuend
           BCS  _B2D161  ;loop again
           BCC  _BD11  ;exit and restore the previous value
;-----------------------
_BD1       SBC  #$27  ;normal jump comes here
           BCS  _B2D161

_BD11      PHA  
           TXA  
           CLC  
           ADC  #$10
           TAX  
           PLA  
           ADC  #$27
           DEY  
           STY  _L10K
           ... continue with next section

隔离部分显示了应用的变体:如果第一个 sub 清除进位,则通过减去增加 1 的值(#28 而不是 #27)并恢复下一个 sub 的进位来“模拟”。
这样我就可以再次依靠 Carry 来决定分支的位置。

我要感谢 Sep Roland 提供的建议代码(与我最初使用的代码相同),但不幸的是它没有完成这项工作。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...