LC-3 Assembly - Reference (LC3 Opcodes, Directives, Traps)

Ace your homework & exams now with Quizwiz!

Condition Code Registers (Summary)

CONDITION CODE REGISTERS (CCRs) There are 3 1-bit registers called CCRs: N (negative), Z (zero), P (positive) Each 1-bit CCR is set immediately after any of these operations are executed: ADD, AND, NOT, LDI, LDR, LEA Only one of the three CCRs will be set to true (1) , depending on the result of the above operations. (The other two CCRs will be set to zero) If the result of any of those operations is negative, the N bit is set to true, and Z and P are set to false. Z is set for zero values and P is set for positive values, etc. Commands which use these bits are: BRz, (Branch if result was zero) BRn, (Branch if result was negative) BRp, (Branch if result was positive) BRzp (Branch if result was ZERO OR POSITIVE) BRzn (Branch if result was ZERO OR NEGATIVE) BRnp (Branch if result was NOT ZERO) BRnzp, (Branch regardless of result, always) NOTE: the order of combined "nzp" conditions in the commands above are interchangeable. AND, they are treated as "OR" conditionals: zp means if "z or p" is true, then branch. SEE BR for more info.

Comments

Comments Any text following a semi-colon ";" in your pre-assembled code is considered a comment. Like .ORIG x3000 ; ->this is the comment<- Comments will be stripped out when your code is assembled. They never make it into the run-time execution of your program.

HALT (TRAP x25)

HALT (TRAP x25) Stops execution of the program and prints a message to the console. NOTE: HALT is different than .END (note the "dot" END). .END is an assembly directive and it simply indicates where the last line of your code exists in memory.

Hello World

Hello World A Simple "Hello World" program in LC-3 that prints infinitely. See code samples slide set for more samples. Copy paste the code below into a simulator like http://wchargin.github.io/lc3web/ ------------------- cut here --------------------------- .ORIG x3000 ; code start START ; just a label LEA R0, HI ; load the address of the "HI" PUTS ; print hello world BR START ; jump back to start HALT ; stops execution of your code HI .STRINGZ "Hello World!\n" ; your message .END ; code end

IN (TRAP x23)

IN (TRAP x23) Print a prompt to console and read a single character into R0. The Character is echoed.

JMP JMP R0

JMP ("JUMP REGISTER") JMP R0 Jump to the address stored in R0 JMP does NOT STORE a 'return address ' in R7, as do JSR and JSRR.

JSR JSR LABEL JSR #offset (11 bit)

JSR "jump to a subroutine" JSR LABEL JSR #offset Jump to LABEL or to the 11bit OFFSET specified. 11 bits provides a maximum range of -2014 to 1023 for the jump. Stores a 'return address' in R7 that can be used to return program flow to the next position after the JSRR call. Either RET or JMP R7 will return to the stored address. WARNING: TRAPS that are called AFTER a jump will overwrite R7. You must save R7 immediately when your subroutine starts, to ensure you can return safely to the calling location.

JSRR JSRR R0

JSRR ("JUMP TO SUBROUTINE REGISTER") JSRR R0 Jump to the address stored in R0. STORE a 'return address' in R7 that can be used to return program flow to the next position after the JSRR call. Either RET or JMP R7 will return to the stored address when ready. EXAMPLE LD R0, MY_SUB ; load the address of a subroutine JMP R0; jump to it ... MY_SUB ; do something here RET ; jump back WARNING: TRAPS that are called AFTER a jump will overwrite R7. You must save R7 immediately when your subroutine starts, to ensure you can return safely to the calling location.

LABEL LABEL .FILL #10

