在 LC3 中使用非法向量号执行了陷阱

A trap was executed with an illegal vector number in LC3

我一直在做一项作业,我必须将给定的数字转换为 LC3 中的不同基数。要做到这一点,我需要使用除法,虽然我有一个作业在做同样的事情,但这个除法算法是不同的。

我应该在这个作业中使用扩展除法。基本算法是:

给定一个 32 位数字,将前 16 位存储到内存地址(称为高分子),最后 16 位(低分子)存储到另一个地址,除数,另一个 16 位数字,存储到另一个。因此,在子例程中,数字将从内存中提取到不同的寄存器中,算法将按如下方式工作:

为简单起见,我们的讲师让我们使用 0 作为高分子。所以,为了实现算法,我想出了以下程序:

下面是我目前的完整代码:

    .ORIG   x3000
    LEA R0, MPROMPT
    TRAP    x22
LOOP
    JSR GETDEC      ;Input an unsigned (decimal) integer
    ADD R0, R0, #0  ;Exit if the input integer is 0
    BRZ EXIT

    JSR NEWLN       ;Move cursor to the start of a new line
    AND R1, R1, #0  ;R1 = 10 (output base 10 DECIMAL)
    ADD R1, R1, #10 
    JSR PRINT       ;Print the integer in decimal

    JSR NEWLN       ;Move cursor to the start of a new line
    AND R1, R1, #0  ;R1 = 2 (output base 2 BINARY)
    ADD R1, R1, #2
    JSR PRINT       ;Print the integer in binary

    JSR NEWLN       ;Move cursor to the start of a new line
    AND R1, R1, #0  ;R1 = 8 (output base 8 OCTAL)
    ADD R1, R1, #8
    JSR PRINT       ;Print the integer in octal

    JSR NEWLN       ;Move cursor to the start of a new line
    AND R1, R1, #0  ;R1 = 16 (output base 16 HEXADECIMAL)
    ADD R1, R1, #15
    ADD R1, R1, #1
    JSR PRINT       ;Print the integer in hexadecimal

    JSR NEWLN       ;Move cursor to the start of a new line

    BRNZP   LOOP
EXIT                ;Loop exit point
    TRAP    x25     ;HALT program execution
MPROMPT .STRINGZ "Enter a sequence of unsigned integer values\nEnter 0 To Quit\n"

;Subroutine NEWLN*************************************************************
;Advances the console cursor to the start of a new line
NEWLN   
    ST  R7, NEW7    ;Save working registers
    ST  R0, NEW0

    LD  R0, NL      ;Output a newline character
    TRAP    x21

    LD  R0, NEW0    ;Restore working registers
    LD  R7, NEW7
    RET         ;Return
;Data
NL  .FILL   x000A   ;Newline character
NEW0    .BLKW   1   ;Save area - R0
NEW7    .BLKW   1   ;Save area - R7

;Subroutine GETDEC************************************************************
;Inputs an unsigned integer typed at the console in decimal format
;The input value is returned in R0
GETDEC
    ;Save Values of ALL Registers that don't need to change
    ST  R1, GET1
    ST  R2, GET2
    ST  R3, GET3
    ST  R4, GET4
    ST  R5, GET5
    ST  R6, GET6
    ST  R7, GET7    ;Save R7 to be able to return to main

    AND R3, R3, #0  ;Prepare a value
    LEA R0, GPROMPT
    TRAP    x22
GETDKEY
    TRAP    x20     ;To input a keystroke   
    ADD R2, R0, #-10    ;Subtract new keystroke by 10 (new line, or enter)
    BRZ GFINIS      ;If R2 is 0 we just pressed enter, so we break out
    TRAP    x21     ;Echo keystroke     
    ADD R2, R0, #0  ;Get the number back
    AND R2, R2, #15 ;We mask to only get the first four bits
    ADD R3, R3, R3  ;1st addition: x + x = 2x
    ADD R4, R3, #0  ;Store the 2x
    ADD R3, R3, R3  ;2nd addition: 2x + 2x = 4x
    ADD R3, R3, R3  ;3rd addition: 4x + 4x = 8x
    ADD R3, R3, R4  ;4th addition: 8x + 2x = 10x
    ADD R3, R3, R2  ;10x + new number
    BRNZP   GETDKEY     ;Go back to get next number
