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

汇编炸弹人游戏中lda b,x指令与调试器结果不符问题排查

炸弹人汇编游戏中lda b,x指令异常问题排查

问题描述

我正在用汇编语言开发一款炸弹人风格的游戏,地图由*、空格和b组成。使用player1和player2两个字节型变量存储玩家当前位置(最大值为250)。输入有效指令时,对应移动函数会将玩家位置加载到寄存器b,根据移动方向增减数值,并在当前位置留下痕迹(玩家1为.,玩家2为,),但该功能无法正常工作。

调用移动验证逻辑时,寄存器x存储地图起始地址,寄存器b存储玩家位置,但lda b,x指令有时会返回地图文本中不存在的ASCII码。奇怪的是,手动计算寄存器b与x的地址和,并用调试器查看该内存地址时,显示的却是正确字符。

核心代码

.area PROG (ABS)

    keyboard     .equ 0xFF02
    screen    .equ 0xFF00

    b1:         .byte 57       
    b2:         .byte 70
    b3:         .byte 141
    b4:         .byte 155
    b5:         .byte 216
    m:          .byte 19
    player1:    .byte 96  
    player2:    .byte 80


    statep1:   .byte 1    ;0-exploted, 1-playing, 2-goal
    statep2:   .byte 1
    turn:      .byte 0    ;0-P1, 1-P2
    statemap: .byte 0    ;0-no_bombs, 1-w_bombs


                .org 0x100
                .globl begin

    menu:       .ascii "\n\n\n\n\n----------------------------------------------"
                .ascii "\n-            Bomberman                  -"
                .ascii "\n----------------------------------------------"
                .ascii "\nModo de juego: player 1- W,A,S,D             "
                .ascii "\n               player 2- I,K,J,L             "
                .ascii "\n                                              "
                .ascii "\To exit the program press 'p' at any"
                .ascii "\nmoment.                                      "
                .ascii "\nTo show the hidden bombs press 'b' at        "
                .ascii "\any moment.                            "
                .ascii "\n----------------------------------------------"
                .asciz "\n to begin press 'b':"
            
    goal1:      .asciz "\n\33[31mplayer 1\33[37m: goal!"
    goal2:      .asciz "\n\33[34mplayer 2\33[37m: goal!"
    playing1:   .asciz "\n\33[31mplayer 1\33[37m: playing..."
    playing2:   .asciz "\n\33[34mplayer 2\33[37m: playing..."   
    exploted1: .asciz "\n\33[31mplayer 1\33[37m: exploted"
    exploted2: .asciz "\n\33[34mplayer 2\33[37m: exploted!"

            
            
    t1:         .asciz "\nturn \33[31mplayer 1\33[37m: (W,A,S,D...b...p): "
    t2:         .asciz "\nturn \33[34mplayer 2\33[37m: (I,J,K,L...b...p): "

        
            
    map :      .ascii "\n******************M*****"
                .ascii "\n*                      *"
                .ascii "\n*     b            b   *"
                .ascii "\n*                      *"
                .ascii "\n*                      *"
                .ascii "\n*              b       *"
                .ascii "\n*   b                  *"
                .ascii "\n*                      *"
                .ascii "\n*              b       *"
                .asciz "\n************************"
            
    wins1:      .asciz "\nwins PLAYER 1!"
    wins2:      .asciz "\nwins PLAYER 2!"


    begin:
        ldu 0xf000
        lbsr read_menu  

    program:
            clra
            clrb
            lbsr siguiente_turn
            lbsr validate_input
            lbsr pmap
            
            
    finish: clra
            sta 0xFF01
            
    read_menu:
        ldx #menu
        lbsr loop
        lda keyboard
        cmpa #'b
        lbeq begin_program
        cmpa #'p
        lbeq finish1  
        bra begin   
    begin_program:
        clra
        lda #'0    
        sta statemap 
        lbsr pmap
        clra
        rts
    finish1:
        clra
        sta 0xFF01
    
    exit1:
        clra
        bra program
    pmap:   
        clra    
        clrb    
        ldx #map
        lda statemap
        cmpa #'0
        beq no_bombs
        cmpa #'1
        beq w_bombs
    w_bombs:
        lda ,x+
        beq exit1
        cmpb player1
        beq is_1
        cmpb player2
        beq is_2
        sta screen
        incb
        bra w_bombs
    no_bombs:
        lda ,x+
        beq exit1
        cmpb player1
        beq is_1
        cmpb player2
        beq is_2
        cmpa #'b
        beq is_b
        sta screen
        incb
        bra no_bombs
    is_1:
        lda #'1
        sta screen
        incb
        clra
        lda statemap
        cmpa #'0
        beq no_bombs
        cmpa #'1
        beq w_bombs
    is_2:
        lda #'2
        sta screen
        incb
        clra
        lda statemap
        cmpa #'0
        beq no_bombs
        cmpa #'1
        beq w_bombs 
    is_b:
        lda #' 
        sta screen
        incb
        bra no_bombs

    siguiente_turn:  
            clra
            lda turn
            cmpa #'0
        lbeq p1
            cmpa #'1
        lbeq p2
        
    p1:     
        lbsr imprimir_state
            ldx #t1
            lbsr loop
            rts

    p2:     
        lbsr imprimir_state 
        ldx #t2
            lbsr loop
            rts    
    imprimir_state:
        lbsr pstate1
        lbsr pstate2
        rts
    pstate1:
        clrb
            ldb statep1
            cmpb #0
        lbeq e1
            cmpb #1
        lbeq j1
            cmpb #2
        lbeq m1
            clrb
    pstate2:      
            ldb statep2
            cmpb #0
        lbeq e2
            cmpb #1
        lbeq j2
            cmpb #2
        lbeq m2
            clrb
            
    e1:     ldx #exploted1
            lbsr loop
            rts
    e2:     ldx #exploted2
            lbsr loop
            rts
    j1:     ldx #playing1
            lbsr loop
            rts
    j2:     ldx #playing2
            lbsr loop
            rts
    m1:     ldx #goal1
            lbsr loop
            rts
    m2:     ldx #goal2
            lbsr loop
            rts                  
    validate_input:
        lda keyboard
        ldb turn   
        ldx #map       
        cmpb #'0
        lbeq validate_input_p1 
        cmpb #'1
        lbeq validate_input_p2 
        clrb
    validate_input_p1:
        cmpa #'w
        lbeq move_up_p1 
        cmpa #'a
        lbeq move_left_p1
        cmpa #'s
        lbeq move_down_p1
        cmpa #'d
        lbeq move_right_p1
        cmpa #'b
        lbeq changeb       
        cmpa #'p
        lbeq finish2        
        lbsr program
        rts
    validate_input_p2:
        cmpa #'i
        lbeq move_up_p2
        cmpa #'j
        lbeq move_left_p2
        cmpa #'k
        lbeq move_down_p2
        cmpa #'l
        lbeq move_right_p2
        cmpa #'b
        lbeq changeb
        cmpa #'p
        lbeq finish2        
        lbsr program
        rts
    changeb:
        clra
        lda statemap
        cmpa #'0
        lbeq change1
        cmpa #'1
        lbeq change0
    change1:
        clra
        ldb #'1
        stb statemap
        lbsr pmap
        clrb
        rts
    change0:
        clra
        ldb #'0
        stb statemap
        lbsr pmap
        clrb
        rts
    exit_validate1:
        clra        
        lda #'1
        sta turn
        clra
        rts
    exit_validate2:
        clra
        lda #'0
        sta turn
        clra
        rts

    finish2:
        clra
        sta 0xFF01


    move_up_p1:
        ldb player1
        lda #'.
        sta b,x
        ldb player1
        subb #25
        lbsr validate_pos
        stb player1
        lbsr exit_validate1
        rts
    move_left_p1:
        lda #'.
        sta b,x
        ldb player1
        decb
        lbsr validate_pos
        stb player1
        lbsr exit_validate1
        rts
    move_right_p1:
        lda #'.
        sta b,x
        ldb player1
        incb
        lbsr validate_pos
        stb player1
        jsr exit_validate1
        rts
    move_down_p1:
        lda #'.
        sta b,x 
        ldb player1
        addb #25
        lbsr validate_pos
        stb player1
        lbsr exit_validate1
        rts
    move_right_p2:
        lda #',
        sta b,x
        ldb player2
        incb
        lbsr validate_pos
        stb player2
        lbsr exit_validate2
        rts
    move_left_p2:
        lda #',
        sta b,x
        ldb player2
        decb
        lbsr validate_pos
        stb player2
        lbsr exit_validate2
        rts
    move_up_p2:
        lda #',
        sta b,x 
        ldb player2
        subb #25
        lbsr validate_pos
        stb player2
        lbsr exit_validate2
        rts
    move_down_p2:
        lda #',
        sta b,x
        ldb player2
        addb #25
        lbsr validate_pos
        stb player2

        lbsr exit_validate2
        rts
    validate_pos:
        lda b,x
        cmpb #225   
        lbhs program
        cmpb #25 
        lbls program
        cmpa #'* 
        lbeq program
        cmpa #'1
        lbeq program
        cmpa #'2
        lbeq program
        cmpa #'M
        lbeq state_goal
        cmpa #'b
        lbeq state_exploted

        rts
    state_exploted:
        ldb #0
        lda turn
        cmpa #1
        lbeq goal_2
        stb statep1
        lbra exit_validate1
    exploted_2:
        sta statep2
        lbra exit_validate2
    state_goal:
        ldb #2 
        lda turn
        cmpa #1
        lbeq goal_2
        stb statep1
        lbra exit_validate1
    goal_2:
        sta statep2
        lbra exit_validate2

    loop:  
        lda ,x+
        lbeq exit
        sta screen
        bra loop
    exit:
            rts

            .org 0xFFFE     ;RESET
            .word begin  

