sections in this module | City
College of San Francisco - CS270 Computer Architecture Module: Simple Machine |
module list |
Advanced
Operations
Now that we've covered the simple instructions for the SM and the
technique of converting C code to a form that is easier to
translate to assembly instructions, let's practice these skills
using our SM.
Loops and if-statements require decisions. Decisions in SM involve comparing the counter register (CTR) to zero. There are two instructions for this: JLT and JEQ (JMP is not included as there is no comparison). If the comparison is true the branch is taken and the PC is changed to the address in the instruction. For example,
JLT 0x10
could be written in pseudocode
if (ctr < 0) goto 0x10
In order to perform a comparison on CTR, data must first be moved there. In SM, the CTR is only attached to the accumulator and there are two instructions that move data between them
The first code snippet we did in class was very simple
(which also could be written in C as res=(a<b) )
This comparison does not compare to zero, so we must transform it first:
Transforming it using the techniques of the last section:
Now we can write the SM code pretty easily
Instructions |
Translated to hexadecimal |
# if
((a-b) < 0) goto altb;
# remember SUB A is A - accum LOAD
B
SUB A MVAC JLT ALTB # res=0; LOAD ZERO STORE RES # goto ageb; JMP AGEB # altb: res=1; ALTB: LOAD ONE # offset 7 STORE RES # ageb: AGEB: HALT # offset 0x9 PAD: HALT A: # offset 0xb B: # offset 0xc RES: # offset 0xd ZERO: # offset 0xe ONE: # offset 0xf |
0x100c 0x900b 0x4000 0x6007 0x100e 0x200d 0x7009 0x100f 0x200d 0x0 0x0 0x2 0x41 0x0 0x0 0x1 |
This program is adv1 in the lecturenotes/sim directory of the public work area.
Arrays
In order to make loops interesting we must use arrays. From the
last section
in
higher-level code |
in
assembler |
element = myarray[i] |
temp=&myarray[0]; // or temp=myarray; temp += i; element = *temp; |
This first instruction on the right requires a new instruction LA (load address), which takes the address in the instruction and places it in the accumulator (rather than the LOAD instruction which loads the data AT the address in the instruction and places it in the accumulator). Note that LA can be used to load any small unsigned constant value into the accumulator. In normal parlance this is called a load immediate.
The last statement on the right needs some more explanation. Our Simple Machine is able to perform indirection using a special-purpose register, the address register (areg for short). If you can generate an address and you want the corresponding data, you simply
This first step requires you to get the address (by LOADing it or
calculating it) into the accumulator, then move it to the areg using
the MVAA instruction (move accumulator to areg). The last step simply
uses the address in the areg and places the data found at that address
in the accumulator. Thus LIA overwrites the accumulator. Neither LIA
nor MVAA use the address part of the instruction.
Now we are ready to translate our sequence:
Similar
to LIA is the SIA instruction. The only difference is the direction of
the memory transfer. LIA loads the data using the areg's address and
places it in the accumulator. SIA stores the data in the accumulator at
the address specified in the areg.
Addressing Modes
Now that we have covered most of the SM instructions, we can discuss the addressing modes that our SM uses. If you remember, the addressing mode indicates how to resolve an operand. For example, in our SM, if the ADDR field is 0x10, it could mean value 0x10 or address 0x10, depending on the instruction. This is determined by the addressing mode. In SM, each instruction has set addressing modes. On most machines, some instructions have multiple addressing modes. The mode in use is determined by the binary encoding of the instruction.
The SM uses five addressing modes. Let's go through what each
means in general and for our SM
addressing mode |
general meaning |
use in SM |
Register |
The value is in a register.
On most machines, the register must be specified in the
instruction. |
In SM, the register (usually
the accumulator) is implicit. This is true in instructions
such as LOAD (where the destination uses the register
addressing mode) and STORE (where the source uses the
register addressing mode). In the MVAC instruction, both source and destination use register addressing mode where the register is implicit. |
Memory (or
Memory Direct) |
The value is in memory. The
address of the value is encoded in the instruction. |
In SM, the LOAD instruction
uses Memory addressing mode for the source operand. This
addressing mode is also used by STORE, ADD and SUB.
Interestingly, MIPS does not use the Memory addressing mode. |
Immediate |
The value is a constant which
is encoded into the instruction. |
In SM, the LA instruction
uses Immediate addressing mode. |
Base |
The address of the value is
in a register (the "base" register). The instruction specifies which register. |
The LIA instruction uses the
base (or "register indirect") addressing mode |
Absolute |
The address to jump to is
encoded in the instruction |
The J instructions use
Absolute addressing mode. |
MIPS will have two additional addressing modes: base plus displacement and PC-relative. We will discuss those later.
Loops
The interesting thing to use loops for is to perform operations on an array. Although the abilities of the SM in that area are limited, lets look at a very basic case:
int
arr[N]; sum=0 ;
for (i=0;i<N;i++) sum +=
arr[i];
We will first convert this to comparisons to zero and gotos:
i=0; sum=0
loop: if ((i-N)==0) goto
loopdone;
sum += arr[i];
i++;
goto loop;
loopdone:
Now let's look at the code for various parts:
initialization | if ((i-N)==0) goto loopdone; | sum += arr[i]; |
i++;goto loop; |
LA 0 STORE SUM STORE I |
LOAD N SUB I MVAC JEQ loopdone |
LA ARR ADD I MVAA LIA ADD SUM STORE SUM |
LA 1 ADD I STORE I JMP LOOP |
Using this straightforward conversion there are 3 initialization instructions here and 14 instructions per iteration. A loop of 1000 iterations would execute 14003 instructions.
Let's rewrite the loop to take advantage of the SM's strengths, such as they are. The SM is meant to use the ctr register as a loop counter, but the only way to utilize this effectively (and avoid interfering with the accumulator) is to decrement the counter using DECR. Here is a rewrite of the loop that tries to do just that:
for (i=(N-1); i>=0; i--) sum += arr[i];
Rewriting using gotos:
i=(N-1); sum=0;
loop: if (i < 0 ) goto
loopdone;
sum += arr[i];
i--;
goto loop;
loopdone:
This looks very similar to our original code - we are just going through the loop in the opposite order. However, when we convert it to SM code we get a surprise
initialization | if (i < 0 ) goto loopdone; | sum += arr[i]; | i--;
goto loop; |
LA 1 SUB N MVAC LA 0 STORE SUM |
JLT loopdone |
LA ARR ADDC MVAA LIA ADD SUM STORE SUM |
DECR JMP loop |
By keeping the index in the ctr register we had a big win! We now have 5 initialization and 9 instructions/iteration, or 9005 instructions for our 1000 iteration loop! This is a big example of targeting code to the machine. Fortunately, real machines are not so limited as our SM and writing efficient code is not as "tricky"
Let's try our "convert the code to use pointers" trick and see what we get. We will find that, although this can be a win with real machines, it is not so for our SM - again because of the issue of contention between the accumulator and the counter register.
Here is the code:
int *ptr; for
(ptr=&arr[N-1],sum=0; ptr>=&arr[0]; ptr--) sum +=
*ptr;
int * ptr = &arr[N-1];
loop: if ((ptr -
&arr[0]) < 0) goto loopdone;
sum += *ptr;
ptr--;
goto loop
loopdone:
initialization | if (i < 0 ) goto loopdone; | sum += arr[i]; | i--;
goto loop; |
LA 1 SUB N STORE NM1 LA ARR ADD NM1 STORE PTR |
LA ARR SUB PTR MVAC JLT loopdone |
LOAD PTR MVAA LIA ADD SUM STORE SUM |
LA 1 SUB PTR STORE PTR JMP loop |
This takes 6 initialization and 13 instructions per iteration. Not a big win from the straightforward method for the SM.
Let's write the code for the winning solution here:
LA 1 SUB N MVAC LA 0 STORE SUM loop: JLT loopdone LA ARR ADDC MVAA LIA ADD SUM STORE SUM DECR JMP loop loopdone:HALT 0x0 SUM: N: ARR: |
0xB001 #offset 0 0x9011 0x4000 0xB000 0x2010 0x600E #offset 5 0xB012 0x3000 0xE000 0xC000 0x8010 0x2010 0xA000 0x7005 0x0 #offset E 0x0 0x0 #offset 0x10 0x5 0x14 #offset 0x12 0xfff9 0x103 0xffe2 0x243 |
This program is adv2
in the lecturenotes/sim
directory of the public work area. (I know this is confusing right now.
We will revisit the use of pointers again when we cover loops in MIPS
later.)
Another loop problem
Suppose we had a modification of our previous loop:
for (i=(N-1); i>=0; i--) arr[i] += num;
Can you write the resulting Simple Machine program? There is a solution in the file adv3 in the lecturenotes/sim directory of the public work area.
Prev | This page was made entirely
with free software on linux: Kompozer, the Mozilla Project and Openoffice.org |
Next |