0% found this document useful (0 votes)
13 views

Mips Data Notes

Uploaded by

st.andrews.eve
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
13 views

Mips Data Notes

Uploaded by

st.andrews.eve
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 9

The Memory Subsystem Accessing Memory on the MIPS

• memory subsystem typically provides capability to load or store bytes • addresses are 32 bit (but there are 64-bit MIPS CPUs)
• each byte has unique address, think of: • only load/store instructions access memory on the MIPS
• memory as implementing a gigantic array of bytes • 1 byte (8-bit) loaded/stored with lb/sb
• and the address is the array index
• 2 bytes (16-bit) called a half-word, loaded/stored with lh/sh
• addresses are 32 bit on the MIPS CPU we are using
• 4 bytes (32-bits) called a word, loaded/stored with lw/sw
• most general purpose computers now use 64-bit addresses (and there are
• memory address used for load/store instructions is sum of a specified register
64-bit MIPS)
and a 16-bit constant (often 0) which is part of the instruction
• typically small group of (1,2,4,8,..) bytes can be loaded/stored in single
• for sb & sh operations low (least significant) bits of source register are used.
operations
• lb/lh assume byte/halfword contains a 8-bit/16-bit signed integer
• general purpose computers typically have complex caching systems to
improve memory performance (not covered in this course) • high 24/16-bits of destination register set to 1 if 8-bit/16-bit integer negative

• operating systems on general purpose computers - typically provide virtual • unsigned equivalents lbu & lhu assume integer is unsigned
memory (covered later in this course) • high 24/16-bits of destination register always set to 0
1 2

MIPS Load/Store Instructions Code example: storing and loading a value (no labels)

assembly meaning bit pattern # simple example of load & storing a byte
lb rt , I(rs ) rt = mem[rs +I] 100000ssssstttttIIIIIIIIIIIIIIII # we normally use directives and labels
lh rt , I(rs ) rt = mem[rs +I] | 100001ssssstttttIIIIIIIIIIIIIIII main:
mem[rs +I+1] << 8 li $t0, 42
lw rt , I(rs ) rt = mem[rs +I] | 100011ssssstttttIIIIIIIIIIIIIIII li $t1, 0x10000000
mem[rs +I+1] << 8 | sb $t0, 0($t1) # store 42 in byte at address 0x10000000
mem[rs +I+2] << 16 | lb $a0, 0($t1) # load $a0 from same address
mem[rs +I+3] << 24 li $v0, 1 # print $a0
sb rt , I(rs ) mem[rs +I] = rt & 0xff 101000ssssstttttIIIIIIIIIIIIIIII syscall
sh rt , I(rs ) mem[rs +I] = rt & 0xff 101001ssssstttttIIIIIIIIIIIIIIII li $a0, '\n' # print '\n'
mem[rs +I+1] = rt >> 8 & 0xff li $v0, 11
sw rt , I(rs ) mem[rs +I] = rt & 0xff 101011ssssstttttIIIIIIIIIIIIIIII syscall
mem[rs +I+1] = rt >> 8 & 0xff li $v0, 0 # return 0
mem[rs +I+2] = rt >> 16 & 0xff jr $ra
mem[rs +I+3] = rt >> 24 & 0xff source code for load_store_no_label.s

3 4
Assembler Directives Code example: storing and loading a value

# simple example of load & storing a byte


SPIM has directive to initialize memory and associate labels with addresses. main:
li $t0, 42
.text # following instructions placed in text
la $t1, x
.data # following objects placed in data
sb $t0, 0($t1) # store 42 in byte at address labelled x
.globl # make symbol available globally
lb $a0, 0($t1) # load $a0 from same address
a: .space 18 # int8_t a[18];
li $v0, 1 # print $a0
.align 2 # align next object on 4-byte addr
syscall
i: .word 2 # int32_t i = 2;
li $a0, '\n' # print '\n'
v: .word 1,3,5 # int32_t v[3] = {1,3,5};
li $v0, 11
h: .half 2,4,6 # int16_t h[3] = {2,4,6};
syscall
b: .byte 7:5 # int8_t b[5] = {7,7,7,7,7};
li $v0, 0 # return 0
f: .float 3.14 # float f = 3.14;
jr $ra
s: .asciiz "abc" # char s[4] {'a','b','c','\0'};
.data
t: .ascii "abc" # char s[3] {'a','b','c'};
x: .space 1 # set aside 1 byte and associate label x with its
source code for load_store.s

