목차11개 항목
컴퓨터는 0과 1로 된 기계어만 해석할 수 있다. 사람이 이를 직접 쓰기는 어려우므로 명령어를 기호로 쓰는 어셈블리 언어를 만들고, 어셈블러가 이를 기계어로 번역한다. 여기서는 기본 컴퓨터의 명령어로 간단한 프로그램을 짜 본다.
명령어 기호와 16진수 코드
| 분류 | 기호 | 16진수 코드 (직접 / 간접) |
|---|---|---|
| 메모리 참조(MRI) | AND, ADD, LDA, STA, BUN, BSA, ISZ | 0xxx |
| 레지스터 참조(RRI) | CLA, CLE, CMA, CME, CIR, CIL, INC, SPA, SNA, SZA, SZE, HLT | 7xxx |
| 입출력 | INP, OUT, SKI, SKO, ION, IOF | Fxxx |
16비트 명령어의 맨 앞 16진수 한 자리가 I 비트 + Opcode, 나머지 세 자리가 주소다.
기계어에서 어셈블리로
두 수를 더하는 프로그램의 기계어는 다음과 같다.
| 주소 | 16진수 코드 | 의미 |
|---|---|---|
| 000 | 2004 | 2 = LDA, 004번지 값을 AC로 |
| 001 | 1005 | 1 = ADD, 005번지 값을 더함 |
| 002 | 3006 | 3 = STA, 결과를 006번지에 저장 |
| 003 | 7001 | HLT, 정지 |
| 004 | 0053 | 데이터 83 |
| 005 | FFE9 | 데이터 −23 (F로 시작 → 부호 비트 1, 2의 보수) |
| 006 | 0000 | 결과 저장 공간 |
2진수 → 16진수 → 명령어 기호로 바꾸고, 004·005·006번지에 A, B, C 같은 심볼(라벨) 을 붙이면 어셈블리 프로그램이 된다.
어셈블리 언어
한 줄은 세 필드로 이루어진다.
| 필드 | 내용 |
|---|---|
| Label | 심볼 주소 (없으면 비워 둠, 끝에 쉼표) |
| Instruction | 명령어: MRI, RRI·I/O 명령어, 또는 의사 명령어 |
| Comment | / 뒤의 주석 |
의사 명령어 (Pseudo Instruction)
실제 opcode가 아니라 어셈블러에게 주는 지시다.
| 의사 명령어 | 의미 |
|---|---|
ORG N | 이어지는 코드를 메모리 N(16진수)번지부터 배치 |
END | 프로그램의 끝 |
DEC N | N은 10진수 데이터 |
HEX N | N은 16진수 데이터 |
DEC·HEX가 붙은 줄은 명령어가 아니라 데이터다.
예: 83 − (−23) = 106
ORG 100 / 100번지부터 시작
LDA SUB / 빼는 수(−23)를 AC로
CMA / 1의 보수
INC / +1 → 2의 보수 (부호 반전)
ADD MIN / 빼어지는 수(83)를 더함 → 83 − (−23)
STA DIF / 결과를 DIF에 저장
HLT
MIN, DEC 83
SUB, DEC -23
DIF, HEX 0
END기계어에서 뺄셈은 CMA → INC → ADD, 즉 빼는 수를 2의 보수로 만든 뒤 더하는 것이다. 결과는 0x006A(106)다.
어셈블러: 2-pass
어셈블러는 위에서부터 한 줄씩 읽지만, LDA SUB를 만나는 시점에는 SUB가 몇 번지인지 아직 모른다. 그래서 프로그램을 두 번 훑는다.
- First pass: 번역하지 않고, 위치 계수기(LC, Location Counter)로 각 줄의 주소를 세면서 심볼 테이블(라벨 → 주소)을 만든다.
ORG를 만나면 LC를 그 값으로 설정한다. - Second pass: 심볼 테이블과 명령어 표를 참조해 각 명령어를 기계어로 번역한다.
프로그램 루프
100개 수의 합을 구하는 프로그램은 다음 구조로 만든다.
ORG 100
LDA ADS / 배열 시작 주소
STA PTR / 포인터 초기화
LDA NBR / −100
STA CTR / 카운터 초기화
CLA / 합 = 0
LOP, ADD PTR I / 포인터가 가리키는 수를 더함 (간접 주소)
ISZ PTR / 포인터 +1
ISZ CTR / 카운터 +1, 0이 되면 다음 명령을 건너뜀
BUN LOP / 아직이면 반복
STA SUM / 합 저장
HLT
ADS, HEX 150 / 배열 시작 주소
PTR, HEX 0
NBR, DEC -100
CTR, HEX 0
SUM, HEX 0
ORG 150
DEC 75 / 배열 A(100) 시작
...
END카운터를 −100에서 시작해 ISZ(증가 후 0이면 건너뛰기)로 0이 될 때까지 반복하는 것이 기본 컴퓨터의 루프 방식이다.
곱셈 프로그래밍
기본 컴퓨터에는 곱셈 명령어가 없으므로 시프트와 덧셈으로 구현한다. 승수의 각 비트를 오른쪽부터 확인해, 1이면 (그 자리만큼 왼쪽으로 시프트된) 피승수를 부분 곱으로 더한다.
X = 0000 1111 (피승수 15)
Y = 0000 1011 (승수 11)
0000 1111 ← 비트0 = 1: X
0001 1110 ← 비트1 = 1: X를 1번 시프트
0000 0000 ← 비트2 = 0
+ 0111 1000 ← 비트3 = 1: X를 3번 시프트
-----------
1010 0101 = 165서브루틴
여러 번 호출되거나 재사용되도록 만든 코드 묶음이다. 기본 컴퓨터는 BSA(Branch and Save Address)로 호출한다.
BSA SH4를 실행하는 순간 PC는 이미 다음 명령어 주소(예: 102)를 가리킨다.- BSA는 이 복귀 주소를 서브루틴의 첫 워드(SH4 번지)에 저장하고, 그다음 워드부터 실행한다.
- 서브루틴 끝에서
BUN SH4 I(간접 분기)로 저장해 둔 주소로 돌아간다.
예를 들어 AC를 왼쪽으로 4비트 시프트하는 서브루틴은 CIL을 네 번 한 뒤, AND MSK(MSK = HEX FFF0)로 순환되어 들어온 하위 4비트를 0으로 지운다. 마스크(mask) 는 AND 연산으로 원하는 비트만 남기는 기법이다.
파라미터가 여러 개면 BSA 다음 워드들에 파라미터(또는 그 주소)를 두고, 서브루틴이 복귀 주소를 포인터처럼 써서 차례로 읽으며 1씩 증가시킨 뒤 마지막 위치로 복귀한다.
입출력 프로그래밍
키보드 입력은 INPR과 FGI, 프린터 출력은 OUTR과 FGO를 쓴다.
CIF, SKI / FGI = 1(입력 있음)이면 다음 명령 건너뜀
BUN CIF / 아니면 다시 확인 (대기)
INP / 문자를 AC로
OUT / 같은 문자를 출력(에코)
STA CHR- 문자는 8비트이므로 16비트 워드 하나에 두 문자를 묶어(packing) 저장할 수 있다. 첫 문자를 입력받아 왼쪽으로 8비트 시프트하고, 두 번째 문자를 입력받아 합친다.
- 버퍼에 저장할 때는 시작 주소를 포인터에 넣고
STA PTR I(간접 저장) →ISZ PTR(포인터 증가)을 반복한다. - 두 워드(숫자든 문자든)를 비교할 때는 한쪽을 2의 보수로 만들어 더한 뒤 결과가 0인지 확인한다.
핵심 정리
- 어셈블리 한 줄 = 라벨 + 명령어 + 주석,
ORG·END·DEC·HEX는 의사 명령어. - 어셈블러는 1st pass에서 심볼 테이블, 2nd pass에서 기계어 번역을 한다.
- 뺄셈은 CMA + INC + ADD, 곱셈은 시프트 + 덧셈, 루프는 음수 카운터 + ISZ.
- 서브루틴은 BSA로 복귀 주소를 첫 워드에 저장하고,
BUN 라벨 I로 돌아온다.