How does 'alignment of memory operands' help MIPS to be pipelined? - mips

How does 'alignment of memory operands' help MIPS to be pipelined?
The book says:
Fourth, as discussed in Chapter 2, operands must be aligned in memory. Hence,
we need not worry about a single data transfer instruction requiring two data
memory accesses; the requested data can be transferred between processor and
memory in a single pipeline stage.
I think I understand that one data transfer instruction does not require two or more data memory aaccesses.
However, I am not sure what does it have to do with the alignment of memory operands.
Thanks, in advance!

The lw instruction requires that the memory address be word aligned.
Therefore, to access an unaligned word, one would need to access the two word boundaries that the required word intersects and mask out the necessary bytes.
For example, suppose you desire to load a word stored at address 0x2. 0x2 is not word aligned, so you would need to load the half word stored at 0x2 and the half-word stored at 0x4.
To do so, one might write:
lh $t0 2($zero)
lh $t1 4($zero)
sll $t1 $t1 16
or $t2 $t0 $t1
This only gets more complicated if you want to load for example a word stored at address 0x3:
# load first byte
lb $t0 3($zero)
# load second word, mask out first 3 bytes
lw $t1 4($zero)
lui $t2 0x0000FFFF
ori $t2 $t2 0xFFFFFFFF
or $t1 $t1 $t2
# combine
sll $t1 $t1 8
or $t2 $t0 $t1
So, it can be seen that the requirement for word alignment doesn't help MIPS to be pipelined, but rather that access to unaligned words requires excess memory accesses — this is a limitation of the ISA.

Related

How to translate MIPS into C and how to reduce MIPS instructions?

Supposing that f, g, h, i are stored in $s0~$s4 respectively and the base addresses of arrays A and B are in $S6 and $S7.
sll $t0, $s0, 2
add $t0, $s6, $t0
sll $tl, $sl, 2
add $tl, $s7, $tl
lw $s0, 0($t0)
addi $t2 , $t0, 4
lw $t0, 0($t2)
add $t0, $t0, $s0
SW $t0, 0($tl)
I'm not familiar with MIPS so I Wonder how to translate MIPS into C and how to minimize these MIPS instructions?
how to translate MIPS into C
You recognize the patterns, here for array indexing / array element access.
On a byte addressable machine (all modern hardware), a 4-byte integer occupies 4 bytes in memory, and each of those bytes has a unique memory address.  Because of the way the hardware works, we only use one of those 4 addresses to refer to the whole 4-byte integer, namely we use the lowest address among the 4.  The hardware can load a 4-byte integer from memory given that one address (the lowest).
Since each 4-byte integer in memory occupies 4 addresses, in an array of 4-byte integers, the memory address of the first element and the memory address of the second element are 4 addresses apart even though are sequential index positions (i.e. they are only 1 index position apart).
The formula for indexing a 4-byte integer array, then is to convert the index into a byte offset, then add the byte offset to the base address of the array.  The first part of that: converting an index to a byte offset, is sometimes referred to as "scaling".  Scaling is conceptually done by multiplication, so in A[i], i needs to be scaled by the size of the array elements of A.  If 4-byte integers that means scaling (multiplying) the index by 4.  A quick way of doing that is shifting by 2 bit positions, which has the same effect as multiplying by 4.
The C language automatically scales when doing array references, whereas assembly language requires explicit scaling.  C can do this because it knows the type of the array, whereas assembly language does not.
In C we can do expressions like A[i].  The C language allows us to break that down somewhat into *(A+i), which separates the pointer arithmetic addition A+i from the dereferencing of that sum, dereferencing with the unary indirection operator, *.  As previously mentioned, C automatically scales, so A+i becomes the equivalent of A+i*4, in which we can substitute shifting for multiplication: A+(i<<2).
Next, we need to know if the dereference is for read or for write.  When A[i] is accessed for its value, we will see it on what we call the "right hand side" of an assignment operator, as in ... = A[i].  When A[i] is access to update/store a value, we will see it on what we call the left hand side of an assignment operator, as in A[i] = ....
So, the sequence for doing A[i] for read (right hand side) in C is the following in assembly:
sll $temp1, $i, 2
addu $temp2, $A, $temp1
lw $temp3, 0($temp1)
Where $tempN is some register (usually a designated temporary) chosen to hold an intermediate value.  Since multiple instructions are needed to accomplish anything, sequences of instructions are interconnected with registers that hold the intermediate states.  And also, in assembly we name registers, not variables, so in my above $i and $A should be a registers names representing those variables rather than variable names directly used.
The pattern for write/store array access is similar but ends with a sw instruction instead, to store some value into memory at the index position.
These instruction sequence are interconnected by the use of these registers, and the sequences can be interrupted or interspersed with other instructions — what we have to follow then is the above pattern by paying attention to to the register usages that interconnect them rather than the specific sequences.
In your sample code:
sll $t0, $s0, 2 # sourcing an index in $s0, scaling it into temp $t0
add $t0, $s6, $t0 # adding a base array in $s6, putting back into $t0
sll $tl, $sl, 2
add $tl, $s7, $tl
lw $s0, 0($t0) # accessing the value of $s6[$s0*4], aka A[f]
addi $t2 , $t0, 4
lw $t0, 0($t2)
add $t0, $t0, $s0
SW $t0, 0($tl)
We can see the pattern for a read access to an index in $s0, and an array in $s6, these, we are told, map to f and A, so those three instructions comprise A[f] to read a value from A at index f.
The rest are done similarly.  Your job is to use this knowledge to find the other array indexing patterns in the above sequence.  Find out how the results of the array indexing operations are used and you'll have the complete C code.
NOTE that the sample you've been given incorrectly uses add and addi when pointer arithmetic should use addu and addiu — we don't want signed integer overflow checking on pointer arithmetic, as pointers are unsigned.
One of the add instructions is not for pointer arithmetic, but should probably still have used addu if this is intended to be replicated in C, because the C language does not have a built in operator to trap on overflow.

"Memory limits" using sw in mips

Lets say i have the following command in MIPS:
sw $t0, 0($sp) # $sp=-4
Does that mean that the register $t0 is saved from 0 to -3 byte or from -4 to -7 byte ?
Stack growing downward in memory to make space for new data to be saved. The stack pointer $sp point to the top of stack.
The stack pointer $sp starts at a high memory address and decrements to expand as needed. Figure (b) shows the stack expanding
to allow two more data words of temporary storage. To do so, $sp decrements by 8 to become 0x7FFFFFF4. Two additional data words,
0xAABBCCDD and 0x11223344, are temporarily stored on the stack.
So in your case if I understand your question well the sw is word- addressable and the word will be stored on that location in memory which $sp point to. In case you store the next word it must have an offset of 4.
[Harris&Harris]
UPDATE
Take this example when you use lb
Say you have this word 0x23456789
when using lb $s0,1($0) After the load byte instruction, lb $s0, 1($0),
$s0 would contain 0x00000045 on a big-endian system and 0x00000067 on a
little-endian system.[Harris&Harris]

how can I know number of instruction access?

I'm studying computer architecture. I'm confused about some quiz.
when executing n instructions in load-store arch.
lw $t0, 32($s3)
add $t0, $s2, $t0
sw $t0, 48($s3)
then what is number of memory access, and number of instruction access?
I think num of memory access is 2 and num of instruction access is 3. Is it right?
Yes it's right, Just for the sake of understanding it better here is some explanation.
MIPS using load word instruction lw to read data word from memory into register and
store word sw to write a word in memory.
lw $t0, 32($s3)
This load a word from memory into register $t0
add $t0, $s2, $t0
This means you are on the register side no memory involved.
sw $t0, 48($s3) This store a word in memory.
You are using 3 instruction which two of them involve with memory access

What happens when I give an offset to a "temporary register" in MIPS

For example:
$t0 = A
$t1 = B
$t2 = C
If I do the following command
lw $t1, 4($t0)
would it load $t2 into $t1?
As long as your temporary registers are next to each other in memory.
i.e.
Reference: $t1 $t2
Mem Blocks: [byte][byte][byte][byte][byte][byte][byte][byte]...
Programs like Logisim should have the registers packed tightly.
Helpful page here from UC Berkeley.
If I do the following command
lw $t1, 4($t0)
would it load $t2 into $t1?
No, it would not. The lw instruction is used to load data from memory, not to copy the value of one register into another register. To quote from the MIPS manual:
LW rt, offset(base) MIPS32 (MIPS I)
Purpose:
To load a word from memory as a signed value
Description: rt ← memory[base+offset]
The contents of the 32-bit word at the memory location specified by the aligned effective address are fetched,
sign-extended to the GPR register length if necessary, and placed in GPR rt. The 16-bit signed offset is added to the
contents of GPR base to form the effective address.
In other words, what lw $t1, 4($t0) does is form an effective address by adding the value of $t0 with the value 4, and load a word (four bytes) from that address into register $t1.

MIPS: Does a load word create a data hazard if an instruction loads from the same register?

Does a load word create a data hazard if a subsequent instruction loads from the same register?
I have
lw $t0 0($t1)
addi $s0, $t1, 4
Would this create a data hazard, since you need what is stored in the register for both operations? What if the instructions are reversed or there is an offset?
No. In general, register reads do not create hazards. In this case if $t1 was read by the lw, then it can be read by the next instruction without a pipeline stall/hazard.