📕Binary Numbers
📗숫자들은 모든 base(진수)로 표현 가능하다.
- 123 base 10 = 111011 base 2 ==> base는 몇 진수인지를 뜻함.
📗이진수의 single digit는 컴퓨팅 관점에서 더 이상 쪼갤 수 없다.
- 모든 정보는 binary digits(bit) 로 구성되어 있다.
1011 base 2 -> (1 * 2^3) + (0 * 2^2) + (1 * 2^1) + (1*2^0)
= 8+0+2+1 = 11 base 10
📕MSB & LSB
📗MSB
- most significant bit : most left bit
📗LSB
- least significant bit : most right bit
endian이랑 MSB & LSB를 혼동하면 안됨
💡endian은 byte단위로 데이터를 저장하는 방식이고, MSB & LSB는 bit단위로 저장하는 방식.
31bit의 자리가 MSB이고, 0bit의 자리가 LSB이다
📕Unsigned Numbers
📗RISC-V word is 32-bit long
- 0~2^32 -1까지의 범위를 나타낸다.
- 부호 비트가 없기 때문.
📗32비트 이진수는 비트 값 곱하기 2의 거듭제곱으로 나타낼 수 있습니다.
이러한 양수들을 unsigned numbers라고 부른다.
📕Signed Numbers
📗컴퓨터 프로그램은 양수와 음수를 동시에 계산한다.
- 우리는 음수와 양수를 구별할 수 있는 확실한 기준이 필요하다.
📗구별할 수 있는 방법
- sign and magnitude
- 1's complement (1의 보수)
- 2's complement (2의 보수)
📗최종적 해결방법은 2의 보수 표현 방식
- 32-bit long일 때 표현할 수 있는 범위는 -2^32 ~ 2^31 -1
📗Msb를 sign bit로 지정
1 -> 음수 , 0 -> 양수
📕Negation and Sign Extension
📗숫자를 부정하는 방법
~X + 1 = -X
- "~"는 0은 1로, 1은 0으로 바꾸는 연산자
- e.g) ~(0001) = 1110
📗부호 확장자는 더 많은 bits를 사용해서 숫자들을 표현한다.
- 하지만 숫자적인 value는 보존한다.
📗부호 비트를 왼쪽으로 확장하면서 bit를 확장시킴
- +2 : 0000 0010 -> 양수이므로 남은 자리를 모두 0으로 채움.
- 0000 0000 0000 0010
- -2 : 1111 1110 -> 음수이므로 남은 자리를 모두 1로 채움.
- 1111 1111 1111 1110
- 확장시킬 때 남은 자리를 sing-bit로 채움.
📕Representing Instructions in the Computer
📗인스트럭션들은 machine code라고 불리는 이진수로 인코딩 됩니다.
- 인스트럭션의 숫자 버전이 기계어이다.
📗RISC-V Instructions
- 32-bit instructions words로 인코딩 되는 것이 규칙이다.
- opcode, register numbers
📗Instruction format
- R-type : 산술 및 논리 명령 (immediate를 제외한)
- I-type : 데이터 전송(load), 즉시 연산 (immediate)
- S타입 : 데이터 전송(store)
- incoding 방식이 다르다.
📕R-type Instructions
📗RISC - V R-type instruction format
opcode : 어떤 작업을 하는가를 나타냄.
instruction | Format | funct7 | rs2 | rs1 | funct3 | rd | opcode |
add(add) | R | 0000000 | reg | reg | 000 | reg | 0110011 |
sub(sub) | R | 0100000 | reg | reg | 000 | reg | 0110011 |
📗Example
- add x9, x20 , x21
📕I-type Instructions
📗RISC-V I-type instructions format
Instructions | Format | immediate | rs1 | funct3 | rd | opcode |
addi(add immediate) | I | constant | reg | 000 | reg | 0010011 |
lw(load word) | I | address | reg | 010 | reg | 0000011 |
📗설계 원칙 3
좋은 설계는 좋은 타협을 요구한다.
- 형태가 다르면 디코딩이 복잡해진다 하지만 32-bit 인스트럭션은 균일하게 허락한다.(디코딩인 듯)
- 형식을 가능한 비슷하게 유지한다.
📕S-type Instructions
📗RISC - V S-type Instructions format
Instruction | Format | immediate | rs2 | rs1 | funct3 | immediate | opcode |
sw(store word) | S | address | reg | reg | 010 | address | 010011 |
📗12-bit immediate는 두 개의 field로 분리된다.
- 모든 인스트럭션 형식의 rs1 및 rs2 필드를 동일한 위치에 유지합니다.
- 유사하게 opcode와 funct3 필드는 모든 위치에서 같은 size/place이다.
📕Logical Operations
📗RISC -V는 비트 별 논리적 연산자에 대한 인스트럭션을 제공합니다.
- 논리적 연산자는 word의 bits of groups를 삽입하고 추출하는데 유용하다.
📗Shift 인스트럭션은 word의 모든 비트를 왼쪽이나 오른쪽으로 이동시킬 수 있습니다.
📗sra/ srai
- 오른쪽으로 이동시키고, sign -bit를 채운다
- ex) 1100 0011 -> 1110 0001
- sri는 오른쪽으로만 이동하고 sing-bit를 채우지 않음.
📕AND/OR Instructions
📗AND 인스트럭션은 word의 bit를 mask 하는데 유용하다. [and, andi]
📗OR 인스트럭션은 word의 bit를 include 하는데 유용하다. [or, ori]
📕XOR Instruction
📗XOR 인스트럭션은 differencing operation을 허락한다. [xor, xori]
📗RISC-V에서는 NOT operation은 XOR 인스트럭션으로 구현할 수 있다.
- xor은 bit가 같을 때 0을 , 다를 때는 1을 생성한다.
- 32bit에 0으로 32개를 밀든 1로 32개를 밀든 생성해서 xor연산을 하면 not 연산과 같은 결과가 나온다.
📕Instructions for Making Decison
📗컴퓨터를 단순한 계산기와 구별하는 요소는 결정하는 능력이다.
- 의사 결정은 it문을 사용해서 표현한다.
📗조건이 참일 경우 레이블이 지정된 인스트럭션으로 분기한다.
- 아닐 경우 순서대로 진행
📗Examples
💡beq rs1, rs2, L1
- if(rs1==rs2), branch to instruction labeled L1.
💡bne rs1, rs2, L1
- if(rs1!= rs2), branch to instruction labeled L1.
💻bne와 beq는 conditional branches라고 불린다.
📕Compiling if-then-else into Conditional Branches
📗consider an if-else statement
- if ( i==j ) f=g+h; else f= g-h;
- f, g, h, i and j는 registers x19/20/21/22/23에 각각 상응된다.
📗Compiled RISC - V code
bne x22, x23, Else // go to Else if i!= j
add x19, x20, x21 // f=g+h (skipped if i!= j)
beq x0, x0, Exit // if 0 == 0 , go to exit -> Unconditional branch
Else : sub x19, x20, x21 // f=g-h (skipeend if i == j )
Exit :
📕Compiling a while Loop in C
📗Consider an while statement in C
📗Compiled RISC - V code
Loop : slli x10, x22, 2 // Temp reg x10 = i*4
add x10, x10, x25 // x10 = address of save [i]
lw : x9, 0(x10) // Temp reg x9 = save [i]
bne : x9, x24, Exit // go to Exit if save [i]!= k
addi x22, x22, 1 // i= i+1
beq x0, x0, Loop // goto Loop
Exit :
save 배열은 4byte 배열이기에 인덱스가 한 칸 증가하면 레지스터는 4칸이 증가한 주소를 저장해야 한다.
기존 주소 (x25) + 4칸이 증가한 주소인 x10을 x10에 저장한다.
x9 레지스터에는 x10에 해당하는 데이터인 save [i]를 불러온다.
그리고 while 조건절을 검사한다.
x9에는 save [i]에 대한 값이 있고, k가 들어있는 x24를 비교해서 같지 않다면 Exit로 이동. 아니라면 순차적으로 진행한다.
i에 i +1을 더한 값을 저장하고, 루프로 돌아간다.
📕More Conditional Operators
📗Branch by comparison (blt / bltu and bge/bgeu)
blt rs1, rs2, l1 // less than
- if(rs1 <rs2), branch to instruction labeled L1
bge rs1, rs2, L1 //greater than?
- if(rs1 >= rs2), brnach to instruction labeled L1
📗Signed and unSigned comparison
rs1 11111111 11111111 11111111 11111111
rs2 00000000 00000000 00000000 00000000
💻blt rs1, rs2, L1
- L1으로 이동해라 만약 rs1( -1 ) < rs2 ( 1) ==> TRUE
💻bltu rs1, rs2, L1
- L1으로 이동해라 만약 rs1(2^32-1) < rs2(1) ==> False
즉 blt는 Sign numbers를 비교, bltu는 Unsigned numbers를 다룸!!
📗Case/ Switch
- 분기 주소 테이블(또는 분기 테이블)은 프로그램이 테이블로 인덱스 하고 적절한 순서로 분기해야 하는 것만을 허용한다.
📕Procedure Calls
📗프로시저는 프로그래머가 한 번에 작업의 한 부분을 집중할 수 있게 해 준다.
위 코드와 아래 코드는 같습니다.
📗Caller?
- "calls" the procedure
- procedure를 호출합니다.
📗Arguments
- Data for the procedure
- procedure에 사용되는 데이터입니다.
📗Callee
- The "called" procedure
- 호출당하는 부분입니다.
📗Return
- Data from the procedure
- procedure 호출을 통해서 얻게 된 데이터입니다.
caller는 procedure를 호출합니다.
procedure는 callee입니다.
caller는 callee에게 arguments를 전달합니다.
callee는 결과를 caller에게 리턴합니다.
📕Procedure Execution
📗Program은 procedure 실행 6단계를 반드시 따라야 합니다.
- 프로시저가 매개 변수에 액세스 할 수 있는 위치에 매개 변수 배치
- 제어권을 프로시저로 이동
- 프로시저에 필요한 저장공간을 확보한다.
- 주어진 작업을 수행한다.
- 호출하는 프로그램이 엑서스 할 수 있는 위치에 결괏값을 배치한다.
- 제어권을 프로시저가 호출당했던 위치에 반환한다.
📗PC
- Progrma Counter의 약자
- 현재 인스트럭션의 주소를 의미함.
t는 작업 시작 기준? 그런 의미인 듯.
t단계에서는 procedure(g, h)로 이동을 한다.
t+1 단계에서는 제어권을 프로시저로 옮기고, 필요한 저장공간을 확보
- 여기서 저장공간이란 caller가 넘겨준 g, h를 담아둘 공간
t+2 단계에서는 프로시저의 본문인 작업을 진행한다.
t+3 단계에서는 프로시저의 결괏값을 반환한다.
t+4 단계에서는 t단계에서의 진행이 모두 끝났기에 다음으로 이동한다.
📕Supporting procedures in Computer Hardware
📗RISC - V는 함수 호출을 위해서 9개의 레지스터를 할당합니다.
- x10~x17 : 8개의 매개변수 레지스터 ( 파라미터를 전송하거나 값을 반환할 때 사용되는)
- x10과 x11은 결괏값을 반환하는 데 사용한다.
- x1 : 원점을 반환하기 위한 하나의 반송 주소 레지스터
📗만약 argumetns와 result가 엄청 많다면 레지스터가 모자라지 않을까?
- 그래서 parameter가 일정 개수 이상이면 메모리에 저장된다.
- 메모리에 저장해서 꺼냈다가 넣었다가 하는 작업은 레지스터에 비해서 굉장히 비효율적이기에 우리는 최대한 파라미터의 개수를 적게 사용해서 레지스터에 저장하는 것이 효율적이다.
📗RISC - V는 프로시저만을 위한 인스트럭션을 제공합니다.
- 그것은 주소로 분기하고 동시에 다음 명령의 주소를 목적지 레지스터에 저장합니다.
📗jump-and-link 인스트럭션(jal) for procedure call
jal x1, ProcedureAddress // jump to
ProcedureAdress and write return address to x1
- Jump : 프로시저에게 control을 넘겨준다.
- Link : control이 원점으로 되돌아갈 수 있도록 링크를 만들다.
- 이 링크는 return address라고 불리고, x1 register에 저장된다.
그림을 보면 이해하기 훨씬 수월할 것입니다.
📗RISC - V는 indirect jump를 사용하여 프로시저로부터의 return을 지원합니다.
📗Jump-and-Link register instruction(jalr) for procedure return
jalr x0, 0(x1)
- 레지스터 x1에 저장된 주소로 분기합니다.
- x0을 destination register로 사용한다 그 효과는 return address를 버리는 것이다.
📕Using More Registers
📗프로시저가 8개 이상의 인수와 2개의 반환 값을 사용하는 경우, 추가 인수를 저장하고 값을 반환하기 위해 "메모리"가 필요합니다.
📗프로시저를 실행하려면 레지스터의 수가 제한되어 있기 때문에 호출자의 로컬 값을 메모리로 이동해야 합니다.
- Registers spilling : 레지스터의 값을 메모리에 저장하다
📗Register spilling 하는데 이상적인 데이터 구조는 스택이다.
- Stack은 가장 늦게 들어온 것이 가장 먼저 나간다.
- 분명한 푸시와 팝 동작이 없다.
- Load, Store 인스트럭션은 스탁 안에 있는 메모리에 액세스 할 때 사용된다.
📗Stack은 위에서 아래 주소로 확장된다.
- RISC - V에서 Stack 포인터는 register X2 (named sp)
- 스택 포인터는 저장(즉, 푸시) 및 복원(즉, 팝)된 각 레지스터에 대해 한 단어로 조정됩니다.
- push -> go down, pop -> go up
📕Compiling a Leaf Procedure
📗Compiling a C procedure that doesn't call another procedure
leaf_example :
addi sp, sp , -12 // adjust stack to make room for 3 items
sw x5, 8(sp) // save registers x5 for use afterwards
sw x6, 4(sp) // save registers x6 for use afterwards
sw x20, 0(sp) // save registers x20 for use afterwards
add x5, x10, x11 // regitser x5 contains g+h
add x6, x12, x13 // register x6 contains i+j
sub x20, x5, x6 // f= x5-x6, which is (g+h)-(i+j)
addi x10, x20, 0 // returns f (x10 = x20 + 0)
lw x20, 0 sp) // restore register x20 for caller
lw x6, 4(sp) // restroe register x6 for caller
lw x5, 8(sp) // restore register x5 for caller
addi sp, sp, 12 //adjust stack to delete 3 items
jalr x0, 0(x1) //branch back to calling routine
📕Register Saving Convention
📗값이 사용되지 않는 레지스터를 저장하고 복원하는 것을 방지하기 위해 RISC-V는 레지스터 19개를 두 그룹으로 분리합니다.
📗Caller saved registers
- x5~x7 and x28~x31 : 프로시저 호출에서 callee가 보존하지 않는 임시 레지스터
- Callers는 호출 전에 임시적으로 값을 스택에 저장한다.
- 이러한 레지스터의 내용은 프로시저 호출의 결과로 수정될 수 있습니다.
📗Callee saved registers
- x8~x9 and x18~x27 : 프로시저 호출에 저장해야 하는 레지스터 저장(사용하는 경우 callee가 저장 및 복원)
- Callee는 스택이 사용되기 전에 임시적으로 값을 저장한다.
- Callee는 caller에게 반환하기 전에 그것들은 복구한다.
- 이러한 레지스터의 내용은 프로시저 호출을 통해 보존됩니다.
sw/lw x5 및 x6은 이전 예에서는 필요하지 않지만 sw/lw는 필요합니다. (??)
📕Calling Convention
✔요약
- Sign Numbers and Unsign Numbers
- 각각의 수가 표현할 수 있는 범위가 다름.
- Unsign Numbers
- 0~2^32-1
- Sign Numbers
- - 2^32 ~ 2^31-1
- 음수를 표현하기 위해서는 MSB(31번째 자리)를 sign bit로 할당
- 0이면 양수, 1이면 음수
- 음수를 표현하기 위해서는 2의 보수방식을 채택
- not 연산 후 +1을 더해줌.
- RISC-V에는 인스트럭션 type이 3가지 있다.
- R-type
- I-type
- S-type
- 각각의 쓰임과 인스트럭션을 잘 알아둬야할 듯. (Instruction Format이 다름)
- RISC-V에서는 NOT instructions이 따로 필요하지 않다.
- XOR로 구현 가능함.
- Procedure 각각의 요소에 대해서 알아야 할듯.
- caller
- callee
- arguments
- Return
- 프로시저 실행의 6단계
- RISC - V는 프로시저 호출에 대해서 9개의 레지스터를 할당한다.
- x12 ~ x17 : 매개변수 전송
- x10 ~ x11 : 리턴 값 저장.
- x1 : 원점으로 돌아가기 위한 return address를 저장.
- stack이라는 자료구조는 spilling registers를 하는데 효과적이다.
- high address에서 low address로 확장된다.
- x2는 stack pointer이다.
- push와 pop으로 값을 저장하거나 복구한다.
- RISC-V는 레지스터를 2개의 그룹으로 분리했다.
- Caller
- x5~x7 and x28~x31 : temporary register
- Callee
- x8~x9 and x18~x27 : save register
- Caller
'Computer Science > Computer Architecture' 카테고리의 다른 글
[computer archiecture] - arithmetic_for_computers(1) (0) | 2022.10.19 |
---|---|
[computer architecture]-instruction_language_of_computer(3) (0) | 2022.10.11 |
[computer architecture] - instructions- language_of_computer(1) (1) | 2022.10.08 |
[computer architecture] -Computer Abstractions and Technology (2) (0) | 2022.09.29 |
[Computer architecture] - Computer Abstractions and Technology (1) (2) | 2022.09.22 |