View

300x250

이 글은 insight 출판사의 [밑바닥부터 만드는 컴퓨팅 시스템 / The Elements of Computing System]이라는 책에 있는 프로젝트(과제) 를 수행하는 글입니다.
과제 수행을 위한 언어로 C#을 선택했지만, Java와 거의 유사하여 Java를 알면 쉽게 이해할만한 코드들이예요.


Chapter 4. 기계어 - Project

Chapter 4의 프로젝트에서는 무언가를 설계하고 만들지는 않는다. Hack 언어로 간단한 프로그램을 작성해보는 과제를 해결해보면서 컴퓨터 플랫폼과 Hack언어, 기계어에 친해지는게 목적이다. 추후에 어셈블러, 컴파일러 등을 만들 때 Hack 언어와 동작에 대한 이해가 필요하므로 과제를 잘 수행해보자.

 

이번 과제를 해결하기 위해서는 교재에서 주는 도구가 필요합니다.
https://www.nand2tetris.org/software < 다운로드 링크
원래 사지방에서 Linux만 쓸 수 있었어서 이걸 못스고 있었었는데,
얼마전에 Windows가 들어와서 쓸 수 있게 되었어요.
그래도 C#으로 필요한 시스템과 체계를 계속 만들어보고 싶은데, 할 수 있는 만큼은 계속 만들어볼게요!

 

1. 곱셈 프로그램 (Mult.asm)

R0, R1에 있는 두 값을 곱한 값을 R2에 저장하는 프로그램을 작성해보자. 

 

우리가 쓰는 Hack 명령어는 곱셈과 같은 복잡한 명령어를 지원하지 않기 때문에, 덧셈과 반복문으로 곱셈을 구현해주어야 한다. R0를 변수로 가져와 반복문마다 -1을 하고, R0가 0이 될 때 까지 SUM에 R1을 더하는 것을 반복하여 곱셈 프로그램을 만들어주었다. @XXX 명령어를 사용했을 때, 예약되어있거나 이미 한번 선언된 값의 경우 해당 메모리주소를 가리키고, 처음 쓰는 경우에는 새로운 메모리주소를 가리키는 것에 익숙해지자. @XXX를 사용하면 그 메모리주소는 A 레지스터에 저장되며, 메모리에 있는 데이터는 M으로 접근할 수 있다. D는 단순한 데이터 레지스터로 사용한다.  

	@R0		// 변수 선언
	D=M
	@I
	M=D		// I에 R0의 값을 대입
	@SUM
	M=0		// SUM에 0을 대입

(LOOP)
	@R1
	D=M
	@SUM
	M=D+M	// R1을 SUM에 더함

	@I
	M=M-1	// I--
	D=M
	@END
	D;JLE	// (I <= 0) 이면 END

	@LOOP	
	0;JMP	// 아니면 LOOP

(END)
	@SUM	
	D=M
	@R2	
	M=D		// R2에 SUM의 값 대입

이 프로그램을 어셈블러를 이용해 기계어로 번역하면 아래와 같은 코드를 얻을 수 있다.

0000000000000000
1111110000010000
0000000000010000
1110001100001000
0000000000010001
1110101010001000
0000000000000001
1111110000010000
0000000000010001
1111000010001000
0000000000010000
1111110010001000
1111110000010000
0000000000010001
1110001100000110
0000000000000110
1110101010000111
0000000000010001
1111110000010000
0000000000000010
1110001100001000

이 기계어를 제공되는 CPU Emulator로 작동시키면 아래와 같은 결과를 얻을 수 있다. 아래 예시에서 R0에 3, R1에 5를 넣고 돌린 프로그램의 결과로 R2에 3x5인 15가 들어간 것을 확인할 수 있다.

왼쪽이 실행 전, 오른쪽이 실행 후

 

2. I/O 조작 프로그램 (Fill.asm)

키보드의 입력이 있을 때는 검은색을 화면에 기록하고, 입력이 없을 때는 공백을 기록하는 프로그램을 만들어보자. 

 

반복문으로 입력이 있을 때까지 기다리면서 공백을 기록하다가, KBD에서 입력이 들어오면 검은 색을 기록하는 프로그램이다. SCREEN의 주소는 0x4000~0x5FFF, KBD의 주소는 0x6000로 메모리매핑이 되어있음을 이용하면 된다. R0에 스크린주소, R1에 키보드 주소를 저장하여 R0을 순서대로 +1 하다가 KBD와 같아졌을 때 다시 0x4000으로 돌아가서 똑같이 반복하도록 프로그램을 짜주어 구현하였다. 

	@KBD
	D=A
	@R1
	M=D			// KBD의 주소를 R1에 저장

(RESET)
	@SCREEN
	D=A-1
	@R0
	M=D			// SCREEN - 1 을 R0에 저장 (RESET)
    			// KBDINPUT에서 R0를 +1 하기 때문에 SCREEN부터 시작한다

	@KBDINPUT
	0;JMP		// KBD INPUT으로 JMP

(FILL)
	@0			// A 레지스터에 0 대입 후 -1
	D = !A		// D = 1111 1111 1111 1111
	@R0
	A=M
	M=D			// R0가 가진 주소에 (-1)을 넣는다

(KBDINPUT)
	@R0
	M=M+1		// R0레지스터에 +1 (주소 증가)
	@R1
	D=M			// KBD주소 D로 가져오기
	@R0
	D=D-M		
	@RESET		// R0이 0x6000 이 되었을 때 RESET한다.
	D;JLE		// KBD - R0(스크린주소) <= 0 이면(RESET)으로 JMP 

	@R0
	A=M
	M=0			// SCREEN에 0 넣기 (채워져 있으면 지우고)

	@KBD
	D=M
	@FILL
	D;JNE		// KBD에서 가져온 값이 0이 아니라면 SCREENFILL

	@KBDINPUT
	0;JMP

위 코드를 어셈블러로 기계어로 번역하면 아래 2진 코드를 얻을 수 있다.

0110000000000000
1110110000010000
0000000000000001
1110001100001000
0100000000000000
1110110010010000
0000000000000000
1110001100001000
0000000000001111
1110101010000111
0000000000000000
1110110001010000
0000000000000000
1111110000100000
1110001100001000
0000000000000000
1111110111001000
0000000000000001
1111110000010000
0000000000000000
1111010011010000
0000000000000100
1110001100000110
0000000000000000
1111110000100000
1110101010001000
0110000000000000
1111110000010000
0000000000001010
1110001100000101
0000000000001111
1110101010000111

이 프로그램을 실행한 결과는 아래와 같다.

키보드에서 값을 받아올 때는 화면에 검은 줄이 생기고, 받아오지 않을 때는 공백으로 비워둔다. SCREEN의 마지막 부분에 다다를 경우 다시 처음으로 돌아와 같은 작업을 반복한다.

320x100
Share Link
reply
반응형
«   2024/05   »
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 31