본문으로 건너뛰기
5분 AI.
TRENDSHIFT REPOSITORIES #2 딥다이브 · 2026-10-23 분석

mgba 딥다이브
— C 코드로 작은 게임기의 시간을 재현하다

에뮬레이터

빠른 판단

무엇
GBA·GB·GBC의 CPU·메모리·영상·오디오 동작을 C로 재현하는 크로스플랫폼 에뮬레이터
이럴 때
보유 게임을 로컬에서 실행할 때
mGBA는 Game Boy Advance와 Game Boy·Game Boy Color를 소프트웨어로 재현하는 에뮬레이터입니다. 게임을 실행하는 도구 안에서 C 함수 포인터, 명령어 해석, 메모리 매핑, 이벤트 스케줄링, 오디오 동기화가 어떻게 만나는지 살펴봅니다. 주 언어 C · ⭐ 7,521 · 포크 1,139 · MPL-2.0 · 2026-10-23 GitHub 기준. 코드 설명은 커밋 fd9dc5c 기준이며, 정식 릴리스 0.10.5와 개발 중인 0.11.0의 차이도 짚습니다.
목차
  1. 프로젝트 한줄 요약
  2. 왜 주목받는가
  3. 기술 스택 전체 지도
  4. 아키텍처 심화 분석
  5. 디렉토리 구조 해부
  6. 학습 포인트 (기술별)
  7. 하드웨어 / 시스템 요구사항
  8. 직접 해볼 수 있는 실습 과제
  9. 관련 기술 심화 학습 로드맵
  10. 핵심 키워드 사전
  11. 참고 링크

1프로젝트 한줄 요약

게임 파일을 읽어, 가상 게임기의 상태를 한 단계씩 바꾸는 프로그램

mGBA는 게임기의 부품과 그 부품이 움직이는 순서를 코드로 구현한 프로그램입니다. 게임 파일에 들어 있는 기계어를 해석하고, 가상 메모리를 읽고 쓰며, 화면과 소리를 만들어 컴퓨터의 출력 장치로 전달합니다. 에뮬레이터의 핵심은 그림을 비슷하게 그리는 것보다, 하드웨어의 상태가 언제 바뀌는지 재현하는 데 있습니다.

용어
에뮬레이션 (emulation)
다른 기계의 동작 규칙을 소프트웨어로 흉내 내는 것입니다. 원래 GBA의 CPU가 처리하던 명령을 내 컴퓨터의 CPU가 해석합니다. 게임 코드를 웹이나 PC용 코드로 미리 다시 만드는 과정과는 다릅니다.
용어
ROM과 코어 (core)
ROM은 이 문서에서 카트리지의 프로그램·데이터를 담은 파일을 뜻합니다. 코어는 게임기 동작을 구현한 엔진입니다. 창·메뉴·입력 장치를 제공하는 프론트엔드는 이 엔진을 호출합니다.
한 문장 비유

mGBA는 작은 게임기의 부품을 맡아 연기하는, 정교한 인형극 무대입니다

ROM은 대본이고, CPU는 다음 지시를 읽는 배우입니다. 메모리는 소품 창고이며, 화면과 소리는 관객이 보는 결과입니다.

대본 내용만 맞아도 공연이 완성되지는 않습니다. 조명이 켜질 때와 음악이 나올 때를 맞추는 무대감독이 필요합니다. mGBA에서는 mTiming이 그 시간을 관리합니다.

게임 하나를 열면 일어나는 일

  1. src/core/core.c의 mCoreFindVF()가 파일 내용을 판별해 GBA 또는 GB 코어를 고릅니다.
  2. GBA의 경우 GBACoreCreate()가 공통 함수표를 채우고, init 호출이 CPU·보드·렌더러를 준비합니다.
  3. 프론트엔드가 ROM과 설정을 연결하고 reset을 호출합니다.
  4. 코어가 명령어와 하드웨어 이벤트를 진행하고, 프론트엔드가 픽셀·오디오를 출력합니다.

이 흐름은 src/platform/example/client-server/server.c의 _mExampleRun()에서 특히 잘 보입니다. 입력을 받아 setKeys를 호출하고, runFrame 뒤에 화면 버퍼를 보냅니다. 이 예제의 네트워크 연결은 화면 전송 학습용이며, 게임기의 통신 케이블을 인터넷으로 구현했다는 뜻은 아닙니다.

이 글에서 얻을 것
문법을 아는 단계에서, 부품 사이의 계약을 읽는 단계로

함수 하나의 정답보다 누가 상태를 소유하고, 누가 호출하며, 어느 시점에 결과가 보이는가를 배웁니다. 이 질문은 게임 엔진, 오디오 프로그램, 장치 시뮬레이터에도 그대로 적용됩니다.

2왜 주목받는가

관심 지표와 기술적 매력을 구분해서 읽기

2-1. 순위는 관심을 보여 주고, 코드는 공부할 이유를 보여 줍니다

2026-10-23 분석 대상 선정 기준은 TrendShift Repositories #2입니다. 같은 날 GitHub 기준 스타는 7,521개, 포크는 1,139개입니다. 다만 이 수치와 순위만으로 특정 영상·사건·기능이 유행의 원인이라고 단정할 수는 없습니다. 여기서는 소스와 문서에서 드러나는 학습 가치에 초점을 맞춥니다.

첫째, 하나의 엔진을 여러 제품 형태로 재사용합니다. Qt GUI, SDL 프론트엔드, Libretro 연동과 Python 바인딩이 공통 코어 주변에 놓입니다. 둘째, CPU뿐 아니라 센서·저장·영상·디버거까지 이어져, 낮은 수준의 구현이 사용자 기능으로 바뀌는 과정을 볼 수 있습니다.

셋째, 오래된 기계를 다루면서도 이식성과 유지보수를 계속 다룹니다. CHANGES의 개발 버전 항목에는 Qt 6 지원, DMA 경계 동작 수정, 헤드리스 프론트엔드 등이 있습니다. 이는 분석 커밋의 변경 기록이며, 모두 0.10.5에 들어 있다는 의미는 아닙니다.

2-2. 다른 에뮬레이터와 비교하면 보이는 위치

도구공식 자료상 중심mGBA를 공부할 때의 차별점
mGBAGBA와 GB·GBC, Qt·SDL, 디버깅·스크립트C의 공통 코어 계약에서 CPU·주변장치·GUI까지 추적하기 좋음
VBA-MGB·GBA 에뮬레이터. wxWidgets 및 SDL 포트mGBA에서는 Qt와 mCore의 경계를 중심으로 같은 문제의 다른 설계를 배움
SameBoyGB·GBC·Super Game Boy, 정확도와 디버깅 기능GBA의 ARM·Thumb까지 함께 공부하려면 mGBA의 대상 범위가 알맞음

