You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将微处理器汇编代码从筛选4的倍数改为筛选3的倍数?

汇编代码修改求助:将筛选4的倍数改为筛选3的倍数

我是微处理器课程的学生,第一次接触汇编编程。教授提供了一段汇编代码,功能是把数组里4的倍数存入地址$1600,非4倍数压入栈后再存入地址$1650。现在要求把代码改成筛选3的倍数,教授也给了修改提示,但我缺乏汇编基础,修改后出现错误且无法排查,希望能得到修改后的正确代码,以及详细的逻辑讲解。


原代码(筛选4的倍数)

; Copy all the values which are divisible by four to a starting address $1600.
; The indivisible by four is pushed onto the stack, and use the effective address
; to pull them out after finishing the loop. The starting address is $1650.
; Array pointer starts from the beginning, and using DBNE to decrement the loop

N       equ     12
        org     $1600
        fill    0,128           ; each row in the memory displays 16 bytes
cnt     rmb     1               ; indivisible counter
        org     $1ff0
        fill    0,16

        org     $2000           ; start RAM address
        lds     #$2000          ; initialize the stack pointer
        ldy     #$1600          ; load the starting address for divisible by 4
        ldx     #array          ; load the starting address of array to Reg. X
        ldaa    #N              ; use B as the loop counter, B = N
        clr     cnt             ; clear cnt counter
loop    brclr   0,x,$03,yes     ; if bits 1 & 0 are 0s, then branch to yes
        ldab    1,x+
        inc     cnt             ; increment cnt counter for indivisible
        pshb                    ; push onto the stack for the indivisible
        bra     chkend
yes     movb    1,x+,1,y+       ; copy the divisible by 4 value to a new location
chkend  dbne    a,loop          ; decrement B by 1, if B NE 0, branch to loop

; use the effective address to load/pull the elements from the stack

        ldy     #$1650
        ldx     #$1fff          ; first available address for the stack
        ldaa    cnt
loop2   movb    1,x-,1,y+       ; stack is first in last out
        dbne    a,loop2
        swi
array   db      3,4,9,12,19,20,24,31,48,53,64,72
        end

教授给出的修改提示(中文翻译)

  • idiv 指令:累加器D除以寄存器X,余数会存入D中
  • 寄存器X存放常量3
  • 寄存器Y用作数组指针
  • 累加器A为空时,A:B组合成累加器D
  • 可以用累加器B作为循环计数器,同时存储3的倍数的目标起始地址
  • 循环开始时,要把循环计数器的值存到临时地址,比如$15FE
  • 先清零A,再用ldab 0,y,这样D的值就是[0 : 第一个数组元素]
  • 执行idiv后,比较累加器D是否为0
  • 如果D不为0,把累加器B的值压入栈
  • 如果D为0,重新加载3的倍数的目标地址(更新后的)
  • 处理完当前数组元素后,从$15FE重新加载循环计数器,然后递增数组指针
  • 用dbne b,loop执行下一次循环

修改后的代码(筛选3的倍数)

; 筛选数组中3的倍数存入地址$1600,非3倍数压栈后存入$1650
N             equ     12
TEMP_LOOP_CNT equ     $15FE  ; 临时存储循环计数器的地址
TEMP_DIV_ADDR equ     $15FF  ; 存储3的倍数的当前目标地址
TEMP_VAL      equ     $15FD  ; 临时存储当前数组元素
DIV3_DEST     equ     $1600  ; 3的倍数的起始存储地址

        org     $1600
        fill    0,128           ; 初始化目标存储区域为0
cnt     rmb     1               ; 非3倍数的计数器
        org     $1ff0
        fill    0,16

        org     $2000           ; RAM起始地址
        lds     #$2000          ; 初始化栈指针(栈向低地址增长)
        ldx     #3              ; X寄存器存入除数3
        ldy     #array          ; Y作为数组指针,指向数组起始位置
        ldab    #N              ; B寄存器作为循环计数器,初始值为数组长度
        clr     cnt             ; 清零非3倍数计数器
        ldaa    #DIV3_DEST
        sta     TEMP_DIV_ADDR   ; 初始化3的倍数的目标地址

