首页 > 解决方案 > 为什么我的斐波那契 6502 在 144 和 233 时出现故障?

问题描述

以下程序:

PORTB = $6000
PORTA = $6001
DDRB = $6002
DDRA = $6003

E  = %10000000
RW = %01000000
RS = %00100000

VARX = $4000
VARY = $4001
VARZ = $4002

NUM = $4005
DIV = $4006
RES = $4007
MOD = $4008

BACK_TO_FRONT = $4020

  .org $8000

reset:
  lda #%11111111 ; Set all pins on port A to output
  sta DDRA

  lda #%11100000 ; Set top 3 pins on port B to output
  sta DDRB

  lda #%00011100 ; Set 8-bit mode; 2-line display; 5x8 font
  sta PORTA
  lda #0         ; Clear RS/RW/E bits
  sta PORTB
  lda #E         ; Set E bit to send instruction
  sta PORTB
  lda #0         ; Clear RS/RW/E bits
  sta PORTB

  lda #%01110000 ; Display on; cursor on; blink off
  sta PORTA
  lda #0         ; Clear RS/RW/E bits
  sta PORTB
  lda #E         ; Set E bit to send instruction
  sta PORTB
  lda #0         ; Clear RS/RW/E bits
  sta PORTB

  lda #%01100000 ; Increment and shift cursor; don't shift display
  sta PORTA
  lda #0         ; Clear RS/RW/E bits
  sta PORTB
  lda #E         ; Set E bit to send instruction
  sta PORTB
  lda #0         ; Clear RS/RW/E bits
  sta PORTB

  lda #$0
  sta VARX

  lda #$1
  sta VARY

  lda #$a
  sta DIV

loop:
  lda VARX

  clv
  clc
  adc VARY
  clc
  clv

  sta VARZ

  lda VARY
  sta VARX

  lda VARZ
  sta VARY

  lda VARY
  sta NUM


  ldx #$0

  store_digits:  
    jmp divide

    return_from_div:

    lda MOD
        sta BACK_TO_FRONT, x

        inx

        lda RES
        sta NUM

        lda #$0
        cmp NUM
        bcc store_digits

   dex

   print_digits:
    ldy BACK_TO_FRONT, x
    lda digit_table, y
    sta PORTA
    lda #RS         ; Set RS; Clear RW/E bits
    sta PORTB
    lda #(RS | E)   ; Set E bit to send instruction
    sta PORTB
    lda #RS         ; Clear E bits
    sta PORTB

    dex

    sec
    cpx #$1
    bcc print_digits

    ldx #$0
    delay:
            lda #%00000100
            sta PORTA
            lda #RS         ; Set RS; Clear RW/E bits
            sta PORTB
            lda #(RS | E)   ; Set E bit to send instruction
            sta PORTB
            lda #RS         ; Clear E bits
            sta PORTB
        cpx #$f
        beq next

        inx

        jmp delay 

    next:

        lda #%10000000
        sta PORTA

    lda #0         ; Clear RS/RW/E bits
    sta PORTB
    lda #E         ; Set E bit to send instruction
    sta PORTB
    lda #0         ; Clear RS/RW/E bits
    sta PORTB

  jmp loop

divide:
  lda #$0
  sta RES

  lda #$0
  sta MOD

  div_loop:
    lda NUM
    cmp DIV
    bcc answer

    lda NUM

    sec
    sbc DIV
    clc
    clv

    sta NUM

    inc RES
    jmp div_loop

  answer:
    lda NUM
    sta MOD
    jmp return_from_div

digit_table:
  .word $8c0c
  .word $cc4c
  .word $ac2c
  .word $ec6c
  .word $9c1c


  .org $fffc
  .word reset
  .word $0000

在 65C02(WDC 版本)上运行。连接到 ROM(从地址 0x8000 开始)和 RAM 芯片(地址 0x4000)和连接到 HD44780(1602 标准 LCD)的 VIA (65C22)。

该程序有效,但部分有效。它输出 1 然后 2 然后 3 ... 然后 89 而不是 144 打印 1,而不是 233 打印 2. 然后 1 再然后 98 ??? 然后是61。

标签: assemblyfibonacci6502

解决方案


您决定返回的方式print_digits不正确:

; I've omitted the SEC since it's pointless
cpx #$1
bcc print_digits

print_digits仅当无符号小于 1时才会跳转X。唯一可能的值是 0,因此上述也可以描述为跳转到print_digitsifX等于 0。

如果我们查看整个print_digits循环,则可以使用以下伪代码对其进行描述:

x = numDigits - 1;
do
{
    print(digits[x]);
    x--;
} while (x == 0);

唯一能给你正确输出的场景numDigits是 1 或 2。对于任何大于此的值,你将打印一个数字,然后退出循环。


你真正想要的是这样的:

x = numDigits - 1;
do
{
    print(digits[x]);
    x--;
} while (x >= 0);

也就是说,替换:

dex
sec
cpx #$1
bcc print_digits

和:

dex                ; Updates the N flag after decrementing X
bpl print_digits   ; Jump if N is clear, i.e. if X >= 0

推荐阅读