LABEL: START_HERE PROMPT_STRING A pre-assembly tag (does not have to be called "LABEL"!) that identifies a location in memory - usually where we have stored, or will store a number from a register. A label can be called anything (not just "LABEL") and note that it does NOT start with a "." (dot) as do assembly directives like ".ORIG" and ".FILL". You can declare a label one time, but of course you can reference it many times, such as: LD R0, MYLABEL ; <-referencing the label LD R1, MYLABEL ; <- referencing the label . . MYLABEL .FILL #10 ; <- definition of the label The above code loads the decimal VALUE of 10 (note the #10 indicates decimal, vs x for hex or b for binary) into the R0 and R1 registers. NOTE 1: In fact, the LABEL reference in the LD commands is 'coded' into the LD command-lines AFTER ASSEMBLY as a RELATIVE distance FROM the command in which it is referenced, TO the target memory location. So consider: LD R0, MYLABEL ; <- start HERE ; 1 away ; 2 away ; 3 away MYLABEL .FILL x0 ; ; 4 away The above code snippet reference MYLABEL is used in the LD command. But MYLABEL is 4 locations away from the LD command. This is a relatively short distance. In fact, to use a LABEL, most commends like LD only have 9bits (or less) of space in which to express this distance, after assembly. So, although we do not *think* about distances when we are working with LABELS, the actual final distance cannot be "too far" (more than 9bits). Specifically, 9bits allows for + or - a distance of: -256 <= distance <= 255 NOTE 2: A label can also be used to tag the location of a specific line in your program such as: LABEL1 LD R0, LABEL2 The above line of code exists at LABEL1, but loads R0 from the address at LABEL2. Labeling commands in this way is mostly useful when used in conjunction with BR (branching) commands to build control loops.

LC-3 Opcodes & Directives (Summary)

LC-3 Programs are written using a combination of ONLY the following opcodes, traps, and directives.... Opcodes: ----------------------------------- ADD - add 2 registers or 1 register and a 'small value' AND - logical "and" between 2 registers NOT - logical NOT between 2 registers LD - Load a value directly from an address or offset LDI - Load Indirect LDR - Load Relative LEA - Load Effective Address (use with .STRINGZ!) ST - Store direct STI - Store indirect STR - Store relative BR - Branch JMP - Jump to address in a register (no return) JSR - Jump to 11bit OFFSET (uses R7 to return when done) JSRR - Jump to address in a register (same as JMP, but return via R7) RET - Jump to the address in R7 (same as JMP R7) RTI - Jump to the address in R6 (the interrupt register) TRAP - jump to a built-in subroutine or function TRAPS - converted when assembled* -------------------------------------------- * these are DIRECTIVE equivalents for TRAPS (no '.' dot!) GETC - get a character from the input console and put it in R0 IN - get a character from the input console (like GETC, but echoed) OUT - print a character from the R0 register PUTS - print a string of characters based on the R0 address PUTSP - print a string of 'double characters" based on the R0 address HALT - halt execution of the program DIRECTIVES - converted when 'assembled" -------------------------------------------- .ORIG - where your code starts in memory .FILL - fill a single location in memory with a value .BLKW - fill a block of locations in memory with a value .STRINGZ - fill a block of locations in memory with a string .END - where your code ends in memory

LD LD R0, LABEL (load into R0)

LD ("LOAD") LD R0, LABEL LD R0, #102 Load register R0 with the CONTENTS at the address represented by LABEL, where LABEL is expressed as follows: LABEL .FILL x1234 In this case, R0 will be loaded with the value x1234. This value SITS AT an address (we do not really care which one) that has been tagged with LABEL. LABEL helps LD know where to go to get a value. Alternatively, an offset value can be specified instead of a label (#102 above). NOTE: LABEL must be a 'short distance away' from LD, since LABEL represents an offset distance to 'reach forward or backward' relative to the LD instruction, (to x1234 in this case). It is critical that that 'distance' not be too far. To be specific, the distance from the actual LD command to the LABEL cannot be more than a a signed 9bit value... specifically: -256 <= distance <= 255

LDR LDR R0, R1, #4 ("load VALUE into R0")

LDR ("LOAD RELATIVE") LDR R0, R1, #4 Load register R0 with the VALUE AT the address in (R1 + (decimal value 4)). So, Find the address by adding (R1+4) and get the value at that address and put it in R0. NOTE: The offset value (#4 decimal above) cannot be bigger than a 6bit signed value. Specifically -32 <= distance <= 31. So it is an even SHORTER jump than for the LD command which has 9bits available for the offset.

LEA LEA R0, LABEL ("load ADDRESS into R0")