비교 근거: VBA-M 공식 저장소, SameBoy 공식 소개. 지원 범위와 구성 방식의 비교이며, 같은 조건의 성능·정확도 측정 결과는 아닙니다.

mGBA를 공부할 가치는 여러 화면과 플랫폼이 같은 에뮬레이션 엔진을 공유하도록 만든 경계에서 드러납니다. SDL로 바꾸어도 ARM 명령어의 의미를 다시 구현하지 않는 이유를 이해하는 것이 좋은 출발점입니다.

2-3. README의 목표와 검증 가능한 구현

README 표현소스에서 확인할 근거해석할 때 주의할 점
빠르고 정확한 에뮬레이션사이클 계산, 메모리 대기 시간, 하드웨어 테스트 자료설계 방향을 뒷받침하지만 경쟁 도구보다 항상 빠르다는 증거는 아님
되감기·상태 저장src/core/rewind.c, src/gba/serialize.c화면만 저장하는 기능이 아니라 가상 기계의 상태 복원이 필요함
통신 케이블 지원README는 같은 컴퓨터에서의 연결을 명시네트워크 멀티플레이는 README의 계획 항목에 있으므로 구분해야 함
비유

좋은 교육용 건축물은 겉모습만 멋진 건물이 아닙니다. 배관·전기·기둥이 어디서 연결되는지 읽을 수 있어야 합니다. mGBA의 공통 코어와 플랫폼 폴더는 그 연결부를 살펴볼 수 있게 해 줍니다.

3기술 스택 전체 지도

네이티브 코어 · 데스크톱 화면 · 빌드와 검증 도구

웹 서비스의 용어를 빌리면 백엔드는 로컬 에뮬레이션 코어, 프론트엔드는 Qt·SDL 화면입니다. 일반 실행 경로에 HTTP 서버나 클라우드 DB가 필요한 구조는 아닙니다. SQLite도 사용자 계정 서버가 아니라 게임 데이터베이스 기능에 쓰는 선택 의존성입니다.

3-1. 백엔드에 해당하는 부분: C11 코어

영역실제 파일·설정배울 수 있는 기술
언어 기준CMakeLists.txt: CMAKE_C_STANDARD 11고정 폭 정수, 구조체, 함수 포인터, 조건부 컴파일
GBA CPUsrc/arm/arm.c, src/arm/isa-arm.c, src/arm/isa-thumb.cARM·Thumb 명령 디코딩과 실행, 파이프라인 상태
GB CPUsrc/sm83/, src/gb/다른 CPU와 하드웨어를 같은 코어 인터페이스로 감싸기
주변장치src/gba/memory.c, src/gba/video.c, src/gba/audio.c, src/gba/dma.c주소 매핑, 영상 타이밍, 샘플 생성, 메모리 전송
공통 기능src/core/, src/util/스레드, 상태 저장, 가상 파일, 순환 버퍼

3-2. 프론트엔드: C++14·Qt와 SDL

src/platform/qt/CMakeLists.txt는 C++14를 요구하며, QT_VERSIONS 6 5 순서로 Qt를 탐색합니다. Core·Widgets·Network를 찾고 Multimedia는 선택 모듈로 취급합니다. FORCE_QT_VERSION에 5 또는 6을 지정하는 분기도 있습니다.

SDL은 src/platform/sdl/CMakeLists.txt에서 SDL_VERSION "3"이 기본입니다. SDL 3을 찾지 못하면 2, 그다음 1.2를 찾습니다. 이는 버전 번호를 하나로 고정한 잠금 파일이 아니라 사용 가능한 라이브러리를 선택하는 탐색 정책입니다.

용어
바인딩 (binding)
한 언어의 기능을 다른 언어에서 호출하게 연결한 계층입니다. Python 바인딩은 새 에뮬레이터를 Python으로 다시 만든 것이 아닙니다. C 코어를 CFFI로 연결합니다. Lua는 실행 중인 코어를 제어하는 스크립트 언어로 쓰입니다.

3-3. 의존성에 기록된 버전: 고정 값과 최소 조건을 구분하기

항목소스에 기록된 값근거와 의미
CMake3.12 이상루트 CMakeLists.txt 첫 줄의 실제 최소 요구
개발 버전0.11.0 · ABI 0.11version.cmake. 정식 릴리스 번호와 구분
동봉 zlib1.2.12src/third-party/zlib/zlib.h의 ZLIB_VERSION
동봉 libpng1.6.51src/third-party/libpng/png.h의 버전 매크로
동봉 SQLite3.51.1src/third-party/sqlite3/sqlite3.h의 SQLITE_VERSION
Python CFFI1.6 이상src/platform/python/setup.py: cffi>=1.6
Python 이미지 확장Pillow 2.3 이상같은 파일의 pil 선택 의존성. pytest는 테스트용
그 밖의 기능FFmpeg·libzip·Lua·json-c·libedit 등CMake의 find_feature()로 탐색. 하나의 설치 버전으로 고정되지 않음

동봉 버전은 저장소 안의 사본에 대한 값입니다. CMake가 시스템 라이브러리를 찾는 경우 실제 링크 대상 버전은 달라질 수 있습니다. FFmpeg는 녹화, libpng·zlib는 이미지와 압축, libzip은 압축 ROM, Lua는 스크립트 기능과 연결됩니다.

3-4. 인프라·빌드: 기능을 조합하는 CMake

# CMakeLists.txt의 기본값 일부를 간추린 구성 지도
M_CORE_GBA=ON      M_CORE_GB=ON
BUILD_QT=ON        BUILD_SDL=ON
BUILD_SHARED=ON    BUILD_STATIC=OFF
BUILD_LIBRETRO=OFF BUILD_PYTHON=OFF
BUILD_SUITE=OFF    BUILD_CINEMA=OFF

ON은 기능을 요청하는 기본값이지, 모든 환경에서 반드시 포함된다는 보장은 아닙니다. Qt·SDL 라이브러리를 찾지 못하면 해당 프론트엔드가 제외될 수 있습니다. LIBMGBA_ONLY 분기는 프론트엔드를 끄고 정적 라이브러리 중심으로 구성합니다.

CMakePresets.json의 clang·gcc 프리셋은 Ninja, Debug, CMAKE_EXPORT_COMPILE_COMMANDS=ON을 설정합니다. 이름만 보고 컴파일러 실행 파일까지 고정한다고 해석하면 안 됩니다.

테스트 구성은 src/platform/test/CMakeLists.txt에 있습니다. BUILD_SUITE는 cmocka 기반 단위 테스트, BUILD_CINEMA는 화면 결과 비교 도구를 만듭니다. README는 외부 Buildbot 배지와 Docker 이미지를 안내하지만, 이 커밋의 프로젝트 .github/에는 후원 설정만 있으며 GitHub Actions 워크플로는 없습니다. 서드파티 libpng의 워크플로를 mGBA 자체 CI 설정과 혼동하지 않아야 합니다.

