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

LC3四位加法程序求助:TRAP指令触发非法指令异常

问题排查与LC-3汇编代码优化指导

一、非法指令错误原因排查

你遇到的IllegalInstructionException(提示Undefined Instruction x0000),核心原因是标签缩进错误:

  • 在GET_NUMBER子程序中,LOOP标签没有顶格书写,LC-3汇编器会将缩进的标签识别为非法操作码,编译后对应机器码为x0000,执行到此处就会触发非法指令异常。
  • TRAP指令本身是合法的(x22=PUTS、x23=GETC、x21=OUT),错误并非TRAP指令本身,而是前面的非法标签导致的指令解析错误。

二、代码逻辑核心问题梳理

除了标签错误,代码还有多处逻辑缺陷:

  1. 数字输入处理逻辑混乱:
    • 读取字符后未正确将ASCII字符转换为数字(需减去x30即十进制48),也未实现num = num * 10 + digit的累加逻辑,无法正确获取输入的多位数。
    • 未将读取到的数字存入NUM1变量,后续LD R1, NUM1读取的是初始值0,完全丢失输入数据。
  2. 数值转ASCII逻辑错误:
    • CONVERT_SUM中用sum - 30的方式完全错误,正确的单数字转ASCII应为digit + x30;且多位数需要逐位拆分后逐个转换输出,不能直接对总和做一次转换。
  3. 寄存器使用违规:
    • LC-3子程序调用时,R0-R3是临时寄存器,子程序内部修改R1后没有保存现场,会破坏主程序的寄存器值;R4-R7是保存寄存器,使用前应先保存原值。

三、修正后的完整代码

.ORIG x3000

        ; 打印第一个输入提示
        LEA     R0, PROMPT1
        TRAP    x22
        JSR     GET_NUMBER     ; 获取第一个数字,结果存在R0
        ST      R0, NUM1       ; 存入NUM1变量

        ; 打印第二个输入提示
        LEA     R0, PROMPT2
        TRAP    x22
        JSR     GET_NUMBER     ; 获取第二个数字,结果存在R0
        ST      R0, NUM2       ; 存入NUM2变量

        ; 计算两数之和
        LD      R1, NUM1
        LD      R2, NUM2
        ADD     R3, R1, R2

        ; 打印结果提示并输出总和
        LEA     R0, RESULT
        TRAP    x22
        JSR     PRINT_NUMBER   ; 输出R3中的总和
        TRAP    x25            ; 终止程序(HALT等价TRAP x25)

; 子程序:GET_NUMBER
; 功能:读取用户输入的最多4位十进制数,结果存在R0
; 寄存器使用:R0(返回值)、R1(临时存储数字)、R2(读取的字符)、R3(计数器,限制4位)
GET_NUMBER
        ST      R1, SAVE_R1    ; 保存寄存器现场
        ST      R2, SAVE_R2
        ST      R3, SAVE_R3
        AND     R0, R0, #0     ; 初始化结果为0
        AND     R1, R1, #0
        AND     R3, R3, #0
        ADD     R3, R3, #4     ; 设置最大输入位数为4

INPUT_LOOP
        TRAP    x23            ; 读取一个字符(存在R0)
        ADD     R2, R0, #0     ; 复制字符到R2
        ADD     R0, R0, #-10   ; 判断是否为回车(ASCII 10)
        BRz     INPUT_EXIT     ; 回车则退出输入
        ADD     R0, R2, #-48   ; 字符转数字(ASCII '0'-'9'是48-57)
        BRn     INPUT_LOOP     ; 非数字字符重新读取
        BRp     CHECK_DIGIT    ; 是数字则继续