问题原因分析

  • 寄存器B的赋值顺序错误
    部分移动函数(如move_left_p1、move_right_p2等)中,执行sta b,x写入玩家痕迹时,B寄存器还未被加载为当前玩家位置,此时B的值是上一次操作残留的垃圾值,导致写入错误内存地址,同时可能干扰后续验证逻辑的寄存器状态。正确顺序应先加载玩家位置到B,再执行写入操作。

  • 变址寻址的符号扩展问题
    如果使用的是Motorola 6809架构,lda b,x属于8位变址寻址,会将B寄存器的值作为有符号数进行16位扩展。当玩家位置(B的值)大于127时,符号扩展后会变成负数,导致实际计算的地址为X + 0xFFxx,和手动计算的无符号地址X + B完全不符,从而读取到地图外的内存数据。

  • 验证逻辑顺序颠倒
    validate_pos中先执行lda b,x读取地图内容,再检查B的值是否越界(cmpb #225、cmpb #25)。若B的值已超出地图有效范围,lda b,x会访问地图外的内存,返回非地图内的字符。应先校验位置合法性,再执行读取操作。

  • 地图长度与位置计算的匹配问题
    上下移动时按加减25计算行偏移,需确保地图每行恰好25个字符(包括换行符)。另外,.asciz会在地图末尾添加一个0字节,需确认玩家位置的最大值250是否在地图的有效字节范围内,避免访问到末尾的0或地图外区域。

内容的提问来源于stack exchange,提问作者Gonzalo Martín

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 15:35:56