앞 장에서 우리는 트릿(trit)이라는 가장 작은 조각을 손에 쥐었습니다. -1, 0, +1을 담는 세 상태의 단위, 그리고 거기에 구분자 U를 더한 네 부호 T·O·A·U. 나는 그 장을 닫으며 "이 부호들이 모여 무엇이 되는가"라는 질문을 일부러 남겨 두었습니다. 한 알의 트릿은 그 자체로는 아무것도 아닙니다. 글자 하나가 아직 단어가 아니듯이. 이 장에서 나는 그 트릿들이 어떻게 하나의 완결된 단위로 묶이는지, 그리고 그 묶음이 어떻게 크라우니의 메모리 구조 전체를 결정하는지를 정확한 스펙으로 보여 드리려 합니다. 단위의 이름은 큐브(Cube)입니다.
크라우니의 메모리 구조는 큐브라 불리는 기본 단위에서 출발합니다. '큐브'는 정육면체를 뜻하지만, 여기서의 함의는 기하학적 형태가 아니라 구조적 완결성입니다. 가로 3, 세로 3, 높이 3으로 쌓은 27칸, 그 27칸이 비로소 의미 있는 정보를 담는 최소 집합이 됩니다.
1 큐브 = 27 트릿 = 3³
이 수는 우연이 아닙니다. 3진 체계의 기본 단위가 트릿이라면, 27은 그 트릿들이 의미 있는 데이터와 메타데이터를 함께 담을 수 있는 최소 단위입니다. 기존 컴퓨터에서 1바이트(8비트 = 256값)가 메모리 주소의 기본 단위인 것과 같이, 크라우니에서는 큐브가 그 역할을 맡습니다.
실제 메모리 할당에서 큐브는 7바이트 + 1패딩 = 8바이트로 정렬됩니다. 이는 현대 CPU의 캐시 라인 효율을 고려한 선택이며, 27트릿 자체의 논리 폭(2비트 × 27 = 54비트)과는 구분됩니다.
트릿은 2비트로 인코딩됩니다(상태 3개 ≤ 2² = 4). 따라서 한 바이트(8비트)에는 최대 4개의 트릿이 들어갑니다. 27트릿은 T1(LST, Least Significant Trit) = index 0에서 시작해 T27(MST, Most Significant Trit) = index 26까지 순차 배치되며, 표준 레이아웃은 다음과 같습니다.
byte[0]: T1(1:0) T2(3:2) T3(5:4) T4(7:6)
byte[1]: T5 T6 T7 T8
byte[2]: T9 T10 T11 T12
byte[3]: T13 T14 T15 T16
byte[4]: T17 T18 T19 T20
byte[5]: T21 T22 T23 T24
byte[6]: T25 T26 T27 (미사용)
byte[7]: 패딩
byte[6]의 마지막 2비트는 미사용으로 남고, byte[7] 전체가 정렬 패딩입니다. 27트릿이 24트릿(byte[0]~byte[5])과 메타 3트릿(byte[6])으로 자연스럽게 갈리는 이 구조는, 다음 절에서 보일 데이터/메타 분리와 정확히 맞물립니다.
큐브의 마지막 세 트릿 T25·T26·T27은 일반 데이터를 담지 않고 역할 태그로 기능합니다. 레고 상자에 붙은 "이 안에 자동차 부품이 들었습니다"라는 딱지처럼, 큐브 스스로 자신이 무엇인지를 선언하는 자리입니다.
T27 — 큐브 역할 태그(Role Tag). 이 큐브가 무엇인지 구분합니다.
| 값 | 의미 | 내용 |
|---|---|---|
| T(+1) | 데이터 | T1~T24가 균형3진 정수값(또는 문자열·셀참조)을 담는다 |
| O(0) | 명령(opcode) | T1~T6이 ISA729 6-트릿 인코딩을 담는다 |
| A(-1) | 체이닝 | 이전 큐브의 데이터를 확장한다 — 연속 큐브가 하나의 논리값을 표현 |
T26 — 값 타입 태그(Type Tag). T27이 T(데이터)일 때만 해석됩니다.
| 값 | 타입 | 비고 |
|---|---|---|
| T(+1) | 숫자(정수) | 균형3진 인코딩 |
| O(0) | 문자열 | UTF-8 또는 3진 압축 인코딩 |
| A(-1) | 셀 참조 | 규칙 기반 에이전트의 셀 저장소를 가리킴 |
T25 — 크기 태그(Size Tag). 역시 T27이 T(데이터)일 때 적용됩니다.
| 값 | 크기 | 의미 |
|---|---|---|
| T(+1) | 확장 | 이 값은 다음 큐브로 이어진다 |
| O(0) | 보통 | 정확히 1개 큐브에 수용된다 (가장 일반적) |
| A(-1) | 소형 | 1개 큐브의 일부만 사용한다 (메모리 절약 마크) |
세 태그가 T·O·A 세 값으로 똑같이 갈린다는 점에 주목하기 바랍니다. 부호 체계의 대칭성이 메타데이터 설계에까지 일관되게 투영되어 있습니다.
런타임이 큐브 하나를 해석할 때의 순서는 명확합니다. 언제나 T27을 먼저 읽습니다.
의사코드로 옮기면 분기는 세 갈래로 끝납니다.
if (cube.t[26] == T) value = balanced_ternary_to_i64(cube.t[0..25]);
else if (cube.t[26] == O) execute(decode_opcode(cube.t[0..5]));
else /* A */ extend_previous(cube);
명령 큐브의 경우 T1~T6을 다시 세 쌍으로 끊어 command = (T1,T2), group = (T3,T4), sector = (T5,T6)로 읽고 opcode = sector × 81 + group × 9 + command를 계산합니다. 이 공식은 3절에서 다시 정밀하게 다룹니다.
데이터 큐브에서 실제 정수값을 담는 트릿은 T1~T26의 26트릿입니다. T27만이 순수한 역할 태그이고, 나머지는 수치 표현에 동원될 수 있습니다. 이로써 표현 가능한 정수 범위는 다음과 같습니다.
최대값 = (3²⁶ − 1) / 2 = ±141,214,768,240
약 54비트에 해당하는 폭이며, 64비트 정수형 int64에 충분히 수용됩니다. 이 자릿수는 그대로 외워 두어도 좋습니다 — 큐브 한 칸이 담을 수 있는 정수의 절대 한계이기 때문입니다.
십진 정수를 균형3진으로 옮기는 과정은 표준 3진 변환과 한 군데에서 갈라집니다. 핵심은 나머지가 2일 때 −1로 바꾸고 몫을 1 올리는 것입니다.
encode_balanced_ternary(int64 val, trit out[26]):
for i = 0..25:
r = val % 3
if (r == 2) { r = -1; val += 1; } // A로 인코딩, 올림
out[i] = r // T(+1), O(0), A(-1)
val /= 3
이 보정 덕분에 균형3진은 중복 표현이 없고, 음수와 양수가 완전 대칭입니다. 0을 기준으로 수직선을 접으면 양쪽이 포개진다는 뜻이며, 이 대칭성이 뒤이어 메모리 정렬과 타입 체계에까지 일관되게 흐릅니다.
두 트릿(2-trit)을 한 묶음으로 보면 0~8의 정수 아홉 값으로 사상됩니다. 순서는 반드시 A→O→T(−1→0→+1)입니다.
| 쌍 | 트릿값 | 정수 |
|---|---|---|
| AA | (−1, −1) | 0 |
| AO | (−1, 0) | 1 |
| AT | (−1, +1) | 2 |
| OA | ( 0, −1) | 3 |
| OO | ( 0, 0) | 4 |
| OT | ( 0, +1) | 5 |
| TA | (+1, −1) | 6 |
| TO | (+1, 0) | 7 |
| TT | (+1, +1) | 8 |
이 아홉 매핑이 다음 절 ISA729의 sector/group/command 인코딩에 그대로 재사용됩니다. 같은 표가 데이터에도 명령에도 쓰인다는 점 — 바로 이것이 크라우니가 데이터와 명령을 같은 살로 짠다는 증거입니다.
명령어 집합 ISA729는 729개 슬롯을 가집니다. 729 = 3⁶ = 9 × 9 × 9, 3진 체계에서 자연스럽게 솟아오르는 수입니다.
729 슬롯은 9 섹터(sector) × 9 그룹(group) × 9 커맨드(command)로 조직됩니다.
opcode = sector * 81 + group * 9 + command
sector = opcode / 81
group = (opcode % 81) / 9
command = opcode % 9 (sector, group, command ∈ [0, 8])
명령 큐브의 T1~T6 위치는 이 세 좌표를 2-트릿씩 담습니다.
T1, T2 → 2-트릿 = command (0~8)
T3, T4 → 2-트릿 = group (0~8)
T5, T6 → 2-트릿 = sector (0~8)
T7~T26 → O 패딩, T27 = O (명령 역할)
9개 섹터는 각각 하나의 기능 영역을 맡습니다. 6-트릿 접두는 (sector, group, command) = (s, 0, 0)일 때의 선두 패턴입니다.
| 섹터 | opcode 범위 | 접두 | 기능 영역 |
|---|---|---|---|
| 0 | 0–80 | AA____ | 스택·흐름 제어·함수·코루틴·디버그 |
| 1 | 81–161 | AO____ | 산술·비트·통계·벡터·행렬·노이즈 |
| 2 | 162–242 | AT____ | 비교·논리·3진 연산 |
| 3 | 243–323 | OA____ | 제어 흐름 (JMP·CALL·RET) |
| 4 | 324–404 | OO____ | 입출력·표현 |
| 5 | 405–485 | OT____ | 컬렉션·배열·맵 |
| 6 | 486–566 | TA____ | 타입·메모리 |
| 7 | 567–647 | TO____ | 에러·수학 확장·네트워크 |
| 8 | 648–728 | TT____ | 셀·CTP·트릿·테스트·ISA 반성 |
몇 가지 대표 opcode를 6-트릿으로 풀어 보면 공식이 빈틈없이 닫히는 것을 확인할 수 있습니다.
NOP(0) = sector 0, group 0, command 0 → AAAAAAADD(81) = sector 1, group 0, command 0 → AOAAAAEQ(162) = sector 2, group 0, command 0 → ATAAAAPRINT(324) = sector 4, group 0, command 0 → OAAAAACELL_NEW(696) = sector 8(TA), group 5(OT), command 3(OA) → OAOTTA마지막 예의 검산: 8 × 81 + 5 × 9 + 3 = 648 + 45 + 3 = 696. 좌표 셋이 곧바로 트릿 패턴이 되고, 트릿 패턴이 곧바로 정수 opcode가 됩니다.
여기서 한 가지 구분을 분명히 해 둡니다. 슬롯 총량은 9×9×9 = 729로 고정이며, VM은 fallthrough를 포함해 729/729를 모두 구현합니다. 한편 "의미 있는 명령"의 이론적 상한은 별도로 489로 추정되는데, 이는 구현 슬롯 수가 아니라 설계 여백의 추정치입니다. 책의 다른 장에서 489라는 수를 만나거든 이 둘을 혼동하지 마시기 바랍니다.
이 1:1 정합은 크라우니 헌법 9조(2026-05-21 선언)의 핵심 문구 — "한선씨 RPN = ISA729 1:1" — 의 달성 상태를 그대로 가리킵니다. 한국어 RPN으로 적은 더해가 ISA729의 ADD와, 빈틈 없이 한 칸씩 맞물린다는 선언입니다. 이 상승의 사다리 — Rust/Swift → 한선씨 고수준 → 한선씨 RPN → 기계어 — 는 뒤의 한선씨 장에서 본격적으로 오르게 됩니다.
개별 큐브가 메모리에 배열되는 방식은 프로그램 실행 구조를 직접 결정합니다.
가장 기본적인 구조는 명령 큐브의 단순 나열입니다.
[명령1][명령2][명령3] … [명령N]
각 명령 큐브는 독립적으로 해석되고, 프로그램 카운터(PC)는 한 번에 한 큐브씩 전진합니다.
스택 기반 머신에서는 데이터 큐브와 명령 큐브가 메모리상 섞여 존재할 수 있습니다. 다만 한 가지 불변 규칙이 있습니다 — PC가 실행을 위해 도달한 큐브는 반드시 T27 = O여야 합니다. PC가 데이터 큐브(T27 = T)에 닿으면 그것은 체계 오류(system exception)입니다.
두 개 이상의 큐브가 하나의 값을 표현해야 할 때, 체이닝 큐브(T27 = A)가 개입합니다.
[큐브1: 데이터, T25=T(확장)] → [큐브2: T27=A(체이닝)] → … → [큐브N: T25=O(보통)]
문자열, 배열, 큰 정수처럼 한 큐브에 다 담기지 않는 값이 이렇게 표현됩니다. 마지막 큐브의 T25는 언제나 O(보통)이어야 하며, 이는 값의 종료를 뜻합니다. T25 = O가 곧 마침표인 셈입니다.
큐브의 27트릿 구조가 가장 우아하게 빛나는 자리 중 하나가 한글 압축입니다. 크라우니는 한글 문자열을 1큐브에 3글자씩 담을 수 있습니다.
한글 한 글자는 초성·중성·종성으로 분해됩니다. 각 요소가 갖는 경우의 수(초성 19, 중성 21, 종성 28)는 2-트릿(범위 0~8)으로는 부족하므로, 모두 3-트릿(범위 0~26)으로 인코딩합니다.
초성(19값) → trit[0:2]
중성(21값) → trit[3:5]
종성(28값) → trit[6:8]
1 한글 = 9 트릿 = 3-트릿 × 3
따라서:
3글자 = 27트릿 = 1큐브
UTF-8에서 한글 1자는 3바이트입니다. 3진 압축을 적용하면 트릿당 0.5바이트(2비트) 환산으로 다음과 같이 줄어듭니다.
UTF-8 : 3글자 × 3바이트 = 9.00 바이트
3진 : 3글자 × 9트릿 ÷ 4트릿/바이트 = 2.25 바이트
절약률: (9 − 2.25) / 9 = 25%
한글 1자가 정확히 9트릿, 큐브 하나가 정확히 27트릿이라는 사실이 맞아떨어지기에 가능한 절약입니다. 한글 기반 프로그램과 문서 처리에서 문자열 집약도를 높여 줍니다.
나는 이 장을 쓰며, 큐브가 단순한 메모리 단위가 아님을 거듭 확인했습니다. 27트릿의 고정 구조(fixed structure)를 통해 크라우니는 세 가지를 한꺼번에 얻습니다.
트릿 → 큐브 → 프로그램. 앞 장에서 손에 쥔 한 알의 트릿이, 이 장에서 27칸의 완결된 단위가 되고, 그 단위가 줄지어 프로그램이라는 성을 이룹니다. 이 계층적 상승 — 작은 것의 구조가 큰 것의 구조에 그대로 되살아나는 동형성 — 이야말로 우리가 이 책 전체에서 추적할 단 하나의 줄기입니다. 그렇다면 이 큐브가 디스크 위에, 메모리 위에 실제로 어떤 바이트열로 적히는가. 다음 장 "TOAU 인코딩"에서 그 마지막 한 겹을 벗겨 보겠습니다.
첫 번째 책은 선물이에요. 가입하면 100맘을 드리니까, 두 번째 책부터 자유롭게 읽을 수 있어요. 친구를 추천하면 50맘도 생겨요.