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

Sjasm循环宏定义问题:DLOOP_TOP未替换实际值求助

实现类JavaScript风格的Z80 Sjasm宏循环语法

需求目标

希望通过Sjasm宏实现类似JavaScript的do-while/do-djnz循环语法,预期使用方式如下:

L_E52A:
        ld hl, $58A0
        ld c, $12

        _do
                inc hl
                ld b, $1E

                _do 
                        ld (hl), a
                        inc hl
                _djnz
                inc hl
                dec c
        _while nz

        ret

当前问题代码

以下是尝试编写的宏代码,但无法正常运行,核心问题是DLOOP_TOP未被替换为实际的循环标签地址:

DLOOP_3 = 0
DLOOP_2 = 0
DLOOP_TOP = 0

    MACRO DLOOP_PUSH arg
DLOOP_3 = DLOOP_2
DLOOP_2 = DLOOP_TOP
DLOOP_TOP = arg
    ENDM

    MACRO DLOOP_POP
DLOOP_TOP = DLOOP_2
DLOOP_2 = DLOOP_3
DLOOP_3 =  0
    ENDM

    MACRO _do
        DLOOP_PUSH $
DLOOP_TOP:
    ENDM

    MACRO _while flag
        jr flag, DLOOP_TOP
        DLOOP_POP
    ENDM

    MACRO _djnz
        djnz DLOOP_TOP
        DLOOP_POP
    ENDM

问题根源

  1. 符号与变量混淆:Sjasm中,跳转指令需要引用标签符号,而非变量存储的地址数值。你用DLOOP_TOP = arg存储的是地址值,但DLOOP_TOP:定义的是一个固定标签名,两者没有关联,导致跳转时无法正确解析。
  2. 全局变量冲突:嵌套循环时,全局变量DLOOP_TOP/DLOOP_2/DLOOP_3会被内层循环覆盖,外层循环的标签信息丢失,跳转逻辑混乱。

解决方案

利用唯一标签生成的思路,通过计数器为每个循环生成独立的标签名,避免嵌套冲突,同时让跳转指令能正确引用对应标签:

; 初始化循环计数器,用于生成唯一标签后缀
DLOOP_COUNT = 0

MACRO _do
    ; 递增计数器,确保每个循环有唯一标识
    DLOOP_COUNT = DLOOP_COUNT + 1
    ; 定义当前循环的顶部标签,格式为DLOOP_1、DLOOP_2...
    DLOOP_{DLOOP_COUNT}:
    ; 记录当前循环层级,供后续结束宏使用
    DLOOP_CURRENT = DLOOP_COUNT
ENDM

MACRO _while flag
    ; 跳转到当前层级的循环顶部
    jr flag, DLOOP_{DLOOP_CURRENT}
    ; 循环结束,递减计数器释放层级
    DLOOP_COUNT = DLOOP_COUNT - 1
ENDM

MACRO _djnz
    ; DJNZ跳转到当前层级的循环顶部
    djnz DLOOP_{DLOOP_CURRENT}
    ; 循环结束,递减计数器释放层级
    DLOOP_COUNT = DLOOP_COUNT - 1
ENDM

工作原理

  • 每次调用_do时,计数器DLOOP_COUNT递增,生成唯一的循环标签(如DLOOP_1、DLOOP_2),同时记录当前层级到DLOOP_CURRENT。
  • _while和_djnz通过DLOOP_CURRENT引用对应层级的标签,执行跳转逻辑。
  • 循环结束后递减计数器,确保嵌套循环的层级正确回溯。

展开效果示例

你的目标代码展开后会变成以下可正常汇编的Z80代码:

L_E52A:
        ld hl, $58A0
        ld c, $12

        ; 外层_do展开
        DLOOP_1:
        DLOOP_CURRENT = 1
                inc hl
                ld b, $1E

                ; 内层_do展开
                DLOOP_COUNT = 2
                DLOOP_2:
                DLOOP_CURRENT = 2
                        ld (hl), a
                        inc hl
                ; 内层_djnz展开
                djnz DLOOP_2
                DLOOP_COUNT = 1
                inc hl
                dec c
        ; 外层_while nz展开
        jr nz, DLOOP_1
        DLOOP_COUNT = 0

        ret

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 05:35:12