시냅스

명령어: 컴퓨터 언어 본문

컴퓨터구조

명령어: 컴퓨터 언어

ted k 2022. 7. 2. 21:00

명령어

  • 하드웨어가 알아들을 수 있는 언어
  • 그 어휘를 명령어 집합이라고 한다.
  • MIPS
  • cf) 내장 프로그래밍 개념 : 여러 종류의 데이터와 명령어를 메모리에 숫자로 저장할 수 있다는 개념.

 

하드웨어 연산

  • MIPS 산술 명령어는 반드시 한 종류의 연산만을 지시한다.
  • 항상 변수 세 개를 갖는 형식을 엄격히 지킨다.
  • 아래는 MIPS 어셈블리어를 통한 덧셈 명령어 예시이다.
    add a, b, c # b와 c의 합이 a에 자리한다.
    add a, a, d # b, c, 와 d의 합이 a에 들어간다.
    add a, a, e # b, c, d, e의 합이 a에 들어간다.
  • 명령어가 피연산자를 반드시 세 개씩 갖도록 제한하는 것은 하드웨어를 단순하게 하자는 원칙과 부합한다.
  • 피연산자의 개수가 가변적이면 하드웨어가 복잡해진다.

 

피연산자

  • 피연산자는 레지스터라고 하는 하드웨어로 직접 구현된 특수 위치 몇 곳에 있는 것만들 사용할 수 있다.
  • MIPS 구조에서 레지스터의 크기는 32비트이다.
  • 32비트가 한 덩어리로 처리되는 것을 워드 (word) 라고 부른다.
  • 레지스터의 개수는 제한되어 있고, 현대 컴퓨터는 MIPS에서처럼 32개이다.
  • 32개로 제한하는 이유는 작은 것이 더 빠르다는 하드웨어 설계 원칙과 부합한다.

 

메모리 피연산자

  • 배열이나 구조체 같은 자료구조는 메모리에 보관한다.
  • MIPS의 산술연산은 레지스터에서만 실행되므로 데이터 전송명령어라고 하는 메모리와 레지스터 간에 데이터를 주고받는 명령어가 있어야 한다.
  • 메모리에 기억된 데이터 워드에 접근하려면 명령어가 메모리 주소를 지정해야 한다.
  • 메모리 주소가 인덱스 역할을 하는 큰 일차원 배열이다.

  • 적재 (load) : 메모리에서 레지스터로 데이터를 복사해 오는 데이터 전송 명령
    • 연산자 이름과 메모리에서 읽어 온 값을 저장할 레지스터
    • 메모리 접근에 사용할 상수와 레지스터
    • 로 구성된다.
    • 실제 명령어 이름은 lw(load word)이다.
  • 메모리 주소가 4씩 차이나는 것은, word가 32비트 -> 4바이트 이기 때문이다.
  • 이런 특성을 정렬제약 이라고 부른다.
    • 정령제약은 메모리 내에서 데이터는 자연스러운 경계를 지켜서 정렬되어야 한다는 요구 조건.
  • 컴퓨터는 제일 왼쪽(최상위)에 저장하는 big end, 제일 오른쪽(최하위) little end로 나뉜다.
    • MIPS는 big-endian 에 속한다.
  • 적재와 반대로 레지스터에서 메모리로 데이터를 보내는 명령을 저장 (store) 라고 한다.
  • 저장 명령의 생김새는 적재와 같다.
  • 실제 이름은 SW(sotre word) 이다.

 

상수 또는 수치 피연산자

  • MIPS 산술 명령의 절반 이상이 상수를 피연산자로 사용할 수 있다.
  • lw $t0, AddrConstant4($s1) # $t0 = constatn 4 add $s3, $s4, $t0 # $s3 = $s3 + $t0 ($t0 == 4)
  • $s1 + AddrConstant4 는 상수 4가 저장되어 있는 메모리 주소라고 가정한다.
  • 아래는 적재 명령을 사용하지 않는 방법이다.
addi $s3, $s3, 4 # $s3 = $s3 + 4
  • 위의 상수(4)를 수치(immediate) 피연산자 라고 한다.

 

