在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的方波输出到端口a的第5位,将30Hz的方波输出到PortA的第6位?换言之,我如何从60岁变成20岁和30岁?我是否让计数检查为7并递增计数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

根据我对指令集的阅读,这应该可以工作,并且比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

或者,使用dey/dex作为count1/count2

然后我们不需要任何内存来存储计数器,我假设具有内存操作数的指令具有更长的编码

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字节的代码。

最新更新