Motorola 68000汇编:栈传参实现字符串过滤与长度计算
任务
开发Motorola 68000程序,实现以下功能:
- 生成字符串C,包含所有存在于字符串A但不存在于字符串B的字符。
- 计算新字符串C的长度。
所有逻辑需在一个或多个子例程中实现,参数通过栈传递。
初始实现代码
基于之前的字符串拼接/比较代码,结合优化建议,完成了初始实现代码:
ORG $8000 ; ---------- 数据段 ---------- StringA DC.B 'I say Hello',0 StringB DC.B 'I say World',0 StringC DS.B 256 ; 调用者必须保证空间足够 LenRes DS.W 0 ; 字符串C的长度(结果) ; ---------- 主程序 ---------- START: PEA.L StringC ; 压入C的地址 PEA.L StringB ; 压入B的地址 PEA.L StringA ; 压入A的地址 BSR.S FilterAndLength ; 构建C,返回长度到D0 MOVE.W D0,LenRes ; 存储长度 ADDA.L #12,A7 ; 弹出参数 SIMHALT ; ---------- FilterAndLength(&A,&B,&C) ---------- ; 输出: D0 = 字符串C的长度 ; 修改寄存器: D1-D2, A0-A3 FilterAndLength: MOVEA.L 4(A7),A0 ; A0指向A MOVEA.L 8(A7),A1 ; A1指向B(基地址) MOVEA.L 12(A7),A2 ; A2指向C CLR.W D0 ; 长度初始化为0 NextCharA: MOVE.B (A0)+,D1 ; 从A取下一个字符 TST.B D1 BEQ Finish ; 到达A的末尾 MOVEA.L A1,A3 ; 重置B的扫描指针 ScanB: MOVE.B (A3)+,D2 TST.B D2 BEQ NotFound ; 扫描完B未找到匹配 CMP.B D2,D1 BEQ NextCharA ; 在B中找到该字符,跳过 BRA ScanB NotFound: ; 字符不在B中,保留到C MOVE.B D1,(A2)+ ADDQ.W #1,D0 BRA NextCharA Finish: CLR.B (A2)+ ; 给C添加结束符 RTS END START
技术问询
- 该代码能否进一步精简或优化?
- 是否正确理解了任务要求(跳过A中所有在B出现过的字符,生成C并返回其长度)?
- 是否值得添加额外功能,比如溢出检查、对齐时的快速字/长字操作,或将字符存在性检测拆分为独立子例程?
位图优化版本代码
已基于建议实现了位图优化版本代码,请确认该代码是否存在问题或仍有可改进之处:
ORG $8000 ; ---------- 数据段 ---------- StringA DC.B 'I say Hello',0 StringB DC.B 'I say World',0 StringC DS.B 256 ; 调用者保证空间足够 LenRes DS.W 0 ; |C| ; ---------- 主程序 ---------- START: PEA.L StringC ; 压入C的地址 PEA.L StringB ; 压入B的地址 PEA.L StringA ; 压入A的地址 BSR.S FilterLen_Bitmap ; 构建C,长度存入D0 MOVE.W D0,LenRes ADDA.L #12,A7 SIMHALT ; --------------------------------------------------------------- ; FilterLen_Bitmap(&A,&B,&C) – D0 = 字符串C的长度 ; 位图压入后的栈布局: ; +32 返回地址 +36 &A +40 &B +44 &C ; --------------------------------------------------------------- ; 使用寄存器: A0/A1, D0-D2. 无需保存其他寄存器. ; --------------------------------------------------------------- FilterLen_Bitmap: ; ---- 分配并清空32字节位图(8次CLR.L -(A7))---- MOVEQ #7,D1 ClrBmp: CLR.L -(A7) DBF D1,ClrBmp ; A7指向位图基地址 ; ---- 用字符串B构建位图 ---- CLR.W D0 ; 高位字节清零 MOVEA.L 40(A7),A0 ; A0 = &B MOVE.B (A0)+,D0 BEQ.S BuildDone ; B为空则跳过 Bloop: MOVE.W D0,D1 LSR.W #3,D1 ; 字节偏移0-31 BSET D0,(A7,D1.W) ; 设置对应位 MOVE.B (A0)+,D0 BNE.S Bloop BuildDone: ; ---- 过滤A到C ---- MOVEA.L 36(A7),A0 ; A0 = &A MOVEA.L 44(A7),A1 ; A1 = &C CLR.W D0 ; 长度计数器清零 CLR.W D1 MOVE.B (A0)+,D1 BEQ.S Finish Aloop: MOVE.W D1,D2 LSR.W #3,D2 ; 位图字节偏移 BTST D1,(A7,D2.W) ; 字符是否在B中? BNE.S Skip MOVE.B D1,(A1)+ ; 保留该字符 ADDQ.W #1,D0 Skip: MOVE.B (A0)+,D1 BNE.S Aloop Finish: CLR.B (A1) ; 给C添加结束符 ADDA.W #32,A7 ; 弹出位图 RTS END START
问题解答
1. 初始代码的精简与优化
初始实现逻辑正确,可做以下优化:
- 指令合并:
ScanB循环中,将TST.B D2和后续判断合并,用CMPI.B #0,D2直接检测B的结束,减少一条指令:ScanB: MOVE.B (A3)+,D2 CMPI.B #0,D2 BEQ NotFound CMP.B D2,D1 BEQ NextCharA BRA ScanB - 跳转精简:
NotFound后的BRA NextCharA可保留,但如果调整循环结构,能进一步减少无条件跳转的开销。 - 栈帧优化:使用
LINK A6,#0建立栈帧,参数访问会更直观(如8(A6)对应&A),同时自动处理返回地址,提升代码可读性。
2. 任务理解正确性
完全符合任务要求:代码将A中所有未在B出现的字符筛选出来存入C,返回C的长度,所有逻辑封装在子例程中,参数通过栈传递,功能实现准确。
3. 额外功能的必要性分析
- 溢出检查:建议添加。如果
StringC空间不足,会导致内存覆盖,可在写入C前检查当前长度是否超过预设容量(如255),超出时设置错误标志或停止写入。 - 快速字/长字操作:无必要。字符串按字节存储,字/长字操作无法提升效率,反而可能引入对齐问题。
- 拆分独立子例程:视需求而定。如果后续有复用字符存在性检测的场景,拆分能提升代码复用性;仅针对当前任务的话,拆分会增加调用开销,得不偿失。
位图版本的问题与改进
位图版本通过预构建B的字符位图,将存在性检测从O(n)优化到O(1),长字符串场景下性能优势明显,当前代码的改进点:
- 寄存器初始化优化:构建位图时,用
MOVEQ #0,D0替代CLR.W D0,指令字节数更少,执行效率更高。 - 栈空间节省:如果仅处理ASCII字符(0-127),可将位图压缩为16字节,减少栈空间占用。
- 注释清晰度:栈布局注释可补充说明“压入8个长字后,栈顶为位图基地址”,避免误解。
- 结束符风格统一:将
Finish中的CLR.B (A1)改为CLR.B (A1)+,与初始代码的结束符写入逻辑保持一致。
内容的提问来源于stack exchange,提问作者Pato
相关产品推荐
相关产品推荐