GFINIS
    ADD R0, R3, #0  ;Put number into R0

    ;Restore the values of registers that don't need change
    LD  R1, GET1
    LD  R2, GET2
    LD  R3, GET3
    LD  R4, GET4
    LD  R5, GET5
    LD  R6, GET6
    LD  R7, GET7    ;Get back the value of R7
    RET
;Data
GPROMPT .STRINGZ "Enter an unsigned integer> "  ;Input Prompt
GET1    .BLKW   1
GET2    .BLKW   1
GET3    .BLKW   1
GET4    .BLKW   1
GET5    .BLKW   1
GET6    .BLKW   1
GET7    .BLKW   1

;Subroutine PRINT*************************************************************
;Displays an unsigned integer in any base up to 16, e.g. binary, octal, decimal
;Parameters - R0: the integer - R1: the base
PRINT
    ST  R0, PR0
    ST  R1, PR1
    ST  R2, PR2
    ST  R3, PR3
    ST  R4, PR4
    ST  R5, PR5
    ST  R6, PR6
    ST  R7, PR7 

    LEA R7, ARGLIST ;Point to ARGLIST to start populating the args
    STR R0, R7, #0  ;Put R0 to be the low numerator
    AND R0, R0, #0  ;R0 is not needed after this, so it is cleared

    ADD R7, R7, #1  ;Go down on pointer once to store next arg
    STR R0, R7, #0  ;Put R0, now x0000, to be the high numerator

    ADD R7, R7, #1
    STR R1, R7, #0  ;Store the base, R1, to be the DVR
    ADD R7, R7, #1  ;Have R7 point to Quotient

    LEA R6, BUFFER
    AND R5, R5, #0  ;To make sure R5 is cleared
    LEA R4, DIGITS  ;Prepare pointer to the digits  
SDIV
    JSR DIVIDE

    LDR R2, R7, #0  ;Since the addresses should now be ready, 
                ;R7 would point to quotient, passed to R2
    LDR R3, R7, #1  ;Pass remainder to R3

    ADD R3, R3, R4
    LDR R5, R3, #0
    ADD R6, R6, #-1 ;Decrement to get to the next one
    STR R5, R6, #0  ;Store number into buffer

    LEA R7, ARGLIST ;Go back to ARGLIST to store new numerator
    STR R2, R7, #0
    ADD R7, R7, #3  ;Point to quotient

    ADD R0, R2, #0  ;Pass quotient into R0
    BRP SDIV        ;If number is at least 1, then divide again

    ADD R0, R6, #0  ;If we got here, then we should have the converted number
    TRAP    x22     ;Last but not least we display

    LD  R0, PR0
    LD  R1, PR1
    LD  R2, PR2
    LD  R3, PR3
    LD  R4, PR4
    LD  R5, PR5
    LD  R6, PR6
    LD  R7, PR7
    RET
;Data
DIGITS  .STRINGZ "0123456789ABCDEF" ;Digits
        .BLKW   18          ;Output Buffer
BUFFER  .FILL   x0000           ;Null
PR0 .BLKW   1
PR1 .BLKW   1
PR2 .BLKW   1
PR3 .BLKW   1
PR4 .BLKW   1
PR5 .BLKW   1
PR6 .BLKW   1
PR7 .BLKW   1

;Subroutine DIVIDE************************************************************
;Extended division is done here
DIVIDE  
    ST  R1, DIV1
    ST  R2, DIV2
    ST  R3, DIV3
    ST  R4, DIV4
    ST  R5, DIV5
    ST  R6, DIV6
    ST  R7, DIV7

    LEA R6, ARGLIST ;Point straight to where arguments start

    LDR R5, R6, #0  ;Load NUMLOW into R5
    ADD R6, R6, #1  ;Go down one step in pointer

    LDR R4, R6, #0  ;Load NUMHIGH into R4
    ADD R6, R6, #1  ;Go down once more

    LDR R3, R6, #0  ;Load DVR into R3
    ADD R6, R6, #1  ;Go down yet once more to be ready when we 
                ;store results

    LD  R1, M8BIT   ;Make R1 be equal to x0080 to get last bit 
                ;from NUMLOW

    AND R2, R2, #0  ;Set R2 as counter to decrement with each
    ADD R2, R2, #10 ;iteration
    ADD R2, R2, #6

