A row of bytes, each with a number
Memory is a row of
.
Each byte has a number, its
.
The first byte is address 0, the next is 1, and so on up to 4294967295. An
address is a 32-bit number, so it fits in a register. This book writes
addresses as eight hex digits, 0x10000100.
Sixteen bytes of memory, starting at 0x10000100
What does each cell hold, and what does the number under it mean?
What to notice
Each cell is one byte, two hex digits. The label under a cell is the last
digits of its address. Addresses go up by one per cell, left to right. The
first three bytes happen to be the characters H, i and a new line.
Words, halfwords, and which byte comes first
A word is four bytes in a row. It is named by its lowest address: “the word
at 0x10000104” is bytes 0x104, 0x105, 0x106 and 0x107. A
is two bytes.
Which of the four bytes holds the top of the number? On your toolchain and
your core, the lowest address holds the least significant byte. That is
order. Watch sw put 0x12345678 into memory:
sw writes 0x12345678 at 0x10000100
Which byte of the register goes to which address?
sw writes register value 0x12345678 as bytes:
What to notice
The register’s low byte 78 goes to the lowest address, 0x100. The high
byte 12 goes to 0x103. Read the cells left to right and the number looks
backwards: 78 56 34 12. That is not a mistake; it is the rule.
Now read it back. Drag the slider to move the window, or change the operation to see how a halfword or a byte is assembled.
lw reads the four bytes back into a register
Move the window one byte to the right. What happens?
bytes 0x10000100 … 0x10000103, lowest address first: [78 56 34 12]
lw puts 0x12345678 = 305419896 in the register.
What to notice
At 0x100 the four bytes come back as 0x12345678: the strip reverses them
for you. At 0x101 the window turns red and dashed. A word may not start
there. Switch to lh and 0x102 becomes legal again; switch to lb and any
address is fine.
Alignment: where a word may start
A word must start at a multiple of 4. A halfword must start at a multiple of 2. A byte may start anywhere. This rule is .
| access | legal addresses | example |
|---|---|---|
lw, sw | multiples of 4 | 0x10000100, 0x10000104, never 0x10000102 |
lh, lhu, sh | multiples of 2 | 0x10000102, never 0x10000103 |
lb, lbu, sb | any | 0x10000103 |
On real MIPS a misaligned lw does not read a wrong word. It stops the
program with an
exception. GCC knows the rule and never emits a misaligned access, so a
compiled program never meets it. Your own core does not check alignment yet.
It would read the wrong word, and that gap is a recorded open item.
Before reading on, decide:
`sw` stored 0xDEADBEEF at 0x200. What does `lb $t0,0($t1)` with $t1 = 0x200 load?
The memory map
Where do things live? Your test machine uses two separate memories and a fixed plan, its .
Where things live: the test machine's memory map (16 KB of data)
Higher addresses are at the top. The stack starts just under the doors and grows downward.
What to notice
The program sits far up, at 0xBFC00000, the address every MIPS CPU starts
from. The data sits at 0x10000000. The three doors are the top 16 bytes of
the data memory, and the stack starts right under them and grows downward.
Everything the compiler places, it places into these two regions.
The two memories are separate hardware, which is why the code and the data
have different bases. A load reads the data memory; the program memory is
only ever fetched. The smoke scenarios of chapters 1 to 3 used a 4 KB data
memory, so their doors were at 0x10000FF0. Compiled programs use 16 KB.
Go deeper: why alignment exists, and what your core does today
Memory hardware hands out one aligned word per access. A misaligned word
straddles two of them, so it needs two accesses and a shift-and-merge. The
1985 MIPS designers refused to build that path: one access per load, always.
So the ISA forbids misaligned words and traps on them, and the special
instructions lwl/lwr (not covered here) exist for the rare cases that
need the two halves.
Carolyne’s load/store unit takes the same one-access shortcut: it fetches the
containing word and picks bytes out by the low two address bits. But it does
not raise the address error, because the description has no trap policy yet.
A misaligned lw therefore returns the aligned word that contains the
address, silently. It is listed in docs/open_items.md, and GCC’s alignment
discipline is what keeps every compiled program clear of it.
Can you now explain it?
Memory is a numbered row of bytes. A word is four of them, named by the lowest address, with the least significant byte first. Words start at multiples of 4, halfwords at multiples of 2, and the machine's regions sit at fixed addresses.
If you remember only three things
- An address names one byte. Thirty-two bits, written as eight hex digits. A register holds one, which is how pointers work.
- Little-endian: small end first. 78 56 34 12 in memory is 0x12345678 in a register. A dump looks reversed; the rule is not.
- Aligned, or an address error. lw at a multiple of 4, lh at a multiple of 2, lb anywhere. GCC obeys; real MIPS traps; your core does not check yet.
Now try to explain this one yourself: bytes FE FF sit at 0x10000104
and 0x10000105. What does lhu from 0x10000104 load, and what does lh
load? Use the byte order and §3.2’s two extensions.
Go deeper: a model answer, once you have tried
Little-endian: the byte at the lower address is the low byte. So the halfword
is 0xFFFE. lhu zero-extends it: 0x0000FFFE, which is 65534. lh
sign-extends it: bit 15 is 1, so the top fills with ones, 0xFFFFFFFE, which
is −2. Same two bytes, two register values, and only the instruction decides.
Section 4.3 makes this the main subject.
Check your understanding
0/5 answered1.`sw` stores 0xDEADBEEF at address 0x200. Which byte is at 0x200, and which at 0x203?
2.Which of these addresses may `lh` use?
3.An array of words starts at 0x10000010. What is the address of its third word, `a[2]`?
4.A program executes `lw $t0,2($t1)` with $t1 = 0x10000100. What happens on real MIPS?
5.What does 'little-endian' mean?