Nand2tetris VMtranslator优化遇A=-5非法操作错误求助
问题定位与修复方案
错误根源分析
CPU模拟器抛出A = -5非法操作,本质是访问了负数内存地址。查看你的return逻辑:
@5 D=A @LCL A=M-D // 若LCL的值小于5,M-D会产生负数,导致A寄存器为-5 D=M @R14 M=D
出现该问题说明函数调用时的栈帧初始化不完整,LCL指向的地址没有足够的栈帧数据(至少需要5个位置保存返回地址、LCL、ARG、THIS、THAT)。
调用逻辑的核心修复
你的isCalled分支代码缺少栈帧保存和ARG/SP初始化的关键步骤,导致函数执行时LCL未正确指向完整栈帧头部:
- 补全
isCalled分支的栈帧保存逻辑:
原分支仅跳转到函数入口,未保存调用方寄存器状态,也未设置ARG和SP,需补充和else分支对齐的核心流程。 - 统一所有调用的栈帧初始化标准:
无论是否复用调用逻辑,都必须确保:- 返回地址压栈
- LCL、ARG、THIS、THAT依次压栈
- 设置ARG为
SP-nArgs-5 - 设置LCL为当前SP
- 跳转到函数入口
修改后的isCalled分支示例:
if(isCalled(operator, segment, offset)){ sprintf(output, "@%s$retC.%i\nD=A\n@R15\nM=D\n" "// 保存返回地址到栈\n" "@%s$retC.%i\nD=A\n@SP\nM=M+1\nA=M-1\nM=D\n" "// 保存调用方寄存器\n" "@LCL\nD=M\n@SP\nM=M+1\nA=M-1\nM=D\n" "@ARG\nD=M\n@SP\nM=M+1\nA=M-1\nM=D\n" "@THIS\nD=M\n@SP\nM=M+1\nA=M-1\nM=D\n" "@THAT\nD=M\n@SP\nM=M+1\nA=M-1\nM=D\n" "// 设置ARG和LCL\n" "@SP\nD=M\n@5\nD=D-A\n@%li\nD=D-A\n@ARG\nM=D\n" "@SP\nD=M\n@LCL\nM=D\n" "@%s\n0;JMP\n" "(%s$retC.%i)\n", segment, count, segment, count, strtol(offset, NULL, 10), segment, segment, count); count++; }
Return逻辑的健壮性优化
在RESTORE代码开头添加LCL合法性检查(可选调试用),避免非法地址访问:
// RESTORE CODE (RESTORE) @LCL D=M @5 D=D-A @INVALID_LCL // 若LCL<5,跳转到错误处理标记 D;JLT // 原RESTORE逻辑继续 @5 D=A @LCL A=M-D D=M @R14 M=D ...
代码缩减的进阶方案
- 提取公共子程序:
将调用时的寄存器保存、return时的寄存器恢复逻辑,单独做成(SAVE_FRAME)和(RESTORE_FRAME)公共子程序,所有调用/return逻辑直接跳转复用,避免重复生成代码。 - 复用返回标签:
对同一函数名+参数数量的调用,共用同一个返回标签(比如用functionName+nArgs的哈希值替代全局count),减少冗余标签生成。
内容的提问来源于stack exchange,提问作者nickC
相关产品推荐
相关产品推荐