부호있는 수와 부호없는 수

  • 모든 정보는 이진 자리 수로 구성된다.
  • 비트에 해당하는 기수의 멱수(power)를 번호로 사용하는 것이다.
    • (1 x 2^3) + (0 x 2^2) + (1 x 2^1) + (1 x 2^0) = 11
  • LSB(least significant bit) : MIPS 워드의 가장 오른쪽 비트
  • MSB(most significant bit) : MIPS 워드에서 가장 왼쪽 비트
  • 보통 앞의 0들은 표시하지 않는다.
  • 2의 보수 : MSB인 부호 비트 0 -> 양수, 부호 비트 1 -> 음수
    • 레지스터의 남는 공간은 부호에 따라 1로 채우거나 0으로 채운다
      • 부호 확장 (sign extension) 이라고 부른다.
      • 레지스터 내부에 정확한 값을 적재하기 위함이다.
  • 1의 보수법
    • 절대값이 가장 작은 음수를 10...00two , 가장 큰 양수를 01...11two, 같은 개수의 양수와 음수를 나타내는 표현 방법이다.
    • 1의 보수 덧셈기는 맨 끝의 올림수를 처리하기 위해 한 단계를 필요로 하여 2의 보수법이 가장 널리 사용되고 있다.
  • 바이어스된 표현법
    • 가장 큰 음수 00...00로 표현하고 가장 큰 양수 11...11 로 표현하며 0은 10..00 로 표현하는 방식이다.
    • 숫자에 바이어스 값을 더하여 항상 양수로 표현하기 때문에 바이어스된 표현법 이라고 부른다.

 

명령어의 컴퓨터 내부 표현

  • MIPS 레지스터
    • $s0 ~ $7 : 16번에서 23번
    • $t0 ~ $t7 : 8번에서 15번
  • MIPS 어셈블리어 add $t0, $s1, $s2 를 십진수, 이진수 기계어로 표현

  • 처음과 마지막 (0과 32)는 컴퓨터에게 덧셈을 하라고 지시하는 부분이다.
  • 두번째 필드는 덧셈에 사용할 첫 번째 피연산자 레지스터 번호 (17 = $s1) 이다.
  • 세 번째 필드는 두 번째 피연산자 레지스터 번호 (18=$s2) 이다.
  • 네 번째 필드는 계산 결과가 들어갈 레지스터 번호 (8=$t0) 이다.
  • 위와 같은 표현을 명령어 형식(instruction format) 이라고 한다.
  • 어셈블리 언어와 구별하기 위하여 명령어를 숫자로 표현한 것을 기계어 (machine language) 라고 한다.
    • 기계어 : 컴퓨터 시스템 내에서 사용하는 명령어의 이진수 표현

 

명령어의 필드

  • op : 명령어가 실행할 연산의 종류로서 연산자(opcode)라고 부른다.
  • rs : 첫 번째 근원지(source) 피연산자 레지스터.
  • rt : 두 번째 근원지(source) 피연산자 레지스터
  • rd : 목적지(destination) 레지스터. 연산 결과가 기억된다.
  • shamt : 자리이동(shift)
  • funct : 기능 (function) op 필드에서 연산의 종류를 표시하고 funct 필드에서는 그중의 한 연산을 구체적으로 지정한다. 기능 코드(function code)라고 부르기도 한다.
  • 모든 명령어의 길이를 같게 하되, 명령어 종류에 따라 형식은 다르게 한다.

 

논리연산 명령어

  • sll (shift left logical)
  • srl (shift right logical)
  • AND
    • and 연산을 하면서 감추고픈 자리에 0을 대입하면 bit mask 연산이 된다.
  • NOT : 1 -> 0, 0 -> 1
    • NOR : OR 한 값을 다시 NOT

 

판단을 위한 명령어

분기문

beq register1, register2, L1 # 1과 2의 값이 같으면 L1에 가라는 뜻, (branch if equal)
bne register1, register2, L1 # 1과 2의 값이 같지 않으면 L1에 가라는 뜻, (branch if not equal)

 

순환문

while (save[i] == k)
	i += 1;

를 MIPS 어셈블리 코드로 보이면

Loop: sll $t1, $s3, 2 # 더할 자리를 만들어준다. Temp reg $t1 = i * 4
add $t1,$t1,$s6 # t1 = address of save[i]
lw $t0,0($t1) #temp reg $t0 = save[i]
bne $t0,$s5, Exit # go to Exit if save[i] != k
addi $s3, $s3, 1 # i = i + 1
j Loop $ go to Loop # go to Loop
Exit

 

