메모리: 로드 및 저장
메모리는 번호가 매겨진 저장 슬롯이 크게 늘어선 것이며, 각 슬롯은 하나의 바이트(8비트)를 담습니다. 슬롯의 번호가 바로 그 주소입니다. 레지스터는 CPU가 가진 작은 고속 슬롯 집합입니다. 메모리는 훨씬 크지만 느리며, 레지스터에 들어가지 않는 모든 것(배열, 문자열 등)을 담습니다. 메모리에 있는 값을 다루려면 그것을 레지스터로 로드하고, 변경한 뒤, 다시 저장합니다.
레지스터는 적고 메모리는 큽니다. (load word)는 워드를 메모리에서 레지스터로 복사하고, (store word)는 그것을 되돌려 복사합니다. 주소는 offset(register)로 씁니다.
RISC-V 메모리는 바이트 주소 지정 방식이므로, 각 바이트는 순서대로 고유한 주소를 가집니다. 워드는 32비트, 즉 4바이트이므로, 다음 워드에 도달하려면 메모리 포인터를 4만큼 전진시킵니다. 이것이 배열 오프셋이 0, 4, 8, ...인 이유입니다. 실제 하드웨어에서는 4의 배수가 아닌 주소에서 워드를 로드하면 느려지거나 트랩이 발생할 수 있습니다. 이 시뮬레이터는 이를 허용하지만, 워드를 4바이트에 정렬하는 습관을 들여야 합니다.
lw t0, 0(a1) # t0 = 주소 a1의 메모리sw t0, 4(a1) # 주소 a1+4의 메모리 = t0
offset(register)에서 레지스터에 담긴 주소에 작은 오프셋 숫자가 더해집니다. 0(a1)은 a1 자체의 주소이고, 4(a1)은 그로부터 4바이트 뒤입니다. 이를 통해 베이스 레지스터를 바꾸지 않고도 근처의 값에 접근할 수 있습니다.
| Address | Value |
|---|---|
| 0x100C | 0x00000000 |
| 0x1008 | 0x00000000 |
| 0x1004 | 0x00000000 |
| 0x1000 | 0x00000000 |
| 0x0FFC | 0x00000000 |
레지스터와 메모리는 0에서 시작합니다.
a0는 그대로 유지됩니다. 명령어에 쓰인 리터럴 오프셋만 증가하여 다음 대상 메모리 주소로 이동합니다.
이 패턴에 맞는 메모리를 만들려면 데이터 섹션에서 .word(하나 이상의 32비트 값) 또는 .space N(N개의 빈 바이트)으로 이름 있는 메모리를 예약합니다. 각 워드는 4바이트이므로 연속된 항목은 오프셋 0, 4, 8에 위치하며, 이는 저장 명령어에서 사용하는 것과 같은 숫자입니다.데이터 섹션에서 이름 있는 메모리를 예약하려면 .word(하나 이상의 32비트 값) 또는 .space N(N개의 빈 바이트)을 사용합니다. 각 워드는 4바이트를 차지하므로 연속된 항목은 오프셋 0, 4, 8 등에 위치합니다.
.datanums: .word 10, 20, 30, 40 # 네 워드.textla t1, nums # t1 = 배열의 주소li t2, 4 # 개수li t0, 0 # 누적 합계loop:beq t2, zero, donelw t3, 0(t1) # 현재 요소를 불러온다add t0, t0, t3 # 합계에 더한다addi t1, t1, 4 # 다음 워드로 이동 (4바이트)addi t2, t2, -1 # 하나 줄어듦j loopdone:mv a0, t0 # 합계를 출력 (100)li a7, 1ecallli a7, 10ecall
는 배열의 주소를 t1에 넣고, t2는 남은 4개의 요소를 세며, t0는 누적 합계를 담습니다. 각 반복에서 은 요소가 남지 않았을 때 루프를 멈춥니다. 은 t1이 가리키는 요소를 로드하고, 는 그것을 합계에 더하며, 는 포인터를 한 워드 전진시키고, 은 카운트를 줄입니다. 네 요소 모두(10 + 20 + 30 + 40) 후에 done은 100을 출력합니다.
