title: A trap was executed with an illegal vector number in LC3
body: <p>I have been working on an assignment where I must convert a given number into different bases in the LC3. To do this, I need to use division, and while I have had an assignment where I did this same thing, the division algorithm for this one is different. </p>
  
  <p>I am expected to use extended division in this assignment. The basic algorithm is:</p>
  
  <p>Given a 32 bit number, store the first 16 bits into a memory address (called the high numerator), the last 16 bits (the low numerator) into another one, and the divisor, another 16 bit number, into another one. So, in the subroutine, the numbers would be fetched from memory into different registers and the algorithm would work as follows:</p>
  
  <ul>
  <li>Both the registers for high numerator and low numerator are shifted left once (so that if the high bit (left-most) of the low numerator is a 1, it is passed into the low bit of the high numerator, which since shifted should be a zero beforehand)</li>
  <li>The high numerator is compared with the divisor. If greater than or equal to it, subtract the divisor from it and set the low bit of the low numerator. If not, do nothing (eventually it would be greater as we keep shifting)</li>
  <li>Repeat the shift and check 16 times, setting the low numerator's low bit (right-most)</li>
  <li>At the end, the register that had the high numerator would hold the remainder of the division, and the register that had the low numerator would hold the quotient</li>
  </ul>
  
  <p>For simplicity, our instructor is letting us use 0 as the high numerator. So, in order to fulfill the algorithm, I came up with the following procedure:</p>
  
  <ul>
  <li>First I declare a .BLKW of 5, named ARGLIST, where all the arguments would be stored</li>
  <li>PRINT subroutine: I declare all the ST operations to keep the values of the working registers separate from what they will be used for in the subroutine, then I load the address of ARGLIST into a register, where I store the low numerator, and increment to store the high numerator (0) and divisor> Then, I load to the pointers for BUFFER and DIGITS to store results of converting to a specified base. Then the DIVIDE subroutine is called</li>
  <li>DIVIDE subroutine: I load the address of the ARGLIST to the register (R6 as per assignment instructions), load and increment to the necessary registers to have the values ready, perform a loop 16 times where numerators are shifted (and masking is done with x0080 to get the low numerator's high bit), subtract whenever DVR is less than or equal to the high numerator and repeat. Then the quotient and remainder are stored where R6 pointed (incrementing to get to the next one of course) and return</li>
  <li>So back in PRINT: I load into R2 and R3 (kept the same to attempt to reuse as much code from assignment 2 as possible) from the values that R7 is pointing, as it also points to ARGLIST which should now be populated, then the subroutine continues just like in assignment 2</li>
  <li>So when the whole storing into the buffer has happened, I point back to the beginning of ARGLIST to "update" the low numerator and point to the quotient to be ready for the next iteration (the next division)</li>
  </ul>
  
  <p>Below is the full code I have so far:</p>
  
  <pre><code>    .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&gt; "  ;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
  </code></pre>
  
  <p>I think the algorithm should be working, but as I run it on the LC3, I get the following error:</p>
  
  <pre><code>A trap was executed with an illegal vector number
  </code></pre>
  
  <p>And the processor is halted. For some reason, I noticed that when I checked my code in the LC3 it gets erased right after this line:</p>
  
  <p><code>ADD    R0, R2, #0</code></p>
  
  <p>Which would be right before branching to call the DIVIDE subroutine again. </p>
  
  <p>Why would this be happening? As far as I am able to tell, I have been saving and restoring the registers properly (last time I had a similar issue to this, and someone pointed out I was saving to the same .BLKW which caused an error), but the error persists. Please let me know if anyone has any idea of what could be malfunctioning, or if there's any more information you need. Thank you for any help in advance</p>