//****************************************************************************//
//************** More Assembly Instructions- October 3rd, 2017 **************//
//**************************************************************************//
- 2 tests down, 2 A's thus far, but the hardest one hasn't been returned yet...
- Also, checking assembly code is stressful. I thought regular debugging was bad enough, but comparing actual machine code to physical hardware components to see if they match up is entirely new levels of blood-pressure-raising pedantic
- "Eh, tha there's nothin' compare wi' what us ol' time fellers faced. Yeh see, back in the ol' days, I fought off dem' electrons wi' nothin' but a sauterin' iron an' a copper pipe! Yessir!"
- Also, Prof. Leahy is sorry/not sorry for forgetting to give us a break last time
-----------------------------------------------------------------------
- Today, we'll be going over the CONTROL instructions for the LC-3 ISA. These are what let us do more than just execute instruction x3000, then x3001, then x3002, then...
- The first command is the CONDITIONAL BRANCH (BR)
- Format: [0000 | n | z | p | pcoffset9]
- If any of the N, Z, P bits are on, then it'll check it's respective register (N, Z, P) (e.g. if the "n" bit is 1, it'll check to see if there's a 1 stored in the "N" condition code register); if ANY of those registers contain a 1, then it'll change the PC address to the address pointed to by the "pcoffset9"
- In assembly, we write "BRN" for "check if N is 1", "BRP" for "check if P is 1", and "BRZ" for "check if Z is 1"
- To force it to ALWAYS branch, you can do "BRNZP", and make ALL of them 0
- As a shortcut for this, there's an UNCONDITIONAL BRANCH instruction if we just write "BR"; this'll always change the address (this is how WHILE loops work)
- If you leave ALL of the "n", "z", "p" fields as 0, then the instruction will never execute and it'll just get skipped over. It becomes a "no-op"; an instruction that doesn't do anything!
- Let's say we have the following Java code:
"int a[] = {5, 3, 6, 8, 3, 4};
int total = 0;
for (int i = 0; i < 6; i++) {
total = total + a[i];
}"
-...how would an assembly programmer think about this?
- All of the "a" variables and "total" would be saved in memory, since we want them to be persistent later on
- "i" is just temporary, though, so we'll keep it in R0 as the "loop counter"
- We'll then keep the current value of "total" in R1, and the current index of a we're looking at ("a[i]") in R2
- R3 would then be the address of the START of the array,
- Now, we do NOT have a function for checking equality...but we DO have a built-in function in the computer for checking if it's 0: the "Z" register!
- "Even in C or C++, it's slightly more performant to have your arrays count down to 0 and end there; not all compilers will do this optimization for you."
- So, we want our array counter to start at 6; let's start writing the assembly code
- The assembly program:
.ORIG x3000
AND R0, R0, 0 ;;clears R0; serves as our "i" counter
ADD R0, R0, 6 ;;this would NOT fit in the instruction if the # is >255, so we could instead declare a symbol "ArraySize .FILL 6", and replace this line with "LDR R0, ArraySize"
AND R1, R1, 0 ;;stores our "total"
LEA R3, A ;;stores the starting address in our array
LoopStart LDR R2, R3, 0 ;;gets the current array element; LoopStart points to it
ADD R1, R1, R2 ;;adds number to total and stores it in "total"
ADD R3, R3, 1 ;;moves our "current array element" up
ADD R0, R0, -1 ;;decrements our counter
BRP LoopStart ;;AS LONG AS the R0 value is still positive, go back up to our "LoopStart" address! Note that this command is LINKED with the one before it; it's testing the most recently changed register, so the counter HAS to be set right before we test for branching!
ST R1, Total;; stores our total value in the "Total" address
HALT
;;all our variables
Total .Fill 0 ;;where we will store our total value after it's calculated
A .FILL 5 ;;declares the array; if no symbol exists, assembly just puts the value in the current address
.FILL 3
.FILL 6
.FILL 8
.FILL 3
.FILL 4
- "EVERY good assembly programmer I've seen comments their code; not just with what the line LITERALLY does, but what algorithm it's supposed to be implementing, etc.; WHY the code exists, AND what it's doing"
- SIDE NOTE: You're currently at the level where you think the compiler always gets things right..."HAHAHAHAHAHAHAHAAAAAAAAAAAAAAAAAAAAAAAAA!!!!!"
- "More immediately relvant to you guys, though, if you've ever programmed in C (and if you haven't, you will in a few weeks), there's an option in the C compiler to print out the assembly your program generates. That could be a good learning tool."
- Now, back to control instructions:
- The JUMP (JMP) instruction is ALSO a control instruction, although we did go over it earlier
- Format: [1100 | 000 | BaseR | 000000]
- This is used because, if you were paying attention, the BR instruction only has 9 bits for the PC offset, so we can ONLY go to addresses that are within -256 or +255 of the current PC address!
- JMP, since it lets us use the value in a base register, has no such limitations
- So, we can use JMP both to do long-distance branching AND to implement GOTO statements
- Side note: do NOT use GOTO! If you're experienced enough to know when using a GOTO is good, you shouldn't be in this course.
- The TRAP instruction
- Basically, modern operating systems have systems to prevent user programs from accidentally (or maliciously) interfering with system functions
- The details of HOW they do this isn't important in this class, but it's mostly built to prevent accidents, rather than to keep out hard-core hackers
- The TRAP function gives us a way of communicating with the operating system
- Format: [1111 | 0000 | trapvect8]
- So, there's 256 different possible addresses we can access with the TRAP command
- Examples of common trapvects:
- x23: IN, stores input from the keyboard in R0
- This'll overwrite anything in there, so MAKE SURE the register doesn't have anything important
- x21: OUT, outputs the character stored in R0 to the monitor
- x25: HALT, halts the program
-...there are more of them
- Also, for convenience, they allow you to call certain TRAP functions using their own keywords without writing it explicitly as a TRAP: HALT, OUT, IN, etc., can be called on their own
- When the TRAP is executed, a few things happen in order:
1) Store the PC in R7 (R7 gets overwritten)
2) Zero-extend trapvect8 (put zeroes in front)
3) Put that into the MAR
4) Address now in the MDR
5) Put the MDR into the PC
- If your program doesn't have a HALT instruction, the computer will just keep running your code
- NOTE: Tuesday NEXT WEEK (not this week), we don't have class. So remember that.