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
  • 중요(토이컴 특징): 명령어를 해석할 때 하위 바이트 → 상위 바이트 순서로 해석 (예: 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
  • 주요 명령어 해석:
    • 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

댓글남기기