5 6

Testing Endian-ness Setting A Register to An Address

C MIPS
• Note the la (load address) instruction is used to set a register to a labelled
uint8_t b; li $t0, 0x03040506 memory address.
uint32_t u; la $t1, u
la $t8, start
u = 0x03040506; sw $t0, 0($t1) # u = 0x03040506;
// load first byte of u lb $a0, 0($t1) # b = *(uint8_t *)&u;
• The memory address will be fixed before the program is run, so this differs
b = *(uint8_t *)&u; li $v0, 1 # printf("%d", a0);only syntatctically from the li instruction.
// prints 6 if little-endian syscall
// and 3 if big-endian li $a0, '\n' • For example, if vec is the label for memory address 0x10000100 then these
# printf("%c", '\n');
printf("%d\n", b); li $v0, 11 two instructions are equivalent:
source code for endian.c
syscall la $t7, vec
li $v0, 0 # return 0 li $t7, 0x10000100
jr $ra
.data • In both cases the constant is encoded as part of the instruction(s).
u: • Neither la or li access memory - they are very different to the lw
.space 4
source code for endian.s
instruction.

7 8
Specifying Addresses - some SPIM short cuts SPIM memory layout

• SPIM allows the constant which is part of load & store instructions can be
omitted in the common case it is 0.
sb $t0, 0($t1) # store $t0 in byte at address in $t1
sb $t0, ($t1) # same Region Address Notes
text 0x00400000 instructions only; read-only; cannot expand
• For convenience, SPIM allows addresses to be specified in a few other ways data 0x10000000 data objects; read/write; can be expanded
and will generate appropriate real MIPS instructions stack 0x7fffefff grows down from that address; read/write
sb $t0, x # store $t0 in byte at address labelled x k_text 0x80000000 kernel code; read-only
sb $t1, x+15 # store $t1 15 bytes past address labelled x only accessible in kernel mode
sb $t2, x($t3) # store $t2 $t3 bytes past address labelled x k_data 0x90000000 kernel data’
only accessible in kernel mode
• These are effectively pseudo-instructions.
• You can use these short cuts but won’t help you much
• Most assemblers have similar short cuts for convenience

9 10

Global/Static Variables add: local variables in registers

• global/static variables need appropriate number of bytes allocated in data C MIPS


segment using .space: int main(void) { main:
double val; val: .space 8 int x, y, z; # x in $t0
char str[20]; str: .space 20 x = 17; # y in $t1
int vec[20]; vec: .space 80 y = 25; # z in $t2
z = x + y; li $t0, 17
initialized to 0 by default, other directives allow initialization to other values: li $t1, 25
int val = 5; val: ..double 5 add $t2, $t1, $t0
int arr[4] = {9,8,7,6}; arr: .word 9, 8, 7, 6
char msg[7] = "Hello\n"; msg: .asciiz "Hello\n" // ...

11 12
add variables in memory (uninitialized) add variables in memory (initialized)

C MIPS (.text)
int x, y, z; main: C MIPS .text
int main(void) { li $t0, 17 # x = 17; int x=17, y=25, z; main:
x = 17; la $t1, x int main(void) { la $t0, x
y = 25; sw $t0, 0($t1) z = x + y; lw $t1, 0($t0)
z = x + y; li $t0, 25 # y = 25; } la $t0, y
} la $t1, y lw $t2, 0($t0)
sw $t0, 0($t1) add $t3, $t1, $t2 # z = x + y
la $t0, x la $t0, z
MIPS .data
MIPS (.data) lw $t1, 0($t0) sw $t3, 0($t0)
la $t0, y .data
.data la $t0, z
lw $t2, 0($t0) x: .word 17 source code for add_memory_initialized.s

x: .space 4 y: .word 25
add $t3, $t1, $t2 # z = x + y
y: .space 4 z: .space 4
la $t0, z
z: .space 4
sw $t3,
source code for add_memory.s
0($t0)

13 14

add variables in memory (array) store value in array element - example 1

C MIPS .text C MIPS

int x[] = {17,25,0}; main: int x[10]; main:


int main(void) { la $t0, x li $t0, 3
x[2] = x[0] + x[1]; lw $t1, 0($t0) int main(void) { # each array element
} lw $t2, 4($t0) // sizeof x[0] == 4 # is 4 bytes
add $t3, $t1, $t2 # z = x + y x[3] = 17; mul $t0, $t0, 4
sw $t3, 8($t0) } la $t1, x
source code for add_memory_array.s
add $t2, $t1, $t0
MIPS .data
li $t3, 17
.data sw $t3, 0($t2)
# int x[] = {17,25,0} .data
x: .word 17,25,0 x: .space 40

15 16
store value in array element - example 2 Printing Array: C to simplified C

C MIPS C Simplified C
#include <stdint.h> main: int main(void) { int main(void) {
li $t0, 13 int i = 0; int i = 0;
int16_t x[30]; # each array element while (i < 5) { loop:
# is 2 bytes printf("%d\n", numbers[i]); if (i >= 5) goto end;
int main(void) { mul $t0, $t0, 2 i++; printf("%d", numbers[i]);
// sizeof x[0] == 2 la $t1, x } printf("%c", '\n');
x[13] = 23; add $t2, $t1, $t0 return 0; i++;
} li $t3, 23 }
source code for print5.c
goto loop;
sh $t3, 0($t2) end:
.data return 0;
x: .space 60 }
source code for print5.simple.c

