1.
TIS-100은 어셈블리어로 코드를 작성하며 퍼즐을 푸는 게임이다. 삼촌의 유물인 고장난 기계를 하나하나 고쳐가면서 스토리를 따라가는 것이 매력이다. 한국에서 이 게임을 플레이하는 주 타겟층은 이미 해킹/프로그래밍을 어느정도 접해본 사람들이겠지만, 매뉴얼에서도 장벽을 느꼈을 사람들을 위해 매뉴얼을 설명하는 가이드를 써보고자 한다.
게임에서 기본적으로 제공해주는 매뉴얼의 번역은 여기에서 찾을 수 있다.
https://gist.github.com/bivoje/a426fdb8e8e5e449e6e5d3b0599824b5
아래의 글과 기타 등등의 인터넷 소스를 참고해서 작성하겠다.
https://steamcommunity.com/sharedfiles/filedetails/?id=1437899653
2. 노드 Nodes
보이는 네모 칸 하나하나를 노드라고 부른다. 우리가 작성하는 코드는 노드 안에 들어간다. 화살표가 가리키는 곳으로 데이터가 이동할 수 있다. 맨 위에는 노드를 가리키는 하나의 화살표가 있는데, 프로그램을 실행하게 되면 거기에서부터 데이터가 들어온다.
목표는 간단하다. 위에서 들어오는 데이터를 지지고 볶아서 화면 아래에 있는 출구로 보내는 것이다.
3. 시스템 아키텍쳐 System Architecture
프로그램을 통과하는 데이터는 -999에서 999까지의 숫자이다. TIS-100에는 이 데이터를 저장하고, 움직이게 하는 아키텍쳐가 있다.
ACC
노드마다 하나씩 붙어있다. ACC을 통해, 값을 더하고 빼거나 할 수 있다. 데이터를 조작하고 싶다면 ACC를 써야 한다!
BAK
BAK은 ACC과 비슷하다. ACC의 임시 저장장소인데, 두 가지 조작만이 가능하다. 1. ACC에서 BAK으로 데이터를 옮길 수 있다. 2. 데이터를 BAK으로 복사할 수 있다.
NIL
null인데 0인 재밌는 아이다. 목적지로 쓰인다면 값은 지워진다. 반대로, 여기에서부터 값을 옮긴다면 0으로 취급된다.
LEFT, RIGHT, UP, DOWN
데이터를 다른 노드로 옮기기 전에 임시적으로 붙들어준다. 제곧내.
ANY
이건 쓸 때 두개의 인접한 노드가 있어야지만 작동한다. 하나의 방향을 보기보다는 모든 방향으로부터 인풋을 받기를 기다렸다가, 들어오는 가장 첫번째 데이터를 받는다. 동시에 들어오면 LAST에 기록된 방향을 읽는다.
LAST
ANY랑 비슷한데, 데이터가 어디서 왔는지를 고려한다. 예를 들어 LEFT에서 온 데이터의 처리를 늦추고 싶다면 LAST를 사용하면 된다. ANY와 함께 쓰이면 다이나믹한 플로우를 구성할 수 있다.
4. 명령어 Instruction set
프로그래밍에 익숙하지 않다면 여기가 좀 헷갈릴 수 있다. 하지만 TIS-100의 명령어는 직관적이다. 예시 코드를 한 번 보고 가자.
START:
MOV UP, ACC #UP 포트에서 ACC 레지스터로 값을 읽어온다.
JGZ POSITIVE #ACC 값이 0보다 크다면 "POSITIVE"로 점프한다.
JIZ NEGATIVE #ACC 값이 0보다 작다면 "NEGATIVE"로 점프한다.
JMP START #값이 양수도 음수도 아니다. "START"로 점프한다.
POSITIVE:
MOV ACC, RIGHT #ACC 레지스터의 값을 RIGHT에 쓴다.
JMP START #"START"로 점프한다.
NEGATIVE:
MOV ACC, LEFT #ACC 레지스터의 값을 LEFT에 쓴다.
JMP START #"START"로 점프한다.
조금 자세히 읽어보면, 아무것도 모르는 상태에서도 어떻게 작동하는지 알 것 같다. 명령어가 매우 직관적이다.
NOP
no-operation
제곧내, 아무것도 하지 않는다. 타이밍을 맞출 때 많이 쓰인다.
MOV
아마 가장 많이 쓰이는 명령어들 중 하나일 것이다. 두 노드 간에 데이터를 움직일 때 사용된다. 1. 데이터가 이미 있는 시작점이 필요하다. 2. ACC, DOWN, ANY와 같은 메모리 위치가 있는 목적지가 필요하다.
MOV UP, ACC #위에서부터 온 데이터가 다른 노드의 ACC으로 간다.
MOV 8, DOWN #'8'이 아래에 있는 노드로 간다.
SWP
ACC와 BAK의 값을 서로 바꾼다.
SAV
ACC의 값으로 BAK의 값을 덮어쓴다. SWP과 SAV은 유일하게 BAK에 존재하는 데이터를 바꿀 수 있는 명령어들이다. 다른 건 에러가 난다.
ADD
ACC에 값을 더한다. ADD ACC하면 ACC의 값이 2배가 될 것이다.
SUB
ACC에서 값을 뺀다. SUB ACC하면 0이 될 것이다.
NEG
음수 부호를 붙여준다. 음수면 양수로, 양수면 음수가 된다.
JMP
해당 라벨로 건너뛴다. switch문 같은 거다.
JEZ
jump equal zero.
ACC의 값이 0이면 해당 라벨로 건너뛴다.
JNZ
jump not zero.
ACC의 값이 0이 아니면 해당 라벨로 건너뛴다.
JGZ
jump greater zero.
ACC의 값이 0보다 크면 해당 라벨로 건너뛴다.
JLZ
jump less zero.
ACC의 값이 0보다 작으면 해당 라벨로 건너뛴다.
JRO
jump relative offset.
JRO는 라벨을 필요로 하지 않는다. 값을 가져갈 수도 있고, ACC의 값에 따라 다르게 행동할 수도 있다. 예를 들어 알아보자.
JRO -2 #두 명령 뒤로
JRO 3 #세 명령 앞으로
JRO ACC #ACC에 들어간 값에 따라 달라짐
HCF
halt and catch fire.
게임을 재시작한다.
5.
친구들이랑 하면 효율성 면에서 경쟁하면서도 할 수 있다.
TIS-100가 실제 어셈블리와 얼마나 비슷한지에 대해서는 흥미로운 레딧 스레드가 있다.
https://www.reddit.com/r/tis100/comments/4fccq0/how_close_is_this_to_true_assembly/
have fun!