AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / coding / 问题 / 79480818
Accepted
Pato
Pato
Asked: 2025-03-03 19:05:04 +0800 CST2025-03-03 19:05:04 +0800 CST 2025-03-03 19:05:04 +0800 CST

68000 汇编 - 字符串连接子程序

  • 772

我正在用汇编语言为 Motorola 68000 编写一个子程序,用于连接两个字符串。该子程序接收两个输入字符串StringA("Hello") 和StringB("World"),并将连接结果存储在StringC("HelloWorld") 中。

代码编译时没有错误,似乎可以工作,但我不确定输出是否正确或实现是否在逻辑上正确。

我写了以下代码:

    ORG $8000
     
StringA DC.B 'Hello',0    ; First string with null terminator
StringB DC.B 'World',0    ; Second string with null terminator
StringC DS.B 20           ; Buffer for the concatenated string (large enough?)

START: 
      lea.l StringA,a0    ; a0 -> "Hello"
      lea.l StringB,a1    ; a1 -> "World"
      lea.l StringC,a2    ; a2 -> Buffer for concatenation
      clr.b d0            

      jsr CopyA           ; Call first subroutine 
      
      SIMHALT             

CopyA: 
      move.b (a0)+,d0     ; Load character from StringA into d0
                          ; Check if it is the null terminator
      beq.s CopyB         ; If yes, start copying StringB
      move.b d0,(a2)+     ; Otherwise, copy character into StringC
      bra CopyA           
      
CopyB:
      move.b (a1)+,d0     ; Load character from StringB into d0
      move.b d0, (a2)+    ; Copy it into StringC
      bne CopyB           ; If the character is not null, continue copying
     
     rts                  ; Return from subroutine
    
     END START

问题:

  • 我的子程序实现正确吗?我使用了jsr和rts,但我想确认这是否是此上下文中的最佳方法。
  • 可以以任何方式进行优化吗?例如,我可以删除哪些冗余指令?
assembly
  • 2 2 个回答
  • 67 Views

2 个回答

  • Voted
  1. Best Answer
    Erik Eidt
    2025-03-04T06:23:36+08:002025-03-04T06:23:36+08:00

    68k 上的指令move特别强大。他们为该move指令提供了最少的操作码位,保留了 16 位指令字的许多位,以便它可以支持两个<ea>操作数。在 68k 中,一个<ea>操作数(有效地址)占用 6 位,因此其中两个意味着 12 位,只剩下 4 位用于其他内容。鉴于大小选择占用 2 位(字节/字/长),移动操作码本身剩下高达 2 位。

    由于设计人员将两个<ea>操作数压缩到该指令中,这意味着move可以将内存移动到内存,同时还可以设置条件代码!

    将其add与大多数其他 68k 指令进行比较:这些指令仅支持一个<ea>操作数和一个数据(或地址)寄存器或一个立即数作为另一个操作数。

    因此,字符串复制应使用类似move (a0)+, (a2)+¹的指令来完成。

    由于此指令设置了条件代码,因此您可以直接在其后跟一个条件分支(例如,在非零/非空时向后)。

    该算法必须稍微改变(如@SepRoland 的建议所示),因为使用这种移动形式,第一个字符串中的空字节将被复制到目标缓冲区中,因此a2在复制第二个字符串之前必须备份 1 个字节(但这次你确实希望复制的空字节来终止字符串 C,因此move (a1)+,(a2)+是完美的并且不需要任何调整)。


    ¹还有一条dbcc指令,可用于形成一个两条指令循环,该循环移动受计数和空终止符限制的内存 - 这些指令在 68010 上运行速度特别快,因为它具有dbcc通过一条指令向后分支的模式,无需提取指令即可运行。 (后来的 68k 具有更通用的指令缓存,因此可以在没有指令提取的情况下执行更大的循环。)

    • 3
  2. Sep Roland
    2025-03-04T06:01:01+08:002025-03-04T06:01:01+08:00

    我不确定输出是否正确。

    调试器的屏幕显示了什么?如果某处有“HelloWorld”,那么它似乎已经成功了,不是吗?

    StringC DS.B 20           ; Buffer for the concatenated string (large enough?)
    

    只需将两个长度相加,并允许一个额外的字节用于结束零即可。因此,这里 11 个字节就足够了。但我们不要吝啬,为通用缓冲区分配一个合适的大小。如果您使用 2 的幂数,那么它就是非常好的“汇编风格”。

    我的子程序实现正确吗?我使用了jsr和rts,但我想确认这是否是此上下文中的最佳方法。

    最好的?其实不是,因为你的子程序非常接近调用点(距离从 -128 到 +127),你可以使用bsr.s指令以更少的字节到达它。它在指令字中内置了相对位移,而不像jsr必须在指令字后添加它。rts其余的就像你写的一样。这并不快,但如果需要位置无关的代码(没有绝对内存引用),这是必需的。

    可以以任何方式进行优化吗?例如,我可以删除哪些冗余指令?

    • clr.b d0调用子程序之前的内容似乎是多余的。
    • 当然应该避免使用无条件bra CopyA。我建议您以类似于处理第二个字符串的方式处理第一个字符串,但在两次复制操作之间从 A2 中减去 1。这将删除零字节,只需用第二个字符串的第一个字符覆盖它即可(如果第二个字符串为空,则为零)。

        ORG $8000
         
    StringA DC.B 'Hello',0    ; First string with null terminator
    StringB DC.B 'World',0    ; Second string with null terminator
    StringC DS.B 256          ; Buffer for the concatenated string
    
    START: 
          lea.l  StringA, a0   ; a0 -> "Hello"
          lea.l  StringB, a1   ; a1 -> "World"
          lea.l  StringC, a2   ; a2 -> Buffer for concatenation        
    
          bsr.s  CopyA         ; Call first subroutine 
          
          SIMHALT             
    
    CopyA:
          move.b (a0)+, d0     ; Load character from StringA into d0
          move.b d0, (a2)+     ; Copy it into StringC
          bne.s  CopyA         ; If the character is not null, continue copying
          subq.l #1, a2        ; Remove the null
    CopyB:
          move.b (a1)+, d0     ; Load character from StringB into d0
          move.b d0, (a2)+     ; Copy it into StringC
          bne.s  CopyB         ; If the character is not null, continue copying
          rts                  ; Return from subroutine
        
    END START
    

    这是一个有趣的变化:

        ORG $8000
         
    StringA DC.B 'Hello',0    ; First string with null terminator
    StringB DC.B 'World',0    ; Second string with null terminator
    StringC DS.B 256          ; Buffer for the concatenated string
    
    START: 
          lea.l   StringA, a0   ; a0 -> "Hello"
          lea.l   StringB, a1   ; a1 -> "World"
          lea.l   StringC, a2   ; a2 -> Buffer for concatenation        
    
          bsr.s   CopyA         ; Call first subroutine 
          
          SIMHALT
               
    ; IN (a0,a1,a2)
    CopyA:
          bsr.s   Copy
          subq.l  #1, a2        ; Remove the null
          movea.l a1, a0
    Copy: move.b  (a0)+, d0     ; Load character from StringB into d0
          move.b  d0, (a2)+     ; Copy it into StringC
          bne.s   Copy          ; If the character is not null, continue copying
          rts                   ; Return from subroutine
        
    END START
    

    对于第一个字符串,本地Copy子程序会正常调用,而对于第二个字符串,执行会直接进入这些Copy指令。第一次执行会rts返回本地,但第二次执行会rts返回主程序。

    • 2

