CS/마이크로프로세서

[마이크로프로세서] ATmega 128 구조

nowkoes 2023. 10. 10. 00:00

ATmega 128 구조

개요

기본 구조

 

 지난 시간에 ATmega 128에 대한 대략적인 개요를 파악했었다. 이번 시간에는 ATmega 128의 CPU와 메모리 구조를 파악해 보는 시간을 가지도록 해보자. 시작하기 앞서 ATmega 128은 프로그램(SRAM)과 데이터(FLASH, EEPROM)가 분리되어 있으므로 Havard 구조를 채택하고 있다는 점 알아두자. 그리고, 해당 구성요소들은 컴퓨터 구조 시간에서 한 번씩 다뤘던 내용이므로, 헷갈린다면 해당 게시글들을 확인해 보자.


본문

CPU 구조

ATmega 128 구조

 

 ATmega 128의 CPU 구조다. 여기서 ALU를 포함해 범용 레지스터(General Purpose Register), 상태 제어 레지스터(Status and Control), 프로그램 카운터, 플래시 메모리, 명령 레지스터, 명령 디코더코어부라고 한다. 코어는 프로세서의 기본 연산을 수행하는 구성 요소로, 이는 프로그램 명령어를 해석하고 실행하는 데 결정적인 역할을 한다. 

 

 기본 동작 원리는 간단하다. PC 레지스터로부터 다음 명령어 주소를 얻고, 플래시 메모리 내 해당 주소로부터 다음 명령어를 인출한다. 그리고 인출된 명령어는 명령 레지스터에 저장되고, 명령어 디코더가 이를 해석한다. 마지막으로 해석된 명령에 따라 제어 신호를 발생시킨다. 이제 구성 요소들에 대해 알아보자.

 

상태 레지스터

 

 산술논리연산장치 ALU두 개의 연산자를 받아 32개의 범용 레지스터와 직접적으로 연계되어 동작한다. 연산자가 ALU로 전달되면, ALU는 레지스터 간 또는 레지스터와 상수 간의 산술 또는 논리 연산을 수행한다. ATmega 128의 ALU는 이러한 연산을 파이프라이닝 기법을 사용하여 하나의 클럭 사이클 내에서 처리할 수 있다. 그리고 연산 결과는 다시 범용 레지스터로 전달되거나 다음 연산의 입력으로 사용된다. 이때 연산 결과에 대한 ALU의 상태를 상태 레지스터로 갱신한다.

 

 상태 레지스터(Status and Control Register, SREG)8비트로 구성되며, ALU에서 수행된 연산에 따른 여러 상태 플래그를 갖고 있다. ALU에서 연산이 수행된 후, 그 결과와 연산 중 발생한 여러 상황들이 상태 레지스터의 플래그로 업데이트된다. 그리고 조건 분기 명령어에서 조건을 평가하는 데 사용되어, 프로그램의 실행 흐름을 제어한다. 

 

 

 위에서 보는 것과 같이 ATmega 128에는 32개의 8비트범용 레지스터가 있다. 이러한 레지스터들은 AVR 고성능 RISC 명령을 수행하는데 최적화된 레지스터로서, 데이터 연산, 입/출력 제어, 상태 저장 등 다양한 목적으로 사용된다. 이때 범용 레지스터는 RAM 메모리에 비해 접근 속도가 매우 빠르므로, 컴파일 시 레지스터를 이용하여 빠르게 연산하도록 최적화가 이루어진다. 

 

#include <avr/io.h>

int main()
{
    unsigned char a = 0xFF;
    PORTA = a;
    
    return 0;
}

 다음과 같이 코드가 있다고 가정해 보자. 이렇게 작성된 코드는 컴파일러에 의해 기계어 코드로 변환될 때, 최적화 과정을 거친다. 즉, 우리는 C언어 환경에서 메모리에 a를 쓰라고 프로그래밍했지만, 컴파일 과정에서 자주 사용하는 변수를 레지스터에 값을 로드하는 것이다. 예를 들어, 위 코드는 어셈블리어로 다음과 같이 변환될 수 있다.

 

    ldi r24, 0xFF  ; 레지스터 r24에 0xFF 값을 로드
    out PORTA, r24 ; PORTA에 r24의 값을 출력