LEA ("LOAD EFFECTIVE ADDRESS") LEA R0, LABEL LEA R0, #102 Load register R0 with the address of LABEL (not its contents!). Often used with .STRINGZ and PUTS to print a string. Alternatively, an offset value can be specified instead of a label (#102 above). Note1: Even if LABEL refers to a 'string of characters' in memory, we are still only loading the ADDRESS of LABEL into R0. Any subsequent PUTS (for example) will get the ADDRESS of the string from R0, and will print 'characters' starting at that address, until a null character is encountered. NOTE2: LABEL must be a 'short distance away' from LEA, since LABEL represents an offset distance to 'reach forward or backward' relative to the LEA instruction, (to x1234 in this case). It is critical that that 'distance' not be too far. To be specific, the distance from the actual LEA command to the LABEL cannot be more than a a signed 9bit value... specifically: -256 <= distance <= 255

Literal Numbers: Using #, b, and x decimal, binary, hex

Literal Numbers: Using #, b, and x LD R0, #-256 ; 9 bits maximum for LD! LD R0, xFF00 LD R0, b100000000 LD R0, #255 LD R0, x00FF LD R0, b011111111 #, b, and h are used to indicate the format of a numeric value that immediately follows the symbols #, b, or x, as shown above. # means decimal x means hexadecimal b means binary NOTE: Different commands support more/fewer bits of precision to represent numbers. Use caution when specifying values in commands with these symbols as you could easily exceed the available bits and your code many not execute as you expect. LD for example only supports 9 bits for a value, where a .FILL directive can utilize a full 16 bits. Numeric values can be used by the following commands and directives, but only with the maximum indicated precision (below): Limited to 9 bits of precision: (-256 to 255) LD LEA LDI ST STI BR Limited to 6 bits of precision:(-32 to 31) LDR STR Limited to 5 bits of precision:(-16 to 15) ADD AND .FILL - 16 bits .BLKW - 16 bits

OUT (TRAP x21)

OUT (TRAP x21) Writes the character in the R0 register (bits 0-7) to the console. Bits 8-15 of Register are ignored (characters only require the lower 8 bits).

PUTS (TRAP x22)

