일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
- 마운트
- dff
- 필수 스크립트
- 메모리 세그먼트
- 온라인 ddl
- nandtotetris
- 운용 시 유용한 쿼리
- s3
- 밑바닥부터 만드는 운영체제
- MySQL
- performance스키마
- InnoDB
- 스택머신
- 핵기계어
- 밑바닥부터 구현하는 컴퓨팅 시스템
- 안전하게 테이블 변경
- 구문 분석
- vm머신
- 컴퓨터 아키텍쳐
- 어뎁티브 해시 인덱스
- vm번역기
- innodb 버퍼풀
- innodb구조
- ec2
- 리눅스
- 핵심 데이터 모델링
- Terraform
- jack 문법
- 밑바닥부터 만드는 컴퓨팅 시스템
- 도커
- Today
- Total
이것이 점프 투 공작소
NandToTetris : 어셈블러 (밑바닥부터 만드는 컴퓨팅 시스템) (어셈블러 구현 X) 본문
해당 장 과제인 어셈블러 구현은
고수준 프로그래밍 언어로 구현하기에 포스팅에서 생략합니다!
어셈블러
모든 컴퓨터에는 명령어가 0과 1의 연속으로 작성되는 이진 기계어와 인간이 이해하기 쉬운 표현을 사용하여 명령어를 표현하는 어셈블리 언어가 있습니다.
두 언어 모두 정확히 동일한 작업을 수행하며 완전히 동등합니다.
하지만 어셈블리로 프로그램을 작성하는 것이 바이너리로 작성하는 것보다 훨씬 쉽고 안전합니다.
이러한 이점을 누리기 위해서는 누군가 심볼릭 프로그램을 컴퓨터에서 그대로 실행할 수 있는 바이너리 코드로 번역해 주어야 합니다.
이 번역 서비스를 어셈블러가 수행합니다.
어셈블리어는 2진 코드와 직접 대응되므로, 어셈블러를 구현하는 일은 그렇게 어렵지 않습니다.
다만 어셈블리 프로그램에서 메모리 주소를 기호로 참조하는 기능이 필요합니다.
이 기능은 기호 테이블(symbol table)이라는 일반적인 데이터 구조로 구현됩니다.
배경
기계어는 보통 두 가지 형식, 즉 기호와 2진 형식으로 정의됩니다.
예를들어 2진 명령어가 앞에 8개 비트는 load, 뒤에 8가 bit는 레지스터 R3을 나머지는 7을 나타낸다고 할때
각각의 의미들을 load, R3, 7과 같이 작성하면 자연스러울 것 입니다.
여기서 load같은 연산코드는 연상 기호라 부릅니다.
이러한 기호언어는 어셈블리, 어셈블리를 기계어로 변역하는 도구는 어셈블러라고 합니다.
기호
1. 레이블 : 어셈블리 프로그램은 코드 내 위치를 표시하기 위해 기호를 정의하고 사용합니다. (ex : LOPP, END)
2. 변수 : 어셈블리 프로그램은 기호 변수를 정의하고 사용할 수 있습니다. (ex : i, sum)
3. 선언 기호 : 어셈블리 프로그램은 미리 선언된 기호를 사용해서 컴퓨터 메모리 내의 특정 주소를 참조할 수 있습니다. (ex : SCREEN, KBD)
모든 기호들은 결국 각각 어떤 다른 주소를 의미하게됩니다.
이러한 기호들을 처리하는 작업들이 어셈들러에서 가장 중요한 기능입니다.
주석 및 레이블 선언은 아무런 코드도 생성하지 않습니다.
그 때문에 레이블 선언이 의사 명령어 (pseudo-instruction)이라고도 합니다.
핵 기계어 명세
어셈블리 핵 프로그램은 각 라인은 어셈블리 명령어, 레이블 선언 및 주석으로 되어있습니다.
- 어셈블리 명령어 : 기호 A명령어 또는 기호 C명령어
- 레이블 선언 : (xxx) 형식의 라인, xxx는 기호
- 주석 : 두 개의 빗금(//)으로 시작되는 라인
기호
선언기호, 레이블 기호, 변수 기호로 나뉩니다.
선언 기호
기호들의 값은 핵 RAM의 주소로 해석됩니다.
- R0, R1, ... , R15는 각각 0, 1, ... , 15 를 가리킵니다.
- Sp, LCL, ARG, THIS, THAT 은 각각 0,1,2,3,4 를 나타냅니다.
- SCREEN, KBD는 각각 16384와 24576를 나타냅니다.
레이블 기호
의사명령어(xxx)는 프로그램의 다음 명령어를 저장하고 있는 ROM의 주소를 기호 xxx가 참조하도록 정의합니다.
변수 기호
기호 xxx가 선언기호가 아니거나, 레이블 선언으로 정의되지 않은 경우에는 변수로 취급됩니다.
변수는 등장한 순서대로 RAM주소 16에서 시작하는 RAM위치에 차례대로 매핑됩니다.
어셈블리-2진 코드 번역
어셈블러는 어셈블리 명령어 마다 다음을 수행합니다.
- 명령어의 필드들을 파싱한다.
- 각 필드마다 그에 대응하는 비트코드를 생성한다.
- 명령어에 참조 기호가 있으면, 그 기호를 숫자 값으로 해석한다.
- 생성된 비트 코드들을 조립하며 16개의 0 또는 1로 이루어진 문자열로 만든다.
- 조립된 문자열을 출력 파일에 기록한다.
기호 처리
어셈블리 프로그램에서는 기호 레이블을, 그 기호가 정의된 라인 앞부분에서도 사용 할 수 있습니다.
이를 코드를 처음부터 끝까지 두번 읽는 2패스 어셈블러로 구현합니다.
어셈블러가 1차로 코드를 읽을 때는 기호 테이블을 만들고, 레이블 기호들을 모두 테이블에 기록하며 아무런 코드도 생성하지 않습니다.
2차로 코드를 읽을 때 앞에서 만든 기호 테이블을 활용하여 변수 기호들을 처리하고 2진 코드를 생성합니다.
자세한 내용은 아래와 같습니다.
초기화
어셈블러는 기호 테이블을 만들고, 선언 기호와 그 기호에 할당된 값들로 테이블을 초기화합니다.
1 패스
어셈블러는 줄 번호를 추적하면서 한 줄씩 전체 어셈블리 프로그램을 훑는다.
이 줄 번호는 0에서 시작하며 A-명령어나 C-명령어를 만날 때 마다 그 값을 1씩 증가시키며,
주석이나 레이블 선언이 나오면 값을 그대로 둡니다.
어셈블러는 레이블 선언 (xxx)가 나올 때 마다 기호 테이블에 새 항목을 추가하고,
기호 xxx에 현재 줄 번호 + 1 값을 연결시킵니다. (ROM의 주소가 된다.)
1 패스가 끝나면 프로그램의 모든 레이블 기호가 그에 대응하는 값과 함께 기호 테이블에 추가됩니다.
2 패스
어셈블러는 전체 프로그램을 다시 훑으며 각 라인을 다음과 같이 파싱합니다.
먼저 기호가 있는 A명령어 (@xxx에서 xxx가 기호)를 만날 때 마다, 기호 테이블에서 xxx를 조사하고
테이블에 그 기호가 있으면 어셈블러는 그 기호를 대응하는 숫자값으로 교체하고 해당 명령어를 번역합니다.
없으면 그 기호는 새 변수라는 뜻이므로, 어셈블러는 기호 테이블에 <xxx, value> 항목을 추가하는데,
여기서 value는 변수를 위해 RAM 공간 내에서 다음 번으로 사용 가능한 주소를 뜻합니다.
그리고 이 주소를 이용하여 해당 명령어의 번역을 완료합니다.
변수를 저장하기 위해 지정된 RAM 공간의 주소는 16부터 시작하며,
코드에 새 변수가 나타날 때 마다 1씩 증가합니다.
'NandToTetris' 카테고리의 다른 글
NandToTetris : 가상머신2-제어 (밑바닥부터 만드는 컴퓨팅 시스템) (0) | 2025.02.26 |
---|---|
NandToTetris : 가상머신1-프로세싱 (밑바닥부터 만드는 컴퓨팅 시스템) (0) | 2025.02.19 |
NandToTetris-Hardware simulator / 컴퓨터 아키텍쳐 (밑바닥부터 만드는 컴퓨팅 시스템) (0) | 2025.02.13 |
NandToTetris-Hardware simulator / 기계어 (밑바닥부터 만드는 컴퓨팅 시스템) (0) | 2025.02.05 |
NandToTetris-Hardware simulator / 레지스터, 메모리, PC 실습 (밑바닥부터 만드는 컴퓨팅 시스템) (0) | 2025.01.30 |