2023-12-09
The work is licensed under
a Creative
Commons Attribution-NonCommercial-ShareAlike 4.0 International
License.
This document describes how to answer questions in the final exam of CISP 310. Specifically, what is an explanation and how it is scored.
Some instructions or definitions are partially correct. In these cases, an answer is in the form of crossing out the part that is wrong, but keeping as much of the original instruction or definition as possible. The answer should also include an explanation.
Some instructions or definitions may be missing entirely. In these cases, an answer is in the form of an insertion of instructions or definitions. The answer should also include an explanation.
Some instructions or definitions should not be present, at all. In these cases, an answer is in the form of a strike-out of the instructions of definitions that should be removed. The answer should also include an explanation.
Some instructions or definitions are correct, but an explanation is requested. In these cases, an answer is in the form of an explanation of what each involved register contains, and the effect of the instruction.
An explanation should relate to C/C++ concepts. For example, the following explanation does not meet the requirement of relating to C/C++ concepts:
add c,d // c=c+d
However, assuming var1
is a local variable, and the
correct offset to var1
from where the stack pointer points
to is already loaded into register c
, then the following
explanation for this instruction meets the requirement:
add c,d // c == &var1
In this example, how register c
gets the offset to
var1
from where the stack pointer points should also be
explained in some prior instructions. See chained explanations for more
details.
In the cases of correction, insertion or deletion, the reason of the correction should be stated. Again, this explanation should relate to C/C++ concepts. In other words, describe what the code is supposed to do, and what the code would have done without the correction. For example, an insertion may look like the following:
\(<\)
ld a,(a) // a==var1, a==&var1 without this instruction
In this example, earlier instructions also need to be chain-commented to explain how reg
a
already has the address of var1
before this
inserted instruction.
Some answers involve the correction, deletion, insertion, or the explanation of instructions that involve the use of one or more registers. In these cases, it is necessary to explain how each involved register gets its value by commenting related earlier instructions.
In the following example, assume var1
is a global
variable in C/C++, and the label GLOBAL_var1
is defined to
bookmark the location of var1
.
ldi a,GLOBAL_var1
sub b,b
st (a),b // describe the effect of the instruction
In this example, the first task to use the opcodes table to look up
what is reg x
and reg y
. However, the
following answer will receive no point value because it does not relate
to concepts in the C/C++ code:
ldi a,GLOBAL_var1
sub b,b
st (a),b // describe the effect of the instruction answer: *a=b
The following answer receives partial credit (2/4) because it does
not fully explain how reg a
and reg b
get their values:
ldi a,GLOBAL_var1
sub b,b
st (a),b // describe the effect of the instruction answer: a==&var1, b==0, effect: var1=0
In order to receive full credit (4/4), the chain of instructions that
contribute to the values of reg a
and b
must
also be explained:
ldi a,GLOBAL_var1 // a==&var1
sub b,b // b==0
st (a),b // describe the effect of the instruction answer: var1=0
In the following example, assume var1
is a global
variable in C/C++, and the label GLOBAL_var1
is defined to
bookmark the location of var1
. Furthermore, assume the code
fragment is to push the address of var1
on the stack.
ldi a, GLOBAL_var1
ld a,(a)
dec d
st (a)
The correction is to remove the ld
instruction. However,
the following answer receives 1/4 of the credit because it has no
explanations:
ldi a, GLOBAL_var1
~ ld a,(a) // <-- DELETE
dec d
st (a)
The following answer receives partial credit (2/4) because it explain partially what happens with the deleted instruction, but not why it is incorrect.
ldi a, GLOBAL_var1
~ ld a,(a) // <-- DELETE, otherwise a==var1
dec d
st (a)
The following answer receives full credit (4/4) because it explains
what is in reg a
at the removed instruction, how reg
a
gets its value prior to the removed instruction,
and what is expected:
ldi a, GLOBAL_var1 // a==&var1
~ ld a,(a) // <-- DELETE, otherwise a==var1
dec d
st (a) // push &var1
Not every explanation is about registers. Some explanations may
relate to a control structure. For example, the lack of a unconditional
branch at the end of a while
loop to get back to the
beginning may require the following explanation:
\(<\)
jmpi f_while0_begin // otherwise there is no repetition
Essentially, the explanation describe what would have happened erroneously if the correction is not in place.
A general strategy is to add comments to track the code all the time, and not to wait until an answer is expected. This strategy can end up saving time because a register may not seem important until it is reference much later in the code. Instead of backtracking and trying to figure out and comment register when needed, the “always-on” commenting means a quick look at commented prior line can connect the reference of a register from the overwriting of the same register that may have occurred many lines before the reference.
While “always-comment” sounds like a major chore, some shorthand can be useful.
For example, if f_var1
is “the offset of
var1
from where the stack pointer points to”, then a
shorthand that makes sense is &f_var1-d
. For
example:
ldi b,f_var1 // b==&f_var1-d
If X_m1
is the “offset of member m1
from
the beginning of a struct X
, then a shorthand can be
&m1-&X
or \(\mathtt{m1}\Delta \mathtt{X}\). Here is an
example:
ldi c,X_m1 // c==&m1-&X
Be careful with the address-of (&
) and dereference
(*
) operators. The following is a list of examples of
notations that can be easily confused:
&var1-d
: the offset of a non-static (auto) local
variable or parameter var1
from where the stack pointer
points to&var1
: the address of a variable
var1
var1
: the value of var1
*var1
: what var1
points to, assuming
var1
is a pointerHere is another list of more examples of notations that can be confusing:
var1.m
: the value of member m
of
var1
, assuming var1
is a structure with a
member m
&(var1.m)
: the address of member m
of
var1
var1->m
: the value of member m
of a
structure (that has a member m
) that is pointed to by
var1
(assuming var1
is a pointer to a
structure)&(var1->m)
: the address of member m
of a structure that is pointed to by var1
The incorrect use of these notations can result in a deduction of points.
If you cannot remember the priority of operators, use parentheses to
indicate how operations should be nested. For example, *p++
is really *(p++)
and not (*p)++
. However,
&p->m
is the same as
&(p->m)
.