Mips Data Notes
Mips Data Notes
• 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
5 6
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
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
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
# 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
.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
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
33 34