프로젝트 3 - 4bit CPU 구조 이해

어셈블리의 이해 및 CPU 프로그래밍하기

바쁜 취준생 2025. 2. 6. 10:50

이 글은 IDEC에서 진행한 4bit CPU 설계 및 이해 강의 내용을 정리한 것입니다.

https://www.idec.or.kr/vod/apply/view/?pay=&search_val=cpu&no=273

 

반도체설계교육센터

강의제목 CPU 설계 및 응용 구분 부산대 / 설계강좌 / 초급/중급 / 이론+실습 강의시간 13시간 열람기간 16일 이용료(일반) 무료 이용료(학생) 무료 강의개요 SoC 설계를 위해서 CPU를 설계하고 응용할

www.idec.or.kr

 

이 CPU만의 전용 ISA(Instruction Set Architecture)이므로 다른 CPU와는 다른 명령어 체계입니다.

그냥 이런 느낌으로 어셈블리로 프로그래밍 한다 이해만 하면 됩니다.

ARM이나 RISC-V같은 것은 깃 허브같은 곳에서 찾아보세요.

 

일단 기본 개념 정리

CPU는 사칙 연산과 같은 산술 연산, 비트단위의 논리 연산을 한다.

이때 2진법의 특성을 활용한 덧셈기, 뺄셈기가 있고, 

곱셈 나눗셈은 계산하는 수가 모두 이진법으로 저장 되어 있어서

비트 시프트를 하면 곱셈과 나눗셈이 *2, *4, *8, /2, /4, /8...가 되는 점과,

숫자의 자리에 따라 이미 ...8 * 1 + 4 * 1 + 2 * 1 + 1 * 1 의 형식으로 숫자가 저장 되어 있어서

8의 자리가 1이면 시프트 연산을 하고 , 0 이면 건너 뛰는 방식으로

자리수 갯수만큼만 시프트 연산하고 다 더하거나 빼면 곱셈과 나눗셈이 가능하다.

 

이때 이런 연산은 그냥 회로다.

클럭과 시작 신호만 주면 연결된 레지스터의 출력 값을 바로 처리해버린다.

그래서 우리는 해당 레지스터에 데이터를 옮기고, 동작 신호를 주고, 출력 결과 데이터를 다시 옮기면 된다.

어셈블리의 프로그래밍은 이 과정 데이터를 옮기고(MOV), 특정 제어 신호(Control Signal, ADD, SUB...)을 주고

다시 데이터를 옮기는(MOV) 과정을 프로그래밍 한다.

이게 어셈블리 프로그래밍이다.

 

이때 기본적으로는 한줄 한줄 실행되어서 순차적으로 처리하지만,

C언어 처럼 IF 구문이나, for 같은 조건문, 반복문 같은 개념을 처리할 수도 있다.

이는 실제로는 같은 코드를 여러번 넣지 않고

기준을 판단하여 조건이 맞으면

조건문이 기계어로 구현된 처음 위치로 돌아가서 다시 코드를 실행한다.

이때, 사용하는 명령어가 JMP 점프 등이 있고, 특정 주소의 명령어로 돌아가는 것이다.

 

이를 C언어 관점에서 보면

프로그래밍 언어중에 컴파일을 하는 언어가 있다. 미리 기계어로 바꿔둔다는 의미이다.

이 컴파일이 하이 레벨 언어를 로우 레벨 언어 기계어로 바꿔주는 과정이다.

그리고 링크 과정에서는 외부 함수를 위한 라이브러리를 포함해서 순서대로 정리해서 하나의 기계어 파일로 만든다.

이를 롬파일이라 부른다.

 

여기서 잠시 링크 과정을 보면

아까 조건문이나 반복문에서 특정 주소로 돌아가서 코드를 다시 실행한다고 했다.

이때 이 특정 주소는 롬파일의 명령어 순서이다.

따라서 모든 필요한 외부 함수까지 다 불러오고 난 뒤에 

함수의 순서를 정리하고 이후에 처음부터 순서대로 주소를 매긴다.

 

이렇게 주소가 정해지고 난 다음에 점프할 주소를 확인하고 JMP 명령어 뒤에 주소를 입력한다.

그래서 이를 링크라고 부른다.

 

이때 순수 기계어로는 0과 1로만 구성되어서 알아보기 힘드니

Mnemonic Code - ADD, AND, NOP

Binary Code - 01010000, 01010100, 00000000

Hex Code - 50, 54, 00

과 같은 표현을 사용하여 프로그래밍한다.

이런 것을 다른 말로는 Opcode란 이름으로 입력 받는다.

 

이제 코드를 보자.

데이터가 많아서 모든 코드를 다 가져올 수는 없다.

교수님의 강의 자료이니 일부만 가져오겠다. 더 자세한 것은 위 링크에 들어가서 직접 확인하면된다.

 

일단 첫번째 키 입력이다.

 

이 다이어 그램 대로 동작한다.

