//****************************************************************************// //************** 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.