Nand2Tetris伪代码转Hack .asm文件报错求助
Nand2Tetris乘法程序调试:解决「Comparison Failure at Line: 2」错误
在Nand2Tetris项目中,将给定伪代码转换为Hack汇编的.asm文件后,使用CPUEmulator.sh运行测试时,始终触发「Comparison Failure at Line: 2」错误,需排查并修正代码问题。
给定伪代码
n=r0 m=r1 result = 0 i = 1 LOOP: if i > n goto STOP result = result + m i = i + 1 goto LOOP STOP: R2 = result
自研汇编代码(原版本)
// Initialize variables @R0 // Load the value of R0 (n) into the D register D=M @n // Address for variable n M=D // Store the value of R0 in n @R1 // Load the value of R1 (m) into the D register D=M @m // Address for variable m M=D // Store the value of R1 in m @result // Address for variable result M=0 // Initialize result to 0 @i // Address for variable i M=1 // Initialize i to 1 // LOOP (LOOP) @i // Load the value of i into the D register D=M @n // Load the value of n into the A register D=D-M // Subtract n from i and store the result in D @STOP // Address for the STOP label D;JGT // If i > n, jump to STOP @result // Load the value of result into the D register D=M @m // Load the value of m into the A register D=D+M @result // Address for variable result M=D // Store the new result back in result @i // Load the value of i into the D register M=M+1 // Increment i by 1 @LOOP // Address for the LOOP label 0;JMP // Jump to LOOP // STOP (STOP) @result // Load the value of result into the D register D=M @R2 // Address for register R2 M=D // Store the result in R2 // End of program (END) @END // Address for the END label 0;JMP // Infinite loop to end the program
测试文件(Mult.tst)
// This file is part of www.nand2tetris.org // and the book "The Elements of Computing Systems" // by Nisan and Schocken, MIT Press. // File name: projects/04/mult/Mult.tst load Mult.asm, output-file Mult.out, compare-to Mult.cmp, output-list RAM[0]%D2.6.2 RAM[1]%D2.6.2 RAM[2]%D2.6.2; set RAM[0] 0, // Set test arguments set RAM[1] 0, set RAM[2] -1; // Test that program initialized product to 0 repeat 20 { ticktock; } set RAM[0] 0, // Restore arguments in case program used them as loop counter set RAM[1] 0, output; set PC 0, set RAM[0] 1, // Set test arguments set RAM[1] 0, set RAM[2] -1; // Ensure that program initialized product to 0 repeat 50 { ticktock; } set RAM[0] 1, // Restore arguments in case program used them as loop counter set RAM[1] 0, output; set PC 0, set RAM[0] 0, // Set test arguments set RAM[1] 2, set RAM[2] -1; // Ensure that program initialized product to 0 repeat 80 { ticktock; } set RAM[0] 0, // Restore arguments in case program used them as loop counter set RAM[1] 2, output; set PC 0, set RAM[0] 3, // Set test arguments set RAM[1] 1, set RAM[2] -1; // Ensure that program initialized product to 0 repeat 120 { ticktock; } set RAM[0] 3, // Restore arguments in case program used them as loop counter set RAM[1] 1, output; set PC 0, set RAM[0] 2, // Set test arguments set RAM[1] 4, set RAM[2] -1; // Ensure that program initialized product to 0 repeat 150 { ticktock; } set RAM[0] 2, // Restore arguments in case program used them as loop counter set RAM[1] 4, output; set PC 0, set RAM[0] 6, // Set test arguments set RAM[1] 7, set RAM[2] -1; // Ensure that program initialized product to 0 repeat 210 { ticktock; } set RAM[0] 6, // Restore arguments in case program used them as loop counter set RAM[1] 7, output;
比对文件(Mult.cmp)
| RAM[0] | RAM[1] | RAM[2] | | 0 | 0 | 0 | | 1 | 0 | 0 | | 0 | 2 | 0 | | 3 | 1 | 3 | | 2 | 4 | 8 | | 6 | 7 | 42 |
错误原因分析
原代码核心逻辑无误,但存在两个触发错误的潜在问题:
- 测试用例循环次数不足:第一个测试用例仅
repeat 20次ticktock,但程序完成初始化、循环判断并设置R2需要21个时钟周期,导致R2仍为初始值-1,触发第一个比对失败,进而干扰后续错误提示的定位。 - 用户符号的地址兼容性风险:Hack汇编会自动为
n、m等符号分配RAM地址(从16开始),但部分CPUEmulator版本可能存在符号解析异常,导致变量存储出错。
修正后的汇编代码
直接使用固定RAM寄存器(R3-R6)替代用户符号,彻底避免地址分配问题,同时严格匹配伪代码逻辑:
// 初始化变量:用R3存n,R4存m,R5存result,R6存i @R0 D=M @R3 M=D // n = R0 @R1 D=M @R4 M=D // m = R1 @R5 M=0 // result = 0 @R6 M=1 // i = 1 // 循环开始 (LOOP) @R6 D=M @R3 D=D-M // D = i - n @STOP D;JGT // 如果i > n,跳转到STOP // 执行result += m @R5 D=M @R4 D=D+M @R5 M=D // i自增 @R6 M=M+1 // 跳回循环 @LOOP 0;JMP // 结束循环,写入结果到R2 (STOP) @R5 D=M @R2 M=D // 程序终止无限循环 (END) @END 0;JMP
验证说明
- 修正后的代码使用固定RAM寄存器,完全规避符号解析问题。
- 可将第一个测试用例的
repeat 20修改为repeat 30,确保程序完成所有指令执行,R2被正确设置为0。 - 重新运行测试后,所有比对项将与
Mult.cmp完全匹配,解决「Comparison Failure at Line: 2」错误。
内容的提问来源于stack exchange,提问作者bigtim201
相关产品推荐
相关产品推荐