17 18

Printing Array: MIPS Printing Array: MIPS (continued)


# print array of ints
# i in $t0
main:
li $t0, 0 # int i = 0;
loop:
end:
bge $t0, 5, end # if (i >= 5) goto end;
li $v0, 0 # return 0
la $t1, numbers # int j = numbers[i];
jr $ra
mul $t2, $t0, 4
.data
add $t3, $t2, $t1
numbers: # int numbers[10] = { 3, 9, 27, 81, 243};
lw $a0, 0($t3) # printf("%d", j);
.word 3, 9, 27, 81, 243
li $v0, 1 source code for print5.s
syscall
li $a0, '\n' # printf("%c", '\n');
li $v0, 11
syscall
addi $t0, $t0, 1 # i++
j loop # goto loop 19 20
Printing Array with Pointers: C to simplified C Printing Array with Pointers: MIPS

# p in $t0, q in $t1
C Simplified C
main:
int main(void) { int main(void) { la $t0, numbers # int *p = &numbers[0];
int *p = &numbers[0]; int *p = &numbers[0]; la $t0, numbers # int *q = &numbers[4];
int *q = &numbers[4]; int *q = &numbers[4]; addi $t1, $t0, 16 #
while (p <= q) { loop: loop:
printf("%d\n", *p); if (p > q) goto end; bgt $t0, $t1, end # if (p > q) goto end;
p++; int j = *p; lw $a0, 0($t0) # int j = *p;
} printf("%d", j); li $v0, 1
return 0; printf("%c", '\n'); syscall
}
source code for pointer5.c
p++; li $a0, '\n' # printf("%c", '\n');
goto loop; li $v0, 11
end: syscall
return 0; addi $t0, $t0, 4 # p++
}
source code for pointer5.simple.c j loop # goto loop
end:
source code for pointer5.s
21 22

Printing 1-d Arrays in MIPS - v1 Example C with unaligned accesses


C MIPS
int vec[5]={0,1,2,3,4}; # ...
// ... li $s0, 0
int i = 0 loop:
while (i < 5) { bge $s0, 5, end
printf("%d", vec[i]); la $t0, vec uint8_t bytes[32];
i++; mul $t1, $s0, 4 uint32_t *i = (int *)bytes[1];
} add $t2, $t1, $t0 // illegal store - not aligned on a 4-byte boundary
// .... lw $a0, ($t2) *i = 0x03040506;
li $v0, 1 printf("%d\n", bytes[1]);
• i in $s0
source code for unalign.c
syscall
addi $s0, $s0, 1
b loop
end:
# ...
.data
vec: .word 0,1,2,3,4 23 24
Example MIPS with unaligned accesses Example MIPS with unaligned accesses