비교

  • slt (set on less than), slti (set on less than immediate)
    • 첫 번째  근원지 레지스터 값이 두 번째 근원지 레지스터의 값보다 작으면 목적지 레지스터 값을 1로, 아니면 0으로
    • 부호가 있는 정수 비교
  • sltu (set on less than unsigned), sltiu (set on less than immediate unsigned)
    • slt와 같지만, 부호가 없는 정수 비교
  • case/switch를 구현하는 가장 간단한 방법은 if-then-else로 바꾸는 것
    • 점프 주소 테이블(jump address table)로 코드의 시작 주소를 표로 만든다.
    • 점프 주소 테이블의 인덱스만 계산해서 해당 루틴으로 점프할 수 있다.
    • jr(jump register) 명령어를 통해 레지스터의 주소를 사용하여 점프한다.

 

하드웨어의 프로시저 지원

  • 프로시저 (procedure) 나 함수는 이해하기 쉽고 재사용이 가능하도록 프로그램을 조화하는 방법.
  • 프로시저는 프로그래머가 한 번에 한 부분씩 집중해서 처리할 수 있게 해준다.
  • 프로시저는 소프트웨어에서 추상화를 구현하는 방법이다.
  • 프로시저는 아래 6 단계를 거친다.
    • 프로시저가 접근할 수 있는 곳에 인수를 넣는다.
    • 프로시저로 제어를 넘긴다.
    • 프로시저가 필요로 하는 메모리 자원을 획득한다.
    • 필요한 작업을 수행한다.
    • 호출한 프로그램이 접근할 수 있는 장소에 결과 값을 넣는다.
    • 프로시저는 프로그램 내의 여러 곳에서 호출될 수 있으므로 원래ㅔ 위치로 제어를 돌려준다.
  • $a0 - $a3 : 전닳할 인수를 가지고 있는 인수 레지스터 4개
  • $v0-$v1 : 반환되는 값을 갖게 되는 값 레지스터 2개
  • $ra : 호출한 곳으로 되돌아가기 위한 복귀 주소를 가지고 있는 레지스터 1개
  • jal 명령어 (jump-and-link instruction) 를 통해 이동한다.
jal ProcedureAddress
jr $ra # 복귀 주소
  • 호출 프로그램(caller)은 $a0-$a3에 전달할 인수 값을 넣은 후 jal X 명령을 이용해서 프로시저 X (피호출 프로그램(callee))로 점프한다. 이후 계산을 끝내 결과를 $v0-$v1에 넣은 후 jr $ra 명령을 실행하여 복귀한다.
  • 현재 수행 중인 명령어의 주소를 기억하는 레지스터는 프로그램 카운터(program counter) 라고 부른다.

 

더 많은 레지스터의 사용

  • 인수 레지스터 4개, 결과 값 레지스터 2개가 부족한 경우
  • 레지스터 스필링을 사용한다.
    • 스택을 사용하여 스택 포인터를 통해 가장 최근에 스택에 할당된 주소를 가리킨다.
    • 스택 포인터는 레지스터 값 하나가 스택에 저장되거나 스택에서 복구될 때마다 한 워드씩 조정된다.
  • 다른 프로시저를 호출하지 않는 프로시저를 말단(leaf) 프로시저 라고 부른다.
  • 재귀(recursive) 프로시저도 있다.

새 데이터를 위한 스택 공간의 할당

  • 스택은 지역변수, 프로시저의 저장된 레시스터 또한 가지고 있다.
  • 이 영역을 프로시저 프레임(procedure frame) 또는 액티베이션 레코드 (activation record)라고 부른다.
  • 프레임 포인터 (frame pointer $fp)가 프로시저 프레임의 첫 번째 워드를 가리키도록 한다.
  • 프레임 포인터가 베이스 레지스터 역할을 하므로 지역 변수 참조가 간단해진다.

 

새 데이터를 위한 힙 공간의 할당

코드가 최하단, 스택이 최상단이다.

  • 동적 자료구조를 위한 메모리 공간
  • 최하위인 코드 세그먼트(== text segment)에는 기계어로 번역된 소스 코드가 들어간다.
  • 그 위로 정적 데이터 영역(static data segment)에는 상수, 기타 정적 변수들이 들어간다.
    • 크기가 고정되어 있어 잘 맞는다.
  • 링크드 리스트와 같은 가변적인 자료구조를 위해 힙 영역(heap segment)이 필요하고 데이터 영역 다음에 들어간다.
    • heap 영역을 필요에 따라 할당하기도, 반납하기도 한다.
    • malloc으로 할당한 후 이 공간을 가리키는 포인터를 결과 값으로 보내고, free로 공간을 반납한다.
    • 공간을 너무 일찍 반납하면 의도와 상관 없는 공간을 가리키는 dangling pointer 가 발생한다.
  • 스택 영역 (stack segment)에는 지역 변수, 매개 변수 등이 들어간다.

  • $zero : 0
  • $a0 ~ $a3 : 함수의 파라미터(argument)로 사용되는 register
    • 만약 인수가 4개를 초과하면, 프레임 포인터 위 스택에 넣고, 처음 네 인수가 $a0-$a3에 있고 나머지는 프레임 포인터를 통해 접근할 수 있는 메모리에 있다고 생각한다.
  • $v0 ~ $v1 : 함수의 return 값(value)로 사용되는 register
  • $t0 ~ $t9 : temporary register. procedure에서 값을 보존(preserve)할 필요가 없는 register.
  • $s0 ~ $s7 : saved register. procedure에서 값을 보존(preserve)해줘야 하는 register