CHECK_DIGIT
        ADD     R0, R0, #-9
        BRp     INPUT_LOOP     ; 大于9的字符重新读取
        ADD     R0, R2, #-48   ; 重新获取数字值

        ; 执行 num = num * 10 + digit
        ADD     R1, R1, R1     ; num *=2
        ADD     R1, R1, R1     ; num *=4
        ADD     R1, R1, R1     ; num *=8(累计*8)
        ADD     R1, R1, R1     ; num *=2(累计*10)
        ADD     R1, R1, R0     ; 加上当前数字

        ADD     R3, R3, #-1    ; 位数计数器减1
        BRp     INPUT_LOOP     ; 未到4位继续读取

INPUT_EXIT
        ADD     R0, R1, #0     ; 将结果存入R0作为返回值
        LD      R1, SAVE_R1    ; 恢复寄存器现场
        LD      R2, SAVE_R2
        LD      R3, SAVE_R3
        RET

; 子程序:PRINT_NUMBER
; 功能:输出R3中的十进制数(最多5位,因4位相加最大为9999+9999=19998)
; 寄存器使用:R0(输出字符)、R1(除数10)、R2(余数)、R3(待输出数字)、R4(栈指针)、R5(计数器)
PRINT_NUMBER
        ST      R0, SAVE_R0
        ST      R1, SAVE_R1
        ST      R2, SAVE_R2
        ST      R4, SAVE_R4
        ST      R5, SAVE_R5
        AND     R5, R5, #0
        ADD     R5, R5, #5     ; 最多5位数字
        LD      R4, STACK_PTR  ; 初始化栈指针(栈从x30FF向下增长)

        ; 将数字逐位压入栈
STACK_LOOP
        AND     R2, R2, #0
        LD      R1, DEC10
DIVIDE_LOOP
        ADD     R2, R2, #1
        ADD     R3, R3, #-10
        BRp     DIVIDE_LOOP
        ADD     R3, R3, #10    ; 恢复被除数
        ADD     R2, R2, #-1    ; 得到余数
        ADD     R0, R2, #48    ; 余数转ASCII
        STR     R0, R4, #-1    ; 压入栈
        ADD     R4, R4, #-1
        ADD     R5, R5, #-1
        BRz     PRINT_LOOP     ; 所有位处理完开始输出
        ADD     R3, R3, #0     ; 判断数字是否为0
        BRnp    STACK_LOOP

        ; 从栈中弹出并输出
PRINT_LOOP
        ADD     R4, R4, #1
        LDR     R0, R4, #0
        TRAP    x21
        ADD     R5, R5, #-1
        BRp     PRINT_LOOP

        ; 输出换行
        LD      R0, NEWLINE
        TRAP    x21

        LD      R0, SAVE_R0    ; 恢复寄存器
        LD      R1, SAVE_R1
        LD      R2, SAVE_R2
        LD      R4, SAVE_R4
        LD      R5, SAVE_R5
        RET

; 数据段
NUM1    .BLKW   1
NUM2    .BLKW   1
PROMPT1 .STRINGZ "Please enter SRC1:\n"
PROMPT2 .STRINGZ "Please enter SRC2:\n"
RESULT  .STRINGZ "The sum is:\n"
DEC10   .FILL   #10
NEWLINE .FILL   #10
STACK_PTR .FILL x30FF
; 寄存器保存区
SAVE_R0 .BLKW 1
SAVE_R1 .BLKW 1
SAVE_R2 .BLKW 1
SAVE_R3 .BLKW 1
SAVE_R4 .BLKW 1
SAVE_R5 .BLKW 1

.END

四、关键优化点说明

  • 标签规范:所有标签均顶格书写,避免汇编器解析错误。
  • 输入处理:实现了数字合法性校验(仅接受0-9字符)、最多4位限制,正确完成num*10+digit的累加逻辑,且保存输入值到变量。
  • 输出处理:通过栈实现多位数的逆序输出,支持最多5位结果(满足4位相加的最大值19998),输出自动换行。
  • 寄存器管理:子程序调用时严格保存/恢复寄存器现场,避免破坏主程序的寄存器状态。
  • 代码可读性:添加了清晰的注释,拆分功能为独立子程序,便于维护和扩展。

内容的提问来源于stack exchange,提问作者No uh

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 02:07:08