문서와 설정의 차이
README의 오래된 숫자보다 현재 구성 파일을 먼저 확인하세요

README는 CMake 3.1 이상, GUI 의존성 Qt 5, SDL 2 권장을 안내합니다. 분석 커밋은 CMake 3.12 이상을 요구하고 Qt 6·5 탐색과 SDL 3·2·1.2 탐색을 구현합니다. 빌드 환경을 정할 때 이 차이가 실제 오류 원인이 될 수 있습니다.

4아키텍처 심화 분석

상태와 시간이 흐르는 경로를 따라 읽기

4-1. 시스템 전체를 한 장으로 보기

먼저 두 종류의 시간을 구분합시다. 가상 게임기의 시간은 CPU 사이클로 흐르고, 실제 컴퓨터의 시간은 화면 갱신과 오디오 장치의 소비 속도로 흐릅니다. 코어는 전자를 계산하고, 동기화 계층은 후자와 보조를 맞춥니다.

[ROM] | VFile / VDir | mCoreFindVF() / mCoreLoadFile() | +----------+---------------------+ | 공통 mCore 계약 | | init / reset / runLoop / step | | setKeys / getPixels / saveState| +----------+---------------------+ | +----------+----------+ | | [GBA 코어] [GB 코어] ARM / Thumb SM83 메모리 / DMA 메모리 / MBC 영상 / 오디오 영상 / 오디오 | | +----------+----------+ | mTiming: 가상 사이클과 다음 이벤트 | +---- 픽셀 버퍼 ----+---- 오디오 버퍼 | mCoreThread / mCoreSync | Qt / SDL / Libretro 등 프론트엔드 | 실제 화면 / 스피커 / 입력 Lua / 디버거 / Python 바인딩은 공통 코어 주변에서 연결

연결선은 주된 데이터·제어 경로를 요약합니다. BIOS와 게임 저장 파일은 각각 별도의 loadBIOS·loadSave 호출로 연결합니다. Libretro나 단순 예제까지 모두 같은 스레드 구성을 쓰는 것은 아닙니다. Qt 경로에서는 CoreController가 코어 스레드를 관리하고, src/core/thread.c의 _mCoreThreadRun()이 실행 상태에서 core->runLoop(core)를 반복합니다.

4-2. 설계 패턴 ① 함수표와 팩터리: C로 만드는 다형성

include/mgba/core/core.h의 struct mCore에는 init, runFrame, step, busRead32 같은 함수 포인터가 있습니다. 호출자는 같은 이름으로 요청하지만, 실제 실행되는 함수는 코어에 따라 달라집니다.

// src/gba/core.c: GBACoreCreate()의 함수표 연결 중 일부
core->init = _GBACoreInit;
core->reset = _GBACoreReset;
core->runFrame = _GBACoreRunFrame;
core->runLoop = _GBACoreRunLoop;
core->step = _GBACoreStep;

src/core/core.c의 _filters[]는 GBAIsROM과 GBACoreCreate, GBIsROM과 GBCoreCreate를 짝짓습니다. mCoreFindVF()는 판별 함수가 맞는 항목의 생성 함수를 호출합니다. 팩터리는 어떤 구현을 만들지 결정하고, 다형성은 만들어진 구현을 같은 방식으로 사용하는 성질입니다.

비유

리모컨의 재생 버튼은 같지만 TV와 오디오 내부의 동작은 다릅니다. 프론트엔드는 리모컨을 사용하고, 코어 생성 함수는 알맞은 기기의 버튼 배선을 연결합니다.

배울 점: C++의 상속 문법이 없어도 역할을 분리할 수 있습니다. 대신 함수표 초기화, 객체 수명, 포인터 형식의 일관성을 개발자가 책임져야 합니다. _GBACoreInit()과 _GBACoreDeinit()를 짝지어 읽으면 자원 소유권도 드러납니다.

4-3. 설계 패턴 ② 이산 이벤트: 다음 일이 생길 때까지 진행하기

src/arm/arm.c의 ARMStep()는 opcode의 비트를 뽑아 _armTable에서 실행 함수를 고릅니다. ThumbStep()는 _thumbTable[opcode >> 6]을 사용합니다. 명령어 실행으로 사이클이 누적되고, ARMRunLoop()는 cpu->cycles < cpu->nextEvent인 동안 진행합니다.

이벤트 시각에 닿으면 GBAProcessEvents()를 거쳐 mTimingTick()으로 넘어갑니다. mTimingSchedule()은 이벤트를 시각순 연결 리스트에 넣습니다. 시각이 같으면 priority 값이 작은 항목이 앞섭니다. 힙이나 OS 타이머를 쓰는 구현은 아닙니다.

# 스케줄러 규칙을 손으로 따라가는 예: 값은 학습용
현재 시각: 100
등록 순서: A(시각 130, 우선순위 8)
           B(시각 120, 우선순위 9)
           C(시각 130, 우선순위 3)
정렬 결과: B -> C -> A
시각 132에 처리: B는 12, C와 A는 2 사이클 늦음

mTimingTick()은 이미 지난 이벤트를 꺼내 콜백에 지연량을 넘깁니다. 영상 콜백 _startHblank()와 _startHdraw()는 다음 예약에서 cyclesLate를 뺍니다. 늦게 처리된 만큼 매번 다음 예약까지 밀리면 오차가 계속 쌓이므로 이를 보정하는 것입니다.

가상 시간을 정확히 계산하는 일과 실제 화면·소리의 재생 속도를 맞추는 일은 서로 다른 문제입니다. 이 구분이 있어야 빠른 감기, 일시정지, 디버깅을 넣어도 하드웨어의 내부 시간 관계를 설명할 수 있습니다.

4-4. 설계 패턴 ③ 어댑터: 파일의 출처를 숨기는 VFile

include/mgba-util/vfs.h의 VFile은 read, seek, map, close 등의 함수 포인터를 묶습니다. 디스크 파일, 메모리 블록, 압축 파일 내부 항목을 코어가 비슷한 방식으로 다루도록 하는 계약입니다.

// src/core/test/core.c의 findEmpty 테스트를 간추린 흐름
struct VFile* vf = VFileMemChunk(NULL, 0);
struct mCore* core = mCoreFindVF(vf);
// 빈 데이터이므로 ROM 판별 결과는 NULL이어야 합니다.
vf->close(vf);

src/core/core.c의 mCoreFind()는 압축 디렉터리를 열 수 있으면 내부 항목을 순회해 코어를 찾습니다. mCoreLoadFile()은 로딩이 실패하면 열린 ROM을 닫습니다. 단순히 파일 경로만 추상화한 것이 아니라, 열린 자원의 처리 책임까지 함께 읽어야 합니다.