相关问题

  • x86 - 通过 RETF 从 32 位切换到 64 位

  • 小 ESP32-C3(基于 RISC-V)的浮点汇编指令上无法识别的操作码

  • 如何使用GNU Assembler (GAS)从相应的.s文件创建手写的ELF文件

  • 我无法读取gameboy的LY寄存器

  • 获取Assembly中的参数值

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    重新格式化数字,在固定位置插入分隔符

    • 6 个回答
  • Marko Smith

    为什么 C++20 概念会导致循环约束错误,而老式的 SFINAE 不会?

    • 2 个回答
  • Marko Smith

    VScode 自动卸载扩展的问题(Material 主题)

    • 2 个回答
  • Marko Smith

    Vue 3:创建时出错“预期标识符但发现‘导入’”[重复]

    • 1 个回答
  • Marko Smith

    具有指定基础类型但没有枚举器的“枚举类”的用途是什么?

    • 1 个回答
  • Marko Smith

    如何修复未手动导入的模块的 MODULE_NOT_FOUND 错误?

    • 6 个回答
  • Marko Smith

    `(表达式,左值) = 右值` 在 C 或 C++ 中是有效的赋值吗?为什么有些编译器会接受/拒绝它?

    • 3 个回答
  • Marko Smith

    在 C++ 中,一个不执行任何操作的空程序需要 204KB 的堆,但在 C 中则不需要

    • 1 个回答
  • Marko Smith

    PowerBI 目前与 BigQuery 不兼容:Simba 驱动程序与 Windows 更新有关

    • 2 个回答
  • Marko Smith

    AdMob:MobileAds.initialize() - 对于某些设备,“java.lang.Integer 无法转换为 java.lang.String”

    • 1 个回答
  • Martin Hope
    Fantastic Mr Fox msvc std::vector 实现中仅不接受可复制类型 2025-04-23 06:40:49 +0800 CST
  • Martin Hope
    Howard Hinnant 使用 chrono 查找下一个工作日 2025-04-21 08:30:25 +0800 CST
  • Martin Hope
    Fedor 构造函数的成员初始化程序可以包含另一个成员的初始化吗? 2025-04-15 01:01:44 +0800 CST
  • Martin Hope
    Petr Filipský 为什么 C++20 概念会导致循环约束错误,而老式的 SFINAE 不会? 2025-03-23 21:39:40 +0800 CST
  • Martin Hope
    Catskul C++20 是否进行了更改,允许从已知绑定数组“type(&)[N]”转换为未知绑定数组“type(&)[]”? 2025-03-04 06:57:53 +0800 CST
  • Martin Hope
    Stefan Pochmann 为什么 {2,3,10} 和 {x,3,10} (x=2) 的顺序不同? 2025-01-13 23:24:07 +0800 CST
  • Martin Hope
    Chad Feller 在 5.2 版中,bash 条件语句中的 [[ .. ]] 中的分号现在是可选的吗? 2024-10-21 05:50:33 +0800 CST
  • Martin Hope
    Wrench 为什么双破折号 (--) 会导致此 MariaDB 子句评估为 true? 2024-05-05 13:37:20 +0800 CST
  • Martin Hope
    Waket Zheng 为什么 `dict(id=1, **{'id': 2})` 有时会引发 `KeyError: 'id'` 而不是 TypeError? 2024-05-04 14:19:19 +0800 CST
  • Martin Hope
    user924 AdMob:MobileAds.initialize() - 对于某些设备,“java.lang.Integer 无法转换为 java.lang.String” 2024-03-20 03:12:31 +0800 CST

热门标签

python javascript c++ c# java typescript sql reactjs html

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve