Skip to content

Memory

MIPS is a load-store register architecture1. Which means, it divides instructions into two categories: memory access and ALU operations. The arithmetic and logical operations are part of the ALU operations. Incidentally, ALU is called the arithmetic and logic unit.

MIPS has 32 registers, each are 32-bit long (or 4-byte long). Each word contains 32 bits (or 4 bytes). Not surprisingly, memory addresses are also 32-bit long.

So what is the significant of this magic number 32? It means that each memory address can fit into a register nicely. However, note that MIPS uses byte addresses. So, data in each memory address holds a single byte (i.e., 8 bits). Which means, consecutive words differ by 4 in their addresses.

Word Alignment

Consecutive words differ by 4 in their address.

Memory Instruction

Only load and store instructions can access data in memory. However, there are several variants of the instructions.

Word Addressing

Word Addressing

MIPS
1
lw $rt, offset($rs)
MipC
1
$rt = $rs[offset]; // assume integer

Transfer a word from memory to register. The address is computed as $rs + offset where offset is a 16-bit 2s complement number.

MIPS
1
sw $rt, offset($rs)
MipC
1
$rs[offset] = $rt; // assume integer

Transfer a word from register to memory. The address is computed as $rs + offset where offset is a 16-bit 2s complement number.

In both instructions, the address is compute the same way: $rs + offset. Here, the register $rs holds the base address of the memory. Typically it will match with an array in the high-level program. Note that both instructions throws an error when the result $rs + offset is not word aligned (i.e., not multiple of 4 in the case of MIPS).

Visualisation

MIPS
1
lw $t0, 4($s0)
MipC
1
$t0 = $s0[4];

Load Word

Steps:

  1. Memory address = $s0 + 4 = 8000 + 4 = 8004.
  2. Memory word at Mem[8004] is loaded into $t0.
    • Remember, we abstract memory as a single-dimension array.

MIPS
1
sw $t0, 12($s0)
MipC
1
$s0[12] = $t0;

Load Word

Steps:

  1. Memory address = $s0 + 12 = 8000 + 12 = 8012.
  2. Content of $t0 is stored into word at Mem[8012].
    • Remember, we abstract memory as a single-dimension array.

Byte Addressing

Byte Addressing

MIPS
1
lb $rt, offset($rs)

Transfer a byte from memory to register. The address is computed as $rs + offset where offset is a 16-bit 2s complement number.

MIPS
1
sb $rt, offset($rs)

Transfer a byte from register to memory. The address is computed as $rs + offset where offset is a 16-bit 2s complement number.

Unlike lw and sw, the address need not be word aligned (i.e., not multiple of 4). As such, the value can be any non-negative number between 0 and 232M-1. Typically, these operations are used for string (i.e., array of char which is 1 byte long).

Which Byte?

There are 4 bytes in a register. In the case of load, we simply set the upper 3 bytes to all 0s. But which byte is going to be stored[^2]? In this case, the lower 1 byte is going to be stored. To put it in C-like syntax:

Stored Byte
1
{ $rs[7] , $rs[6] , $rs[5] , $rs[4] , $rs[3] , $rs[2] , $rs[1] , $rs[0] }

Other Addressing

Other Addressing

Load
1
lh $rt, offset($rs)
Store
1
sh $rt, offset($rs)

Load
1
lwl $rt, offset($rs)
Store
1
swl $rt, offset($rs)

Load
1
lwr $rt, offset($rs)
Store
1
swr $rt, offset($rs)

Out of Scope

These other types of addressing are out of scope for our module. You are not allowed to use them for assignments and/or other assessments.

Unaligned Addressing

Unaligned Addressing

MIPS
1
lw $rt, offset($rs)
MipC
1
$rt = $rs[offset]; // assume integer

Transfer a word from memory to register. The address is computed as $rs + offset where offset is a 16-bit 2s complement number.

MIPS
1
sw $rt, offset($rs)
MipC
1
$rs[offset] = $rt; // assume integer

Transfer a word from register to memory. The address is computed as $rs + offset where offset is a 16-bit 2s complement number.

MIPS disallows loading/storing unaligned word using lw/sw. These two above are pseudo-instructions to load/store unaligned words. They can naively be translated into multiple real instructions with additional temporary registers.

Naive Translation

lw $s0, 3($s1)

Unaligned Load Word
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
lb  $t0, 3($s1)    # 0x00000033

lb  $t1, 4($s1)    # 0x00000044
sll $t1, $t1, 8    # 0x00004400
or  $t0, $t0, $t1  # 0x00004433

lb  $t1, 5($s1)    # 0x00000055
sll $t1, $t1, 16   # 0x00550000
or  $t0, $t0, $t1  # 0x00554433

lb  $t1, 6($s1)    # 0x00000066
sll $t1, $t1, 24   # 0x66000000
or  $t0, $t0, $t1  # 0x66554433

sw $s0, 3($s1)

Unaligned Load Word
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
add $t0, zero, $s0 # 0x66554433
lb  $t0, 3($s1)    # 0x00000033

srl $t0, $t0, 8    # 0x00665544
lb  $t0, 4($s1)    # 0x00000044

srl $t0, $t0, 8    # 0x00006655
lb  $t0, 4($s1)    # 0x00000055

srl $t0, $t0, 8    # 0x00000066
lb  $t0, 4($s1)    # 0x00000066

Examples

As this is one of the more important concepts in MIPS, we will dedicate a section for examples. You are advised to try the example on your own first before looking at the answer.

Array Operations

Assume that each array element occupies a word or 4 bytes (e.g., an integer array int A[N];).

Array Operations (in C)
1
A[7] = h + A[10];
Variable Register
h $s2
A $s3

Note that for A, it is the base address of the first element since it is an array (i.e., &A[0]).

We use a single temporary register $t0.

Array Operations (in MipC)
1
2
3
$t0 = $s3[40];     // $t0 = A[10]     -- 40 is used because 40 = 4 * 10
$t0 = $s2 + $t0;   // $t0 = h + A[10]
$s3[28] = $t0;     // A[7] = $t0      -- 28 is used because 28 = 4 * 7
Array Operations (in MIPS)
1
2
3
lw  $t0, 40($s3)   #  $t0 = A[10]     -- 40 is used because 40 = 4 * 10
add $t0, $s2, $t0  #  $t0 = h + A[10]
sw  $t0, 28($s3)   #  A[7] = $t0      -- 28 is used because 28 = 4 * 7

Note that arithemetic operads (e.g., add) are for registers, not memory!

Swap Elements

Swap Elements (in C)
1
2
3
4
5
6
void swap(int v[], int k) {
  int temp;
  temp = v[k];
  v[k] = v[k+1];
  v[k+1] = temp;
}
Variable Register
&v[0] $a0 ($4)
k $a1 ($5)
temp $t7 ($15)

Note that you do not have to care about the function call (i.e., jump to the current instruction and jump back to the caller).

Swap Elements (in MipC)
1
2
3
4
5
6
$v0 = $a1 << 2;    // $v0    = k * 4     -- for word alignment
$v0 = $v0 + $a1;   // $v0    = (k*4)+v   -- computing the actual address
$t7 = $v0[0];      // temp   = v[k]
$t8 = $v0[4];      // $t8    = v[k+1]
$v0[0] = $t8;      // v[k]   = $t8
$v0[4] = $t7;      // v[k+1] = temp
Swap Elements (in MIPS)
1
2
3
4
5
6
7
swap:
  sll  $2, $5, 2   #  $v0    = k * 4     -- for word alignment
  add  $2, $4, $2  #  $v0    = (k*4)+v   -- computing the actual address
  lw   $15, 0($2)  #  temp   = v[k]
  lw   $16, 4($2)  #  $t8    = v[k+1]
  sw   $16, 0($2)  #  v[k]   = $t8
  sw   $15, 4($2)  #  v[k+1] = temp

Note that this is simplified and may not be a direct translation of the C code.

Exercise

Assume that each array element occupies a word or 4 bytes (e.g., an integer array int A[N];).

Array Operations (in C)
1
A[3] = h + A[1];
Variable Register
h $s2
&A[0] $s3
Array Operations (in MIPS)
1
2
3
lw  $t0, 4($s3)
add $t0, $s2, $t0
sw  $t0, 12($s3)

  1. It is still a von Neumann architecture in which data and progam are stored in the same memory.