배울 점: 파일을 메모리로 대체할 수 있으면 작은 테스트가 쉬워집니다. 네트워크·스토리지 코드를 배울 때도 실제 외부 서비스 없이 경계 조건을 확인하는 설계로 연결할 수 있습니다.

4-5. 설계 패턴 ④ 생산자·소비자: 오디오가 차면 코어도 기다린다

코어는 오디오 샘플을 생산하고, 실제 오디오 출력 쪽은 이를 소비합니다. src/util/audio-buffer.c는 mCircleBuffer 위에 샘플 버퍼를 만듭니다. mAudioBufferAvailable()은 바이트 수를 채널 수와 sizeof(int16_t)로 나누어 샘플 프레임 수로 바꿉니다.

src/core/sync.c의 mCoreSyncProduceAudio()는 동기화가 켜져 있고 버퍼가 상한 이상이면 조건 변수로 기다립니다. mCoreSyncConsumeAudio()는 소비 후 대기 중인 쪽을 깨웁니다. 초기 audioHighWater는 512이지만, 이것을 모든 환경의 지연 시간으로 환산해서는 안 됩니다.

// CoreController::updateFastForward()의 정상 속도 복귀 분기 일부
if (isChange) {
    mCoreSyncLockAudio(&m_threadContext.impl->sync);
    mAudioBufferClear(
        m_threadContext.core->getAudioBuffer(m_threadContext.core));
    mCoreSyncUnlockAudio(&m_threadContext.impl->sync);
}

커밋 fd9dc5c의 메시지는 빠른 감기 종료 시 쌓인 오디오로 잠깐 멈출 수 있던 문제를 설명합니다. 실제 코드도 src/platform/qt/CoreController.cpp에서 정상 속도 복귀 시 버퍼를 잠그고 비웁니다. 커밋 설명의 최대 약 500ms는 해당 문제의 맥락이며, 일반 사용 시 항상 그만큼 지연된다는 뜻은 아닙니다.

배울 점: 처리량이 높아도 오래된 결과가 큐에 남으면 반응성은 나빠집니다. 버퍼 용량만 늘리는 대신, 속도 전환 때 어떤 데이터를 버려도 되는지 결정하는 일이 필요합니다.

4-6. 명령 하나가 메모리와 화면으로 이어지는 경로

단계파일·함수확인할 상태 변화
명령 해석src/arm/arm.c · ARMStep()prefetch, 프로그램 카운터, 조건 플래그, 실행 함수 선택
메모리 접근src/gba/memory.c · GBALoad32()주소 상위 비트로 영역 선택, 대기 사이클 반영, 비정렬 읽기 회전
이벤트 처리src/gba/gba.c · GBAProcessEvents()명령 실행에서 쌓인 사이클을 스케줄러에 전달
한 줄 그리기src/gba/video.c · _startHblank()표시 구간의 줄이며 프레임 건너뛰기 대상이 아닐 때 렌더러의 drawScanline 호출
프레임 전달같은 파일 · _startHdraw()수직 공백 시작에서 프레임 완료·DMA·인터럽트·동기화 처리

메모리는 하나의 거대한 배열로만 취급되지 않습니다. include/mgba/internal/gba/memory.h는 0x02000000을 EWRAM, 0x04000000을 I/O, 0x06000000을 VRAM, 0x08000000을 ROM 시작 주소로 정의합니다. 같은 읽기 명령도 주소에 따라 다른 하드웨어 규칙을 거칩니다.

영상 시각을 관리하는 코드와 픽셀을 만드는 렌더러도 나뉩니다. GBAVideoAssociateRenderer()가 렌더러를 연결하고, _GBACoreInit()는 더미·소프트웨어 렌더러와 조건부 GL 렌더러를 준비합니다. 화면 출력의 구현을 바꾸는 일과 CPU 명령을 바꾸는 일을 분리한 구조입니다.

4-7. 상태 저장은 화면 캡처보다 더 많은 것을 요구합니다

src/gba/serialize.c의 GBASerialize()는 버전·체크섬뿐 아니라 CPU 레지스터, prefetch, 현재 사이클 등도 기록합니다. GBADeserialize()는 버전, 게임 정보, 사이클 값 등의 일관성을 검사합니다.

화면이 같아도 다음 명령이나 예약된 이벤트가 다르면 이후 결과가 달라집니다. 영상 코드가 콜백 전에 상태를 일관되게 맞추라고 주석으로 강조하는 이유도 여기에 있습니다. 저장할 상태를 정의하는 일은 시스템의 실제 상태가 무엇인지 정의하는 일이기도 합니다.

주요 근거: 이벤트 스케줄러 · ARM 실행 루프 · Qt 코어 제어.

5디렉토리 구조 해부

어디부터 읽어야 하는지 알려 주는 저장소 지도
mgba/ |-- CMakeLists.txt 빌드 대상·기능·의존성 탐색 |-- CMakePresets.json Ninja·Debug 프리셋 |-- version.cmake 개발 버전과 Git 버전 문자열 |-- README.md / CHANGES 기능 안내와 변경 기록 |-- CONTRIBUTING.md 기여 정책·코딩 규칙 |-- PORTING.md 플랫폼 이식 지침 |-- include/ | |-- mgba/core/ 공통 코어 계약 | |-- mgba/internal/ CPU·보드 내부 자료구조 | `-- mgba-util/ VFile·버퍼 등 유틸리티 헤더 |-- src/ | |-- core/ 코어 탐색·스레드·동기화·상태 저장 | |-- arm/ ARM·Thumb 명령 실행·디코딩 | |-- sm83/ GB 계열 CPU 구현 | |-- gba/ GBA 메모리·영상·오디오·DMA·통신 | |-- gb/ GB·GBC 하드웨어와 MBC | |-- debugger/ CLI 디버거·GDB 연동 기반 | |-- script/ 스크립트 형식·문맥·언어 엔진 | |-- feature/ 명령줄·녹화·영상 로그 등 | |-- util/ VFS·자료구조·이미지·오디오 도구 | |-- platform/ | | |-- qt/ C++ 데스크톱 GUI | | |-- sdl/ SDL 화면·입력·오디오 | | |-- libretro/ Libretro 연결 계층 | | |-- python/ CFFI 바인딩·Python 테스트 | | |-- test/ 성능·퍼징·영상 비교 도구 | | |-- example/ 클라이언트·서버 예제 | | `-- 3ds/ switch/ wii/ psp2/ 기기별 포트 | `-- third-party/ SQLite·zlib·libpng 등 외부 코드 |-- cinema/ 테스트 ROM·기준 화면·설정 |-- res/ UI 리소스·스크립트 등 |-- doc/ 명령줄·Qt 사용 설명서 `-- tools/ 배포·성능 측정·패키징 보조 도구

