[컴퓨터 구조] 기본 컴퓨터 프로그래밍
이제 설계한 컴퓨터가 제대로 작동하는지 증명해보자.
프로그램은 컴퓨터가 특정 업무를 처리하도록 작성된 명령어 또는 문장이고, 네 가지 종류가 있다.
1. 이진 코드 : 메모리상에 실제로 나타나는 형태의 명령어이다.
2. 8진 / 16진 코드 : 이진 코드로 작성 시 매우 많은 자릿수가 필요하기에 8진수 혹은 16진수를 사용해 자릿수를 감소시킨다.
3. 기호 코드 : 어셈블리 언어로, 각 명령어를 기호화된 이름으로 표현한다.
4. 고급 프로그래밍 언어 : C, Fortran 등..
모든 컴퓨터는 각각의 어셈블리 언어를 가지고 있으며, 언어의 규칙은 컴퓨터 제조업체에서 정한다.
어셈블리 언어는 줄 단위로 해석된다. (Carriage-Return을 한 줄의 끝으로 간주한다)
이제 기본 컴퓨터의 어셈블리 언어를 정의해보자.
각각의 줄은 세 가지 필드로 구성된다.
1. Label Field : 기호 주소를 나타내거나 빈 칸이다.
2. Instruction Field : 기계 명령어나 Pseudo 명령어가 위치한다.
3. Commenet Field : 명령어에 대한 주석이 위치한다. 생략해도 되지만, 되도록이면 작성 해 주자.
Label Field
첫 글자가 문자로 시작하는 세 자리의 영숫자 문자로 구성되고, comma로 끝난다.
Instruction Field
Memory Reference Instruction(MRI)
Register Reference Instruction (non-MRI)
I/O Instruction (non-MRI)
Pseudo Instruction
즉, MRI / non-MRI / Pseudo 세 가지 중 하나이다.
빈칸으로 분리된 2~3개의 기호로 구성된다.
첫 번째 기호 : MRI 연산 코드 중 하나이다.
두 번째 기호 : 기호 주소이다.
세 번째 기호 : I 가 위치하거나 비어있다. I일 경우 간접 주소 명령어이고, 없으면 직접 주소 명령어이다.
위는 명령어 필드 부분의 예시이다.
여기서 Pseudo 명령어는 번역 과정에서 발생되는 특정 상황에 대한 정보를 어셈블러에게 알려주는 명령어이다.
어셈블러가 인식할 수 있는 네 가지 Pseudo 명령어로, ORG 명령어는 어셈블러에게 다음 줄에 오는 명령 혹은 피연산자가 ORG 다음에 기술된 숫자에 해당하는 메모리 영역에 저장된다고 알려주는 역할을 한다.
Comment Field
/ 슬래시 기호로 분리되고 주석 역할을 한다.
메모리 주소를 지정할 때 0과 1은 앞에서 배웠듯 인터럽트에서 돌아오거나 인터럽트의 다음 명령어를 가리킬 때 사용되기 때문에 함부로 할당하면 안 된다.
프로그램은 100번지에서 시작된다. (1이나 2로 설정하면 안 된다)
SUB에 있는 -23을 AC에 가져온다.
-23의 각 비트를 바꿔준다.
-23의 각 비트를 바꿔준 값에서 1을 더해준다. (2의 보수를 취하게 돼 23이 된다)
23과 83을 더한다.
106을 AC에 저장한다.
어셈블리어는 위와 같이 이진수로 변환된다.
어셈블리어를 읽을 때, SUB를 만나면 라벨 컬럼을 읽어가면서 SUB를 찾아야 한다.
SUB가 어딨는지 모르기 때문에 하나 하나 읽어야 하는데.. 효율적이지 않다.
따라서 어셈블러는 기호 프로그램 전체를 두 번 스캔하는 방법을 사용한다.
첫 번째 스캔에서는 피연산자와 기계 명령어에 메모리 영역만 지정하면서 라벨의 주소를 정의하고, 두 번째 스캔에서 제대로 번역을 시작한다.
첫 번째 스캔을 거치면 위와 같이 테이블이 만들어지고, 두 번째 스캔에서 테이블을 활용한다.
어셈블러는 기호 언어를 읽어서 해당되는 이진 프로그램으로 번역하는 역할을 한다. (소스 프로그램 .s -> 목적 프로그램 .o)
이제 예시를 살펴보자.
PL3, LDA SUB I
사용자가 위와 같은 기호 프로그램을 타이핑했다고 하자.
각 줄의 코드는 각 메모리 영역당 두 개의 문자로 연속적으로 저장되고, 여기서는 1워드가 16bit이기 때문에 각 워드당 두 개의 문자가 저장될 수 있다. (지금까지 설계한 컴퓨터는 16비트 컴퓨터이다)
위의 명령어는 7개의 연속적인 메모리 내부에 저장된다.
Carriage-Return 코드로 명령어를 구분하고, 여기서는 주석이 없지만 주석이 있다면 / 를 인식해 모든 주석 부분을 날린다.
첫 번째 스캔(First Pass)
어셈블러는 각 명령어의 위치를 추적하기 위해 Location Counter라고 부르는 메모리 워드를 사용한다.
여기서는 현재 처리되고 있는 명령어 혹은 피연산자에 지정된 메모리 영역의 값을 저장한다.
ORG 명령어는 LC 값을 처음 위치에 해당하는 값으로 초기화하고, 각 줄의 코드를 처리 할 때 마다 LC값은 1씩 증가한다.
여기서는 ORG 0으로 입력했다고 가정한다. (원래는 안된다!!)
Label의 존재 여부는 comma로 확인하고, ORG 명령어를 만나면 LC값을 재설정한다.
이후 END 명령어를 만나면 First Pass를 종료한다.
좌측은 어셈블리 소스 프로그램이고, 우측은 First Pass를 거친 결과이다.
두 번째 스캔(Second Pass)
Second Pass는 talbe-lookup에 의해 번역된다.
즉, 특정 항목이 테이블 내에 저장된 항목과 일치하는지 하나씩 확인하는 작업을 거친다.
사용하는 테이블은 총 4가지이다.
1. Pseudo Instruction table
2. MRI table
3. non-MRI table
4. Address-symbol table (First Pass에서 제작함)
이번에도 ORG 0 으로 입력됐다고 가정하자.
라벨들은 무시되고 바로 명령어 부분으로 넘어가 처음 만나는 기호를 체크한다.
Pseudo 명령어도 아니고 MRI 명령어도 아니면서 non-MRI 명령어도 아닌 기계 코드 기호를 만나면 테이블 상에서 대응되는 이진수 코드를 찾을 수 없다.
따라서 이 경우 에러 메세지를 프린트해서 프로그램 작성자에게 특정 line에서 에러가 발생했음을 알린다.
어셈블리어에서 반복문을 사용해보자.
먼저 프로그램은 100번지에서 시작한다.
150을 불러오고 AC에 저장한다.
PTR에 AC값인 150을 저장한다.
-100을 불러오고 AC에 저장한다.
CTR에 AC값인 -100을 저장한다.
결과만 SUM에 저장하면 되기 때문에 AC를 클리어한다.
기호 I를 포함하기 때문에 간접 ADD 명령어이다. 150번지의 피연산자가 AC에 더해진다.
PTR과 CTR은 1 증가된다. (PTR은 다음 피연산자의 주소를 가리킨다)
계속 반복하다가 CTR이 0이 되면 10Line을 스킵한다.
SUM에 현재 AC값을 저장하고, HLT 명령어를 만나 작동을 멈춘다.
컴퓨터에서 사용 가능한 명령어의 수는 정해져있다.
명령어로 제공된다는건 명령어를 수행하기 위한 하드웨어가 준비돼 있다는 걸 의미하고, 명령어로 제공되지 않는 연산을 수행하기 위해서는 기존 명령어들을 적절하게 사용하는 프로그램 (소프트웨어) 을 작성해야 한다.
8bit * 8bit 곱셈을 구현해보자. (X * Y)
X에 Y를 곱한다.
한 번에 두 개의 숫자만 더할 수 있으니 중간합을 저장하기 위해 P를 사용한다.
X는 Y의 각 비트 중에서 1인 경우만 P에 더해지고, 각 비트를 확인 할 때 마다 X값은 왼쪽으로 시프트된다.
총 8번 더해야 하기에 CTR값을 -8로 설정했고, 반복이 끝날 때 마다 CTR값을 1씩 증가시켜줬다.
Y값을 AC에 로드시키고 E와 AC를 오른쪽으로 순환시키고 시프트된 숫자를 저장함으로써 Y의 각 비트를 확인한다.
cil = circulate left / cir = circulate right
논리 연산은 AND CMA CLA 세 가지 명령어를 적절히 사용해서 구현한다. (+ CIL CIR)
프로그램에서 여러 번 사용되는 명령어를 서브루틴이라고 부른다.
서브루틴이 사용될 때 마다 서브루틴을 시작하는 곳으로 분기하는 명령어가 실행되고, 서브루틴을 마무리 한 후 하던 일을 계속한다.
프로그램은 100번지에서 시작한다.
AC에 1234를 가져온다.
서브루틴 SH4를 실행한다. (돌아올 주소는 SH4에 저장하고, PC에는 SH4 + 1을 넣는다. 따라서 서브루틴은 10A부터 시작)
X에 AC의 값을 저장한다. (cil 4번 하고 AND MSK 연산 수행하니 1234는 2340이 된다. 16진수와 2진수 헷갈리지 말기)
이 다음은 같은 로직이니 생략함.
마지막으로 character 입출력에 대한 Interrupt Service Routine을 살펴보자.
0번지에는 인터럽트가 실행된 후 돌아올 주소가 저장되고, 1번지에는 Interrupt Service를 수행하는 주소가 저장된다.
1. CLA / AC를 초기화한다.
2. ION / 인터럽트가 실행될 수 있도록 설정한다.
3. LDA X / X에 값을 로드한다.
4. ADD Y / 여기서 인터럽트가 발생했다!!!! (R이 1로 설정됐다)
인터럽트가 발생했으니 1번지에 있는 주소를 읽어 200번지로 간다.
5. SRV, STA SAC / AC값을 SAC 저장소에 저장한다.
6. CIR / E값을 AC(1) 로 옮긴다
7. STA SE / E 값을 SE 저장소에 저장한다.
8. SKI / Input Flag가 1이면 다음 명령어를 패스하고, 1이 아니면 다음 명령어를 실행한다.
9. BUN NXT / Input Flag가 0인 경우 실행된다. NXT로 가서 Output Flag를 확인한다.
10. INP / Input Flag가 1인 경우 실행된다. AC에 문자를 입력한다.
11. OUT / 출력한다.
12. STA PT1 I / Input Buffer에 값을 저장한다.
13. ISZ PT1 / PT1 값을 하나 증가시키고 해당 값이 0이면 다음 명령어를 건너뛴다.
...
OUTPUT에서도 비슷한 명령어를 수행한 후, IEN을 1로 하고 원래 하던 작업으로 돌아간다. (인터럽트 서비스가 종료됐다)
'Computer Science > Computer Architecture' 카테고리의 다른 글
[컴퓨터 구조] 기본 컴퓨터의 구조와 설계 (2) | 2022.10.04 |
---|---|
[컴퓨터 구조] 레지스터와 마이크로 연산 (0) | 2022.10.02 |
[컴퓨터 구조] 데이터의 표현 (0) | 2022.10.02 |
댓글
이 글 공유하기
다른 글
-
[컴퓨터 구조] 기본 컴퓨터의 구조와 설계
[컴퓨터 구조] 기본 컴퓨터의 구조와 설계
2022.10.04 -
[컴퓨터 구조] 레지스터와 마이크로 연산
[컴퓨터 구조] 레지스터와 마이크로 연산
2022.10.02 -
[컴퓨터 구조] 데이터의 표현
[컴퓨터 구조] 데이터의 표현
2022.10.02