C64 GB2312 텍스트 렌더러 (han64)
A Commodore 64용 GB2312 중국어 텍스트 렌더러, 8×8 비트맵 폰트와 동적 문자 캐싱을 사용합니다.
범위 v1 (렌더링)
- 2501+ 간체 중국어 문자 (GB2312 행 $B0-$D7)
- 8×8 픽셀 비트맵 폰트 (각 문자당 8 바이트)
- GB2312 인코딩된 텍스트 표시 (이진 파일에서)
- 동적 캐릭터 캐싱 (256개 캐릭터 슬롯)
- 랭크 기반 GB2312 → 글리프ID 조회
- 파이썬에서 오프라인 테이블 생성
- C64에서 6502 어셈블리 (ACME)로 런타임 렌더링
스코프 v1.5 (현재: 다양한 문자셋)
- 래스터 IRQ를 사용한 이중 문자셋 지원 (512개 캐릭터 슬롯)
- 8×7 픽셀 비트맵 폰트 (각 글리프당 7바이트)로 공간 절약
스코프 v2 (미래: IME)
- 캐넌디트 선택 기능을 가진 풍인 입력 방법
- 인터랙티브 텍스트 편집
- 커서 이동 및 스크롤
- 아래 "미래 작업" 섹션을 참조
핵심 아키텍처 (v1)
GB2312 text file (chabuduo.bin)
↓
GB2312 → glyphID lookup (rank-based tables)
↓
Cache check (2502-byte cache array)
↓
Copy glyph bitmap (8×8) if not cached
↓
Write character code to screen RAM
↓
VIC-II renders using custom charset
주요 원칙
- 런타임 중 유니코드 없음
- 밀집된 내부 글리프ID (0..2500)
- GB2312는 I/O에만 사용됩니다
- 모든 무거운 처리는 오프라인에서 수행됩니다
- 빠른 글리프 복사를 위한 자기 수정 코드
글리프 세트
정확히 2501개의 한자
모두는 다음과 같습니다
- GB2312로 인코딩 가능합니다
- BMP 유니코드 (UTF-16 대용어 없음)
추가 문자:
- ~70개 ASCII
- 8 GB2312 문장부호/특수문자 (행 1–15)
글리프 저장
font8.bin 또는 font7.bin (v1.5용)
배치:
- 글리프ID × 8 바이트 (v1.5용은 7 바이트)
- 1 바이트당 행, 8 비트 사용: 8×8 비트맵 (v1.5용은 8×7)
글리프ID 순서 (중요)
glyphID는 GB2312 행/열 순서에 할당됩니다
이유:
- GB2312 인코딩/디코딩을 단순화합니다
- 단일 glyphID의 재사용을 가능하게 합니다 → gb2312 테이블
- 텍스트 렌더링 시 지역성을 향상시킵니다
- 두 번째 역매핑 테이블을 피합니다
빈도는 IME 후보 순서 내에서 처리되며, glyphID 숫자에는 영향을 미치지 않습니다.
인코딩: GB2312
- ASCII:
0x00–0x7F(현재 v1에서 건너뛰고 있습니다) - 한자: 2 바이트
- hi 바이트 (행):
0xB0–0xD7(40 행 지원됨) - lo 바이트 (열):
0xA1–0xFE(행당 94 열)
- hi 바이트 (행):
- 사용되지 않음/유효하지 않음: 기타 바이트 범위
- BOM 없음
- 상태 없음, 스트리밍 친화적
GB2312는 엄격히 I/O 형식이며, 내부 논리에 사용되지 않습니다.
GB2312 조회 구현
실행 시간은 랭크 기반 인코딩을 사용하여 GB2312 → 글리프ID 매핑을 압축합니다.
각 행 ($B0-$D7)에는 다음과 같은 테이블이 있습니다.
- 기본 글리프ID (2 바이트): 이 행의 시작 글리프ID
- 랭크 배열 (94 바이트): 각 열($A1-$FE)마다 순위(0..count-1) 또는 $FF로 누락된 경우를 저장합니다
이는 사용되지 않는 GB2312 코드에 대해 글리프ID를 할당하지 않고 누락된 문자를 효율적으로 표현할 수 있게 합니다.
런타임 테이블(v1)
오프라인으로 파이썬을 통해 생성됩니다(tools/gb40.py).
gb40_rows.asm
40개 행 테이블을 포함합니다(gb_row_B0부터)gb_row_D7), 각각에 대해:
!word baseGlyphID ; 2 bytes
!byte rank[94] ; 94 bytes: rank or $FF if missing
포인터 테이블 gb_row_ptr_lo와 gb_row_ptr_hi를 main.asm에서 참조합니다.
문자 캐시
캐시 (main.asm에서 2501+ 바이트)
- glyphID (0..2501)로 인덱싱됩니다.
- 글리프가 로드되어 있으면 문자 슬롯 (0-255)을 저장하고, 캐시되지 않았으면 0을 저장합니다.
- 캐시가 가득 찼을 때 (chrptr이 256에 도달하면), 이후 문자는 공백으로 표시됩니다
이는 한 번에 256개의 고유 문자만 표시할 수 있게 제한하지만, 캐싱을 통해 총 2501자 이상의 문서를 허용합니다.
Python 빌드 파이프라인
입력:
gb2312_chars.txt(GB2312 코드를 가진 2501자 한자)- 폰트 비트맵 데이터 (8×8 비트맵)
출력:
font8.bin(2501 × 8 바이트)font7.bin(2501 × 7 바이트 for v1.5)gb40_rows.asm(40 행 테이블로 순위 인코딩)
모든 테이블은 !binary와 !source을 사용하여 어셈블리에 포함됩니다.
런타임 (C64 / 6502)
- UTF-8 없음
- 런타임 중 Unicode 없음
- 동적 메모리 없음
- 모든 테이블은 읽기 전용입니다
- 어셈블러: ACME
- 빌드:
acme main.asm(또는 Makefile 참조)
렌더링 경로 (v1):
- 텍스트 스트림에서 GB2312 바이트 쌍을 읽기
GB2312_LookupGlyphID를 통해 글리프ID 검색 (랭크 기반)- 글리프ID를 인덱싱하는 캐시 배열 확인
- 캐시되지 않았다면,
CopyGlyph8를 통해 8×8 비트맵을 복사하여 사용자 정의 문자 세트에 저장 - 화면 RAM에 문자 슬롯을 쓰다
- VIC-II는 $3000에서 사용자 정의 문자셋으로 표시한다
이것이 무엇이 아니다
- UTF-16이 아니다
- Unicode 실행 시간이 아니다
- 사전 기반(아직은 아니다)
- 전통 중국어가 아니다
- GBK/GB18030 실행 시간이 아니다(오프라인에서는 호환 가능)
미래 작업 (v2 - IME)
Pinyin IME 기능
- Pinyin 입력법 자음 분석
- 초기 버킷 (b, p, m, f, d, t, n, l 등 + Ø로 자음으로 시작)
- 후보 선택 UI
- 구문 사전 (2-4 문자)
- 간핀 약자 모드
- MRU 학습
- 빈도 기반 후보 순서
개선된 렌더링
- dual charset 지원 (512 문자 슬롯을 통해 래스터 IRQ)
- charset1은 화면 상단 절반에 사용됨
- charset2는 화면 하단 절반에 사용됨
- 래스터 IRQ는 13행 (스캔라인 104)에서 전환됨
- 두 번째 IRQ는 25행 (스캔라인 200)에서 다시 전환됨
- 스크롤 지원 (행 복사 + IRQ 조정)
- 커서 이동 (색상 기반 또는 전용 글꼴)
- 인터랙티브 텍스트 편집
데이터 소스
- 윈한 데이터베이스를 사용한 푸인 맵핑
- SUBTLEX-CH 또는 전다를 사용한 빈도 데이터
- UTF-8 입력/출력 도구
디자인 철학
- 구조는 지혜보다 중요
- 오프라인 복잡성, 런타임 간단성
- 인코딩과는 언어가 다릅니다
- 6502 먼저, 현대 도구 두 번째
텍스트 렌더링 (v1)
- VIC-II 텍스트 모드와 사용자 정의 문자셋
- 40×25 문자
- 사용자 정의 문자셋은 $3000 (뱅크 6)에 있습니다
- 화면 RAM은 $0400에 있습니다
- 색상 RAM은 $D800에 있습니다 (현재 흰색 회색 $0F로 설정됨)
- 화면에 동시에 256개의 고유한 글꼴 제한
IME 렌더링 (v2 - 미래)
- 상단 줄: IME 입력 및 후보 영역
- 최대 10개 후보 표시:
ying 1英 2婴 3鹰 4应 5营 6蝇 7迎 8赢 9盈 0影 - 다음/이전 페이지 마커가 >10개 후보
- 하단 24줄: 일반 텍스트 뷰 영역
- 커서는 텍스트 영역에서 이동하지만 IME 영역에서는 이동하지 않음












