我想看看我能不能在我的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”中而停止。我试过几种方法,但都不起作用。
1条答案
按热度按时间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。这有点混淆了发生了什么。如果INDEX
和INDEX+1
只包含您要跳转到的地址,则可以直接使用间接形式JMP (INDEX)
。它将为您节省一个时钟周期和一个字节,也更具可读性。