본문으로 건너뛰기

버그 제보

이상한 점을 알려 주시면 고칠게요. 지금 보고 있는 페이지와 브라우저 정보가 함께 담겨요.

페이지:

Computer Science

기본 컴퓨터 프로그래밍

작성 2026. 10. 12.추가
목차11개 항목

컴퓨터는 0과 1로 된 기계어만 해석할 수 있다. 사람이 이를 직접 쓰기는 어려우므로 명령어를 기호로 쓰는 어셈블리 언어를 만들고, 어셈블러가 이를 기계어로 번역한다. 여기서는 기본 컴퓨터의 명령어로 간단한 프로그램을 짜 본다.

명령어 기호와 16진수 코드

분류기호16진수 코드 (직접 / 간접)
메모리 참조(MRI)AND, ADD, LDA, STA, BUN, BSA, ISZ0xxx6xxx / 8xxxExxx
레지스터 참조(RRI)CLA, CLE, CMA, CME, CIR, CIL, INC, SPA, SNA, SZA, SZE, HLT7xxx
입출력INP, OUT, SKI, SKO, ION, IOFFxxx

16비트 명령어의 맨 앞 16진수 한 자리가 I 비트 + Opcode, 나머지 세 자리가 주소다.

기계어에서 어셈블리로

두 수를 더하는 프로그램의 기계어는 다음과 같다.

주소16진수 코드의미
00020042 = LDA, 004번지 값을 AC로
00110051 = ADD, 005번지 값을 더함
00230063 = STA, 결과를 006번지에 저장
0037001HLT, 정지
0040053데이터 83
005FFE9데이터 −23 (F로 시작 → 부호 비트 1, 2의 보수)
0060000결과 저장 공간

2진수 → 16진수 → 명령어 기호로 바꾸고, 004·005·006번지에 A, B, C 같은 심볼(라벨) 을 붙이면 어셈블리 프로그램이 된다.

어셈블리 언어

한 줄은 세 필드로 이루어진다.

필드내용
Label심볼 주소 (없으면 비워 둠, 끝에 쉼표)
Instruction명령어: MRI, RRI·I/O 명령어, 또는 의사 명령어
Comment/ 뒤의 주석

의사 명령어 (Pseudo Instruction)

실제 opcode가 아니라 어셈블러에게 주는 지시다.

의사 명령어의미
ORG N이어지는 코드를 메모리 N(16진수)번지부터 배치
END프로그램의 끝
DEC NN은 10진수 데이터
HEX NN은 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가 몇 번지인지 아직 모른다. 그래서 프로그램을 두 번 훑는다.

  1. First pass: 번역하지 않고, 위치 계수기(LC, Location Counter)로 각 줄의 주소를 세면서 심볼 테이블(라벨 → 주소)을 만든다. ORG를 만나면 LC를 그 값으로 설정한다.
  2. 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로 돌아온다.
원본 기록1

댓글

GitHub 계정으로 댓글을 남길 수 있어요.