ToyCom 어셈블리어 정리
ToyCom은 CPU 동작 방식을 이해하기 위한 교육용 어셈블리어 프로그램이다. 예시를 통해서 어려운 어셈블리어를 이해 해보자.
ToyCom 기본 특징
프로그램 구조
-
어셈블리어를 사용(ToyCom 전용)
-
ToyCom3 버전 사용 (ToyCom2은 문제가 많아서 사용X)
메모리와 명령어 해석
-
주소 : 명령어
형태로써 2바이트 16진수로 구성- 8bit=1byte이고, 주소가 0000이라면 앞의 두자리와 뒤의 두자리가 각각 1byte인 것
- 예를들어 FE 80 라는 주소를 2진수로 확인해 보면?
- 16진수
FE
→ 2진수1111 1110
- 16진수
80
→ 2진수1000 0000
- 16진수
-
중요(토이컴 특징): 명령어를 해석할 때 하위 바이트 → 상위 바이트 순서로 해석 (예:
80 FE
로 읽음).- 입력 시 명령어를 상위-하위 바이트 순서로 입력해야 메모리에 올바르게 저장됨. (즉, 반대로 입력해야 한다는 의미!!)
- 예: 명령어가
80 FE
라면, 프로그램 작성 시FE 80
으로 입력. - IR(Instruction Register)은 상위-하위 순서로 처리하므로 혼동 주의.
-
명령어의 구성: 상위 5비트는
opcode
(연산 코드), 나머지 비트는 주소나 데이터.- 예:
LDI
명령어는 데이터 로드,CALL
명령어는 함수 호출. - 참고:
CALL
은 원하는 주소 입력시 그 주소로 이동하고, 마지막에 ret를 붙혀서 다시 복귀하는 형식이다.
- 예:
-
점프(=BR) 명령어와 오프셋(=offset) 계산에 중요한 특징이 있다.
-2
를 주소계산에 적용해야 하는 점이다.-
PC
(Program Counter)가 이미 다음 명령어로 이동한 상태(=PC+2를 미리한다는 의미, 토이컴 특징)이기 때문에, 점프 주소에서 2를 빼서 정확한 위치로 점프- 따라서 결국 100의 주소로 점프를 원하면 실제로 100의 주소로 정상 점프 됨
- 예: 16진수 fE 80 은 2진수로 나타내면 1111 1110 과 1000 0000 이다. 물론, 10000000 11111110 으로 반대로 보고 해석을 해야함(토이컴 특징)
- 앞의 연산코드인 5bit를 먼저 해석하면 10000 이고 이는 BR 명령어를 의미한다.(점프 명령어)
- 나머지 bit를 해석하면 000 1111 1110 이니까 0 f e 로 해석이되고, 이를 offset으로 본다.
- 계산기로 프로그래머용 HEX 선택 후 100-2 를 계산해보면 FE가 나옴을 알 수 있다.
그런데, 100h로 점프하는걸 원했던 명령어인데 왜-2
를 하냐면 앞서 설명한 PC+2 특징 때문이다.
-
-
참고
- 세미콜론(=;)은 주석을 의미
- 토이컴을 다시 실행시켜야 모두 reset됨
예시로 살펴보기
전체 설명서
report #1
코드보시면 확인하실 수 있습니다.
report #2
R1은 1~10까지 더한 값을 넣는 레지스터
R2는 1~10까지 더해 줄 값을 업데이트 하는 레지스터
그리고 9x9단에서 R2를 다시 초기화해서 사용합니다.
=> R2, R3, R4 만 관찰하시면 됩니다.(R2 x R3 = R4 처럼 표기)
report #3
R0와 R1가 서로 계속 연산해갑니다.
R2는 20개 인지 횟수를 count 하기위한 레지스터입니다.
=> R2 레지스터가 20일 때 총 20개의 수열이 생성되었던 것입니다.
=> 마지막으로 피보나치 수열을 1, 1, 2,,,, 이런식으로 나오는 갯수를 count 하였습니다.
즉, 피보나치 수열은 맨처음에 0이 있다고 보고 시작하지만 0은 카운트 하지 않았다는 의미입니다!
report #4
R0, R1, R2는 막대기로 사용합니다. 따라서 이부분만 보시면 됩니다.
R3, R4, R5는 원반의 크기를 나타냈습니다.
처음 R0가 6인 이유는 원반의 크기를 전부 더한 값이기 때문입니다. (1+2+3)
구현시작 레포트 #1
-
동작 흐름:
- 프로그램은 학번의 끝자리(=8) + 100번지부터 실행 => 108부터
A=13, B=16, C=1을 초기화.
A-B >0 이면 C를 +1, A-B <= 0이면 C를 -1
A=21 초기화
A-B >0 이면 C를 +1, A-B <= 0이면 C를 -1
- 프로그램은 학번의 끝자리(=8) + 100번지부터 실행 => 108부터
-
주요 명령어 해석:
-
LDI R0, #13
: A에 13 저장. -
CMP R0, R1
: A와 B 비교. (결과 플래그 레지스터에 저장)-
BRZ
,BRS
: 조건에 따라 분기. (플래그 레지스터 값 기준 분기)
-
-
INC R2
,DEC R2
: C 값을 증가/감소.
-
; report #1
0000: FE 80 ; BR 0100h(offset=100h-2h=FE) => 10000 000 1111 1110 = 80 FE
0100: 06 80 ; BR 0108h(offset=8h-2h=06) => 10000 000 0000 0110 = 80 06
; A=13..
0108: 13 08 ; LDI R0,#13 => 00001 000 0001 0011 = 08 13
010A: 16 09 ; LDI R1,#16 => 00001 001 0001 0110 = 09 16
010C: 01 0A ; LDI R2,#1 => 00001 010 0000 0001 = 0A 01
010E: F0 F8 ; CALL 200h(offset=200h-110h=F0) => 11111 000 1111 0000 = F8 F0
; A=21..
0110: 21 08 ; LDI R0,#21 => 00001 000 0010 0001 = 08 21
0112: EC F8 ; CALL 200h(offset=200h-114h=EC) => 11111 000 1110 1100 = F8 EC
0114: 01 00 ; HALT
0200: 04 38 ; CMP R0 R1 => 00111 000 000 001 00 = 38 04
0202: FC 90 ; BRZ(=0) 0300h(offset=300h-204h=FC) => 10010 000 1111 1100 = 90 FC
0204: FA A0 ; BRS(<0) 0300h(offset=300h-206h=FA) => 10100 000 1111 1010 = A0 FA
0206: 00 22 ; INC R2,++1 => 00100 010 000 000 00 = 22 00
0208: 00 48 ; RET
0300: 01 22 ; DEC R2,--1 => 00100 010 000 000 01 = 22 01
0302: 00 48 ; RET
구현시작 레포트 #2
동작 흐름:
프로그램은 학번의 끝자리(=8) + 100번지부터 실행 => 108부터
R1 값을 초기화
CALL 명령을 사용하여 subroutine 함수를 만들고, subroutine에서 1부터 10까지 더한 값을 R1에 저장
RET 명령을 사용하여 Main 함수로 복귀한 후 이중 loop를 돌리면서 구구단을 계산
; report #2
0000: FE 80 ; BR 0100h(offset=100h-2h=FE) => 10000 000 1111 1110 = 80 FE
0100: 06 80 ; BR 0108h(offset=8h-2h=06) => 10000 000 0000 0110 = 80 06
0108: 00 09 ; LDI R1,#00 => 00001 001 0000 0000 = 09 00
010A: F4 F8 ; call 0200h(offset=200h-10Ch=F4) => 11111 000 1111 0100 = F8 F4
; R2 => 1, R3 => 1, R4 => 1 combine 1x1, 1x2,,,,9x9
; R2 is 1dan, 2dan, 3dan.. , R3 is count 1,2...9 , R4 is result
010C: 01 0A ; LDI R2,#01 => 00001 010 0000 0001 = 0A 01 (1dan)
010E: 40 F8 ; CALL 0150h(offset=150h-110h=40) => 11111 000 0100 0000 = F8 40
0110: 02 0A ; LDI R2,#02 => 00001 010 0000 0010 = 0A 02 (2dan)
0112: 3C F8 ; CALL 0150h(offset=150h-114h=3C) => 11111 000 0011 1100 = F8 3C
0114: 03 0A ; LDI R2,#03 => 00001 010 0000 0011 = 0A 03 (3dan)
0116: 38 F8 ; CALL 0150h(offset=150h-118h=38) => 11111 000 0011 1000 = F8 38
0118: 04 0A ; LDI R2,#04 => 00001 010 0000 0100 = 0A 04 (4dan)
011A: 34 F8 ; CALL 0150h(offset=150h-11Ch=34) => 11111 000 0011 0100 = F8 34
011C: 05 0A ; LDI R2,#05 => 00001 010 0000 0101 = 0A 05 (5dan)
011E: 30 F8 ; CALL 0150h(offset=150h-120h=30) => 11111 000 0011 0000 = F8 30
0120: 06 0A ; LDI R2,#06 => 00001 010 0000 0110 = 0A 06 (6dan)
0122: 2C F8 ; CALL 0150h(offset=150h-124h=2C) => 11111 000 0010 1100 = F8 2C
0124: 07 0A ; LDI R2,#07 => 00001 010 0000 0111 = 0A 07 (7dan)
0126: 28 F8 ; CALL 0150h(offset=150h-128h=28) => 11111 000 0010 1000 = F8 28
0128: 08 0A ; LDI R2,#08 => 00001 010 0000 1000 = 0A 08 (8dan)
012A: 24 F8 ; CALL 0150h(offset=150h-12Ch=24) => 11111 000 0010 0100 = F8 24
012C: 09 0A ; LDI R2,#09 => 00001 010 0000 1001 = 0A 09 (9dan)
012E: 20 F8 ; CALL 0150h(offset=150h-130h=20) => 11111 000 0010 0000 = F8 20
0130: 01 00 ; HALT
; gugudan
0150: 01 0B ; LDI R3,#01 => 00001 011 0000 0001 = 0B 01 (x1)
0152: 00 0C ; LDI R4,#00 => 00001 100 0000 0000 = 0C 00
0154: 88 2C ; ADD R4 R4 R2 => 00101 100 100 010 00 = 2C 88
0156: 00 23 ; INC R3,++1 => 00100 011 000 000 00 = 23 00 (x2)
0158: 88 2C ; ADD R4 R4 R2 => 00101 100 100 010 00 = 2C 88
015A: 00 23 ; INC R3,++1 => 00100 011 000 000 00 = 23 00 (x3)
015C: 88 2C ; ADD R4 R4 R2 => 00101 100 100 010 00 = 2C 88
015E: 00 23 ; INC R3,++1 => 00100 011 000 000 00 = 23 00 (x4)
0160: 88 2C ; ADD R4 R4 R2 => 00101 100 100 010 00 = 2C 88
0162: 00 23 ; INC R3,++1 => 00100 011 000 000 00 = 23 00 (x5)
0164: 88 2C ; ADD R4 R4 R2 => 00101 100 100 010 00 = 2C 88
0166: 00 23 ; INC R3,++1 => 00100 011 000 000 00 = 23 00 (x6)
0168: 88 2C ; ADD R4 R4 R2 => 00101 100 100 010 00 = 2C 88
016A: 00 23 ; INC R3,++1 => 00100 011 000 000 00 = 23 00 (x7)
016C: 88 2C ; ADD R4 R4 R2 => 00101 100 100 010 00 = 2C 88
016E: 00 23 ; INC R3,++1 => 00100 011 000 000 00 = 23 00 (x8)
0170: 88 2C ; ADD R4 R4 R2 => 00101 100 100 010 00 = 2C 88
0172: 00 23 ; INC R3,++1 => 00100 011 000 000 00 = 23 00 (x9)
0174: 88 2C ; ADD R4 R4 R2 => 00101 100 100 010 00 = 2C 88
0176: 00 48 ; RET
; subroutine
0200: 01 0A ; LDI R2,#01 => 00001 010 0000 0001 = 0A 01
0202: 28 29 ; ADD R1, R1, R2 => 00101 001 001 010 00 = 29 28 (+1)
0204: 00 22 ; INC R2 => 00100 010 000 000 00 = 22 00
0206: 28 29 ; ADD R1, R1, R2 => 00101 001 001 010 00 = 29 28 (+2)
0208: 00 22 ; INC R2 => 00100 010 000 000 00 = 22 00
020A: 28 29 ; ADD R1, R1, R2 => 00101 001 001 010 00 = 29 28 (+3)
020C: 00 22 ; INC R2 => 00100 010 000 000 00 = 22 00
020E: 28 29 ; ADD R1, R1, R2 => 00101 001 001 010 00 = 29 28 (+4)
0210: 00 22 ; INC R2 => 00100 010 000 000 00 = 22 00
0212: 28 29 ; ADD R1, R1, R2 => 00101 001 001 010 00 = 29 28 (+5)
0214: 00 22 ; INC R2 => 00100 010 000 000 00 = 22 00
0216: 28 29 ; ADD R1, R1, R2 => 00101 001 001 010 00 = 29 28 (+6)
0218: 00 22 ; INC R2 => 00100 010 000 000 00 = 22 00
021A: 28 29 ; ADD R1, R1, R2 => 00101 001 001 010 00 = 29 28 (+7)
021C: 00 22 ; INC R2 => 00100 010 000 000 00 = 22 00
021E: 28 29 ; ADD R1, R1, R2 => 00101 001 001 010 00 = 29 28 (+8)
0220: 00 22 ; INC R2 => 00100 010 000 000 00 = 22 00
0222: 28 29 ; ADD R1, R1, R2 => 00101 001 001 010 00 = 29 28 (+9)
0224: 00 22 ; INC R2 => 00100 010 000 000 00 = 22 00
0226: 28 29 ; ADD R1, R1, R2 => 00101 001 001 010 00 = 29 28 (+10)
0228: 00 48 ; RET
구현시작 레포트 #3
동작 흐름:
프로그램은 학번의 끝자리(=8) + 50번지부터 실행 => 58부터
CALL 명령을 사용하여 subroutine 함수를 만들고, subroutine에서 피보나치 수열을 20개 까지 구하기
단 20개 수열 중 제일 마지막 숫자를 R0에 저장한다
RET으로 main 복귀 후 종료
; report #3
0000: 56 80 ; BR 0058h(offset=58h-2h=56) => 10000 000 0101 0110 = 80 56
0058: F6 F8 ; call 0150h(offset=150h-5Ah=F6) => 11111 000 1111 0110 = F8 F6
005A: 01 00 ; HALT
; subroutine
; R0 => result(1, 1, 2, 3,,,, count by 20), R1 => add, R2 => count
0150: 01 08 ; LDI R0,#01 => 00001 000 0000 0001 = 08 01
0152: 01 09 ; LDI R1,#01 => 00001 001 0000 0001 = 09 01
0154: 02 0A ; LDI R2,#02 => 00001 010 0000 0010 = 0A 02 count:2
0156: 04 28 ; ADD R0 R0 R1 => 00101 000 000 001 00 = 28 04
0158: 00 22 ; INC R2,++1 => 00100 010 000 000 00 = 22 00 count:3
015A: 04 29 ; ADD R1 R0 R1 => 00101 001 000 001 00 = 29 04
015C: 00 22 ; INC R2,++1 => 00100 010 000 000 00 = 22 00 count:4
015E: 04 28 ; ADD R0 R0 R1 => 00101 000 000 001 00 = 28 04
0160: 00 22 ; INC R2,++1 => 00100 010 000 000 00 = 22 00 count:5
0162: 04 29 ; ADD R1 R0 R1 => 00101 001 000 001 00 = 29 04
0164: 00 22 ; INC R2,++1 => 00100 010 000 000 00 = 22 00 count:6
0166: 04 28 ; ADD R0 R0 R1 => 00101 000 000 001 00 = 28 04
0168: 00 22 ; INC R2,++1 => 00100 010 000 000 00 = 22 00 count:7
016A: 04 29 ; ADD R1 R0 R1 => 00101 001 000 001 00 = 29 04
016C: 00 22 ; INC R2,++1 => 00100 010 000 000 00 = 22 00 count:8
016E: 04 28 ; ADD R0 R0 R1 => 00101 000 000 001 00 = 28 04
0170: 00 22 ; INC R2,++1 => 00100 010 000 000 00 = 22 00 count:9
0172: 04 29 ; ADD R1 R0 R1 => 00101 001 000 001 00 = 29 04
0174: 00 22 ; INC R2,++1 => 00100 010 000 000 00 = 22 00 count:10
0176: 04 28 ; ADD R0 R0 R1 => 00101 000 000 001 00 = 28 04
0178: 00 22 ; INC R2,++1 => 00100 010 000 000 00 = 22 00 count:11
017A: 04 29 ; ADD R1 R0 R1 => 00101 001 000 001 00 = 29 04
017C: 00 22 ; INC R2,++1 => 00100 010 000 000 00 = 22 00 count:12
017E: 04 28 ; ADD R0 R0 R1 => 00101 000 000 001 00 = 28 04
0180: 00 22 ; INC R2,++1 => 00100 010 000 000 00 = 22 00 count:13
0182: 04 29 ; ADD R1 R0 R1 => 00101 001 000 001 00 = 29 04
0184: 00 22 ; INC R2,++1 => 00100 010 000 000 00 = 22 00 count:14
0186: 04 28 ; ADD R0 R0 R1 => 00101 000 000 001 00 = 28 04
0188: 00 22 ; INC R2,++1 => 00100 010 000 000 00 = 22 00 count:15
018A: 04 29 ; ADD R1 R0 R1 => 00101 001 000 001 00 = 29 04
018C: 00 22 ; INC R2,++1 => 00100 010 000 000 00 = 22 00 count:16
018E: 04 28 ; ADD R0 R0 R1 => 00101 000 000 001 00 = 28 04
0190: 00 22 ; INC R2,++1 => 00100 010 000 000 00 = 22 00 count:17
0192: 04 29 ; ADD R1 R0 R1 => 00101 001 000 001 00 = 29 04
0194: 00 22 ; INC R2,++1 => 00100 010 000 000 00 = 22 00 count:18
0196: 04 28 ; ADD R0 R0 R1 => 00101 000 000 001 00 = 28 04
0198: 00 22 ; INC R2,++1 => 00100 010 000 000 00 = 22 00 count:19
019A: 04 29 ; ADD R1 R0 R1 => 00101 001 000 001 00 = 29 04
019C: 00 22 ; INC R2,++1 => 00100 010 000 000 00 = 22 00 count:20
019E: 24 10 ; MV R0 R1 => 00010 000 001 001 00 = 10 24
01A0: 00 48 ; RET
구현시작 레포트 #4
동작 흐름:
Main 함수 프로그램은 학번의 끝자리(=8) + 50번지부터 실행 => 58부터
CALL 명령을 사용하여 subroutine 함수를 만들고, subroutine에서 하노이 탑 문제를 해결(원반, 막대기 3개로 고정)
RET으로 main 복귀 후 프로그램 종료
; report #4
0000: 56 80 ; BR 0058h(offset=58h-2h=56) => 10000 000 0101 0110 = 80 56
0058: F6 F8 ; call 0150h(offset=150h-5Ah=F6) => 11111 000 1111 0110 = F8 F6
005A: 01 00 ; HALT
; subroutine
; R0,R1,R2 => bar and R3,R4,R5 => disk
; init => R0 : 1+2+3, R1 : 0, R2 : 0 and R3 : 1, R4 : 2, R5 : 3
0150: 06 08 ; LDI R0,#06 => 00001 000 0000 0110 = 08 06
0152: 00 09 ; LDI R1,#00 => 00001 001 0000 0001 = 09 00
0154: 00 0A ; LDI R2,#00 => 00001 010 0000 0010 = 0A 00
0156: 01 0B ; LDI R3,#01 => 00001 011 0000 0001 = 0B 01
0158: 02 0C ; LDI R4,#02 => 00001 100 0000 0010 = 0C 02
015A: 03 0D ; LDI R5,#03 => 00001 101 0000 0011 = 0D 03
015C: 0E 28 ; SUB R0 R0 R3 => 00101 000 000 011 10 = 28 0E
015E: 4C 2A ; ADD R2 R2 R3 => 00101 010 010 011 00 = 2A 4C
0160: 12 28 ; SUB R0 R0 R4 => 00101 000 000 100 10 = 28 12
0162: 30 29 ; ADD R1 R1 R4 => 00101 001 001 100 00 = 29 30
0164: 4E 2A ; SUB R2 R2 R3 => 00101 010 010 011 10 = 2A 4E
0166: 2C 29 ; ADD R1 R1 R3 => 00101 001 001 011 00 = 29 2C
0168: 16 28 ; SUB R0 R0 R5 => 00101 000 000 101 10 = 28 16
016A: 54 2A ; ADD R2 R2 R5 => 00101 010 010 101 00 = 2A 54
016C: 2E 29 ; SUB R1 R1 R3 => 00101 001 001 011 10 = 29 2E
016E: 0C 28 ; ADD R0 R0 R3 => 00101 000 000 011 00 = 28 0C
0170: 32 29 ; SUB R1 R1 R4 => 00101 001 001 100 10 = 29 32
0172: 50 2A ; ADD R2 R2 R4 => 00101 010 010 100 00 = 2A 50
0174: 0E 28 ; SUB R0 R0 R3 => 00101 000 000 011 10 = 28 0E
0176: 4C 2A ; ADD R2 R2 R3 => 00101 010 010 011 00 = 2A 4C
0178: 00 48 ; RET
댓글남기기