PUTS (TRAP x22) Write a string of characters to the console from R0 register. Start with the character at the ADDRESS contained in R0. Only write the first 8 bits from that location (top 8 of the 16 bits are ignored). Continue at the next memory location until/if it contains the character value 0x0000. (stop at x0000 - don't print it to console).

PUTSP (TRAP x24)

PUTSP (TRAP x24) PUTSP is a special type of "put" that writes 'two characters at a time' from from a single memory location. This is possible since registers have 16 bits, and characters only need 8 bits. Thus, memory locations CAN be loaded with two ascii codes - one in the lower 8 bits, and one in the upper 8 bits. PUTSP starts with two characters at address specified by R0 (The characters themselves are NOT IN R0 - they are at the ADDRESS specified by R0!). At the address, the first character is based on bits 0-7, and the second character is based on bits 8-15. Like PUTS, PUTSP stops when 0x0000 is encountered in memory.

RET "return" (no args)

RET "return" (no args) RET - Jump to the address that has been stored in R7. Same as "JMP R7"

RTI "return from interrupt" (no args)

RTI "Return from interrupt" RTI - Jump to the address in R6 (the interrupt register)

ST ST R0, LABEL ("store from R0")

ST ("STORE") ST R0, LABEL ST R0, #102 Store the value in R0 at the location specified by LABEL. Alternatively, an offset value can be specified instead of a label (#102 above). NOTE: LABEL and offset must fit in 9 bits (a "short jump"). That's a range of -256 <= offset <= 255.

STI STI R0, LABEL ("store from R0")

STI ("STORE INDIRECT")

STR STR R0, R1, #4 ("store from R0")

STR ("STORE RELATIVE") STR R0, R1, #4 Store the CONTENTS of register R0 at the LOCATION specified by (R1+decimal 4). So get the value of R1, add 4 to produce and address. THAT'S where you will store the contents of R0. NOTE: The offset value (#4 decimal above) cannot be bigger than a 6bit signed value. Specifically -32 <= distance <= 31. So it is an even SHORTER jump than for the LD command which has 9bits available for the offset.

Traps (Summary)

Traps Traps are a essentially a single opcode that can perform a number of predefined tasks. The standard 'tasks' listed below are all types of traps that are interpreted by the assembler as directives, and converted into the trap opcode. However, you can think of them as commands, assuming you use them properly. The hex shown below simply indicates the equivalent trap statement. GETC (x20) - Read a character from console into R0, not echoed. This will cause execution of your program to pause ('get trapped') until a character is entered. Same as TRAP x20. OUT (x21) - Write the character in R0 (bits 0-7) to the console Sam as TRAP x21. PUTS (x22) - Write a string of characters to console. Start with the character at the address contained in R0. Only write the first 8 bits from that location (top 8 of the 16 bits are ignored). Continue at the next memory location until 0x0000 is encountered (stop at x0000). IN (x23) - Print a prompt to console and read in a single character into R0. Character is echoed. This will cause execution of your program to pause until a character is input. PUTSP (x24) - Write a string of characters to the console, 2 characters per address location. Start with characters at address in R0. First character based on bits 0-7, and the second character based on bits 8-15.. Stop when 0x0000 is encountered. HALT (x25 ) - Stops execution of the program and prints a message to the console.

"GOTCHA's"

"GOTCHA's" Here are a few things you might have missed that are undermining your program execution: Did you put your .END directive BEFORE your final opcodes (like .FILL #123)? If so, you have prevented the assembler from seeing all of your code. Be sure .END is the last thing in your program. Did you forget to put a #, b, or x in front of a number, like "10" or "-4"? If so, the specific simulator you are using may be making assumptions about the format of that number (or just failing). Use #, b, or x in all cases where you specify a literal number to avoid problems. Did you use a literal offset (number) with a command that is TOO BIG for that specific command? (>5bits? >6bits? >9bits? > 11bits?). For example, LEA R0, R1, #256 will not work because LEA can only support offsets up to 9 bits (-256 to 255). See the "Literal Numbers" slide for more information on limits. Did you use a TRAP (IN, OUT, PUTS, etc) from inside a 'function' that you called using JSR? If so, that TRAP may have overwritten your R7 register - undermining your RET "return" call. Be sure to store R7 somewhere as soon as you get to your function, and return it to R7 before calling RET to return to the calling address. If all else fails, restart your LC-3 simulation tool from scratch. In the case of this one: http://wchargin.github.io/lc3web/ Just refresh the web page (but be sure you have saved and changes you made to your code that are not already in your text editor!

.END

.END (assembly directive - starts with a dot) Indicates the end of your program's code in memory. Does NOT stop execution of the program (see HALT for that). Should be placed AFTER declaration of any memory storage area you happen to be using via the LABEL, .FILL, .BLKW, or .STRINGZ directives.

.FILL .FILL x1234

.FILL (assembly directive - starts with a dot) .FILL x1234 LABEL .FILL x1234 The .FILL directive fills a 16bit memory location with a single value. The 2nd example above places the hex value 1234 in memory at the location tagged by LABEL. This value can be anything: an ascii character code, a numeric value, etc, as long as it can fit in 16 bit memory. NOTE: Fill values can be specified in hex, binary, or decimal, as indicated below: .FILL x1234 ; hex value 1234 (decimal 4660) .FILL #4660; decimal value 4660 .FILL b1001000110100; binary format (decimal 4660) To be avoid confusion, you should always indicate a format when specifying numbers

.STRINGZ .STRINGZ "Hello World!"

.STRINGZ (assembly directive - starts with a dot) .STRINGS "Hello World!" LABEL .STRINGS "Hello World!" Declares a group of characters in memory, and terminates that group with a special "null" character to indicate the end of the string. This means that it takes "N+1" memory locations to store your string, where your string has "N" characters. Often used with the LABEL directive so that registers can be easily loaded with the address of this string such as: LEA R0, LABEL PUTS In the above case, LEA 'loads" R0 with the ADDRESS of the 1st character of the string (NOT THE STRING ITSELF1). Thereafter, the PUTS directive can be used to print the string by starting a LABEL and printing each successive character in memory, until PUTS runs into the "NULL" (x0000) character. NOTE: You could do the EXACT same thing by using many individual .FILL directives (one for each character) to place each individual character's ascii code (in hex, decimal, or binary notation) into memory. AND by adding an extra "Null" character to terminate the string. But that would be a lot more typing! Here's what it would look like, roughly: LABEL .FILL x0048 ; this is hex for capital 'H' .FILL x0065 ; this is hex for lower case 'e' .FILL x006C; hex for 'l', etc. . ; skipping 'lo world' letters... . .FILL x0021 ; hex for '!' .FILL x000 ; NULL terminates the string!

ADD ADD R2, R1, R0 ADD R2, R1, #4

ADD ADD R2, R1, R0 ADD R2, R1, #4 Add the values in R1 and R0, and place the result in R2. Alternatively, you can specify a small incremental value that you want to add to R1, before storing in R2 (#4 above). NOTE: The offset value (#4 decimal above) cannot be bigger than a 5 BIT signed value. Specifically -16 <= value <= 15.

AND AND R0, R1, R2

AND ("LOGICAL AND") And the individual bits of R1 with R2 and store the final result in R0. 1 & 1 == 1; 1 & 0 == 0; 0 & 1 == 0; 0 & 0 == 0; So that: 111011101 and 00010000 = 00010000 Note that the second argument above acts as a "mask" that will always indicate if the 4th bit of the first operand was 0 or 1. If it was zero, the result is zero, else, the 4th bit must have been a 1.

Assembler Directives (Summary)

Assembler Directives ("pseudo ops") Are human-readable 'fake instructions' that get converted when you 'assemble' your LC-3 code. They give extra information to the assembler. They ALWAYS start with a "." (dot). They include: .ORIG .FILL .BLKW .STRINGZ .END They are converted into standard LC-3 commands and addresses when assembled, but you can think of them as 'valid commands' if used properly.

BR BR LABEL BR #102

BR ("BRANCH ALWAYS") BR LABEL BR #102 Jump to the location specified by the label. Ignore the CCRs (condition code registers) N, Z, or P. Alternatively, an offset value can be specified instead of a label (#102 above, means jump forward by #102 decimal locations in memory). NOTE: LABEL and offset must fit in 9 bits (a "short jump"). That's a range of -256 <= offset <= 255.

GETC (TRAP x20)

GETC (TRAP x20) Read a character from the console into R0 register. The character is not "echoed" which means you will not see your own typing, unless your program prints the character back out (see the OUT trap) Only R0 is affected. Only one character is read (so GETC is usually inside a loop). Has no arguments.

LDI: LDI R0, LABEL ("load ADDRESS into R0")

LDI: ("LOAD ADDRESS INDIRECT") LDI R0, LABEL Get the address at LABEL and then get the address at THAT address (this is the indirect part). FINALLY, get the value at the second address. Question: Is the second address a full 16bit address? (effectively a "long jump"?)

NOT NOT R0, R1

NOT: Take the value in R1 as binary, flip its 16 bits (0->1 and 1->0), and store that result in R0

.BLKW .BLKW #20

.BLKW (assembly directive - starts with a dot) .BLKW #20 .BLKW #20 #4 LABEL .BLKW #20 #4 Initialize successive locations in memory to a value. Note that #, x, or b can be used to indicate the size of the allocation in decimal, hex, or binary. If no argument is provided after #20 is specified, the initialization value will be zero (#0, or x0000). A second value can be provided after the #20 to indicate the initialization value for memory. In the above example, all 20 locations will be set to a value of 4. When used with a label as shown above, the label can be thought of as the start of an ARRAY of data. If each memory location is meant to represent one value that can be represented in 16 bits, then a #20-sized block represents an array of 20 elements, which LABEL indicating the address of the first element in the array. Note that .BLKW can also be used to effectively initialize a blank string, as might be done with the .STRINGZ directive. WARNING: Not clear what bit limits if any may be imposed for the first argument (#20, above). There may be a limit to the number of spaces that can be reserved, depending on the simulation tool being used.

.ORIG .ORIG x3000

.ORIG (assembly directive - starts with a dot) .ORIG x3000 Indicates the starting address where your program should be placed in memory. By convention, the address is usually expressed in hex as "x3000", but it can be larger. Valid ranges may depend on the specific LC-3 simulator you are using. When in doubt, use x3000. Only one .ORIG is allowed per program module.

5 Addressing Modes

5 Addressing Modes REGISTER MODE: Copy from register to register. No addresses! • R1 <- R1 + R2 • R1 <- NOT R2 Opcodes that use this mode: ADD, AND, NOT, LD, LDI, LDR, LEA, ST, STI, STR. JMP, RET, JSRR. ------------ IMMEDIATE MODE: Copy from register, but add an offset to the VALUE: • R1 <- R1 + #-2 ; subtract 2 (decimal) Opcodes: ADD, AND, LEA. -------- Base+Offset Mode: Load/Store from a memory location specified by a register+offset • R1 <- M[R2+4]; (R2+4) gives the address to load FROM • M[R2+4] <- R1 (R2+4) gives the address to store TO Opcodes: Data: LDR, STR, TRAP, RTI. -------- PC-RELATIVE MODE: Load/Store from a memory location relative to the current program counter, plus an offset • R1 <- M[PC+6]; (PC+6) gives address to load from • M[PC+6] <- R1; (PC+6) gives address to store TO Opcodes: LD, ST, BR, JSR. --------- INDIRECT MODE: • R1 <- M[M[R2+4]] • M[M[R2+4]] <- R1 Opcodes that use this mode: LDI, STI

BRn BRn LABEL BRn #102

BRn ("BRANCH IF NEGATIVE): BRn LABEL Jump to the Label only if the 1-bit Conditional code register N was set to true. This occurs only if the result of one of the following operations was NEGATIVE: ADD, AND, NOT, LDI, LDR, LEA So basically if you just did an operation from the above list and want to jump somewhere if the result stored in ANY register is NEGATIVE (regardless of which register!), "BRn LABEL" will jump to the LABEL, otherwise execution will continue on the next line as normal. NOTE: LABEL offset must fit in 9 bits (a "short jump")

BRnzp BRnzp LABEL BRnzp #102

BRnzp ("BRANCH ALWAYS"): BRnzp LABEL BRnzp #102 Jump to the LABEL specified regardless of Conditional Code Registers (CCRs). NOTE: LABEL offset must fit in 9 bits (a "short jump")

BRp BRp LABEL BRp #102

BRp ("BRANCH IF POSITIVE"): BRp LABEL BRp #102 Jump to the LABEL only if the 1-bit Conditional code register P was set to true. This occurs only if the result of one of the following operations was POSITIVE: ADD, AND, NOT, LDI, LDR, LEA So basically if you just did an operation from the above list and want to jump somewhere if the result stored in ANY register is POSITIVE (regardless of which register!), "BRp LABEL" will jump to the LABEL, otherwise execution will continue on the next line as normal." NOTE: LABEL offset must fit in 9 bits (a "short jump")

BRz BRz LABEL BRz #102

BRz ("Branch if zero") BRz LABEL BRz #102 Jump to the Label only if the 1-bit Conditional code register Z was set to true. THis occurs only if the result of one of the following operations was ZERO: ADD, AND, NOT, LDI, LDR, LEA So basically if you just did an operation from the above list and want to jump somewhere if the result stored in ANY register is ZERO (regardless of which register!), "BRz LABEL" will jump to the LABEL, otherwise execution will continue on the next line as normal. NOTE: LABEL offset must fit in 9 bits (a "short jump")


Related study sets

Cybersecurity Management I - Strategic - C727 UCertify Practice Test (A)

View Set

ap world history unit 2 practice test for Mr.Schabo. PLZ READ TIP IMPORTANT NOTE SHOWN

View Set

Chapter 20: Nursing Management of the Pregnancy at Risk: Selected Health Conditions and Vulnerable Populations

View Set

Microeconomics Chapter 11, Chapter 11 Quiz, Microeconomics Chapter 11

View Set