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

机器码行为模拟器lw指令输出异常问题求助

机器码模拟器LW指令加载失败排查

模拟器说明

我用C语言实现了一款机器码行为模拟器,可接收机器码输入并展示每个执行状态下的内存与寄存器信息。使用教授提供的汇编器将汇编代码转换为机器码,模拟器会将输入的整数当作32位二进制指令处理。

正常测试案例

测试以下汇编代码时,模拟器运行完全正常:

lw      0   1   five    load reg1 with 5 (uses symbolic address)
        lw      1   2   3       load reg2 with -1 (uses numeric address)
start   add     1   2   1       decrement reg1
        beq     0   1   2       goto end of program when reg1==0
        beq     0   0   start   go back to the beginning of the loop
        noop    
done    halt                    end of program
five    .fill   5       
neg1    .fill   -1      
stAddr  .fill                   start will contain the address of start (2)

对应的输出结果:

total of 17 instructions executed
final state of machine:

@@@
state:
        pc 8
        memory:
                mem[ 0 ] 8454151
                mem[ 1 ] 9043971
                mem[ 2 ] 655361
                mem[ 3 ] 16842754
                mem[ 4 ] 16842749
                mem[ 5 ] 29360128
                mem[ 6 ] 25165824
                mem[ 7 ] 5
                mem[ 8 ] -1
                mem[ 9 ] 2
        registers:
                reg[ 0 ] 0
                reg[ 1 ] 0
                reg[ 2 ] -1
                reg[ 3 ] 0
                reg[ 4 ] 0
                reg[ 5 ] 0
                reg[ 6 ] 0
                reg[ 7 ] 0
end state

异常测试案例

但测试一段加载两个字并相加的简单汇编代码时,第一条LW指令可正常工作,第二条LW指令无法正确加载目标值:

lw      0   1   five    load reg1 with 5
        lw      1   2   one     load reg2 with 1
start   add     0   1   2       adds reg1 with reg2
done    halt                    end of program
five    .fill   5       
one    .fill    1      
stAddr  .fill                   start will contain the address of start (2)

对应的输出结果:

@@@
state:
        pc 1
        memory:
                mem[ 0 ] 8454148
                mem[ 1 ] 9043973
                mem[ 2 ] 65538
                mem[ 3 ] 25165824
                mem[ 4 ] 5
                mem[ 5 ] 1
                mem[ 6 ] 2
        registers:
                reg[ 0 ] 0
                reg[ 1 ] 5
                reg[ 2 ] 0
                reg[ 3 ] 0
                reg[ 4 ] 0
                reg[ 5 ] 0
                reg[ 6 ] 0
                reg[ 7 ] 0
end state

@@@
state:
        pc 2
        memory:
                mem[ 0 ] 8454148
                mem[ 1 ] 9043973
                mem[ 2 ] 65538
                mem[ 3 ] 25165824
                mem[ 4 ] 5
                mem[ 5 ] 1
                mem[ 6 ] 2
        registers:
                reg[ 0 ] 0
                reg[ 1 ] 5
                reg[ 2 ] 0
                reg[ 3 ] 0
                reg[ 4 ] 0
                reg[ 5 ] 0
                reg[ 6 ] 0
                reg[ 7 ] 0
end state

核心simulate函数代码

已确认机器码本身无问题,以下是模拟器的核心simulate函数实现:

void simulate(stateType * state){
    int run = 0; 
    int count = 0;
    int opcode, arg0, arg1, arg2, offsetField;
    
    while (!run){
        printState(state);

        opcode = (state->mem[state->pc] & 29360128) >> 22;
        arg0 = (state->mem[state->pc] & 3670016) >> 19;
        arg1 = (state->mem[state->pc] & 458752) >> 16;
        arg2 = (state->mem[state->pc] & 7) >> 0;
        offsetField = convertNum(state->mem[state->pc] & 65535) >> 0;

        printf("%d\n",opcode);
        printf("%d\n",arg0);
        printf("%d\n",arg1);
        printf("%d\n",arg2);
        printf("%d\n",offsetField);
        
        switch(opcode) {
            case HALT:
                run = 1;
                ++state->pc;
            case ADD:
                state->reg[arg2] = state->reg[arg0] + state->reg[arg1];
                ++state->pc;
                break;
            case NAND:
                state->reg[arg2] = ~(state->reg[arg0] | state->reg[arg1]);
                ++state->pc;
                break;
            case LW:
                state->reg[arg1] = state->mem[state->reg[arg0] + offsetField];
                ++state->pc;
                break;
            case SW:
                state->mem[state->reg[arg0] + offsetField] = state->reg[arg1];
                ++state->pc;
                break;
            case BEQ:
                if (state->reg[arg0] == state->reg[arg1]){
                state->pc = state->pc + offsetField + 1;
                }
                else {
                    ++state->pc;
                }
                break;
            case JALR:
                state->reg[arg1] = state->pc + 1;
                state->pc  = state->reg[arg0];
                break;
            case NOOP:
                ++state->pc;
                break;
        }
    ++count;
    }
    
    
    printf("machine halted\n");
    printf("total of %d instructions executed\n", count);
    printf("final state of machine:\n");
    printState(state);
}

问题排查分析

1. Opcode提取掩码错误

32位指令的操作码(opcode)通常占据**最高6位(bit31bit26)**,但当前代码中使用的掩码`29360128`(十六进制`0x1C00000`)仅覆盖了bit22bit24,仅3位,导致提取的opcode值完全错误,进而引发switch分支匹配错误(比如第二条LW指令被识别为其他指令,跳过了正确的加载逻辑)。

正确的opcode提取代码应为:

opcode = (state->mem[state->pc] & 0xFC000000) >> 26;

2. HALT分支缺少break语句

在switch的HALT分支中,设置run=1并递增pc后未添加break,导致代码会继续执行后续的ADD分支逻辑,错误地修改寄存器值并再次递增pc,引发异常行为。需添加break语句:

case HALT:
    run = 1;
    ++state->pc;
    break; // 添加该语句终止switch分支

3. 指令字段提取逻辑验证

当前代码中arg0、arg1的掩码和移位位数也不符合常规32位指令格式(比如arg0应为bit25bit23,掩码`0x3800000`,右移23位;arg1应为bit22bit20,掩码0x700000,右移20位),需根据目标指令集的格式修正字段提取逻辑。以LW指令格式[opcode(6)][arg0(3)][arg1(3)][offset(16)]为例,正确的字段提取代码应为:

opcode = (state->mem[state->pc] & 0xFC000000) >> 26;
arg0 = (state->mem[state->pc] & 0x3800000) >> 23;
arg1 = (state->mem[state->pc] & 0x700000) >> 20;
offsetField = convertNum(state->mem[state->pc] & 0xFFFF);

内容的提问来源于stack exchange,提问作者Zachary Herman

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 05:15:55