.data
li $t0, 1
# data will be aligned on a 4-byte boundary
sb $t0, v1 # will succeed because no alignment needed
# most likely on at least a 128-byte boundary
sh $t0, v1 # will fail because v1 is not 2-byte aligned
# but safer to just add a .align directive
sw $t0, v1 # will fail because v1 is not 4-byte aligned
.align 2
sh $t0, v2 # will succeeed because v2 is 2-byte aligned
.space 1
sw $t0, v2 # will fail because v2 is not 4-byte aligned
v1: .space 1
sh $t0, v3 # will succeeed because v3 is 2-byte aligned
v2: .space 4
sw $t0, v3 # will fail because v3 is not 4-byte aligned
v3: .space 2
sh $t0, v4 # will succeeed because v4 is 2-byte aligned
v4: .space 4
sw $t0, v4 # will succeeed because v4 is 4-byte aligned
.space 1
sw $t0, v5 # will succeeed because v5 is 4-byte aligned
.align 2 # ensure e is on a 4 (2**2) byte boundary
sw $t0, v6 # will succeeed because v6 is 4-byte aligned
v5: .space 4
li $v0, 0
.space 1
jr $ra # return
v6: .word 0 # word directive aligns on 4 byte boundary source code for unalign.s
source code for unalign.s

25 26

Data Structures and MIPS Printing 1-d Array in MIPS -v2

C data structures and their MIPS representations:


C MIPS
• char ... as byte in memory, or register int vec[5]={0,1,2,3,4}; li $s0, vec
• int ... as 4 bytes in memory, or register // ... la $t0, vec
int *p = &vec[0]; add $s1, $t0, 16
• double ... as 8 bytes in memory, or $f? register
int *end = &vec[4]; loop:
• arrays ... sequence of bytes in memory, elements accessed by index while (p <= end) { bgt $s0, $s1, end
(calculated on MIPS) int y = *p; lw $a0, 0($s0)
printf("%d", y); li $v0, 1
• structs ... sequence of bytes in memory, accessed by fields (constant offsets
p++; syscall
on MIPS)
} addi $s0, $s0, 4
A char, int or double // .... b loop
• can be stored in register if local variable and no pointer to it • p in $s0 end:
• end in $s1 .data
• otherwise stored on stack if local variable vec: .word 0,1,2,3,4
• stored in data segment if global variable
27 28
Computing sum of 2-d Array : C Computing sum of 2-d Array : MIPS

Assume we have a 2d-array:


int32_t matrix[6][5];

We can sum its value like this in C


int row, col, sum = 0;
// row-by-row
for (row = 0; row < 6; row++) {
// col-by-col within row
for (col = 0; col < 5; row++) {
sum += matrix[row][col];
}
}

MIPS directives for an equivalent 2d-array


mips .data matrix: .space 120 # 6 * 5 == 30 array elements
each 4 bytesmips .text
29 30
“‘
Computing sum of 2-d Array : MIPS Structs in MIPS

li $s0, 0 # sum = 0
li $s2, 0 # row = 0
loop1: bge $s2, 6, end1 # if (row >= 6) break
li $s4, 0 # col = 0
loop2: bge $s4, 5, end2 # if (col >= 5) break
la $t0, matrix
mul $t1, $s2, 20 # t1 = row*rowsize
mul $t2, $s4, 4 # t2 = col*intsize
add $t3, $t0, $t1 # offset = t0+t1
add $t4, $t3, $t2 # offset = t0+t1
lw $t5, 0($t4) # t0 = *(matrix+offset)
add $s0, $s0, $t5 # sum += t0
addi $s4, $s4, 1 # col++
j loop2
end2: addi $s2, $s2, 1 # row++
j loop1
end1: 31 32
Implementing Structs in MIPS Implementing Structs in MIPS

C struct definitions effectively define a new type.


// new type called "struct student" Accessing structure components is by offset, not name
struct student {...}; li $t0 5012345
// new type called student_t la $t1, stu1
typedef struct student student_t; sw $t0, 0($t1) # stu1.id = 5012345;
li $t0, 3778
Instances of structures can be created by allocating space: sw $t0, 44($t1) # stu1.program = 3778;
# sizeof(Student) == 56
stu1: # student_t stu1; la $s1, stu2 # stu = &stu2;
.space 56 li $t0, 3707
stu2: # student_t stu2; sw $t0, 44($s1) # stu->program = 3707;
.space 56 li $t0, 5034567
stu: sw $t0, 0($s1) # stu->id = 5034567;
.space 4 # student_t *stu;

33 34

You might also like