如何将微处理器汇编代码从筛选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存到临时地址,方便后续更新。
主循环:逐个判断数组元素
- 每次循环先把B里的循环计数器存到临时地址——因为接下来要修改B加载数组元素,得先把计数保住。
- 把当前数组元素加载到B,再存到临时变量:因为
idiv指令会修改D寄存器的值,必须先把原元素存起来。 - 清零A寄存器,把8位数组元素扩展成16位的D寄存器(0x00加元素值),满足
idiv的16位除法要求。 - 执行
idiv,用D除以X里的3,余数存在D中。如果余数不为0,跳去处理非3倍数分支;余数为0则处理3的倍数。 - 处理3的倍数时,从临时地址取出当前目标存储地址,把保存的元素放进去,再把目标地址加1,准备存下一个。
- 处理非3倍数时,把保存的元素压进栈,同时把非倍数计数器加1。
- 最后把数组指针Y加1,指向下一个元素,重新加载循环计数器到B,用
dbne判断计数器是否减到0,没到0就继续循环。
栈元素转存到$1650
- 循环结束后,把Y指向$1650,X指向栈里最后一个压入的元素地址($1fff)。
- 用非倍数计数器的值作为循环次数,把栈里的元素逐个取出存到$1650开始的地址:因为栈是后进先出,从高地址往低地址取,能保证元素顺序和原数组一致。
- 最后用
swi触发软件中断,结束程序。
内容的提问来源于stack exchange,提问作者NeverendingFlame42
相关产品推荐
相关产品推荐

