임베디드 면접 용어 사전
메모리·아키텍처폰노이만

하버드 구조

명령과 데이터 버스를 분리한 구조. 동시 접근이 가능해 파이프라인 효율이 높다.

명령어와 데이터를 별도의 메모리·버스로 분리한 컴퓨터 구조.

폰 노이만 구조와의 대비

폰 노이만 (Von Neumann)
        ┌─────────────────┐
        │ CPU             │
        └──┬──────────────┘
           │ 하나의 버스
        ┌──┴──────────────┐
        │ 명령어 + 데이터 │
        └─────────────────┘
→ 명령어를 읽을 때와 데이터를 읽을 때 버스를 나눠 써야 한다
   (폰 노이만 병목)

하버드 (Harvard)
        ┌─────┐
   ┌────┤ CPU ├────┐
   │    └─────┘    │
┌──┴────┐      ┌───┴───┐
│ 명령어│      │데이터 │
└───────┘      └───────┘
→ 동시에 접근 가능. 명령어 인출과 데이터 접근이 병렬

이름의 유래

1944년 하버드 대학의 Mark I 컴퓨터가 프로그램을 천공 테이프에, 데이터를 별도 저장소에 둔 데서 왔다.

장점

  • ① 명령어 인출과 데이터 접근이 동시에 → 처리량 향상
  • ② 명령어 폭과 데이터 폭을 다르게 할 수 있다
    • (예: 명령어 14비트, 데이터 8비트 — PIC 마이크로컨트롤러)
  • ③ 명령어 메모리를 읽기 전용으로 두어 안전성 확보
  • ④ 파이프라인 구성이 쉽다

②가 임베디드에서 실질적이다. 명령어 폭을 데이터와 독립적으로 정해 코드 밀도를 최적화할 수 있다.

순수 하버드의 불편함

  • 프로그램 메모리에 있는 상수 테이블을 읽으려면?
  • 별도의 특수 명령이 필요하다
// AVR — 플래시의 데이터를 읽으려면 PROGMEM과 전용 함수
const char msg[] PROGMEM = "Hello";
char c = pgm_read_byte(&msg[0]);      // 일반 포인터로는 못 읽는다

이것이 AVR(아두이노) 프로그래밍이 번거로운 이유다. 문자열을 플래시에 두면 RAM은 아끼지만 읽는 코드가 달라진다.

수정 하버드 구조 — 현실의 타협

대부분의 현대 MCU가 쓰는 방식이다.

  • 버스는 분리되어 있다 (I-Bus, D-Bus) → 병렬 접근의 이득
  • 주소 공간은 통합되어 있다 → 같은 포인터로 접근 가능

ARM Cortex-M이 정확히 이 구조다.

Cortex-M3/M4 의 버스
├─ ICode Bus : 플래시에서 명령어 인출 (0x00000000~0x1FFFFFFF)
├─ DCode Bus : 플래시에서 상수 데이터 읽기 (같은 영역)
└─ System Bus: SRAM, 주변장치 (0x20000000~)

같은 플래시 영역을 두 버스로 동시에 접근한다. 그래서 코드 실행 중에 .rodata 상수를 읽어도 버스 경합이 없다.

const uint8_t table[256] = { … };   // 플래시에 있지만
uint8_t v = table[i];                // 일반 포인터로 그냥 읽힌다  ← 통합 주소 공간

AVR과 달리 특수 함수가 필요 없는 이유가 여기에 있다.

실무에서 왜 알아야 하나

① 성능 이해

  • SRAM에서 코드를 실행하면?
  • System Bus 하나로 명령어와 데이터를 모두 처리 → 경합 발생 → 느려질 수 있다
  • 반대로 플래시가 느린 경우(웨이트 스테이트)에는 SRAM 실행이 빠르다

"RAM 실행이 항상 빠르다"는 것은 오해다. 버스 구조와 플래시 대기 사이클을 함께 봐야 한다.

② 부트로더와 플래시 쓰기

  • 플래시에 쓰는 동안에는 그 플래시에서 명령어를 인출할 수 없다
  • 플래시 쓰기 루틴은 반드시 RAM에서 실행해야 한다
__attribute__((section(".ramfunc"))) void flash_write(...) { … }

링커 스크립트에서 이 섹션을 RAM에 배치하고, startup에서 복사한다. OTA 펌웨어 업데이트를 구현할 때 반드시 마주치는 문제다.

③ 캐시 구조

I-Cache와 D-Cache가 분리된 것도 하버드 발상의 연장이다. 자기 수정 코드나 OTA 후에는 I-Cache를 무효화해야 새로 쓴 코드가 실행된다.

함께 보면 좋은 용어

노트에서 맥락과 함께 보기 — 메모리·아키텍처 — 메모리맵·MMU/MPU·캐시·DMA·엔디안·정렬