ITER    ADD R4, R4, R4  ;Shift NUMHIGH to the left once
    AND R7, R5, R1  ;Masking. If R5[7] == 1, then R7 == x0080               
    BRNZ    NOADD       ;(or positive)

    ADD R4, R4, #1  ;If this happens then R5[7] was set, so we're 
                ;adding the bit that would be lost if R5 
                ;shifts left

NOADD   ADD R5, R5, R5  ;Shift NUMLOW to the left once

    NOT R7, R3      ;Subtract NUMHIGH and DVR. If 0 or positive 
    ADD R7, R7, #1  ;then subtract and increment NUMLOW
    ADD R7, R4, R7
    BRN DECCNT      ;If negative then DVR is greater than NUMHIGH,
                ;go straight to decrement the loop count 
    ADD R4, R7, #0
    ADD R5, R5, #1

DECCNT  ADD R2, R2, #-1
    BRP ITER        ;If count is positive, go back to ITER

    STR R5, R6, #0  ;Store NUMLOW for the Quotient Address
    ADD R6, R6, #1  ;Increment to store in the next one
    STR R4, R6, #0  ;Store NUMHIGH for the Remainder Address

    LD  R1, DIV1
    LD  R2, DIV2
    LD  R3, DIV3
    LD  R4, DIV4
    LD  R5, DIV5
    LD  R6, DIV6
    LD  R7, DIV7

    RET         ;Return
;Data
ARGLIST .BLKW   5       ;Here we will put the LOWNUM, HIGHNUM,
                ;DVR, QUO, and REM
M8BIT   .FILL   x0080               
DIV1    .BLKW   1
DIV2    .BLKW   1
DIV3    .BLKW   1
DIV4    .BLKW   1
DIV5    .BLKW   1
DIV6    .BLKW   1
DIV7    .BLKW   1

    .END

我认为该算法应该有效,但是当我在 LC3 上 运行 它时,我收到以下错误:

A trap was executed with an illegal vector number

并且处理器停止。出于某种原因,我注意到当我在 LC3 中检查我的代码时,它在这一行之后立即被删除:

ADD R0, R2, #0

在分支之前再次调用 DIVIDE 子例程。

为什么会这样?据我所知,我一直在正确地保存和恢复寄存器(上次我遇到了与此类似的问题,有人指出我保存到同一个 .BLKW 导致了错误),但是错误坚持。如果有人知道可能出现故障的原因,或者您是否需要更多信息,请告诉我。提前感谢您的帮助

已解决。有两个主要错误:

1) 不需要戴口罩。如果有的话,掩码本身就是错误的,因为寄存器保存 16 位值。如果我想使用掩码,更合适的值应该是 x8000,但仍然不能使用,因为这实际上是 RTI 的操作码。我所要做的就是确保将 R5(具有低分子的寄存器)纳入分支计算。如果是negative,那么高位显然是1!

2) 这就是破坏程序的原因。请注意,在 PRINT 函数中,我使用的是 LEAR7。这意味着我让这个寄存器负责指向参数。但是在这之后的几行我称之为 JSR:

JSR DIVIDE

我没有意识到在内部发生这种跳转时,能够return正常程序执行所需的 PC 值存储在一个寄存器中。在哪里? R7。所以即使在 DIVIDE 的开头和结尾我有一个 ST 和一个 LD 来恢复 R7 的值,在 return 到 PRINT 它应该是下一条指令的 地址 ,而不是指向 ARGLIST 的指针。程序正确 运行 所需要做的就是添加一个简单的 LEA,添加 3 以指向商和余数,并将指针的操作修改得更远一点以存储更新的低位分子。总而言之,DIVIDE 调用之后的代码如下所示:

SDIV
    JSR DIVIDE

    LEA R7, ARGLIST
    ADD R7, R7, #3

    LDR R2, R7, #0  ;Since the addresses should now be ready, 
                    ;R7 would point to quotient, passed to R2
    LDR R3, R7, #1  ;Pass remainder to R3

    ADD R3, R3, R4
    LDR R5, R3, #0
    ADD R6, R6, #-1 ;Decrement to get to the next one
    STR R5, R6, #0  ;Store number into buffer

    LEA R7, ARGLIST ;Go back to ARGLIST to store new numerator
    STR R2, R7, #0

    ADD R0, R2, #0  ;Pass quotient into R0
    BRP SDIV        ;If number is at least 1, then divide again

    ADD R0, R6, #0  ;If we got here, then we should have the converted number
    TRAP    x22     ;Last but not least we display