nested procedure(함수내에서 또 다른 함수가 호출되는 procedure)에서 혹은 같은 프로세스 내 다른 thread에서, 함수안의 또 다른 함수에서 preseved regiter를 호출할지라도 그 값이 덮여쓰이지 않도록 그 값을 저장하고 복원해야함을 의미한다. 하지만 temporary register은 그럴 필요가 없다.
  • $gp : global pointer. 상수와 같은 static data의 access를 위해 사용된다.
  • $sp : stack pointer. stack의 현재 pointer를 가리키는 register.
  • $fp : frame pointer. stack의 맨 첫번째 item을 가리키는 pointer.
  • $ra : 주로 jr 명령어와 함께 쓰인다. nested procedure에서 또 다른 함수가 호출되고 끝났을때 처음 호출된 함수가 진행되던 부분으로 돌아가야할텐데, 그 위치를 저장하는 register.

Stack과 Heap

  • Stack : 함수 호출시 생성되는 지역, 매개변수들이 저장된다. 컴파일시 그 크기가 결정되며, 위에서 아래로 크기가 커진다.
  • Heap : dynamic data가 저장되는 공간. 동적할당 시 사용된다. Run time에 그 크기가 결정되며, 아래서 위로 크기가 커진다.
  • 만약 함수 내에서 다른 함수가 호출되는 경우 값이 덮여 쓰이는 것을 방지하기 위해 원래의 값을 Stack 에 저장한 뒤 함수가 종료되면 다시 값을 복원한다.

  • Stack은 위에서 아래로 커지는 구조이다.
  • $fp는 stack의 첫 번째 오프셋을 가리키는 포인터
  • $sp는 stack의 현재 오프셋을 가리키는 포인터
    • 헷갈리지만 sp가 head...

  • Function1 안에 Function2가 들어있다.
  • ra, a0을 저장해두고
  • f2가 끝난 후 ra로 f1으로 복귀하고
  • lw를 통해 a0과 ra를 복구한다.

 

MIPS의 32비트 수치를 위한 주소지정 및 복잡한 주소지정 방식

  • 16비트보다 더 큰 상수를 필요로 하는 경우 MIPS는 레지스터의 상위 16비트에 상수를 넣는 lui(load upper immediate)를 제공한다.
  • 몇 조각으로 나눈 후 레지스터에서 재조립하는 방식

 

분기와 점프 명령에서의 주소지정

  • 위는 J 명령을 통해 10000으로 이동하라는 J 타입 명령어 형식이다.
  • 아래는 opcode 2 = j , 10000 = target address 인 어셈블리어이다.

  • 각각 명령에 대한 형식표이다.
  • PC = 레지스터 + 분기주소
    • PC + 4(다음 실행할 라인)
    • PC 상대 주소지정(PC-relative addressing)
  • MIPS 주소지정 방식 요약
    • 수치(immediate) 주소지정 : 피연산자는 명령어 내에 있는 상수이다.
    • 레지스터 주소지정 : 피연산자는 레지스터이다.
    • 베이스(base) 또는 변위(displavement) 주소지정 : 메모리 내용이 피연산자이다. 메모리 주소는 레지스터와 명령어 내의 상수를 더해서 구한다.
    • PC 상대 주소지정 : PC 값과 명령어 내 상수의 합을 더해서 주소를 구한다.
    • 의사직접(pseudodirect) 주소지정 : 명령어 내의 26비트를 PC의 상위 비트들과 연접하여 점프 주소를 구한다.

 

'컴퓨터구조' 카테고리의 다른 글

컴퓨터구조 기억장치의 분류와 특성  (0) 2022.08.05
CPU의 구조와 기능  (0) 2022.08.02
ARM (Adavanced RISC Machine) 이란?  (0) 2022.07.17
컴퓨터 구조 기초  (0) 2022.07.10
컴퓨터 추상화 및 관련 기술  (0) 2022.06.13
Comments