5-1. 폴더 경계에서 읽을 수 있는 책임

경계역할의 차이처음 던질 질문
core ↔ gba·gb공통 호출 규약과 기종별 구현프론트엔드가 CPU 종류를 직접 알아야 하는가?
arm ↔ gba명령어 의미와 GBA 보드의 장치 구성CPU가 메모리 읽기 함수를 어떻게 받는가?
영상 타이밍 ↔ 렌더러그릴 시점과 픽셀 생성 방식프레임 건너뛰기에도 어떤 이벤트는 계속 필요한가?
util ↔ platform재사용 도구와 OS·라이브러리별 연결다른 기기에 이식할 때 무엇을 바꿔야 하는가?
test ↔ cinema검사 도구와 검사에 쓰는 데이터실행 파일의 종료 코드만으로 그래픽 오류를 찾을 수 있는가?

5-2. 코드 규모: 외부 라이브러리를 빼고 보기

분류파일 수물리적 줄 수
C · .c251111,978
헤더 · .h32146,736
C++ · .cpp·.cc11830,991
Python · .py322,925
Lua · .lua121,147
어셈블리 · .s·.S1400

커밋 fd9dc5c의 해당 확장자 파일을 줄 단위로 집계한 값입니다. .git/과 src/third-party/는 제외하고 주석·빈 줄·테스트는 포함했습니다. 헤더는 C/C++가 공유하므로 별도 분류했습니다. 전체 파일 수나 실행 문장 수를 뜻하지 않습니다.

제외한 서드파티의 C만 따로 세면 397,425줄입니다. 이를 코어 구현량에 합치면 외부 라이브러리가 프로젝트의 자체 코드보다 크게 보일 수 있습니다. 규모를 비교할 때는 집계 범위를 먼저 맞추는 습관이 필요합니다.

추천 읽기 순서
예제 → 계약 → 기종 구현 → 시간 → 출력

src/platform/example/client-server/server.c에서 호출 흐름을 잡고, include/mgba/core/core.h → src/gba/core.c → src/arm/arm.c → src/core/timing.c → src/gba/video.c로 좁혀 가세요. 예제의 전체 경로는 src/platform/example/client-server/server.c입니다.

6학습 포인트 (기술별)

각 기술을 따로 외우지 않고 실제 사용 이유와 묶어 배우기

6-1. C: 함수 포인터·수명·고정 폭 정수

struct mCore를 읽을 때는 함수 이름보다 인자와 반환형을 먼저 보세요. void (*step)(struct mCore*)는 코어 상태를 받아 한 단계를 진행하는 계약입니다. bool (*loadROM)(struct mCore*, struct VFile*)에는 실패 가능성과 열린 파일의 수명 문제가 함께 붙습니다.

명령어·레지스터·주소에는 uint32_t, 샘플에는 int16_t 같은 형식이 등장합니다. 데이터 폭이 곧 하드웨어 규칙이기 때문입니다. 포인터 주소 자체를 저장 파일에 쓰는 방식이 아니라, 복원할 값과 형식을 명시하는 방식에 주목하세요.

실습 아이디어

함수표의 세 칸을 끝까지 연결하기

init, runLoop, deinit에 대해 선언·대입·실제 구현 위치를 한 줄씩 적어 보세요. 각 단계가 만드는 자원과 해제하는 자원을 옆에 붙이면 함수 포인터와 메모리 수명을 함께 익힙니다.

6-2. 컴퓨터 구조: 주소와 비트에 의미 붙이기

GBALoad32()는 address >> BASE_OFFSET으로 영역을 고릅니다. BASE_OFFSET은 24입니다. 주소의 상위 8비트가 어떤 장치를 가리키고, 아래 비트가 그 안의 위치를 뜻하는지 먼저 구분하세요.

# 주소 영역을 읽는 연습: 실제 장치 접근은 하지 않습니다.
0x02000000 >> 24 = 0x02   EWRAM
0x04000130 >> 24 = 0x04   I/O 영역
0x06000000 >> 24 = 0x06   VRAM
0x08000000 >> 24 = 0x08   ROM 영역

다음으로 비정렬 접근을 보세요. GBALoad32()의 마지막에는 주소 하위 비트로 회전량을 계산해 ROR(value, rotate)를 반환하는 코드가 있습니다. 호스트 언어의 자연스러운 배열 접근과 가상 CPU의 동작 규칙이 다를 수 있음을 보여 줍니다.

6-3. 자료구조와 시뮬레이션: 연결 리스트를 선택한 이유 생각하기

mTimingEvent 안에 next 포인터가 있어 이벤트 자신이 연결 리스트의 노드가 됩니다. mTimingSchedule()은 삽입 지점을 순회하므로 이벤트 수에 따라 비용이 늘어납니다. 매번 전용 노드를 새로 할당하지 않는 구성도 함께 읽을 수 있습니다.

이것이 모든 상황의 최적 선택이라는 뜻은 아닙니다. 하드웨어 이벤트 수가 작고 정해진 환경과, 수십만 작업이 등록되는 서버 환경은 다릅니다. 같은 규칙을 배열·최소 힙으로 표현하면 어떤 연산이 쉬워지는지 비교하는 것이 좋은 실습입니다.

6-4. 동시성·오디오: 숫자의 단위를 맞추기

mCoreSyncProduceAudio()의 대기 조건을 읽고, 버퍼 값의 단위부터 적어 보세요. 바이트 수, 채널별 값의 수, 샘플 프레임 수는 서로 다릅니다. mAudioResamplerProcess()에서는 sourceRate / destRate가 보간 위치의 증가량으로 쓰입니다.

용어
리샘플링과 역압 (resampling · backpressure)
리샘플링은 초당 샘플 수가 다른 두 오디오 시간축을 연결하는 일입니다. 역압은 소비자가 따라오지 못할 때 생산자가 기다리게 하는 흐름 제어입니다. 앞의 버퍼 대기는 역압의 구체적인 사례입니다.

손계산 연습: 가정한 출력이 48,000Hz·스테레오·16비트라면 100ms 분량은 48,000 × 0.1 × 2 × 2 = 19,200바이트입니다. 이는 단위 변환 예시이며, mGBA의 기본 출력 설정이나 측정 지연을 뜻하지 않습니다.

6-5. Qt·Lua·Python: 경계를 넘는 호출 이해하기

Qt의 CoreController는 UI에서 발생한 요청을 코어 실행·설정과 연결합니다. 빠른 감기 처리를 읽은 뒤에는 같은 클래스의 setFastForward(), setSync()를 찾아 버튼 상태와 실제 실행 설정이 어떻게 연결되는지 추적해 보세요.

