View
7-2. Virtual Machine I : Stack Arithmetic - [밑바닥부터 만드는 컴퓨팅 시스템]
sm_amoled 2019. 12. 1. 10:33구현
추상화된 VM을 구현하는 작업은 두 가지 개념으로 나뉜다.
- 각 데이터구조(스택과 가상메모리 세그먼트)를 구현하여 VM환경을 에뮬레이션 하기
- 각 VM명령들을 대상 플랫폼에서 명령의 의미대로 수행되는 명령어들로 번역하기
이를 위해 아래의 구현 방법을 따를 것이다.
- VM요소와 연산들에서 Hack HW나 기계어로 이어지는 표준 매핑을 정의
- 이를 구현하는 SW설계 가이드라인을 제시
Hack 플랫폼에서의 표준 VM매핑 1부
VM은 플랫폼독립성이 핵심이기 때문에, VM 플랫폼의 아키텍처에 대한 조건이 없었다. 이를 이어나가 모든 HW에서 이 VM이 돌아갈 수 있게 설계를 해보자.
이는 프로그래머가 원하는대로 구현하도록 VM을 설계할 수 있다는 말이기도 하나, VM을 대상 플랫폼에 매핑하는 방법에 대한 가이드라인을 제공하는 것이 일반적인 방법이다. 표준매핑 _standard mapping이라는 가이드라인은 VM을 이용하지 않는 컴파일러가 생성한 프로그램과 VM기반의 프로그램이 통신할 때 지켜야하는 공개규약이 된다. 또, VM 개발자가 표준화된 테스트를 할 수 있게 도와서 여러사람이 테스트 프로그램과 SW를 따로 만들 수 있게 해준다.
이제 Hack에서의 표준 매핑을 정의해보자.
VM에서 Hack으로 번역
VM번역기는 .vm 파일 묶음을 입력으로 받아서 Hack 어셈블리로 된 .asm 파일을 하나 출력한다. VM 명령어들을 어셈블리어로 번역하는 작업을 하며, .vm 파일 내에서의 함수의 순서는 그다지 중요하지 않다.
RAM 사용
Hack의 데이터메모리는 16Bit word로 32K가 구성되어 있다. 첫 16K는 다용도 RAM, 뒤의 16K는 I/O메모리맵이다.
RAM 주소 | 역할 |
0-15 | 16개의 가상 레지스터 |
16-255 | 정적 변수 |
256-2047 | 스택 |
2048-16383 | 힙 |
16384-24575 | 메모리 매핑 I/O |
24576-32767 | 사용하지 않음 |
Hack 기계어 명세에 따르면 0-15의 RAM주소는 R0-R15로 참조가 가능하다. VM구현코드의 가독성을 위해 R0-R4는 우측과 같이 다른 이름을 갖고있다.
레지스터 | 이름 | 사용 방법 |
RAM[0] | SP | 스택포인터 - 스택의 Top + 1의 위치 |
RAM[1] | LCL | 현재 함수의 local segment의 기저주소 |
RAM[2] | ARG | 현재 함수의 argument segment의 기저주소 |
RAM[3] | THIS | 현재 함수의 this segment의 기저주소 |
RAM[4] | THAT | 현재 함수의 that segment의 기저주소 |
RAM[5-12] | temp segment의 내용 저장 | |
RAM[13-15] | 다용도 레지스터 |
메모리 세그먼트 매핑
local argument, this, that은 각각 RAM에 직접 매핑되어 전용 레지스터에 실제 시작주소가 저장된다. 각 세그먼트의 i 번째 항목에 접근하려면 base + i라는 주소로 접근하면 된다. (base는 시작주소의 symbol들)
pointer, temp는 RAM의 고정영역에 바로 매핑된다. pointer는 THIS와 THAT, temp는 R5-R12에 해당한다. 따라서 pointer i에 접근 명령은 RAM 위치 3 + i, temp는 RAM 위치 5 + i에 대응하여 번역된다.
constant는 실제 공간을 차지하지 않는 가상 세그먼트이다. 단순히 상수 i를 제공하여 처리한다.
static은 새로운 기호가 등장하면 어셈블리는 주소 16부터 시작하여 새로운 RAM주소를 기호에 할당한다. XXX.vm에 push static 3라는 명령이 있다면, @XXX.3 -> D = M -> 스택에 D를 Push 하는 방식으로 처리하자.
어셈블리 언어의 기호를 다시 짚어보자.
기호 | 사용법 |
SP LCL ARG THIS THAT | 각각의 담당 가상 세그먼트의 시작주소를 알린다. |
R13-R15 | 다용도로 활용 가능하다. |
Xxx.j 기호들 | Xxx.vm을 번역할 때 정적변수 j는 Xxx.j로 번역된다. 어셈블러가 RAM에 공간을 할당해준다. |
제어흐름 기호들 | function, call, label을 구현할 때 기호가 생긴다. |
VM 구현 설계 제안
VM 번역기는 아래같은 명령줄로 매개변수를 받는다.
prompt> VMTranslator Source
Source는 Xxx.vm인 단일파일이나 .vm파일들이 들어있는 폴더여야 한다. 번역의 결과는 Xxx.asm이라는 어셈블리 파일이며, 입력받은 파일과 같은 폴더에 생성된다.
프로그램의 구조
두 개의 모듈(Parser + CodeWriter)과 메인프로그램으로 VM 번역기를 구현할 수 있다.
Parser 모듈
.vm의 구문분석 처리 및 입력코드에 대한 접근 캡슐화, 공백과 주석 제거를 담당한다.
루틴 | 인수 | 반환 | 기능 |
Constructor | 입력파일/스트림 | - | 입력파일/스트림을 열고 분석을 준비 |
hasMorecommands | - | Boolean | 입력에 명령이 더 있는가? |
advance | - | - | 입력에서 다음 명령을 현재 명령으로 가져온다. hasMoreCommand()가 참일 때 호출 가능. |
commandType | - | C_ARITHMETIC / C_PUSH / C_POP / C_LABEL / C_GOTO / C_IF / C_FUNCTION / C_CALL / C_RETURN | 현재 명령의 Type을 반환. 모든 산술명령에 대해서는 C_ARITHMETIC을 반환. |
arg1 | - | String | 현재 명령의 첫 인수 반환. C_ARITHMETIC의 경우 명령 그 자체를 반환. C_RETURN의 경우 반환하지 않음 |
arg2 | - | Int | 현재 명령의 두번째 인수 반환. C_PUSH, C_POP, C_FUNCTION, C_CALL일 때만 호출 가능 |
CodeWriter 모듈
VM명령을 Hack 어셈블리 코드로 번역한다.
루틴 | 인수 | 반환 | 기능 |
Constructor | 출력파일/스트림 | - | 출력파일/스트림을 열고 기록을 준비 |
setFileName | String(FileName) | - | CodeWriter에게 새로운 번역시작을 알림 |
writeArithmetic | String(Command) | - | 주어진 산술명령을 번역한 코드를 기록 |
writePushPop |
C_PUSH / C_POP(Command) String(Segment) Int(Index) |
- |
주어진 command를 번역한 코드를 기록 ( 여기에서 command는 C_PUSH / C_POP ) |
close | - | - | 출력파일을 닫는다. |
8장에서 더 많은 루틴이 추가될 예정이며, 지금은 이정도만 알아두자! |
메인 프로그램
메인 프로그램은 Parser와 CodeWriter를 생성하고, 각 명령라인을 훑으며 명령에 대한 어셈블리 코드를 생성해야 한다. 여러 개의 .vm파일의 경우(입력이 dir) Parser 여러 개와 CodeWriter 하나를 생성해야 한다.
정리
우리는 2단계 컴파일 모델을 기초로 하여 컴파일러를 설계했다. 10장 - 11장에서 배울 프론트엔드_frontend 단계에서는 고수준코드가 중간코드로 번역되고 이는 VM에서 실행된다. 이 장과 다음 장이 다루는 백엔드_backend 단계에서는 이 중간코드가 HW의 기계어로 번역된다.
중간코드를 VM의 언어로 공식화하는 아이디어는 1970년 후반에 등장한다. 파스칼 컴파일러는 해당 컴파일러가 구현된 컴퓨터면 어디서든 실행 가능한 P-code를 생성했다. 1990년 중에 WWW가 대중화된 후로 크로스플랫폼호환성이 중요해졌다. 이에 sun Microsystems는 인터넷에 연결된 모든 기기에서 실행 가능한 언어인 java를 만들었다. JVM이 중간코드를 실행하는 모델로, JVM은 자바 컴파일러의 목적언이_target language인 bytecode를 구동한다. bytecode로 쓰인 파일들은 적절한 JVM을 탑재한 컴퓨터에서 인터넷상에서 자바코드를 동적으로 배포하는데 사용된다. 자바 런타임 환경은 이 적절한 JVM을 일컬으며, 다양한 프로세서와 OS에 활용된다.
2000년대 초, 마이크로소프트는 .Net Infrastructure를 내세웠다.공용언어런타임이라는 VM모델이 핵심으로, 여러 프로그래밍 언어가 공용언어런타임 위에서 구동되는 중간코드로 번역되어, 다양한 언어로 작성된 코드도 라이브러리를 공유가능케 했다.
VM의 완전운용을 위해 공통 소프트웨어 라이브러리가 필수적이다. (JVM : 표준 자바 라이브러리 / 마이크로소프트 : 공용 언어 런타임) 메모리관리, GUI, 문자열함수, 수학 계산등의 기능을 제공한다. 이에 대해 12장에서 배워보자.
프로젝트
VM 번역기의 첫 부분을 만들어보자- 스택산술명령과 메모리접근명령에 집중할 것. VM to Hack을 만들어보자.
스택산술명령
9개의 스택산술, 논리명령 + push constant x 를 구현하자.
메모리 접근명령
모든 8개의 메모리 세그먼트를 처리하는 Push, Pop을 구현하자.
나중에 인터페이스를 올릴 수 있을 기회가 되면 추가로 포스팅을 할 생각입니당.
'학부생 CS > Elements of Comp-Sys' 카테고리의 다른 글
The Elements of Computing System - Ch.2 PJ (0) | 2020.08.02 |
---|---|
The Elements of Computing System - Ch.1 PJ (0) | 2020.07.26 |
7-1. Virtual Machine I : Stack Arithmetic - [밑바닥부터 만드는 컴퓨팅 시스템] (0) | 2019.11.29 |
6-2. Assembler - [밑바닥부터 만드는 컴퓨팅 시스템] (0) | 2019.11.27 |
6-1. Assembler - [밑바닥부터 만드는 컴퓨팅 시스템] (0) | 2019.11.27 |