assembly “bne”程序集命令未执行其应执行的操作

b0zn9rqh  于 2023-08-06  发布在  其他
关注(0)|答案(1)|浏览(73)

我想看看我能不能在我的6502 cpu上做一个方波音调发生器。在那之后,我试图让它随着时间的推移改变频率,但它总是卡在一个循环中,这个循环对输出的周期进行计数,并在特定数量的周期后改变频率。代码如下:

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

TONE = $0200    ;1 byte
TEMPX = $0201   ;1 byte
TEMPY = $0202   ;1 byte
INDEX = $0203   ;3 bytes

CLEAR = %00000001

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

 .org $c000
MUSIC:
T1:
 ldy #12
 ldx #75
 jmp WAIT_LOOP
T2:
 ldy #8
 ldx #5
 jmp WAIT_LOOP
T3:
 ldy #6
 ldx #37
 jmp WAIT_LOOP
T4:
 ldy #5
 ldx #1
 jmp WAIT_LOOP
T5:
 ldy #4
 ldx #25
 jmp WAIT_LOOP
T6:
 ldy #3
 ldx #64
 jmp WAIT_LOOP
T7:
 ldy #3
 ldx #18
 jmp WAIT_LOOP
T8:
 ldy #2
 ldx #83
 jmp WAIT_LOOP
T9:
 ldy #2
 ldx #55
 jmp WAIT_LOOP
JH:
 jmp HLT

 .org $8000
RESET:               The programm starts here
 ldx #$ff
 txs

 cli

 lda #%11111111   ;setting port B as all output
 sta DDRB
 lda #%11100001   ;setting first 3 pins and last pin of port A as output
 sta DDRA

 lda #%00111000   ;initialize LCD in 8-bit mode, 5x8 font and 2 lines
 jsr LCD_INSTRUCTION
 lda #%00001110   ;initialize LCD to be on and have cursor on
 jsr LCD_INSTRUCTION
 lda #%00000110   ;set cursor move direction and set LCD to not scroll
 jsr LCD_INSTRUCTION

 jsr LCD_CLEAR

 lda #$4c
 sta INDEX
 lda #$00
 sta INDEX +1
 lda #$c0
 sta INDEX +2

 lda #%01010101
 sta TONE

 ldx #0
PRINT_MESSAGE:
 lda MESSAGE,x
 beq PLAY
 jsr PRINT_CHAR
 inx
 jmp PRINT_MESSAGE

PLAY:
 ldy #$ff
 ldx #$ff
PLAY_TONE:
 sty TEMPY
 stx TEMPX

 lda TONE
 and #%0000001
 sta PORTA

 lda TONE
 eor #$ff
 sta TONE

 jsr WAIT

 ldy TEMPY
 ldx TEMPX
 dex
 bne PLAY_TONE
 dey
 bne PLAY_TONE            it always gets stuck jumping to "PLAY_TONE"

INC_INDEX:
 clc
 lda INDEX +1
 adc #7
 sta INDEX +1
 lda INDEX +2
 adc #0
 sta INDEX +2

 jmp PLAY

HLT:
 jmp HLT

MESSAGE: .asciiz "Frequency: var                         Amplitude: 5V   "

WAIT:
 jmp INDEX
WAIT_LOOP:
 dex
 bne WAIT_LOOP
 dey
 bne WAIT_LOOP
 rts

LCD_WAIT:
 pha
 lda #%00000000   ;set port B as all input
 sta DDRB
LCD_BUSY:
 lda #RW
 sta PORTA
 lda #(RW|E)
 sta PORTA
 lda PORTB
 and #%10000000   ;only check busy flag
 bne LCD_BUSY

 lda #RW
 sta PORTA
 lda #%11111111   ;set port B back to all output
 sta DDRB
 pla
 rts

LCD_CLEAR:
 lda #CLEAR       ;clear LCD
 jsr LCD_INSTRUCTION

LCD_INSTRUCTION:
 jsr LCD_WAIT
 sta PORTB
 lda #%0          ;clear RS/RW/E bits
 sta PORTA
 lda #E           ;enable the LCD to send instruction
 sta PORTA
 lda #%0          ;clear RS/RW/E bits
 sta PORTA
 rts

PRINT_CHAR:
 jsr LCD_WAIT
 sta PORTB
 lda #RS         ;clear RW/E bits and switch RS on
 sta PORTA
 lda #(RS|E)     ;enable the LCD to send instruction
 sta PORTA
 lda #RS         ;clear RW/E bits and switch RS on
 sta PORTA
 rts

NMI:
 rti

BRK_IRQ:
 rti

EXIT_INT:
 rti

VECTORS:
 .org $fffa
 .word NMI
 .org $fffc
 .word RESET
 .org $fffe
 .word BRK_IRQ

字符串
我知道代码可能是可怕的效率低下,但我只是希望它的工作(I am using the setup from ben eater)也有一个模拟器的设置,我正在使用的https://www.tejotron.com/
在一定数量的循环之后,代码应该改变频率几次,然后通过卡在循环“HLT”中而停止。我试过几种方法,但都不起作用。

ztmd8pv5

ztmd8pv51#

第一次输入WAITLOOP时,X包含75,Y包含12。它会将X 75计数到0,然后将Y递减到11。然后它回到循环的顶部,将X(此时包含零)从0递减到0(走很长的路),并再次递减Y,直到Y为零。
所以第一次,你有75 + 12 x 256次WAITLOOP的迭代,也就是3147次迭代。执行此操作的代码在每次X迭代中需要5个周期,在每次Y迭代中需要更多的周期。大约16,000个时钟周期。
在调用WAITLOOP的循环中,需要迭代256 x 256次。这是调用WAITLOOP 65,536次。因此,在第一组PLAY_TONE迭代中,仅执行WAITLOOP就花费了大约1030,000,000个周期。这是1030秒或17分钟(假设时钟为1 MHz),不包括循环中的所有其他指令。
我不认为它卡住了,我只是觉得你的循环太大了。

旁注

在我看来,你的JMP INDEX是一个小hincky。这有点混淆了发生了什么。如果INDEXINDEX+1只包含您要跳转到的地址,则可以直接使用间接形式JMP (INDEX)。它将为您节省一个时钟周期和一个字节,也更具可读性。

相关问题