在 6502 的装配中创建两个方波
Creating two square waves in assembly for the 6502
我正在尝试使用 6502 微控制器指令集生成两个输出:一个 20Hz 方波和一个 30Hz 方波。到目前为止,我可以在 20Hz 波上输出:
%uasm65,title="SQUARES"
org 0200h
lda #1d
sta 0a200h
Main:
;jump to the subroutine Delay and do it
jsr Delay
lda 0a200h
inc Count1
lda Count1
cmp #3d
beq Reset1
jmp Main
Reset1:
lda #0d
sta Count1
lda 0a200h
eor #00000001b
sta 0a200h
jmp Main
Reset2:
jmp Main
Delay:
;Save registers on the stack.
pha
txa
pha
tya
pha
;Change the number that is being loaded into the
; 'A' register in order to change the delay time.
lda #01h
OutLoop:
ldx #04h
InLoop1:
ldy #0ffh
InLoop2:
dey
bne InLoop2
dex
bne InLoop1
sec
sbc #1d
bne OutLoop
;Restore registers from the stack.
pla
tay
pla
tax
pla
rts
Count1:
dbt 0d
Count2:
dbt 0d
end
%/uasm65
根据我的理解,我能做的就是获取一个 60Hz 的方波并用它来获得 30Hz 和 20Hz。如何在不影响端口中其他位的状态的情况下,将 20Hz 方波输出到 PortA 的第 5 位,将 30Hz 方波输出到 PortA 的第 6 位?换句话说,我如何从这里的 60 得到 20 和 30?我是否让计数检查 7 并递增计数 2?任何帮助将不胜感激。
您需要 2 个独立的计数器,每个引脚一个
Main:
;jump to the subroutine Delay and do it
jsr Delay
lda 0a200h ; ?? what's this doing here?
inc Count1 ; count1 is for the 20 Hz bit pin
lda Count1
cmp #3d ; 60/20 = 3, so counter1 will have to reach 3
bne Skip1 ; otherwise skip toggling
toggle_pin5:
lda #0d ; reload first Counter
sta Count1
lda 0a200h
eor #00000001b
sta 0a200h
skip1:
inc Count2 ; count2 is for the 30 Hz bit pin
lda Count2
cmp #2d ; 60/30 = 2, so counter2 will have to reach 2
bne Skip2 ; you could also "bne Main" here
toggle_pin6:
lda #0d ; reload 2nd Counter
sta Count2
lda 0a200h
eor #00000010b ; you will want to change this for the correct value to "set bit6 of PortA"
sta 0a200h
skip2:
jmp Main
Reset1: ; not needed anymore
Reset2: ; not needed anymore
Delay: [ ... ]
在你的循环中,分支到 Reset1(或 Reset2),然后跳回到 Main 不是一个好主意,你会跳过第二个引脚的第二次检查。最好只是分支几个指令(就像我所做的那样),或者使用 JSR/RET:
cmp #3d
bne SkipCall ; counter value NOT reached, so skip "Reset"
jsr Reset
SkipCall:
<...>
Reset:
lda #0d
sta Count1
<...>
ret
根据我对 the instruction set 的阅读,这应该可以工作并且比 Tommylee 的代码更短。 (我以此为起点)。
如果您使用在结果达到零时设置零标志的递减量,则在 asm 中向零计数是可取的。那么你不需要单独的比较。这可以将代码大小降低到 0x1D
字节(对于我的第二个版本)。
我假设带有内存操作数的 dec
仍会根据结果设置标志。除了维基百科,我没有看过任何 6502 文档。 :P 问题中的代码使用 dey
/bne
,所以我认为这是正确的并设置了标志。
假设优化更少的指令更好,你应该尽量减少延迟循环。也许只是嵌套的内存递减循环以 bne
作为循环条件(所以你循环 2^n 次)?除非使用内存更耗电?
Main:
ldx #3d ; 60/20 = 3: toggle every 3 iterations
; stx Count5 ; Count5 is for the 20 Hz bit wave on pin5
ldy #2d ; 60/30 = 2: toggle every 2 iteration
; sty Count6 ; Count6 is for the 30 Hz bit wave on pin6
; omit the stores: Count5 and Count6 are already initialized.
; lda 0a200h ; start with the initial state of the I/O port
lda #1d ; constant initial state
squarewave_loop:
jsr Delay
; lda 0a200h ; or do this here, so Delay doesn't have to save/restore A
dec Count1
bne skip1 ; toggle when it reaches zero
toggle_pin5:
stx Count5 ; reload first countdown counter
eor #00000001b
skip1:
dec Count2
bne skip2 ; toggle when it reaches zero
toggle_pin6:
sty Count6
eor #00000010b ; FIXME: which bit maps to bit6 of Port A?
skip2:
sta 0a200h ; always store, even if there was no state change
jmp squarewave_loop
Delay: [ ... ]
Count1:
dbt 3d
Count2:
dbt 2d
或者,对 count1/count2
使用 dey
/ dex
那么我们不需要任何内存来存储计数器,我假设带有内存操作数的指令有更长的编码
Main:
ldx #3d ; 60/20 = 3: toggle every 3 iterations
ldy #2d ; 60/30 = 2: toggle every 2 iteration
; lda 0a200h ; start with the initial state of the I/O port
lda #1d ; constant initial state
squarewave_loop:
jsr Delay
; lda 0a200h ; or do this here, so Delay doesn't have to save/restore A
dex
bne skip1
;toggle_pin5: ; runs when 1st down-counter hits zero
ldx #3d ; reload the countdown
eor #00000001b
skip1:
dey
bne skip2
;toggle_pin6: ; runs when 2nd down-counter hits zero
ldy #2d
eor #00000010b ; FIXME: which bit maps to bit6 of Port A?
skip2:
sta 0a200h ; always store, even if there was no state change
jmp squarewave_loop
Delay: [ ... ]
如果我删除注释并从标签末尾删除 :
字符,这会在 http://www.masswerk.at/6502/assembler.html 上组装。总大小,不包括延迟循环,是 0x1D 字节的代码。
我正在尝试使用 6502 微控制器指令集生成两个输出:一个 20Hz 方波和一个 30Hz 方波。到目前为止,我可以在 20Hz 波上输出:
%uasm65,title="SQUARES"
org 0200h
lda #1d
sta 0a200h
Main:
;jump to the subroutine Delay and do it
jsr Delay
lda 0a200h
inc Count1
lda Count1
cmp #3d
beq Reset1
jmp Main
Reset1:
lda #0d
sta Count1
lda 0a200h
eor #00000001b
sta 0a200h
jmp Main
Reset2:
jmp Main
Delay:
;Save registers on the stack.
pha
txa
pha
tya
pha
;Change the number that is being loaded into the
; 'A' register in order to change the delay time.
lda #01h
OutLoop:
ldx #04h
InLoop1:
ldy #0ffh
InLoop2:
dey
bne InLoop2
dex
bne InLoop1
sec
sbc #1d
bne OutLoop
;Restore registers from the stack.
pla
tay
pla
tax
pla
rts
Count1:
dbt 0d
Count2:
dbt 0d
end
%/uasm65
根据我的理解,我能做的就是获取一个 60Hz 的方波并用它来获得 30Hz 和 20Hz。如何在不影响端口中其他位的状态的情况下,将 20Hz 方波输出到 PortA 的第 5 位,将 30Hz 方波输出到 PortA 的第 6 位?换句话说,我如何从这里的 60 得到 20 和 30?我是否让计数检查 7 并递增计数 2?任何帮助将不胜感激。
您需要 2 个独立的计数器,每个引脚一个
Main:
;jump to the subroutine Delay and do it
jsr Delay
lda 0a200h ; ?? what's this doing here?
inc Count1 ; count1 is for the 20 Hz bit pin
lda Count1
cmp #3d ; 60/20 = 3, so counter1 will have to reach 3
bne Skip1 ; otherwise skip toggling
toggle_pin5:
lda #0d ; reload first Counter
sta Count1
lda 0a200h
eor #00000001b
sta 0a200h
skip1:
inc Count2 ; count2 is for the 30 Hz bit pin
lda Count2
cmp #2d ; 60/30 = 2, so counter2 will have to reach 2
bne Skip2 ; you could also "bne Main" here
toggle_pin6:
lda #0d ; reload 2nd Counter
sta Count2
lda 0a200h
eor #00000010b ; you will want to change this for the correct value to "set bit6 of PortA"
sta 0a200h
skip2:
jmp Main
Reset1: ; not needed anymore
Reset2: ; not needed anymore
Delay: [ ... ]
在你的循环中,分支到 Reset1(或 Reset2),然后跳回到 Main 不是一个好主意,你会跳过第二个引脚的第二次检查。最好只是分支几个指令(就像我所做的那样),或者使用 JSR/RET:
cmp #3d
bne SkipCall ; counter value NOT reached, so skip "Reset"
jsr Reset
SkipCall:
<...>
Reset:
lda #0d
sta Count1
<...>
ret
根据我对 the instruction set 的阅读,这应该可以工作并且比 Tommylee 的代码更短。 (我以此为起点)。
如果您使用在结果达到零时设置零标志的递减量,则在 asm 中向零计数是可取的。那么你不需要单独的比较。这可以将代码大小降低到 0x1D
字节(对于我的第二个版本)。
我假设带有内存操作数的 dec
仍会根据结果设置标志。除了维基百科,我没有看过任何 6502 文档。 :P 问题中的代码使用 dey
/bne
,所以我认为这是正确的并设置了标志。
假设优化更少的指令更好,你应该尽量减少延迟循环。也许只是嵌套的内存递减循环以 bne
作为循环条件(所以你循环 2^n 次)?除非使用内存更耗电?
Main:
ldx #3d ; 60/20 = 3: toggle every 3 iterations
; stx Count5 ; Count5 is for the 20 Hz bit wave on pin5
ldy #2d ; 60/30 = 2: toggle every 2 iteration
; sty Count6 ; Count6 is for the 30 Hz bit wave on pin6
; omit the stores: Count5 and Count6 are already initialized.
; lda 0a200h ; start with the initial state of the I/O port
lda #1d ; constant initial state
squarewave_loop:
jsr Delay
; lda 0a200h ; or do this here, so Delay doesn't have to save/restore A
dec Count1
bne skip1 ; toggle when it reaches zero
toggle_pin5:
stx Count5 ; reload first countdown counter
eor #00000001b
skip1:
dec Count2
bne skip2 ; toggle when it reaches zero
toggle_pin6:
sty Count6
eor #00000010b ; FIXME: which bit maps to bit6 of Port A?
skip2:
sta 0a200h ; always store, even if there was no state change
jmp squarewave_loop
Delay: [ ... ]
Count1:
dbt 3d
Count2:
dbt 2d
或者,对 count1/count2
使用dey
/ dex
那么我们不需要任何内存来存储计数器,我假设带有内存操作数的指令有更长的编码
Main:
ldx #3d ; 60/20 = 3: toggle every 3 iterations
ldy #2d ; 60/30 = 2: toggle every 2 iteration
; lda 0a200h ; start with the initial state of the I/O port
lda #1d ; constant initial state
squarewave_loop:
jsr Delay
; lda 0a200h ; or do this here, so Delay doesn't have to save/restore A
dex
bne skip1
;toggle_pin5: ; runs when 1st down-counter hits zero
ldx #3d ; reload the countdown
eor #00000001b
skip1:
dey
bne skip2
;toggle_pin6: ; runs when 2nd down-counter hits zero
ldy #2d
eor #00000010b ; FIXME: which bit maps to bit6 of Port A?
skip2:
sta 0a200h ; always store, even if there was no state change
jmp squarewave_loop
Delay: [ ... ]
如果我删除注释并从标签末尾删除 :
字符,这会在 http://www.masswerk.at/6502/assembler.html 上组装。总大小,不包括延迟循环,是 0x1D 字节的代码。