Lua 쪽은 src/core/scripting.c가 코어 메서드를 공개 이름에 연결합니다. 예를 들어 C의 frameCounter는 스크립트에 currentFrame으로 노출됩니다. res/scripts/input-display.lua는 callbacks:add("frame", ...) 등록을 보여 줍니다.

-- 개발 버전의 바인딩을 바탕으로 만든 학습용 예제
local frames = 0
callbacks:add("frame", function()
    frames = frames + 1
    if frames % 60 == 0 then
        console:log("프레임: " .. emu:currentFrame())
    end
end)

60프레임마다 출력하는 예제이지, 정확히 1초마다 출력하는 시계는 아닙니다. 빠른 감기나 일시정지에서는 실제 경과 시간이 달라집니다. Lua 공식 매뉴얼은 언어 학습용이며, mGBA 내장 Lua 버전을 5.4로 고정한다는 뜻은 아닙니다.

Python은 src/platform/python/setup.py의 cffi_modules와 src/platform/python/_builder.py를 이어서 읽으세요. 패키지 설치 명령보다 먼저, C 함수와 Python 객체 사이에 어떤 형식·수명 변환이 필요한지 정리하면 좋습니다.

6-6. 테스트: 통과했다는 말의 범위를 구분하기

수준실제 예알 수 있는 것
자료구조 단위src/util/test/circle-buffer.c값·정렬·용량 등 버퍼의 개별 규칙
코어 경계src/core/test/core.cNULL·빈 파일 같은 입력에서의 판별 동작
화면 회귀cinema/, src/platform/test/cinema-main.c정해진 조건에서 기준 화면과 결과가 달라지는지

src/platform/test/cinema-main.c의 _compareImages()는 화면 차이를 비교합니다. 테스트 준비에서는 RTC_FAKE_EPOCH로 RTC의 기준 시각을 고정하고, 프레임 진행에 따라 시간을 계산해 실제 시계에 따른 변동을 줄입니다. 좋은 테스트를 설계하려면 결과뿐 아니라 결과를 만드는 입력·시간·상태도 고정해야 합니다.

7하드웨어 / 시스템 요구사항

재현하는 게임기의 사양과, 실행하는 컴퓨터의 조건은 다릅니다

7-1. 가상 GBA의 수치로 시간 감각 잡기

항목소스 기준 값읽는 위치
CPU 기준 주파수16,777,216Hzinclude/mgba/internal/gba/gba.h: #define GBA_ARM7TDMI_FREQUENCY 0x1000000U
기본 화면240 × 160픽셀include/mgba/gba/interface.h의 화면 상수
한 줄·한 프레임1,232사이클 · 228줄 · 280,896사이클include/mgba/internal/gba/video.h
메모리 일부EWRAM 256KiB · IWRAM 32KiB · VRAM 96KiBinclude/mgba/internal/gba/memory.h의 영역 크기
# 소스 상수로 계산한 가상 프레임 속도
1,232 × 228 = 280,896 사이클 / 프레임
16,777,216 ÷ 280,896 ≈ 59.7275 프레임 / 초

# 32비트 픽셀 버퍼 하나를 가정한 크기
240 × 160 × 4 = 153,600 바이트 = 150 KiB

픽셀 버퍼 계산은 32비트 출력의 예시이며 프로세스 전체 메모리 사용량이 아닙니다. GUI, ROM, 렌더러, 오디오 버퍼, 되감기 상태가 추가 공간을 차지합니다. 가상 CPU가 16.78MHz라고 해서 같은 주파수의 호스트 CPU면 충분하다는 뜻은 아닙니다.

7-2. 사용자 실행 환경: README와 배포물 조건을 함께 보기

항목안내·조건판단 기준
데스크톱 OSREADME: Windows 7 이상, OS X 10.9 이상, Linux, FreeBSD개별 배포물과 Qt·SDL 버전에 따라 실제 요구가 높아질 수 있음
그래픽README: OpenGL 1.1 이상, 셰이더 등 고급 기능은 3.2 이상선택한 출력 경로와 드라이버 지원을 확인
CPU·RAM고정 CPU 모델·최소 RAM 용량은 README에 명시되지 않음필터·녹화·되감기·빠른 감기 조건에 따라 자원 요구가 달라짐
게임 입력키보드, 게임패드. 일부 센서는 대응 장치·설정 필요README의 기능 목록과 해당 프론트엔드 지원을 구분
BIOS내장 구현과 외부 BIOS 로드 지원외부 BIOS가 없다는 이유만으로 모든 실행이 불가능한 구조는 아님

README의 시스템 요구 설명에는 Vista급 컴퓨터라는 표현도 있으나, 지원 플랫폼 목록의 Windows 하한은 7입니다. 하드웨어 성능에 대한 대략적인 설명과 현재 지원 OS 목록을 같은 의미로 읽으면 안 됩니다. macOS도 Qt CMake 분기에서 Qt 5.15는 10.13, Qt 6은 SDK 조건에 따라 10.14·10.15를 설정합니다.

7-3. 개발 환경과 추가 자원

코어 학습에는 C11 컴파일러와 CMake 3.12 이상이 기준이며, Qt 프론트엔드는 C++14 환경도 필요합니다. Python 바인딩은 기본 빌드 대상이 아닙니다. 테스트·녹화·스크립트를 다룰 때 cmocka·FFmpeg·Lua 등의 선택 의존성이 추가됩니다.

첫 학습에서는 녹화·필터·되감기를 한꺼번에 켜기보다 기능별 자원 비용을 구분하세요. 이 자료의 수치는 소스의 상수와 구조에 근거하며, 특정 기기에서의 프레임 속도나 빌드 성공을 보장하지 않습니다.

8직접 해볼 수 있는 실습 과제

코드 읽기에서 시작해 시간·상태·테스트 설계로 확장하기

각 과제에는 남겨야 할 결과물을 정했습니다. 먼저 정적 추적과 손계산을 끝낸 뒤, 실행 환경이 준비된 경우 선택 실습으로 넓혀 보세요. 함수 이름을 찾는 데서 멈추지 말고, 입력·상태 변화·예상 결과를 한 묶음으로 설명해 보세요.

과제 1 · 입문

공통 코어의 호출 지도를 그리기 예상 30~45분

목표: 함수 포인터를 실제 동작에 연결합니다.

  1. include/mgba/core/core.h에서 init·step·runFrame을 찾습니다.
  2. GBACoreCreate()에서 각 항목에 연결하는 함수를 찾습니다.
  3. _GBACoreStep()과 _GBACoreRunFrame()의 반복 조건을 비교합니다.

