---
title: "TI-99/4A: 펌웨어에 더 기대보기"
published: 2026-01-18T23:19:19.000Z
canonical: https://jeff.news/article/1003
---
# TI-99/4A: 펌웨어에 더 기대보기

TI-99/4A 홈 컴퓨터의 GPL 바이트코드로 사운드 리스트, 자동 스프라이트 모션, 충돌 감지를 구현하는 레트로 프로그래밍 탐구기

## 배경

- 1982년산 TI-99/4A 홈 컴퓨터를 가지고 레트로 프로그래밍을 파는 시리즈물임
- 작년에 BASIC과 머신 코드를 다뤘고, 이번엔 펌웨어가 제공하는 **사운드 리스트**, **자동 스프라이트 모션**, **충돌 감지**를 본격 활용함
- 프로그래밍은 주로 Graphics Programming Language(GPL) 바이트코드로 진행 — TI 고유의 커스텀 VM이라고 보면 됨

## 사운드 리스트: 바흐를 SN76489에 우겨넣기

- 사운드 리스트 API 자체는 단순함 — 주소 세팅하고 플래그 켜면 인터럽트 서비스 루틴이 알아서 재생
- 레코드 구조: `[바이트 수][사운드칩 데이터][대기 프레임]`의 반복. 0이면 끝
- 함정이 있음: TI-99/4A에는 CPU, VRAM, GROM 세 가지 주소 공간이 있는데, **사운드 리스트는 VRAM이나 GROM에서만 실행 가능**. 카트리지 ROM에서는 안 됨
- 바흐 미뉴에트를 넣어봤더니 문제 발생:
  - SN76489의 최저음이 ~110Hz라 저음부 G를 못 침 → **전조(transpose)** 필수
  - 볼륨 엔벨로프까지 넣으면 사운드 리스트가 **5KB**에 달함. GROM 한 블록이 6KB인데!
- 다행히 이 곡은 AABB 구조 → A파트/B파트 두 개로 쪼개서 반복 관리하면 **절반으로 축소**
- 솔직한 평가: 사운드 리스트는 효과음용이지, 음악 재생엔 자체 플레이어를 짜는 게 나음. 다만 음악 루틴과 사운드 이펙트를 **채널 분리**해서 병행하는 용도로는 쓸만함

## 스프라이트: 우산을 날려보자

- VDP(비디오 디스플레이 프로세서) 레지스터를 직접 설정해야 함 — BASIC 때와 메모리 레이아웃이 다름
- 16×16 스프라이트를 2배 확대(magnified)로 사용, 우산 모양 = 캔버스 + 손잡이 2개 스프라이트
- **자동 스프라이트 모션 테이블**: VRAM >0780~>07FF에 위치, 스프라이트당 4바이트(Y속도, X속도, 스크래치 2바이트)
- 속도는 **4.4 고정소수점** — "16프레임당 픽셀 수" 단위
- 작년 BASIC 버전에서는 캔버스와 손잡이가 따로 놀았는데(처참했음), 이번엔 제대로 동기화됨

## 충돌 감지: COINC 명령어의 세계

- VDP 하드웨어의 충돌 감지는 "아무 스프라이트끼리 부딪혔는지"만 알려줌 — 너무 대충임
- GPL의 **COINC 명령어**는 훨씬 정교함: **(2X+1)×(2Y+1) 비트 벡터** 기반 충돌 맵을 사용
- 16×15 스프라이트의 충돌 테이블이 33×31 = 128바이트. 모든 가능한 오버랩 위치를 비트맵으로 인코딩
- 비트 정렬이 안 맞아서(33비트 행이 4바이트+1비트) 패딩 없이 빽빽하게 들어감. Python 스크립트로 생성
- **granularity 설정**으로 확대 스프라이트 대응 — granularity 1이면 2×2 블록 단위로 체크하므로 확대 스프라이트도 원래 크기 테이블로 커버됨
- 충돌 처리: X 속도를 반전시키되, 편집 중 인터럽트가 끼면 캔버스와 손잡이가 **따로 방향 전환**할 위험 → moving sprite count(>837A)를 **0으로 세팅**해서 편집 중엔 모션 정지

## 소감

- GPL 바이트코드가 의외로 강력한 부분이 있음 — 특히 COINC는 순수 머신코드로 재현하려면 꽤 고생할 기능
- 반면 간접 참조나 포인터 조작은 제약이 많아서 답답함. GROM만으로는 한계가 명확함
- 다음 편에서 ROM/GROM 하이브리드 카트리지를 다룰 예정

## 핵심 포인트

- 사운드 리스트는 VRAM/GROM에서만 실행 가능하며, 바흐 미뉴에트가 5KB에 달해 6KB GROM 한계에 근접
- AABB 구조 활용으로 사운드 데이터를 절반으로 축소
- 자동 스프라이트 모션은 4.4 고정소수점 속도로 VRAM 테이블 기반 동작
- COINC 명령어는 (2X+1)×(2Y+1) 비트 벡터 기반 충돌 감지 제공, granularity로 확대 스프라이트 지원
- 충돌 처리 시 moving sprite count를 0으로 설정해 인터럽트 중 스프라이트 분리 방지

## 인사이트

GPL 바이트코드는 COINC 같은 고급 기능을 제공하지만, 간접 참조와 포인터 조작의 제약이 커서 ROM/GROM 하이브리드 접근이 현실적인 해법