키 한번 입력하는데 이렇게 복잡한 과정이 필요한 이유는

1초에 백만 클록 이상 클록이 발생하고, 각 클록마다 신호를 감지할 수 있기에,

사람이 반응할 수 없다. 그래서 각 단계가 모두 필요하다.

일단 버튼이 눌렸는지 확인하고, 눌렸으면 일단 저장하고, 

이후 버튼이 떨어졌는지 확인한 뒤에

이 프로그램은 계산기로서 동작하기에, 첫 입력이 숫자인지 확인하는 단계를 거쳐야 된다.

이후 숫자가 맞으면 다음 명령어가 실행되고 숫자가 아니면 BACK이라는 초기화 하는 명령어 시작 위치로 이동한다.

아래가 실제 동작 코드이다.

왼쪽의 ADDR은 롬파일 내부에서 주소이고,

INSTRUCTION이 실제 동작 명령어이다.

그리고 오른쪽에 그 명령어의 Mnemonic Code와 설명을 적었다.

 

===================================================================

 

일단 NOP 아무 동작을 안한다.

 

KEY 레지스터의 값을 AH로 옮긴다.

AH는 Accumulator의 상위 레지스터로 뺄셈 계산을 위해서 값을 옮긴다.

여기서 조건을 판단할 때는 뺄셈을 이용한다.

KEY 레지스터는 입력이 하나라도 있으면 1111 = F 로 바뀐다.

 

이후 1111이란 값을 TMP 레지스터에 옮긴다.

이는 롬파일에서 1111이란 값(F0)를 불러와서 TMP에 저장한다.

아까 KEY 레지스터가 입력이 있으면 1111일 이라고 했고,

뺄셈을 해서 판단을 하기에 해당 값을 불러온 것이다.

이때 명령어 기본 단위가 8비트라, F0의 형태로 데이터가 저장이 되나,

시스템 내부 버스와 TMP와 같은 4비트 레지스터는 상위 4비트만 연결되어 상위 4비트만 저장된다.

 

이후 TMP(=1111)를 BR로 옮긴다.

여기서 B레지스터는 연산을 위한 레지스터다.

A+B에서 B이다.

따라서 이제 KEY레지스터에서 1111을 뺄 준비가 되었다.

 

이제 SUB으로 뺄셈 회로를 동작시킨다.

연산 순서는 AH -BR이다.

이 명령어가 들어오면 컨트롤 블록에서 디코딩 하고 

뺄셈임을 확인해서 해당 회로에 제어 신호를 전달한다.

그러면 회로가 알아서 동작해서 출력을 ACC(Accumulator, AH+AL)의 AH에 저장한다.

그러면서 flag가 동작한다.

flag는 3가지가 있다. sign_flag, zero_flag, carry_flag.

사인 플래그는 음수인지 표시

제로 플래그는 결과가 0인지

캐리 플래그는 캐리 위로 넘기는 값이 발생하는지 알려준다.

이는 연산과 별개로 별도의 레지스터라 그냥 연산이 시작된 순간 바로 동작한다.

이때 캐리 플래그는 내부 연산과정에서 동작하지만,

사인 플래그와 제로 플래그는 ALU외부로 출력되어 조건 판단에 사용한다.

제로 플래그는 일치하는지 확인하여 JZ (Jump Zero)에서 특정 주소로 갈지 판단하고

사인 플래그는 출력 결과가 양수인지 음수인지 확인하여 양수이면(캐리가 1이 생기면) JGE(Jump Greater than equal) 이면 특정 주소 로 점프한다. 

여기서는 뺄셈을 통해 조건을 비교한다고 했다.

따라서 조건 KEY레지스터 값과 1111이 같으면 제로 플래그가 1이 되어서 같은 조건이다고 판단하고 다음 명령어에 저장된 주소로 점프한다.

다르면 그냥 다음 명령어를 실행한다.

이때, 다음 명령어는 데이터 아니냐고 할 수 있는데, 모든 JMP 명령어가 실행되는 순간 자동으로 다음 주소 데이터는 미리 불러와진다. 그래서 대기하다가 맞으면 그 주소가 Program Counter에 들어가서 실행 되는 것이고, 조건에 맞지 않으면 주소 데이터는 버려지고, PC에서 주소를 하나 증가한다. 이때 데이터를 불러오면서 이미 PC 주소는 데이터 위치에 있다. 그래서 다음 주소를 부르면 다음 명령어가 실행된다.

 

이후 입력이 되었다. KEY ==1111이면 0A = NUM1-1 주소로 넘어가서 실행되고

아니면 다음 줄로 넘어가서 JMP START를 수행한다. 그러면 맨 처음 00주소로 돌아가서 다시 실행된다.

 

NUM 1-1

입력이 된 것을 확인했으니, 그 데이터를 일단 저장하는 과정이다.

 

INR데이터를 TMP에 옮긴다.

INR은 입력 데이터이다. 입력 플래그가 KEY이고 실제 데이터는 INR이다.