완료 기준: 선언 → 연결 → 실행의 세 열 표와, 한 명령 실행·한 프레임 실행의 차이를 설명한 문단을 만듭니다. 프레임 함수에 시간 상한 조건도 있다는 점을 포함하세요.

과제 2 · 입문

주소 네 개를 장치 이름으로 바꾸기 예상 30분

목표: 메모리 매핑과 단위 변환을 익힙니다.

  1. 0x02000000, 0x04000000, 0x06000000, 0x08000000의 영역 번호를 계산합니다.
  2. include/mgba/internal/gba/memory.h의 영역 상수와 GBALoad32()의 분기를 연결합니다.
  3. EWRAM·IWRAM·VRAM의 16진수 크기를 바이트와 KiB로 바꿉니다.

완료 기준: 주소·영역·역할·크기를 담은 표를 작성합니다. I/O 주소가 일반 RAM과 같은 읽기 규칙을 갖는다고 가정하지 마세요.

과제 3 · 중급

이벤트 큐를 종이 위에서 실행하기 예상 45~60분

목표: 시각·우선순위·지연 보정을 함께 이해합니다.

  1. 4절의 A·B·C 이벤트를 mTimingSchedule()의 조건대로 삽입합니다.
  2. 시각 132에서 처리 순서와 각 콜백의 지연량을 적습니다.
  3. 원래 주기 20인 A의 다음 예약을 지연 보정 유무로 비교합니다.

완료 기준: A가 시각 130에 예정되어 있었다면 다음 목표는 150입니다. 132에서 단순히 20을 더한 152와, 지연량 2를 뺀 150의 차이를 설명합니다. 값이 작은 priority가 먼저라는 규칙도 확인하세요.

과제 4 · 중급

Lua로 관찰할 값의 계약 만들기 예상 45~90분

목표: C 메서드가 스크립트 API가 되는 연결을 읽습니다.

  1. src/core/scripting.c에서 currentFrame·getKeys의 연결을 찾습니다.
  2. res/scripts/input-display.lua에서 프레임 콜백 등록과 입력 조회 위치를 찾습니다.
  3. 60프레임마다 기록할 값·출력 빈도·일시정지 때의 기대 동작을 문서로 적습니다.

선택 실행: Lua 기능이 포함된 빌드와 사용 권한이 있는 테스트 ROM이 준비되면 6절 예제를 확장할 수 있습니다. 완료 기준: API 대응표와, 프레임 수를 실제 초로 간주할 수 없는 이유를 남깁니다.

과제 5 · 고급

빠른 감기 복귀 문제의 회귀 검사 설계하기 예상 2~3시간

목표: 증상을 큐 상태와 동기화 조건으로 표현합니다.

  1. updateFastForward()에서 정상 복귀·버퍼 초기화·잠금의 순서를 적습니다.
  2. 버퍼가 비어 있음·가득 참, 속도 변경 있음·없음의 조합으로 사례를 나눕니다.
  3. 생산자 대기와 소비자 깨우기 조건을 src/core/sync.c에서 연결합니다.
  4. 정상 복귀 후 오래된 샘플이 남지 않는지 확인할 관찰 지점과 허용 조건을 정합니다.

완료 기준: 최소 네 사례의 사전 상태·조작·예상 상태 표를 만듭니다. 버퍼만 따로 비우는 단위 검사와 실제 출력 스레드를 포함한 통합 검사를 구분하세요.

고급 확장으로는 cinema/gb/acid/config.ini의 skip=15, frames=1을 읽고, src/platform/test/cinema-main.c가 어떤 프레임부터 기준 화면과 비교하는지 추적할 수 있습니다. 기준 화면을 갱신하는 일과 구현 오류를 고치는 일을 구분하는 것이 핵심입니다.

9관련 기술 심화 학습 로드맵

6주 동안 한 번에 하나의 경계를 깊게 이해하기

C의 변수·반복문·함수·기본 포인터를 알고 있다는 전제입니다. 아직 포인터가 낯설다면 1주 차를 두 번 반복하세요. 매주 소스에서 읽은 규칙, 손으로 계산한 예, 자신의 말로 쓴 설명을 하나씩 남깁니다.

주차주제·읽을 파일남길 결과물
1주 차 C 구조체·함수 포인터·객체 수명
include/mgba/core/core.h, src/gba/core.c
함수표 5개 항목의 선언·구현 대응표. 초기화와 해제 자원 목록
2주 차 CPU·명령어·주소 공간
src/arm/arm.c, src/gba/memory.c
한 명령의 인출·디코딩·실행·메모리 접근 지도. 주소 해석 예시
3주 차 사이클·이산 이벤트·영상 타이밍
src/core/timing.c, src/gba/video.c
시각·우선순위가 다른 이벤트 5개를 손으로 처리한 표
4주 차 스레드·조건 변수·오디오 큐
src/core/sync.c, src/util/audio-buffer.c
버퍼 단위 변환표와 생산·소비·대기·깨우기 순서도
5주 차 직렬화·복원·되감기
src/gba/serialize.c, src/core/rewind.c
다음 실행 결과에 영향을 주는 상태 목록. 복원 시 검증할 조건
6주 차 프론트엔드·스크립트·회귀 검사
src/core/scripting.c, src/platform/test/cinema-main.c
기능 하나의 코어→화면 연결 설명과 회귀 검사 계획

9-1. 관심 분야에 따라 갈라지는 다음 단계

전체 코드를 다 읽기보다 기능 하나가 여러 계층을 통과하는 경로를 완주하는 편이 설계를 이해하는 데 도움이 됩니다. 예를 들어 되감기를 골랐다면 상태 저장, 차이 계산, 큐 용량, 복원 시점까지 연결해 보세요.

학습 비유

도시의 모든 도로 이름을 외우기 전에, 집에서 학교까지 한 번 걸어 보세요. 한 경로의 교차로를 이해한 뒤 다른 길로 확장하면 지도가 실제 동작으로 읽힙니다.

10핵심 키워드 사전

