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

Motorola 68000汇编:栈传参实现字符串过滤与长度计算

任务

开发Motorola 68000程序,实现以下功能:

  1. 生成字符串C,包含所有存在于字符串A但不存在于字符串B的字符。
  2. 计算新字符串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

技术问询

  1. 该代码能否进一步精简或优化?
  2. 是否正确理解了任务要求(跳过A中所有在B出现过的字符,生成C并返回其长度)?
  3. 是否值得添加额外功能,比如溢出检查、对齐时的快速字/长字操作,或将字符存在性检测拆分为独立子例程?

位图优化版本代码

已基于建议实现了位图优化版本代码,请确认该代码是否存在问题或仍有可改进之处:

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.12 20:24:50