Почему мой Fibonacci 6502 работает со сбоями для 144 и 233? - PullRequest
1 голос
/ 06 февраля 2020

Следующая программа:

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 (версия WD C). Подключен к ПЗУ (начиная с адреса 0x8000) и к микросхеме ОЗУ (адрес 0x4000) и к VIA (65C22), который подключен к HD44780 (стандартный ЖК-дисплей 1602).

И программа работает , но частично. Он выводит 1, затем 2, затем 3 ... затем 89 и вместо 144 отпечатков 1 вместо 233 отпечатков 2. Затем 1 снова, затем 98 ??? А потом 61.

1 Ответ

2 голосов
/ 06 февраля 2020

То, как вы решаете l oop вернуться к print_digits, неверно:

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

Это перейдет к print_digits, только если X без знака ниже 1. Единственное возможное значение, для которого это может быть истиной, равно 0, поэтому вышеприведенное также можно описать как переход к print_digits, если X равно 0.

Если мы посмотрим на все print_digits l oop, поэтому его можно описать следующим псевдокодом:

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

Единственный сценарий ios, в котором это даст вам правильный результат, - это когда numDigits равен 1 или 2. Для чего-то большего кроме этого, вы напечатаете один ди git, а затем выйдете из l oop.


То, что вы действительно хотите, выглядит примерно так:

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
...