데이터는 미리 별도의 입력 처리 모듈을 거쳐서 16진수 데이터로 입력된다.

 

이후 TMP(=INR)데이터를 CR로 옮긴다.

CR은 3 입력이 끝나기 전에 임시로 저장하는 공간이다.

세 입력은 A+B 에서 'A', '+', 'B' 이다.

여기서 키패드는 16진법을 사용하여 연산 기호는 10 이상을 사용한다.

+는 A로 입력한다. 따라서 숫자는 0부터 9까지다.

 

이후 OUTB로 TMP의 값을 KOUT으로 옮긴다.

KOUT은 입력값을 출력하는 레지스터로 7segment모듈과 연결되어 

데이터가 레지스터에 저장되는 즉시 출력이 나가서 HEX2DEC 모듈을 거쳐서 7segment 출력으로 변환되어 LED로 표현된다.

 

이후 CLR로 AH를 0000으로 초기화 한다.

점프 명령어에서 조건문 연산 = 뺄셈 연산을 위해서 ACC의 AH레지스터와 B레지스터를 자주 사용한다.

그래서 한번 끝나면 지워야 된다.

 

PSAH로 AH의 값을 AL로 PASS한다.

이 또한 AL의 값을 AH=0000으로 초기화 한다.

 

이후 OUT을 통해 ACC(AH+AL)의 값을 HEX2DEC를 거쳐서 7segment로 출력한다.

이러면 연산 전이라 00이 출력된다.

 

이후 NUM1-2로 넘어간다. 여기서는 키패드에서 손을 때는 것을 기다린다.

사람의 반응은 느리기에 떼고 나서야 다른 동작을 한다.

 

KEY레지스터의 값을 AH로 옮기고

 

1111을 TMP레지스터에 저장한다.

 

MOV로 TMP레지스터(=KEY)값을 BR로 옮긴다.

 

SUB으로 AH-BR연산을 수행한다.

 

이후 JZ로 제로 플래그를 확인 후 NUM1-2로 돌아가 떼는 것을 기다리거나

다음 명령어를 실행한다.

 

손을 떼면, CR의 값을 AH로 옮겨서 이것이 숫자인지 확인한다.

 

연산자는 10 이상의 값을 가지고 있으므로

LOAD 1010을 통해 TMP에 십진법 10, HEX A을 불러오고

 

TMP의 값을 B레지스터에 옮긴다.

 

이후 SUB을 통해 AH - BR을 진행하고

 

JGE(Jump Greater than Equal)을 통해 어디로 점프할지 결정한다.

출력 결과에서 sign_flag를 확인해서 1이 나오면 양수란 의미이므로

10보다 크기에 연산자를 입력해서 A+B 가 아닌 ++B가 되므로

다시 BACK이란 초기화 루틴으로 가서 초기화 하고 처음부터 다시 시작된다.

만약 0이면 10보다 작으므로 숫자가 맞으므로 다음 명령어를 실행한다.

 

===================================================================

이런 식으로 코드를 작성한다.

결국 보면 회로 동작 명령어는 한줄이나,

다 데이터 불러오고 레지스터 사이에 데이터 전달하는 것과 

비교연산(뺄셈 연산)결과에 따라 특정 명령어 주소로 이동하는 것이 어셈블리의 전부이다.

 

이 CPU의 경우는 학습용으로 나온 매우 작은 CPU라 일부 이동 명령어를 제거했다.

모든 레지스터 사이에 이동 명령어가 없어서 TMP를 활용해서 데이터를 이동하다보니,

명령어가 길어진 것도 있다.

 

나머지 명령어도 거의 비슷한 구조를 가지고 있으므로 

자세한 내용은 교수님의 강의를 참조하기를 바란다.

다만 강의가 완벽하게 녹화되지는 않아서 잘 들어야 된다.

 

이번 프로그램은 계산기 프로그램이라 이렇게 동작한다.

하지만, 아마 키 입력 이후 계산 파트의 명령어를 어떻게 잘 바꾸면

특정 동작을 하게 프로그래밍 할 수 있을 것 같다.

다만, 너무 복잡하고 동작을 사칙연산으로 표현해야 되서 조금 생각해봐야 될 것 같다.

 

내가 활용할 수 있는 명령어는 

+, -, *, /, AND이다. 원래는 16 키패드라 연산자가 6개까지 가능한데, 결과 출력을 위한 =를 넣느라

5개밖에 안된다.

여기에 ALU에 추가적으로 다른 NAND, XOR등을 넣으면 더 다양한 연산을 할 수 있을 것으로 보인다.

 

이 강의를 통해서 CPU의 동작 및 주요 용어 그리고 어셈블리 프로그래밍에 대해서 배울 수 있었다.

4bit CPU라 할 수 있는 동작이 그렇게 많지는 않지만,

기본 개념은 이를 기반으로 동작하기에 다른 CPU를 이해하는데 문제는 없을 것으로 보인다.