낯선 단어를 코드 속 역할과 연결하는 빠른 찾아보기
용어쉬운 설명
에뮬레이터다른 기계의 명령과 장치 규칙을 소프트웨어로 재현하는 프로그램입니다.
코어 / 프론트엔드코어는 기계의 동작을 계산하고, 프론트엔드는 창·입력·출력을 사용자에게 연결합니다.
ROM이 문서에서는 게임 카트리지의 프로그램과 데이터를 담은 파일을 가리킵니다.
BIOS기기의 시작과 기본 기능을 담당하는 펌웨어입니다. mGBA에는 내장 동작 구현도 있습니다.
ARM / ThumbGBA CPU가 사용하는 명령 체계입니다. 여기서 ARM 명령은 32비트, Thumb 명령은 16비트 폭입니다.
opcodeCPU가 실행할 동작을 비트로 표현한 명령 값입니다. 디코더가 비트를 해석해 실행 함수를 고릅니다.
레지스터CPU 안의 작은 작업 공간입니다. PC는 다음 실행 흐름과 관련된 위치를 나타내는 레지스터입니다.
prefetch앞으로 사용할 명령을 미리 가져온 상태입니다. 정확한 복원에는 이런 내부 상태도 중요합니다.
사이클가상 하드웨어의 진행을 세는 시간 단위입니다. 한 명령이 항상 한 사이클이라는 뜻은 아닙니다.
메모리 매핑주소 범위를 RAM·화면 메모리·장치 레지스터 등에 배정하는 규칙입니다.
I/O 레지스터특정 주소에서 읽고 쓰는 장치 제어 값입니다. 일반 메모리와 다른 부수 효과가 있을 수 있습니다.
VRAM / OAM화면용 데이터 공간과 스프라이트 속성 공간입니다. 영상 구현에서 각각 다른 역할을 맡습니다.
DMACPU가 데이터를 일일이 옮기는 대신 전송 장치가 메모리 사이의 이동을 수행하는 기능입니다.
인터럽트 / IRQ장치가 CPU에 사건을 알리는 신호입니다. 조건에 따라 CPU가 처리 흐름을 바꿉니다.
HBlank / VBlank한 줄·한 화면의 영상 진행에서 표시 구간 밖의 시기입니다. DMA나 인터럽트와도 연결됩니다.
렌더러영상 상태를 실제 픽셀로 바꾸는 부품입니다. 그릴 시점을 정하는 코드와 구분해 읽습니다.
함수 포인터호출할 함수의 위치를 담는 값입니다. mCore는 이를 모아 여러 기종을 같은 방식으로 다룹니다.
팩터리조건에 맞는 구현 객체를 만들어 주는 생성 경계입니다. ROM 판별 뒤 코어 생성이 그 예입니다.
이산 이벤트다음 사건의 시각을 예약하고 그 순서대로 상태를 바꾸는 계산 방식입니다.
VFS / VFile파일의 실제 출처를 감춘 공통 읽기·쓰기 계약입니다. 테스트에서는 메모리 파일로 대체할 수 있습니다.
뮤텍스 / 조건 변수공유 상태 접근을 조절하는 잠금과, 조건이 바뀔 때까지 기다렸다가 깨우는 동기화 도구입니다.
순환 버퍼고정 공간의 끝에 닿으면 처음으로 돌아가며 데이터를 넣고 빼는 큐입니다.
샘플 프레임같은 시점의 모든 채널 값을 묶은 오디오 단위입니다. 스테레오 16비트라면 한 묶음이 4바이트입니다.
리샘플링서로 다른 샘플률 사이에서 오디오 값을 새 시간 간격에 맞춰 만드는 처리입니다.
직렬화 / savestate기계 상태를 저장 가능한 형식으로 표현하는 처리와 그 결과입니다. 게임 내부 저장 기능과 범위가 다릅니다.
엔디언여러 바이트짜리 수를 어떤 순서로 저장하는지에 관한 규칙입니다. 파일 형식과 CPU 재현에서 중요합니다.
MBCGame Boy 카트리지에서 보이는 메모리 뱅크를 바꾸는 제어 장치입니다.
FFI / CFFI다른 언어의 함수를 호출하는 연결 방식과, 이 저장소의 Python 연결에 쓰는 도구입니다.
회귀 검사 / 기준 화면변경 후 예전 동작이 깨졌는지 확인하는 검사와, 영상 결과를 비교할 기준 이미지입니다.
ABI컴파일된 구성 요소가 함수 호출과 데이터 배치 등에서 맞춰야 하는 바이너리 수준의 계약입니다.
헤드리스일반적인 GUI 창 없이 코어를 구동하는 형태입니다. 자동화와 테스트 도구에서 유용합니다.

용어를 기억하기 어렵다면 실제 식별자 하나와 묶으세요. 다형성은 mCore, 이벤트는 mTimingEvent, 파일 추상화는 VFile, 역압은 mCoreSyncProduceAudio()를 떠올리면 됩니다.

11참고 링크

설명을 확인하고 다음 파일로 이동하기 위한 출처

11-1. 공식 저장소·문서·변경 기록

11-2. 핵심 소스와 관련 기술

현재 상태 (2026-10-23 확인)

항목값·범위
저장소mgba-emu/mgba · 설명: mGBA Game Boy Advance Emulator
선정 기준TrendShift Repositories #2 · 2026-10-23 분석
스타 / 포크7,521 / 1,139 · 2026-10-23 GitHub 기준
주 언어 / 생성일C / 2014-12-09 · 2026-10-23 GitHub 기준
최신 정식 릴리스0.10.5 · 2025-03-09 · 2026-10-23 GitHub 기준
분석 소스의 버전version.cmake: 0.11.0, ABI 0.11 · CHANGES는 Future로 표시
최근 push2026-10-19 · 2026-10-23 GitHub 기준. 커밋 작성일과는 다른 지표
분석 기준 커밋fd9dc5c · Util: Flush audio buffer on fast-forward end
커밋 날짜의 구분작성일 2026-09-25 / 반영일 2026-10-19 UTC · Git 기록 기준
자체 코드 규모C 111,978줄 + 헤더 46,736줄 + C++ 30,991줄. Python 2,925줄, Lua 1,147줄, 어셈블리 400줄
집계 범위물리적 줄 수, 주석·빈 줄·테스트 포함. .git/·src/third-party/ 제외. 확장자 기준
라이선스MPL-2.0 · 저장소 LICENSE. 동봉 라이브러리의 고지는 별도 확인
활용할 때 알아둘 한계
개발 소스·정식 배포물·실제 하드웨어는 구분해서 판단하세요

이 글의 구현 설명은 커밋 fd9dc5c에 고정되어 있습니다. 0.11.0 개발 항목을 0.10.5의 기능으로 간주하지 마세요. 성능·게임별 정확도·설치 성공 여부는 운영체제, 라이브러리, ROM과 설정별 검증이 필요합니다.

README의 정확도·저사양 실행 표현은 프로젝트의 안내이며, 경쟁 도구와 같은 조건으로 측정한 결론은 아닙니다. 통신의 로컬 지원과 네트워크 지원 계획도 다릅니다. 코드 규모는 특정 커밋의 파일 집계이며, 전체 커밋 수나 개발 속도·기여자 비중을 나타내지 않습니다.

CONTRIBUTING.md는 AI가 생성한 코드의 PR을 받지 않는다고 명시합니다. 실습 결과를 기여로 발전시키려면 해당 지침을 먼저 읽으세요. 게임·BIOS 파일의 배포 권한은 에뮬레이터 소스 라이선스와 별개의 문제입니다.