메모리 구조

 

 ATmega 128의 메모리 구조다. 크게 명령어를 저장하는 프로그램 메모리(Flash), 프로그램 실행 중 데이터 읽고 쓰기가 가능한 데이터 메모리(SRAM), 전원 오프 시에 주요 변수들을 저장하는 백업용 메모리(EEPROM)로 나뉜다. 또한 최대 64KB까지 확장 가능한 외부 메모리 인터페이스를 제공한다.

 

 

 프로그램 메모리128KB의 플래시 메모리를 활용하여 기계어 코드를 저장한다. 이는 64K 개의 주소와 각 주소당 16bit 데이터를 갖는 구조로 이루어져 있다. 따라서, 16bit의 주소 버스와 16bit의 데이터 버스가 필요하다. 플래시 메모리는 비휘발성 특성을 가지며, 전원이 꺼져도 데이터가 유지된다. 그러나, 재프로그래밍은 약 10,000회로 제한된다. 추가로, 프로그램 메모리는 부트 프로그램 영역과 응용 프로그램 영역으로 분리되어 있고, SPI 통신 방식을 이용한 ISP 기능을 갖고 있어, 프로그램을 쉽게 쓸 수가 있다.

 

 

 데이터 메모리4KB(주소의 개수 4K * 데이터 8bit)의 SRAM을 활용하여 프로그램이 실행되는 동안 변수, 입출력 레지스터, 스택 등의 데이터를 저장한다. 최대 64KB까지 확장 가능한 데이터 메모리는 16비트 주소 버스와 8비트 데이터 버스로 연결하며, 확장 시 외부 메모리를 추가로 구성해야 하고, 기본적으로는 내부 메모리만 부착되어 있다. 

 

 또한 데이터 메모리는 32개의 범용 레지스터 영역, 64개의 I/O 레지스터 영역, 160개의 확장 I/O 레지스터 영역(여기까지 레지스터 파일 영역), 내부 SRAM, 외부 SRAM 영역으로 나뉜다. 

 

 

 CPU는 프로그램을 실행하며 프로시저(Procedure, 특정 작업을 수행하기 위한 일련의 명령어 또는 코드 블록)를 실행시킨다. 프로시저가 다른 프로시저를 호출하면, 호출한 프로시저의 실행이 완료될 때까지 기다린다. 호출한 프로시저의 실행이 완료되면, 호출했던 지점 이후의 문장들을 이어서 실행한다.

 

 이 과정에서 현재 실행 중이던 프로시저의 메모리 주소는 SRAM의 스택(Stack) 영역에 저장된다. 왜냐하면 프로시저 호출이 완료된 후에 원래의 실행 흐름으로 돌아올 수 있도록, 프로시저 호출 이전의 실행 주소를 어딘가에 저장해야 하기 때문이다. 이 과정에서 프로시저 호출과 반환의 특성이 스택의 LIFO 방식과 일치하므로 스택을 사용한다. 

 

 즉, 스택은 메모리의 한 부분으로, 데이터를 임시로 저장하는 데 사용된다. 스택 포인터(Stack Pointer)는 현재 스택의 최상단 주소를 가리키는 16비트 레지스터로, 데이터가 스택에 푸시되면 SP가 감소하고, 데이터가 팝되면 SP가 증가한다. 이렇게 스택 포인터를 통해 프로시저의 호출과 반환을 효율적으로 관리할 수 있다. 이때 주솟값은 다음에 실행될 주솟값을 가지고 있다는 점 주의하자.

 

#include <stdio.h>

int main()
{
    int a = 1;
    int b = 2;
    int c = ADD(a,b);
    
    printf("%d", c);
    
    return 0;
}

int ADD(int a, int b)
{	
	int res = a + b;
	return res;
}

 다음과 같은 코드가 있다고 가정해 보자. 시작 주소가 0x01이라고 하면, 다음과 같이 PC에 주소가 저장될 것이다.

 

int main()
{
    int a = 1;           // PC: 0x01
    int b = 2;           // PC: 0x02
    int c = ADD(a,b);    // PC: 0x03 SP: push(0x04)

 이때 ADD 함수를 호출하라는 분기문을 처리하는데, 이때 PC의 주소 0x03을 스택에 저장하는 것이다.

 

int ADD(int a, int b) // PC: 0xA0
{
    int res = a + b; // PC: 0xA1
    return res; // PC: 0xA2, SP: pop, PC: 0x04
}

 해당 함수가 호출되고 나서, PC는 이전 흐름과 다른 메모리 주소를 사용한다. 이렇게 함수 호출이 끝나면 

 

int main()
{
    ...
    printf("%d", c); // PC: 0x04
    
    return 0; // PC: 0x05
}

 PC는 스택 포인터에 있는 주소를 가져와 PC에 할당한다.

 

 

 데이터 백업용 메모리4KB(4K * 8bit)의 EEPROM을 사용하는 복구용 메모리다. 최대 100,000번 재프로그래밍이 가능하며, 프로그램/데이터 메모리와는 별도의 주소 공간을 사용한다. 이때 I/O 레지스터를 사용하여 주소를 지정하고, 접근 방법이 번거롭다는 특징이 있다. 


요약

ATmega 128 구조
1. CPU 구조
 a. ALU
  - 정의: 범용 레지스터와 연계되어 동작하며 연산을 수행하는 장치
  - 특징: 연산 결과는 범용 레지스터로 전달되거나, 다음 연산의 입력으로 사용. 이때 파이프라이닝 기법을 사용하여 연산을 하나의 클럭 내에서 처리
 b. 상태 레지스터
  - 정의: 8비트로 구성되며, ALU의 연산 결과에 따라 여러 상태 플래그를 갖는 레지스터
  - 특징: 연산 후 결과와 상황들이 상태 레지스터의 플래그로 업데이트되며, 프로그램의 실행 흐름을 제어
 c. 범용 레지스터
  - 정의: 데이터 연산, 입/출력 제어, 상태 저장 등 다양한 목적으로 사용되는 레지스터
  - 특징: 빠른 연상르 위해 컴파일 시 최적화가 이루어짐
2. 메모리 구조
 a. 프로그램 메모리
  - 정의: 128KB(16의 플래시 메모리로 기계어 코드를 저장
  - 특징: 16비트의 주소 버스, 16비트의 데이터 버스를 가짐
 b. 데이터 메모리
  - 정의: 4KB의 SRAM을 사용하며, 프로그램 실행 중 데이터를 저장
  - 특징: 스택 포인터를 활용하며, 여러 영역으로 나뉨. 프로그래밍에 제한이 있음.
 c. 데이터 백업용 메모리
  - 정의: 4KB의 EEPROM을 사용하며, 데이터를 백업하기 위해 사용
  - 특징: 프로그래밍에 제한이 있고, I/O 레지스터를 사용하여 주소를 지정
반응형