안 쓰던 블로그
컴퓨터 구조-MIPS, MIPS 구조 본문
MIPS 구조
1980년대 스탠포드대학에서 John Hennessy와 그의 동료들에 의해 개발됨
Silicon Graphics, Nintendo, Cisco의 제품에서 사용되고 있음
디자인 원리
1. 규칙적인 것이 간단성을 위해 좋음 (일관성있는 명령어 형태)
2. 많이 발생되는 사항을 빨리 처리함 (복잡한 명령어를 여러개 단순한 명령어로)
3. 적을수록 빠름 (32개의 레지스터가 1000개보다 빠름)
4. 좋은 설계는 좋은 절충안을 요구함 (융통성 제공, 적은 수의 명령어 유지)
설계원칙1: 규칙적인 것이 간단성을 위해 좋음
일관성있는 명령어 형태
같은 수의 피연산자 (두 개의 source와 한 개의 destination)
하드웨어로 구현하기 쉬움
명령어
addtion(더하기)
subtraction(빼기)
고급 레벨 코드 | MIPS 어셈블리 코드 | 의미 |
a=b+c; | add a,b,c | a에 b+c를 저장 |
a=b-c; | sub a,b,c | a에 b-c를 저장 |
설계원칙2: 많이 발생되는 사항을 빨리 처리함
MIPS: 단순하고 많이 사용하는 명령어를 포함함
명령어를 해석하고 실행하는 하드웨어는 단순하고 빠름
복잡한 명령어는 여러 개의 단순한 명령어로 수행됨
고급 레벨 코드 | MIPS 어셈블리 코드 | 의미 |
a=b+c-d; | add t,b,c | t에 b+c를 저장 (임시 변수 t에 저장) |
sub a,t,d | a에 t-d를 저장 |
설계원칙3: 적을수록 빠름
MIPS: 적은 수의 레지스터를 포함
적은 수: 32개의 레지스터 (32 비트 또는 64 비트)
32개의 레지스터로부터 데이터를 획득하는 것이
1000개의 레지스터 또는 메모리로부터 데이터를 획득하는 것 보다 빠름
32개의 MIPS 레지스터 세트 종류
고급 레벨 코드 | MIPS 어셈블리 코드 | 의미 |
a=b+c; | add $s0, $s1, $s2 | $s0=a $s1=b $s2=c 저장 $s0에 $s1+$s2를 저장 |
a=b+c-d; | sub $t0, $s2, $s3 add $s0, $s1, $t0 |
$s0=a $s1=b $s2=c $s3=d 저장 $t0에 $s2-$s3를 저장(임시 변수 t) $s0에 $s1+$t0을 저장 |
설계원칙4: 좋은 설계는 좋은 절충안을 요구함
-다중 명령어 형태는 융통성 제공
(1) add, sub: 3개의 레지스터 피연산자 사용
(2) lw, sw: 2개의 레지스터 피연산자와 상수 사용
-적은 수의 명령어 형태를 유지함
워드 주소 메모리 읽기
1워드=4바이트
주소 단위가 워드 기준
1. load 명령어(lw)
load 목적지, 주소
어셈블리 코드 | 의미 |
lw $s3, 1($0) | $s3레지스터에 워드1번지(1+0=1)에서 가져온 데이터를 저장 |
워드1번지값이 0000 0001이므로 위에 사진 같은 경우 F2F2AC07이 $3에 저장
2. store 명령어(sw)
store 소스, 목적지
어셈블리 코드 | 의미 |
sw $t4, 0x3($0) | $s4레지스터 값을 워드3번지(16진수 3+0=1)에 저장 |
위에 사진 같은 경우 워드3번지는 0000 0003이므로 40F30788 있는 곳에 $s4값이 저장된다
바이트 주소 메모리 읽기
주소 단위가 바이트 기준
1. load 명령어(lw)
load 목적지, 주소
어셈블리 코드 | 의미 |
lw $s3, 4($0) | $s3레지스터에 4번지(4+0=1)에서 가져온 데이터를 저장 |
왜 워드 주소 메모리랑 명령어가 같냐면, 워드 기준이든 바이트 기준이든
데이터를 가져올 때 단위는 워드로 통일이기 때문임
위에 사진에서 4번지는 0000 0004고 데이터는 F2F1AC07 이므로 $s3에 저 데이터가 저장됨
4번지는 워드1번지값 0000 0001 과 같은 데이터인데, 4바이트=1워드이기 때문임
2. store 명령어(sw)
store 소스, 목적지
어셈블리 코드 | 의미 |
sw $t7, 12($0) | $s7레지스터 값을 12번지에 저장 |
위에 사진에서 12번지는 0000 000C이므로 40F30788 있는 곳에 $s7값이 저장된다
데이터를 읽는 방식: 빅 엔디안vs리틀 엔디안
빅 엔디안: 높은 비트에서 낮은 비트 순으로 데이터를 읽음
리틀 엔디안: 낮은 비트에서 높은 비트 순으로 데이터를 읽음
하드웨어에서는 보통 리틀 엔디안을 사용함
예제
$t0의 값이 0x23456789라고 가정한다
아래의 프로그램이 Big-Endian 시스템과 Little-Endian 시스템에서 수행한 후에 $s0의 값은?
sw $t0, 0($0)
lb $s0, 1($0)
sw $t0, 0($s0)은 $t0레지스터 값을 $s0레지스터에 store
lb $s0, 1($s0)은 $s0레지스터 1번 인덱스의 1바이트를 $s0에 load
답
빅 엔디안인 경우 답: $s0=00000045
리틀 엔디안인 경우 답: $s0 = 0x00000067
왜?
빅엔디안이면 높은 비트MSB부터 낮은 비트 LSB로 레지스터에 데이터를 저장하기 때문에
23 45 67 89로 짤려서 들어가게 되고, 1번 인덱스를 가져오면 45를 꺼낸다
리틀엔디안이면 낮은 비트SLB->높은 비트 MSB로 저장하기 때문에 89 67 45 23 순서로 들어가고,
1번 인덱스를 가져오면 67이 나온다
기계어
명령어들의 이진 표현 (0 또는 1)
32비트 명령어
명령어 형태
R-Type (레지스터 타입)
I-Type (즉시값 타입)
J-Type (점프 타입)
1. R-Type
레지스터 타입
rs, rt : source 레지스터
rd : destination 레지스터
op : operation 코드 (op코드. 모든 R-Type명령어의 op코드값은 0이다)
funct : function
shamt : shift 명령어에서 사용되는 shift 양
rs, rt, rd : 3개의 레지스터 피연산자(오퍼랜드)
op, funct, shamt : 그 외
예) 다음과 같은 명령어가 있을 때
add $0, $s1, $s2 (=add rd, rs, rt)
sub $t0, $t3, $t5 (=sub rd, rs, rt)
필드값은 아래처럼 들어간다
R-Type명령어 op코드는 0이고
rd가 목적지, re, rt가 소스니까 한 칸씩 들어가고(레지스터 번호 17번 18번 16번)
shamt는 add연산이라 시프트0번이니까 0
funct는 add를 funct로 표기하면 32, sub를 funct로 표기하면 34
머신 코드로 바꾸면 이렇다
2. I-Type
즉시값(Immediate) 타입
3개의 피연산자(오퍼랜드)
rs,rt: 레지스터 피연산자
imm: 16비트 즉시값(immediate)
다른 필드
op: operation 코드 (op 코드)
각각의 I-type 명령어는 개별적인 op 코드값을 갖음
어셈블리 코드가 아래같이 있다면
addi $s0, $s1, 5
addi $t0, $s3, -12
lw $t2, 32($0) //load
sw $s1, 4($t1) //store
필드값은 이렇다
참고로 add와 addi는 다름
즉시값 immediate라서 뒤에 i가 붙었다
add rd,rs,rt 형태였다면 addi는 addi rt,rs,imm 형태
op 8은 addi 의미
rs, rt는 레지스터 번호
imm은 상수값
머신 코드로 하면 아래처럼
3. J-Type
Jump 타입
1개의 피연산자(오퍼랜드)
addr: 주소 피연산자
다른 필드
op: operation 코드 (op 코드)
분기할 때 썼던 jump명령어랑 비슷함
저장된 프로그램
32비트 명령어와 데이터는 메모리에 저장됨
프로그램 실행 과정
1) 프로그램을 메모리에 저장
2) 메모리에 있는 명령어 순차적으로 읽고 실행
3) 프로그램 카운터PC로 다음에 수행할 명령어 파악
기계어 코드 해석
opcode를 분석하는데
opcode가 0이면 R-type명령어. funct비트로 명령어 기능 분석
opcode가 0이 아니면 I-type이나 J-type 명령어
논리 명령어
and, or, xor, nor
and: 원치 않는 비트를 0으로 만드는 비트 마스킹에 쓰임
or: 두 레지스터의 비트를 결합
nor: 비트들을 역전
andi, ori, xori
and, or, xor에 16비트 즉시값(immediate)의 i가 붙어서, 16비트 즉시값이 피연산자로 포함됨
16비트 즉시값은 32비트로 변환될때, 제로 확장(zero-extended)됨
이동 명령어(시프트 비트연산)
sll: shift left logical
srl: shift right logical
sra: shift right arithmetic
sllv: shift left logical variable
srlv: shift right logical variable
srav: shift right arithmetic variable
조건부 분기-beq
beq A, B, C: A와 B가 같으면 C로 분기한다
s0에 4넣고 s1에 1넣고, sll로 쉬프트 연산해서 s1을 4로 만들고
그 다음에 beq가 나오는데 s0과 s1의 값이 4로 같기 때문에 target으로 분기한다
그 뒤에 addi, sub는 실행되지 않는다
조건부 분기-bne
bne A, B, C: A와 B가 다르면 C로 분기한다
아까랑 같이 s0은 4 s1은 4인 상태
bne를 만났는데 다르지 않으므로 분기하지 않고 계속 진행
addi와 sub명령어까지 실행한다
무조건 분기-j
j A: 무조건 A로 분기한다
j A는 무조건 분기하므로 target으로 바로 감
무조건 분기-jr
jr A: A로 분기한다(A는 주소값)
j와 달리 jr은 레지스터 $s0의 주소값을 바로 분기점으로 잡아주었다
jr을 만나면 0x2010번지인 lw로 분기한다
if문
고급 레벨 코드 | MIPS 어셈블리 코드 |
if (i == j) f = g + h; |
# $s0 = f, $s1 = g, $s2 = h bne $s3, $s4, L1 add $s0, $s1, $s2 L1: sub $s0, $s0, $s3 |
bne=만약 s3과 s4가 같지 않다면 L1으로 분기한다
만약 분기했다면 add명령어는 실행x
if/else문
고급 레벨 코드 | MIPS 어셈블리 코드 |
if (i ==j) f = g + h; |
# $s0 = f, $s1 = g, $s2 = h bne $s3, $s4, L1 add $s0, $s1, $s2 L1: sub $s0, $s0, $s3 |
bne=만약 s3과 s4가 같지 않다면 L1으로 분기하고, 분기했다면 add명령어 실행 안 함
if문에 걸려서 f=g+h;를 실행시키고 나면 else문은 실행하면 안 됨
그 else문 처리를 무조건 분기 j로 처리해 줌
while 반복
고급 레벨 코드 | MIPS 어셈블리 코드 |
// determines the power |
# $s0 = pow, $s1 = x addi $s0, $0, 1 add $s1, $0, $0 addi $t0, $0, 128 # t0은 128 while: beq $s0, $t0, done sll $s0, $s0, 1 addi $s1, $s1, 1 j while done: |
while: beq s0 t0 done
beq는 같으면 분기하는 명령어
즉, s0과 t0이 같으면 done으로 분기하며 반복문 안의 명령어를 패스한다
for 반복
고급 레벨 코드 | MIPS 어셈블리 코드 |
//add the numbers |
# $s0 = i, $s1 = sum |
for: beq s0 t0 done
s0과 t0이 같으면 done으로 분기한다
for문의 i!=10과 같은 의미이다
i=0부분은 add $s0, $0, $0
sum=sum+i 부분은 add $s1, $s1, $s0
i++은 addi $s0, $s0, 1
j for 은 조건을 만족할 때까지 for문을 돌게 한다
less than 비교
고급 레벨 코드 | MIPS 어셈블리 코드 |
//add the powers of 2 |
# $s0 = i, $s1 = sum addi $s1, $0, 0 #sum(s1) 0 addi $s0, $0, 1 #i(s2) 0 addi $t0, $0, 101 #t0=101 loop: slt $t1, $s0, $t0 add $s1, $s1, $s0 sll $s0, $s0, 1 j loop |
for문의 i=0은 addi $s0, $0, 1
loop slt t1 s0 t0에서 slt를 먼저 보면,
slt a,b,c는 s0과 t0을 비교, s0이 더 크면 t0=0이고 아니라 더 작으면 1이다
즉, for문에서 i<101 부분의 비교 연산을 수행하고 있다
sll a,b,c는 b<<c 결과를 a에 저장한다는 의미다
한 마디로 왼쪽 이동으로 2배씩 한다
sll s0,s0,1을 했으니 s0<<1이므로 s0^2라는 말과 같게 된다
연습 문제
1. MIPS 구조에서 레지스터가 많을 수록 데이터를 획득하는 것 보다 빠르다 (O,X)
답: x
레지스터 수가 많으면 레지스터를 뒤지는 데에도 시간이 많이 걸리니까 비효율적이다
32개 레지스터 정도가 가장 빠르다
2. $t0의 값이 0x23456789라고 가정했을 때, 리틀 엔디안의 경우
sw $t0, 0($0)
lb $s0, 3($0)의 결과는?
답: 0x00000023
리틀 엔디안이면 LSB부터 89 67 45 23 순서로 레지스터에 들어가기 때문에(SW명령어)
lb를 하면 3번 인덱스인 23가 나온다
3. R-Type에서 add를 funct로 표기하면 무슨 값인가?
답: 32
add를 funct로 표기하면 32, sub를 funct로 표기하면 34
4. 저장된 프로그램 실행 과정을 알맞게 나열한 것은?
1) 메모리에 있는 명령어 순차적으로 읽고 실행
2) 프로그램 카운터PC로 다음에 수행할 명령어 파악
3) 프로그램을 메모리에 저장
1. 1번-2번-3번
2. 2번-3번-1번
3. 3번-1번-2번
답: 3
1. 프로그램을 메모리에 저장
2. 메모리에 있는 명령어 순차적으로 읽고 실행
3. 프로그램 카운터PC로 다음에 수행할 명령어 파악
5. A와 B가 다르면 분기하는 명령어는?
1) beq
2) bne
3) j
4) jr
답: 2
beq는 같으면 분기
j랑 jr은 무조건 분기
6. for(int i=0;i<i!=10;i++) sum=sum+i; 를 MIPS어셈블리 코드로 하면?
단, 변수 i는 레지스터 $s0, 변수 sum은 레지스터 $s1으로 가정한다
#$s0 = i, $s1 = sum
for: beq $s0, $t0, done
add $s1, $s1, $s0
addi $s0, $s0, 1
j for
7. 다음과 같은 MIPS어셈블리 코드가 있다
# $s0 = i, $s1 = sum
addi $s1, $0, 0 #sum(s1) 0
addi $s0, $0, 1 #i(s2) 0
addi $t0, $0, 101 #t0=101
loop: ( )
beq $t1, $0, done
add $s1, $s1, $s0
sll $s0, $s0, 1
j loop
done:
빈칸에 들어갈 명령어는?
답: slt $t1, $s0, $t0
s0<t0 이면 1, 반대면 0인 for문의 조건식이 들어가는 부분이다
'컴퓨터 구조' 카테고리의 다른 글
리눅스 메모리 구조와 값 할당 (0) | 2020.10.13 |
---|---|
컴퓨터구조-캐시 기억장치 (0) | 2020.06.01 |
컴퓨터 구조-분기 명령어, 서브루틴, 0/1/2/3주소 명령어 (0) | 2020.05.30 |
컴퓨터 구조-메모리 구조와 레지스터 (0) | 2020.05.24 |
컴퓨터구조 -명령어를 효과적으로 실행하기 위한 기법 (0) | 2020.05.24 |