If you find errors in the past exams or in this review guide, please email me at prl83@msstate.edu.
The following table examines the last sixteen Exam 2s, dating back to Summer 2018:
Some thoughts:
"Registers" are questions similar to the "Pointers in Assembly" and "Pointers in C" topics that appear alongside certain programming problems.
About 60-80% of the programming problems involve pointers. Since the questions are all about pointers too, that is a lot of pointers: 83.5% of Spring 24 was pointers!
Remember that 0x1008 + 0x0002 = 0x100A NOT 0x1010.
Here is the breakdown of the last 16 semesters of Exam 2 Programming Problems:
If you've mastered Lab 4, you can already do over 1/3 of the problems on Exam 2!
For the rest, go to part 3 of the PIC24 Assembly Primer. The "sub 32" and "32b/8b big sub" problems are also easy to pass with just a few basic facts about subroutines, so that puts you past the halfway mark. All the other questions involve pointers in some way. In the above table, the bolded questions also ask you about register contents. (To determine the register contents, use the cheatsheet from Pointers in C.)
This topic hasn't appeared on too many exams. But it's fairly straightforward, so we'll cover it before we confront the horror of pointers. There are three subtypes of Signed Representation questions.
From Spring 22: Assume that a variable is 8 bits. What is the 2’s complement representation of –14 in hex?
1. Write positive 14 in binary:
0000 1110
2. Change all the zeroes into ones and vice versa:
1111 0001
3. Add 1:
1111 0010
4. Convert to hex (I forgot this step, and the autograder accepted 0b11110010, but it's easy enough, so you might as well not take a chance on the real exam):
0xF2
These are basically free points. From Spring 2022: If i8_a = 0xC3, then is i8_a is a positive value or a negative value? Answer P or N, where P is positive and N is negative.
If it starts with 0-7, it's positive. If it starts with 8-F it's negative.
0xC3 starts with a "C" so it is negative.
N
These questions always deal with the addition of two 8-bit signed variables and ask about the C, Z, OV, and N flags. But we'll cover subtraction as well.
Carry - This was dealt with on Exam 1 Instruction Execution . To review, the Carry flag is set (1), when the addition "wraps around", and is cleared (0) when it does not wrap. (Subtraction is the opposite, 0 when it wraps, 1 when it doesn't.)
Zero - This is even simpler. If the two hex digits of the answer are zero, then the Zero flag is set. It doesn't matter if it overflows or carries. Just look at the two digits.
Overflow - Overflow is a little trickier, mostly because it's new. Basically, if you get the "wrong" answer with signed numbers (e.g. adding two positive numbers and getting a negative answer) then the Overflow flag is set. I wouldn't even try to puzzle it out - just add the following to your cheatsheet:
Addition Overflow
pos + pos = neg
neg + neg = pos
Subtraction Overflow
pos - neg = neg
neg - pos = pos
Negative
The Negative flag is set when the answer is negative. Easy.
From Spring 2022: Assume there are two 8-bit variables a and b, where a = 0xC3 and b = 0x3D. These values use 2’s complement to represent signed values. After calculating a + b, what is the value of the following flags? Answer 1 or 0.
0xC3 + 0x3D = 0x(1)00
The Carry flag is set because we wrap around. C = 1
The Zero flag is set because the two digits that we care about are 0. Z = 1
For the Overflow flag, we see that the first number is negative, and the second is positive. Therefore, we consult our cheatsheet and see that they cannot overflow. OV = 0
Negative flag is cleared because 00 is not negative. N = 0
"In one of the rare noncharlatanic books in finance, descriptively called What I Learned Losing a Million Dollars, the protagonist makes a big discovery. He remarks that a fellow named Joe Siegel, one of the most successful traders in a commodity called “green lumber,” actually thought it was lumber painted green (rather than freshly cut lumber, called green because it had not been dried). And he made it his profession to trade the stuff! Meanwhile the narrator was into grand intellectual theories and narratives of what caused the price of commodities to move, and went bust." - Nassim Nicholas Taleb, Antifragile: Things That Gain from Disorder
To do well in Micro, you do not have to know very much about pointers. This may seem to contradict the previous statement that 83.5% of Exam 2 is pointers, but it's the truth. You don't have to write C programs with pointers (maybe on a couple questions in the last chapter of the Zybooks, so 0.0037% of your grade). You don't have to write assembly code with pointers. All you really need to know about pointers is that "they are the address of some other thing." Of course, you need to be able to translate C code with pointers (according to the rules covered in Part 3 of the PIC24 Assembly Primer), and answer questions about what is in memory where, but virtually the same lines of C code and the same questions are on every exam. We will go over each type of question on this webpage, and even make a cheatsheet for you. All you have to do is practice a little (so you can interpret the cheatsheet easily in a testing situation).
This type of question is on every Exam 2, and has been worth twenty points since Fall 19. As you can see there are only a half-dozen different types of questions and they just repeat with slight changes every semester:
Each question has two parts. On the first, you give the register that the instruction changes, and what its new value is:
On the second, you give the memory address that changes and what its new value is:
If either no register or no memory address is affected by the instruction, you put an 'x' in both blanks. (Why both blanks? Obviously you can't have a register/memory address called 'x' that contains a new value, or a register/memory address that contains x.)
The stack is the last topic taught in the ebook, but the easiest type of these questions to solve, so we'll cover it first. Just like pointers, you don't have to know very much about the stack to answer these questions. W15 is the stack pointer, which means that it contains the memory address of the top (bottom?) of the stack i.e. where to push new stuff onto the stack and pop old stuff from.
Usually 2 out of 5 questions from the Pointers in Assembly section are stack-related, so you'll have 40% of the points already if you get them right. (Often a third question is a "fake stack" question, meaning it involves W15, but is otherwise not stack-related.)
Push - When you push a register/memory address onto the stack, that register does not change. The register that changes is W15. It increases by 2. The memory address that changes is whatever memory address was in W15 before it increased. (You might want to do part 2 of the question first to avoid making the common mistake of increasing W15, and then looking at the new address). The contents of the memory become whatever was in the register/memory address that got pushed.
From Spring 2024:
push W3
Register: W15 (any time you pop or push, the answer is W15)
Contains: 0x1006 (0x1004 + 2)
Memory Location: 0x1004 (because that was what W15 was at the beginning of the question)
Contains: 0x1003 (Because this was in W3. It doesn't matter if it's odd, and/or if it is not an address on the chart.)
Every push question thus far has been pushing a register, but I'll make one up with a memory address so you can see how similar it would be:
push 0x100A
Register: W15 (any time you pop or push, the answer is W15)
Contains: 0x1006 (0x1004 + 2)
Memory Location: 0x1004 (because that's what W15 was)
Contains: 0xCEAF (Because this was in 0x100A.)
Pop - The rules for pop are (mostly) different than for push - and a little trickier: When you pop a memory address from the stack, the register that changes is once again W15. It decreases by 2. The memory location that changes is the location in the pop. It changes to the data in the address in W15 after it decreases. Spring 2024:
pop 0x1008
Register: W15 (any time you pop or push, the answer is W15)
Contains: 0x1002 (0x1004 - 2)
Memory Location: 0x1008 (bc pop 0x1008)
Contains: 0x4321 (The stack pointer W15 is now 0x1002. The data in 0x1002 is 0x4321.)
There was only one question ever on Exam 2 about popping a register, in Summer 19 (but it could be on a final. The format of the question was a little different because two registers change, rather than a register and a memory address, so you were given the registers, and just had to figure out their contents:
pop W2
Register W15 contains: 0x1182 (0x1184 - 2)
Register W2 contains: 0xA467 (because that is the data at address 0x1182)
Let's look at this table from Fall 23 (which is almost identical to the Spring 24 table, and probably several others):
We will start with some imaginary questions that are too easy for Exam 2 and work up to a real one, in order to illustrate the principles of pointers:
mov W0, W1
Register: W1
Contains: 0x1000 (contents of W0)
Memory Location: x
Contains: x
Brackets mean "the address in", so this next question means "move (copy) the thing at the address in W0 to W1"
mov [W0], W1
Register: W1
Contains: 0x8765 (the thing at the address in W0 - aka 0x1000)
Memory Location: x
Contains: x
We can put brackets on the destination register instead:
mov W0, [W1]
Register: x (The destination [W1] is not a register - it is the address in W1, which is 0x1004)
Contains: x
Memory Location: 0x1004
Contains: 0x1000 (contents of W0)
We can even put brackets on both the source and destination registers:
mov [W0], [W1]
Register: x (The destination [W1] is not a register - it is the address in W1, which is 0x1004)
Contains: x
Memory Location: 0x1004 (the address in W1)
Contains: 0x8765 (the thing at the address in W0 - aka 0x1000)
We can also do math with the registers in several ways. The simplest is by adding or subtracting a number to the register inside the brackets. This doesn't affect the actual contents of the register, but it does change the source or destination address. Here is an example from the actual Fall 23 test:
mov W0, [W1 - 2]
Register: x (The destination [W1 -2] is not a register - it is the address in W1 (0x1004) minus 2, which is 0x1002)
Contains: x
Memory Location: 0x1002
Contains: 0x1000 (the thing at W0)
We can also add registers to registers and then use that address. Here is an example from Fall 21:
mov [W0 + W2], W1
Register: W1
Contains: 0x4567 (We first add W0 (0x1010) and W2 (0x0002) to get 0x1012, then move the contents of 0x1012 to W1)
Memory Location: x
Contains: x
A third thing we can do is pre- or post- increment or decrement the registers inside the brackets. Be careful, because this starts to gets tricky:
The register value actually changes
It changes by 1 for a mov.b or 2 for a regular mov.
For a pre-increment/decrement, we use the new address after it changed. For a post-increment/decrement, we use the old address before the change.
From Summer 19:
mov [W0], [++W1]
Register: W1
Contains: 0x1184 (it was 0x1182, this is a 2-byte move, so +2 = 0x1184)
Memory Location: 0x1184 (we increment before doing the move)
Contains: 0xF3E1 (W0 is 0x1186; [W0], aka the data at address 0x1186, is 0xF3E1)
Now we'll do one with minuses, in the source, and post. Fall 22:
mov [W0--], [W1]
Register: W0
Contains: 0x1006 (it was 0x1008, so -2 (no .b) = 0x1006)
Memory Location: 0x100A (this is the address in W1)
Contains: 0x13AD (W0 is 0x1008, we use that address before we decrement. The data at address 0x1008 is 0x13AD)
8-bit moves
The final challenge in this section is dealing with 8-bit moves (mov.b), which aren't that complicated, but do make it much easier to make a mistake. Remember:
Increments (++) and decrements (--) are only 1.
If the source is an odd address, we use the left two digits of whatever we're moving. If it's even we move the right two.
If the destination is an odd address, we replace its left two digits. If it's even we replace the right two.
Be careful, because if the source is even, and the destination is odd, you might take the lower two digits of one number and replace the upper two digits of another number with them, and vice versa, which feels unnatural.
Summer 19 again:
mov.b [W0 + 1], W1
Register: W1
Contains: 0x11F3 (W0 is 0x1186, W0+1 is 0x1187. We go there (to the left two digits of 0x1186) and find 0xF3. W1, the destination was 0x1182, but we replace its right two digits with 0xF3.)
Memory Location: x (we started with a "simple" example)
Contains: x
Now for the most horrible question I could find. It involves mov.b, addition of two registers, post-decrement, and two sets of brackets, all while pretending to be about the stack. From Fall 19:
mov.b [W15--], [W0 + W2]
Register: W15
Contains: 0x1015 (W15 was 0x1016, but we decrement by 1 because mov.b, so 0x1015)
Memory Location: 0x1012 (just add W0 (0x1010) + W2 (0x0002))
Contains: 0x73ED (W15 before the decrement is 0x1016, so we go to that (even) address and find 0x21ED. We take the right (bc even) two digits, 0xED, and move them to the destination. The destination, 0x1012, is also even, so the move affects its right two digits. It contained 0x7345, so now it is 0x73ED. Whew.)
At this point you hopefully understand the concepts of these questions. (If not, contact your TA or instructor.) However, you may find when you try solving a few that you make simple mistakes, and get the question wrong. A cheatsheet will help, but there is no substitute for practice.
For this section, however, I'd take a good cheatsheet over practice any day. I will even make the cheatsheet for you! (You should do a little practice to make sure you know how to use it. ) There are only fourteen C expressions that have ever been tested, and two only appeared once each, on Spring 19. You can just look the expression up on the cheatsheet and do the indicated Zorro method on the table to find the answer. Knowing what an &au32_d[1] or a *pu8_c actually are, and whether they are addresses of arrays or pointers to pointer arrays is completely irrelevant to these questions.
Here is every Pointer in C question that has ever appeared on an Exam 2:
You don't have to understand (or even look at) the above table, but you do have to be able to decipher your cheatsheet. Here are some notes:
Obviously it doesn't matter whether the letter in the variable is u8_a or u8_b or etc, so they are just called x
Integer vs unsigned doesn't matter either*, so on the above table and the cheatsheet they are all u for simplicity's sake. You just have to give an appropriately-sized value or address. (*Two questions on Spring 19 asked if the value was positive or negative)
N is the number of bits in the expression (8, 16, or 32). It sometimes matters, and sometimes does not.
c and k are numbers from the expression.
To use the cheatsheet, find the row containing the expression and the column with the number of bits (N). For example, for au8_d[3] + 1, we use the row auN_x[c] + k, and the column 8.
On the cheatsheet, 8value means the answer is 8 bits, so like 0x00. 16value is 0x0000. 32value is 0x00000000. All addresses are 16 bit (0x0000).
The cheatsheet is in order of most-tested expressions to least (color is unimportant).
Without further ado, here is the cheatsheet:
We'll now practice using it to solve each kind of problem from most-common to least. We'll begin with Spring 24, which contains nine of the twelve common types of expressions:
This is the most common type of expression, appearing 28 times out of 189 questions.
au8_d[3]
We look at the auN_x[c] row, and the 8 column, and find "8value shift 2c".
8value means the answer is in the form 0x00. If the expression were au8_d[0], the answer would be 0x24:
But we have to "shift 2c". c=3, so we go over (up in address, left/down on the memory map) 3x2 digits:
So the answer is 0xFF.
Let's do another one of these from the same exam, without pictures (which may be doing more harm than good).
au32_e[1]
We look this one up on the cheatsheet and find "32value shift 8c".
The 32-bit value across from au32_e is 0xEF12ABCD. This would be au32_e[0], so we've got to go 8x1 digits over to the next 32-bit value: 0x87930CBA
Here’s a copy of the table to make it easier to refer to :)
au8_d + 3
This one is pretty easy. The cheatsheet says "address + k". (Remember that addresses are always 16 bits.) The address of au8_d is 0x1006, and k =3, so the answer is 0x1009.
au16_f + 1
"address + 2k" The address of au16_f is 0x1012. k = 1. 0x1012 + 2*1 = 0x1014.
pu32_b + 1
"16value + 4k" - The value at pu32_b is 0x100A. Add 4*1 and we get 0x100E.
pu8_a + 1
"16value + k" - The value at pu8a is 0x1008, so the answer is 0x1009.
Congratulations, you've already mastered 1/3 of the questions of this section without learning anything about pointers!
*pu8_a
"8value @ value" - The value at pu8_a is 0x1008. So we go there and take the "8value" or 8-bit value we find, which is 0x34.
*pu16_c
"16 value @ value" - The value at pu16_c is 0x1012. So we go there and take the "16value" or 16-bit value we find, which is 0x1221.
au8_d
"address" - This is easy - the address at au8_d is 0x1006, which is the answer.
&pu32_b
"address" - Another easy one - the address at pu32_b is 0x1002. Remember that addresses are always 16 bits.
Going out of order so we can keep using the same table.
&au32_e[1]
"address + 4c" - The address at au32_e is 0x100A. Just add 4x1 to find the answer, 0x100E.
One of the most complicated kinds, but fortunately rare:
au8_d[3] + 1
"8value, shift 2c, add k" - The 8value is 0x24. We shift 3x2 > 0x10 > 0x34 > 0xFF. We add 1 and get 0x00.
Fall 23:
pu8_c
"16value" - The 16value at pu8_c is 0x1003.
pu8_c[1]
"8value @ value shift 2c" - The value at pu8_c is 0x1003. We go to that address, which contains 0x39 (upper byte of 0x1002) then shift 2 digits to get 0x28 (the lower byte at 0x1004).
&u8_a
"address" - Remember that u8_a is at the higher, odd address because it's on the left. So the answer is 0x1001.
These are easy, but unfortunately uncommon. They often appear first on the exam as kind of a warmup:
u8_a
"8value" - Remember that u8_a is at the higher, odd address because it's on the left. So the answer is the upper byte: 0x61.
We have to go back to Spring 19 for the last, unique expressions:
u8_b + u8_c
"add 8values" - We add 0x96 and 0x17. 6+7 = 13 = 0xD. 9+1 = 0xA. The answer, then is 0xAD.
pu8_d++
"16value + 1" - The value at pu8_d is 0x1029, so we add 1 and get 0x1030. NO! Don't make this common mistake! We get 0x102A.