loop    stab    TEMP_LOOP_CNT   ; 保存当前循环计数器值
        ldab    0,y             ; 加载当前数组元素到B
        stab    TEMP_VAL        ; 临时存储数组元素(避免被除法指令修改)
        clra                    ; 清零A,将8位元素扩展为16位被除数D(0x00XX)
        idiv                    ; D除以X(3),余数存入D,商存入X
        cpd     #0              ; 判断余数是否为0
        bne     not_div3        ; 余数不为0,跳转到非3倍数处理

; 处理3的倍数:存入目标地址
div3    ldaa    TEMP_DIV_ADDR   ; 获取当前目标地址
        ldab    TEMP_VAL        ; 取出保存的数组元素
        movb    0,b,0,a         ; 将元素存入目标地址
        inc     TEMP_DIV_ADDR   ; 更新目标地址,准备存储下一个元素
        bra     loop_end

; 处理非3倍数:压入栈并计数
not_div3
        ldab    TEMP_VAL        ; 取出数组元素
        pshb                    ; 压入栈
        inc     cnt             ; 非3倍数计数器加1

loop_end
        incy                    ; 数组指针后移,指向下一个元素
        ldab    TEMP_LOOP_CNT   ; 恢复循环计数器
        dbne    b,loop          ; 计数器减1,不为0则继续循环

; 将栈中元素转存到$1650
        ldy     #$1650          ; 非3倍数的目标起始地址
        ldx     #$1fff          ; 栈中最后一个元素的地址
        ldaa    cnt             ; 加载非3倍数的数量
loop2   movb    1,x-,1,y+       ; 从栈中取出元素(后进先出,保证顺序与原数组一致)
        dbne    a,loop2
        swi                     ; 程序结束

array   db      3,4,9,12,19,20,24,31,48,53,64,72
        end

代码逻辑详解

初始化阶段

  • 先定义数组长度、临时变量的内存地址,同时把$1600开始的内存区域清零,方便后续存储结果。
  • 设置栈指针到$2000(栈向低地址增长);把除数3放进X寄存器,供除法指令使用;Y寄存器指向数组第一个元素,用来遍历数组;B寄存器存数组长度12作为循环计数器;清零非3倍数的计数器,统计需要从栈中取出的元素个数;最后把3的倍数的目标起始地址$1600存到临时地址,方便后续更新。

主循环:逐个判断数组元素

  1. 每次循环先把B里的循环计数器存到临时地址——因为接下来要修改B加载数组元素,得先把计数保住。
  2. 把当前数组元素加载到B,再存到临时变量:因为idiv指令会修改D寄存器的值,必须先把原元素存起来。
  3. 清零A寄存器,把8位数组元素扩展成16位的D寄存器(0x00加元素值),满足idiv的16位除法要求。
  4. 执行idiv,用D除以X里的3,余数存在D中。如果余数不为0,跳去处理非3倍数分支;余数为0则处理3的倍数。
  5. 处理3的倍数时,从临时地址取出当前目标存储地址,把保存的元素放进去,再把目标地址加1,准备存下一个。
  6. 处理非3倍数时,把保存的元素压进栈,同时把非倍数计数器加1。
  7. 最后把数组指针Y加1,指向下一个元素,重新加载循环计数器到B,用dbne判断计数器是否减到0,没到0就继续循环。

栈元素转存到$1650

  • 循环结束后,把Y指向$1650,X指向栈里最后一个压入的元素地址($1fff)。
  • 用非倍数计数器的值作为循环次数,把栈里的元素逐个取出存到$1650开始的地址:因为栈是后进先出,从高地址往低地址取,能保证元素顺序和原数组一致。
  • 最后用swi触发软件中断,结束程序。

内容的提问来源于stack exchange,提问作者NeverendingFlame42

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 06:32:11