t27.aiEnglish

Командное слово

Вы узнаете

Как эмулятор TRI-27 упаковывает команду в 32 бита.

Машина TRI-27 считает тритами, но её команды — 32-битные двоичные слова, которые декодирует закреплённая версия эмулятора Trinity. Опкод занимает биты 7..0, регистр назначения — 12..8, источники лежат выше; в форме с непосредственным значением старшие 15 бит отданы знаковому числу. Виджет вызывает encode() спеки и читает каждое поле обратно через opcode_of(), dst_of() и остальные.

Попробовать

Закодируйте ADD r1, r2, r3 и LDI r1 с 5; скажите, какие биты различаются и почему у формы с непосредственным значением поле src1 уже.

Открыть интерактивный урок →

The TRI-27 instruction word, field by field
The TRI-27 instruction word, field by field ↗

Pick an instruction and its registers. The emulator packs them into a 32-bit word: opcode, destination, sources or an immediate.

specs/isa/ternary_encoding.t27

// SPDX-License-Identifier: Apache-2.0
; specs/isa/ternary_encoding.t27 -- the TRI-27 instruction word as the pinned consumer decodes it
; Rewritten for S05 of gHashTag/trinity#988 (gHashTag/t27#3567). Until 2026-09-12 this file was a
; 38-line `algorithm` block that stated the trit alphabet {-1, 0, +1} and nothing else; it did not
; parse (tools/specs_generate_baseline.txt), yet specs/trinity/capabilities/tri27.toolchain.t27
; names it as the canonical spec of the whole TRI-27 toolchain. It now states the instruction
; encoding that gHashTag/trinity actually executes: src/tri27/emu/decoder.zig at 976df517, which
; calls itself the single source of truth and is the only encoding the owner's tests exercise
; (test_encoder_fuzz.zig, test_comprehensive.zig, test_golden.zig through tri_asm.zig). The trit
; alphabet of the old file survives as TRIT_VALUES. Five other layouts exist in the consumer's
; tree and are recorded as findings, not as contracts. Every field rule below is a function the C
; backend executes; tools/trinity_tri27.py composes them into a decoder and replays
; conformance/trinity/tri27_programs.json through the generated C. ASCII only (L3).
; phi^2 + 1/phi^2 = 3 | TRINITY

module Tri27Encoding;

pub const KIND : str = "isa-encoding";
pub const ID : str = "isa/ternary_encoding";
pub const NAME : str = "The TRI-27 instruction word of the pinned Trinity emulator";
pub const CONSUMER_REPO : str = "gHashTag/trinity";
pub const PINNED_REVISION : str = "976df517419f918f05b78e73767e2fdf4aad14be";
pub const OWNER_MODULE : str = "src/tri27/emu/decoder.zig";
pub const OWNER_LINES : str = "Opcode enum :14-79; decode :126-174; encode :182-210";
pub const TRIT_VALUES : [3]i32 = [-1, 0, 1];
; --- The word ------------------------------------------------------------------------------
pub const WORD_BITS : u32 = 32;
pub const INSTRUCTION_BYTES : u32 = 4;
pub const BYTE_ORDER : str = "little-endian: byte 0 of the instruction holds bits 7:0, the opcode";
pub const OPCODE_SHIFT : u32 = 0;
pub const OPCODE_MASK : u32 = 255;
pub const DST_SHIFT : u32 = 8;
pub const REG_MASK : u32 = 31;
pub const SRC1_SHIFT : u32 = 13;
pub const SRC1_MASK_IMM_FORM : u32 = 15;
pub const SRC2_SHIFT : u32 = 18;
pub const V3_SHIFT : u32 = 23;
pub const IMM_SHIFT : u32 = 17;
pub const IMM_MASK : u32 = 32767;
pub const IMM_SIGN_BIT : u32 = 16384;
pub const IMM_BITS : u32 = 15;
pub const IMM_MIN : i32 = -16384;
pub const IMM_MAX : i32 = 16383;
pub const LAYOUT_IMM_FORM : str = "opcode 7:0, dst 12:8, src1 16:13 (four bits), immediate 31:17 (fifteen bits, two's complement)";
pub const LAYOUT_THREE_OPERAND : str = "opcode 7:0, dst 12:8, src1 17:13, src2 22:18";
pub const LAYOUT_TWO_OPERAND : str = "opcode 7:0, dst 12:8, src1 17:13; bits 31:18 unused";
pub const LAYOUT_BUNDLE3 : str = "opcode 7:0, dst 12:8, src1 17:13, src2 22:18, third register 27:23; the decoder reads this form, the owner's encoder never writes it";
; --- The forty-seven opcodes ----------------------------------------------------------------
pub const OPCODE_COUNT : u32 = 47;
pub const OPCODE_NAMES : [47]str = ["NOP", "LD", "ST", "LDI", "STI", "MOV", "ADD", "SUB", "MUL", "DIV", "INC", "DEC", "EXP", "SIN", "AND", "OR", "XOR", "NOT", "SHL", "SHR", "STR_LOAD", "STR_CONCAT", "STR_PRINT", "FILE_READ", "FILE_WRITE", "FILE_EXISTS", "JMP", "JZ", "JNZ", "CALL", "JGT", "JLT", "RET", "HALT", "DOT", "BIND", "BUNDLE2", "BUNDLE3", "PHI_CONST", "PI_CONST", "E_CONST", "SACR", "LD_IMM", "ADD3", "SUB3", "CMP3", "SYSCALL"];
pub const OPCODE_VALUES : [47]u32 = [0, 2, 3, 4, 5, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 32, 33, 34, 35, 36, 37, 64, 65, 66, 67, 68, 69, 75, 77, 96, 97, 98, 99, 128, 129, 130, 131, 132, 133, 134, 135, 136];
pub const OP_NOP : u32 = 0;
pub const OP_LD : u32 = 2;
pub const OP_ST : u32 = 3;
pub const OP_LDI : u32 = 4;
pub const OP_STI : u32 = 5;
pub const OP_MOV : u32 = 15;
pub const OP_ADD : u32 = 16;
pub const OP_SUB : u32 = 17;
pub const OP_MUL : u32 = 18;
pub const OP_DIV : u32 = 19;
pub const OP_INC : u32 = 20;
pub const OP_DEC : u32 = 21;
pub const OP_EXP : u32 = 22;
pub const OP_SIN : u32 = 23;
pub const OP_AND : u32 = 24;
pub const OP_OR : u32 = 25;
pub const OP_XOR : u32 = 26;
pub const OP_NOT : u32 = 27;
pub const OP_SHL : u32 = 28;
pub const OP_SHR : u32 = 29;
pub const OP_STR_LOAD : u32 = 32;
pub const OP_STR_CONCAT : u32 = 33;
pub const OP_STR_PRINT : u32 = 34;
pub const OP_FILE_READ : u32 = 35;
pub const OP_FILE_WRITE : u32 = 36;
pub const OP_FILE_EXISTS : u32 = 37;
pub const OP_JMP : u32 = 64;
pub const OP_JZ : u32 = 65;
pub const OP_JNZ : u32 = 66;
pub const OP_CALL : u32 = 67;
pub const OP_JGT : u32 = 68;
pub const OP_JLT : u32 = 69;
pub const OP_RET : u32 = 75;
pub const OP_HALT : u32 = 77;
pub const OP_DOT : u32 = 96;
pub const OP_BIND : u32 = 97;
pub const OP_BUNDLE2 : u32 = 98;
pub const OP_BUNDLE3 : u32 = 99;
pub const OP_PHI_CONST : u32 = 128;
pub const OP_PI_CONST : u32 = 129;
pub const OP_E_CONST : u32 = 130;
pub const OP_SACR : u32 = 131;
pub const OP_LD_IMM : u32 = 132;
pub const OP_ADD3 : u32 = 133;
pub const OP_SUB3 : u32 = 134;
pub const OP_CMP3 : u32 = 135;
pub const OP_SYSCALL : u32 = 136;
; Opcodes whose word carries an immediate (decoder.zig :133-136 and :192-195).
pub const IMM_FORM_COUNT : u32 = 23;
pub const IMM_FORM : [23]u32 = [2, 3, 4, 5, 132, 128, 129, 130, 64, 65, 66, 68, 69, 67, 75, 28, 29, 32, 33, 34, 35, 36, 37];
; Opcodes whose word carries a second source register (decoder.zig :138-141 and :187-190).
pub const SRC2_FORM_COUNT : u32 = 7;
pub const SRC2_FORM : [7]u32 = [16, 17, 18, 19, 24, 25, 26];
pub const UNKNOWN_OPCODE_RULE : str = "an opcode byte that is not one of the forty-seven decodes as NOP; decoding never fails";
pub const REGISTER_FIELD_RULE : str = "register fields are five bits wide (0..31); the executor refuses 27..31 with InvalidRegister; in the immediate form src1 is four bits (0..15)";
pub const SRC2_LOSS_RULE : str = "DOT, BIND, BUNDLE2 execute with src1 and src2 but are not in SRC2_FORM: encode writes only src1 and decode reads src2 as 0 (register t0)";
pub const SACR_MODE_RULE : str = "SACR selects its mode by the immediate, but SACR is not in IMM_FORM: decode reads the immediate as 0 and every decoded SACR adds modulo 19683; modes 2, 3 and 4 are reachable only by constructing an Instruction directly, as the owner's tests do";
; --- The t27a field table (T736, specs/compiler/theory/isa_round_trip.t27; gHashTag/t27#6507) ---
; The table above is the pinned one: it is what decoder.zig at PINNED_REVISION executes, and
; tools/trinity_tri27.py replays the owner's programs through it, so it is not changed here. The
; t27a assembler and disassembler (specs/isa/t27a.t27) write and read the widened table below
; instead. Same layout and same shifts; DOT, BIND, BUNDLE2 and BUNDLE3 join the three-operand form,
; SACR joins the immediate form, and BUNDLE3 writes its third register at V3_SHIFT. For the other
; 42 opcodes it writes the same word as `encode` (T736 b). The decoder at PINNED_REVISION reads the
; five widened opcodes the old way. gHashTag/trinity#1437 (180b29ef) made decoder.zig take this
; table instead, as the `t27c gen` output of this file, so on the emulator a t27a word for DOT, BIND,
; BUNDLE2, BUNDLE3 or SACR now means what t27a wrote (T27A_CONSUMER).
pub const T27A_IMM_FORM_COUNT : u32 = 24;
pub const T27A_SRC2_FORM_COUNT : u32 = 11;
pub const T27A_TWO_OPERAND_COUNT : u32 = 12;
pub const T27A_FIELD_RULE : str = "t27a: the immediate form is IMM_FORM plus SACR (src1 four bits, its mode in the immediate); the three-operand form is SRC2_FORM plus DOT, BIND, BUNDLE2, BUNDLE3; BUNDLE3 also writes its third register at bits 27:23; every other opcode writes dst and a five-bit src1 only";
pub const T27A_CONSUMER : str = "gHashTag/trinity src/tri27/emu/decoder.zig since 180b29ef (trinity#1437) decodes and encodes through t27a_src1, t27a_src2, t27a_imm, t27a_imm_form and t27a_encode, vendored as src/tri27/emu/tri27_encoding.zig";
; --- Findings: the other layouts in the consumer's tree, recorded and not followed ----------
pub const FINDING_COUNT : u32 = 6;
pub const FINDINGS : [6]str = ["src/tri27/emu/encoder_simple.zig puts a sixteen-bit immediate at bit 16 (loads, stores) or bit 8 (jumps, calls); src/tri27/emu/asm_parser.zig, the assembler behind `tri tri27 assemble`, uses it, so its words are misread by decoder.zig", "src/tri27/emu/specs/tbin_format.md puts the opcode in bits 31:24 and a four-bit immediate in bits 3:0", "docs/tri27/t27_format.md puts a six-bit opcode in bits 31:26 and an eight-bit immediate in bits 7:0, with opcode numbers (ADD 0x60 ... DEC 0x65) that collide with DOT 0x60", "docs/tri27/README.md puts a six-bit opcode in bits 8:5", "src/tri27/emit_zig.zig emits a VM whose decoder reads the opcode from bits 31:24 and packs bytes big-endian; it also switches on LTI, PUSH, POP and RESET, which no enum declares", "the encoder_simple.zig enum lists 36 opcodes and misses MOV, EXP, SIN, JGT, JLT and every STR_ and FILE_ opcode; every document says 36, the decoder declares 47"];
pub const ENABLED : bool = true;

; --- Field rules ---------------------------------------------------------------------------

pub fn is_defined_opcode(op: u32) -> bool {
    if (op == OP_NOP) { return true; }
    if (op == OP_LD) { return true; }
    if (op == OP_ST) { return true; }
    if (op == OP_LDI) { return true; }
    if (op == OP_STI) { return true; }
    if (op == OP_MOV) { return true; }
    if (op == OP_ADD) { return true; }
    if (op == OP_SUB) { return true; }
    if (op == OP_MUL) { return true; }
    if (op == OP_DIV) { return true; }
    if (op == OP_INC) { return true; }
    if (op == OP_DEC) { return true; }
    if (op == OP_EXP) { return true; }
    if (op == OP_SIN) { return true; }
    if (op == OP_AND) { return true; }
    if (op == OP_OR) { return true; }
    if (op == OP_XOR) { return true; }
    if (op == OP_NOT) { return true; }
    if (op == OP_SHL) { return true; }
    if (op == OP_SHR) { return true; }
    if (op == OP_STR_LOAD) { return true; }
    if (op == OP_STR_CONCAT) { return true; }
    if (op == OP_STR_PRINT) { return true; }
    if (op == OP_FILE_READ) { return true; }
    if (op == OP_FILE_WRITE) { return true; }
    if (op == OP_FILE_EXISTS) { return true; }
    if (op == OP_JMP) { return true; }
    if (op == OP_JZ) { return true; }
    if (op == OP_JNZ) { return true; }
    if (op == OP_CALL) { return true; }
    if (op == OP_JGT) { return true; }
    if (op == OP_JLT) { return true; }
    if (op == OP_RET) { return true; }
    if (op == OP_HALT) { return true; }
    if (op == OP_DOT) { return true; }
    if (op == OP_BIND) { return true; }
    if (op == OP_BUNDLE2) { return true; }
    if (op == OP_BUNDLE3) { return true; }
    if (op == OP_PHI_CONST) { return true; }
    if (op == OP_PI_CONST) { return true; }
    if (op == OP_E_CONST) { return true; }
    if (op == OP_SACR) { return true; }
    if (op == OP_LD_IMM) { return true; }
    if (op == OP_ADD3) { return true; }
    if (op == OP_SUB3) { return true; }
    if (op == OP_CMP3) { return true; }
    if (op == OP_SYSCALL) { return true; }
    return false;
}

pub fn decode_opcode(byte: u32) -> u32 {
    if (is_defined_opcode(byte)) { return byte; }
    return OP_NOP;
}

pub fn has_imm(op: u32) -> bool {
    if (op == OP_LD) { return true; }
    if (op == OP_ST) { return true; }
    if (op == OP_LDI) { return true; }
    if (op == OP_STI) { return true; }
    if (op == OP_LD_IMM) { return true; }
    if (op == OP_PHI_CONST) { return true; }
    if (op == OP_PI_CONST) { return true; }
    if (op == OP_E_CONST) { return true; }
    if (op == OP_JMP) { return true; }
    if (op == OP_JZ) { return true; }
    if (op == OP_JNZ) { return true; }
    if (op == OP_JGT) { return true; }
    if (op == OP_JLT) { return true; }
    if (op == OP_CALL) { return true; }
    if (op == OP_RET) { return true; }
    if (op == OP_SHL) { return true; }
    if (op == OP_SHR) { return true; }
    if (op == OP_STR_LOAD) { return true; }
    if (op == OP_STR_CONCAT) { return true; }
    if (op == OP_STR_PRINT) { return true; }
    if (op == OP_FILE_READ) { return true; }
    if (op == OP_FILE_WRITE) { return true; }
    if (op == OP_FILE_EXISTS) { return true; }
    return false;
}

pub fn has_src2(op: u32) -> bool {
    if (op == OP_ADD) { return true; }
    if (op == OP_SUB) { return true; }
    if (op == OP_MUL) { return true; }
    if (op == OP_DIV) { return true; }
    if (op == OP_AND) { return true; }
    if (op == OP_OR) { return true; }
    if (op == OP_XOR) { return true; }
    return false;
}

pub fn opcode_of(word: u32) -> u32 {
    return word & OPCODE_MASK;
}

pub fn dst_of(word: u32) -> u32 {
    return (word >> DST_SHIFT) & REG_MASK;
}

pub fn src1_of(word: u32, op: u32) -> u32 {
    if (has_imm(op)) { return (word >> SRC1_SHIFT) & SRC1_MASK_IMM_FORM; }
    return (word >> SRC1_SHIFT) & REG_MASK;
}

pub fn src2_of(word: u32, op: u32) -> u32 {
    if (has_src2(op)) { return (word >> SRC2_SHIFT) & REG_MASK; }
    if (op == OP_BUNDLE3) { return (word >> SRC2_SHIFT) & REG_MASK; }
    return 0;
}

pub fn v3_of(word: u32, op: u32) -> u32 {
    if (op == OP_BUNDLE3) { return (word >> V3_SHIFT) & REG_MASK; }
    return 0;
}

pub fn imm_of(word: u32, op: u32) -> i32 {
    if (has_imm(op) == false) { return 0; }
    var raw : u32 = (word >> IMM_SHIFT) & IMM_MASK;
    if ((raw & IMM_SIGN_BIT) != 0) { return (raw as i32) - 32768; }
    return raw as i32;
}

pub fn imm_clamped(imm: i32) -> i32 {
    if (imm < IMM_MIN) { return IMM_MIN; }
    if (imm > IMM_MAX) { return IMM_MAX; }
    return imm;
}

pub fn imm_field(imm: i32) -> u32 {
    var c : i32 = imm_clamped(imm);
    if (c < 0) { return ((c + 65536) as u32) & IMM_MASK; }
    return (c as u32) & IMM_MASK;
}

pub fn encode(op: u32, dst: u32, src1: u32, src2: u32, imm: i32) -> u32 {
    var word : u32 = (op & OPCODE_MASK) | ((dst & REG_MASK) << DST_SHIFT);
    if (has_imm(op)) {
        return word | ((src1 & SRC1_MASK_IMM_FORM) << SRC1_SHIFT) | (imm_field(imm) << IMM_SHIFT);
    }
    if (has_src2(op)) {
        return word | ((src1 & REG_MASK) << SRC1_SHIFT) | ((src2 & REG_MASK) << SRC2_SHIFT);
    }
    return word | ((src1 & REG_MASK) << SRC1_SHIFT);
}

pub fn bundle3_word(dst: u32, src1: u32, src2: u32, v3: u32) -> u32 {
    return OP_BUNDLE3 | ((dst & REG_MASK) << DST_SHIFT) | ((src1 & REG_MASK) << SRC1_SHIFT) | ((src2 & REG_MASK) << SRC2_SHIFT) | ((v3 & REG_MASK) << V3_SHIFT);
}

; The t27a field table. Readers of a t27a word use these, not src1_of / src2_of / imm_of.
pub fn t27a_imm_form(op: u32) -> bool {
    if (op == OP_SACR) { return true; }
    return has_imm(op);
}

pub fn t27a_src2_form(op: u32) -> bool {
    if (has_src2(op)) { return true; }
    if (op == OP_DOT) { return true; }
    if (op == OP_BIND) { return true; }
    if (op == OP_BUNDLE2) { return true; }
    if (op == OP_BUNDLE3) { return true; }
    return false;
}

pub fn t27a_encode(op: u32, dst: u32, s1: u32, s2: u32, v3: u32, imm: i32) -> u32 {
    var w : u32 = (op & OPCODE_MASK) | ((dst & REG_MASK) << DST_SHIFT);
    if (t27a_imm_form(op)) {
        return w | ((s1 & SRC1_MASK_IMM_FORM) << SRC1_SHIFT) | (imm_field(imm) << IMM_SHIFT);
    }
    w = w | ((s1 & REG_MASK) << SRC1_SHIFT);
    if (t27a_src2_form(op)) { w = w | ((s2 & REG_MASK) << SRC2_SHIFT); }
    if (op == OP_BUNDLE3) { w = w | ((v3 & REG_MASK) << V3_SHIFT); }
    return w;
}

pub fn t27a_src1(w: u32, op: u32) -> u32 {
    if (t27a_imm_form(op)) { return (w >> SRC1_SHIFT) & SRC1_MASK_IMM_FORM; }
    return (w >> SRC1_SHIFT) & REG_MASK;
}

pub fn t27a_src2(w: u32, op: u32) -> u32 {
    if (t27a_src2_form(op)) { return (w >> SRC2_SHIFT) & REG_MASK; }
    return 0;
}

pub fn t27a_imm(w: u32, op: u32) -> i32 {
    if (t27a_imm_form(op) == false) { return 0; }
    var raw : u32 = (w >> IMM_SHIFT) & IMM_MASK;
    if ((raw & IMM_SIGN_BIT) != 0) { return (raw as i32) - 32768; }
    return raw as i32;
}

; The invariants are assert statements: as bare expressions the generated Zig rejected them
; ("value of type bool ignored") and the t27b reference reported this spec BLOCKED (#6507).
invariant the_immediate_range_is_fifteen_bits {
    assert IMM_MAX - IMM_MIN == 32767;
}

invariant the_forms_partition_the_opcodes {
    assert IMM_FORM_COUNT + SRC2_FORM_COUNT == 30;
    assert T27A_IMM_FORM_COUNT + T27A_SRC2_FORM_COUNT + T27A_TWO_OPERAND_COUNT == OPCODE_COUNT;
}

test every_opcode_byte_of_the_table_is_defined {
    assert is_defined_opcode(OP_NOP) == true;
    assert is_defined_opcode(OP_SYSCALL) == true;
    assert is_defined_opcode(OP_RET) == true;
    assert is_defined_opcode(1) == false;
    assert is_defined_opcode(6) == false;
    assert is_defined_opcode(70) == false;
    assert is_defined_opcode(137) == false;
    assert is_defined_opcode(255) == false;
}

test an_unknown_opcode_decodes_as_nop {
    assert decode_opcode(1) == OP_NOP;
    assert decode_opcode(50) == OP_NOP;
    assert decode_opcode(OP_HALT) == OP_HALT;
}

test the_immediate_form_round_trips_and_sign_extends {
    var w : u32 = encode(OP_LDI, 3, 0, 0, -5);
    assert w == 4294312708;
    assert opcode_of(w) == OP_LDI;
    assert dst_of(w) == 3;
    assert imm_of(w, OP_LDI) == -5;
    assert imm_of(encode(OP_LDI, 3, 0, 0, 5), OP_LDI) == 5;
    assert imm_of(2147483652, OP_LDI) == -16384;
    assert imm_of(encode(OP_LDI, 0, 0, 0, 16383), OP_LDI) == 16383;
}

test the_immediate_is_clamped_by_the_encoder {
    assert imm_clamped(20000) == 16383;
    assert imm_clamped(-20000) == -16384;
    assert imm_of(encode(OP_JMP, 0, 0, 0, 20000), OP_JMP) == 16383;
}

test the_three_operand_form_round_trips {
    var w : u32 = encode(OP_ADD, 3, 1, 2, 0);
    assert w == 533264;
    assert opcode_of(w) == OP_ADD;
    assert dst_of(w) == 3;
    assert src1_of(w, OP_ADD) == 1;
    assert src2_of(w, OP_ADD) == 2;
    assert imm_of(w, OP_ADD) == 0;
}

test the_two_operand_form_carries_src1_only {
    var w : u32 = encode(OP_MOV, 3, 1, 0, 0);
    assert w == 8975;
    assert src1_of(w, OP_MOV) == 1;
    assert src2_of(w, OP_MOV) == 0;
}

test src1_is_four_bits_in_the_immediate_form {
    var w : u32 = encode(OP_JGT, 2, 17, 0, 7);
    assert w == 926276;
    assert src1_of(w, OP_JGT) == 1;
    assert imm_of(w, OP_JGT) == 7;
}

test dot_bind_and_bundle2_lose_src2_through_encode {
    var w : u32 = encode(OP_DOT, 3, 1, 2, 0);
    assert src1_of(w, OP_DOT) == 1;
    assert src2_of(w, OP_DOT) == 0;
    assert src2_of(encode(OP_BIND, 3, 1, 2, 0), OP_BIND) == 0;
    assert src2_of(encode(OP_BUNDLE2, 3, 1, 2, 0), OP_BUNDLE2) == 0;
}

test the_bundle3_raw_word_carries_three_sources {
    var w : u32 = bundle3_word(3, 1, 2, 4);
    assert w == 34087779;
    assert src1_of(w, OP_BUNDLE3) == 1;
    assert src2_of(w, OP_BUNDLE3) == 2;
    assert v3_of(w, OP_BUNDLE3) == 4;
    assert v3_of(w, OP_ADD) == 0;
}

test sacr_and_the_two_operand_opcodes_carry_no_immediate {
    assert imm_of(encode(OP_SACR, 4, 1, 0, 3), OP_SACR) == 0;
    assert imm_of(encode(OP_MOV, 4, 1, 0, 3), OP_MOV) == 0;
    assert has_imm(OP_SACR) == false;
}

test the_forms_are_disjoint {
    assert has_imm(OP_ADD) == false;
    assert has_src2(OP_ADD) == true;
    assert has_imm(OP_JMP) == true;
    assert has_src2(OP_JMP) == false;
    assert has_imm(OP_DOT) == false;
    assert has_src2(OP_DOT) == false;
    assert has_imm(OP_SYSCALL) == false;
}

; The t27a table counts its forms by walking all 256 bytes, so the three counts are measured, not
; restated.
test the_t27a_forms_partition_the_forty_seven_opcodes {
    var b : u32 = 0;
    var imm_form : u32 = 0;
    var src2_form : u32 = 0;
    var two_operand : u32 = 0;
    var both : u32 = 0;
    while (b < 256) {
        if (is_defined_opcode(b)) {
            if (t27a_imm_form(b)) { imm_form = imm_form + 1; }
            if (t27a_src2_form(b)) { src2_form = src2_form + 1; }
            if (t27a_imm_form(b) == false) {
                if (t27a_src2_form(b) == false) { two_operand = two_operand + 1; }
            }
            if (t27a_imm_form(b)) {
                if (t27a_src2_form(b)) { both = both + 1; }
            }
        }
        b = b + 1;
    }
    assert imm_form == T27A_IMM_FORM_COUNT;
    assert src2_form == T27A_SRC2_FORM_COUNT;
    assert two_operand == T27A_TWO_OPERAND_COUNT;
    assert both == 0;
}

; The five opcodes the pinned table loses keep every carried operand in the t27a table.
test the_t27a_table_keeps_what_the_pinned_one_loses {
    var w : u32 = t27a_encode(OP_DOT, 3, 1, 2, 0, 0);
    assert t27a_src1(w, OP_DOT) == 1;
    assert t27a_src2(w, OP_DOT) == 2;
    assert src2_of(encode(OP_DOT, 3, 1, 2, 0), OP_DOT) == 0;
    assert t27a_src2(t27a_encode(OP_BIND, 3, 1, 26, 0, 0), OP_BIND) == 26;
    assert t27a_src2(t27a_encode(OP_BUNDLE2, 3, 1, 9, 0, 0), OP_BUNDLE2) == 9;
    assert t27a_imm(t27a_encode(OP_SACR, 4, 1, 0, 0, 3), OP_SACR) == 3;
    assert t27a_imm(t27a_encode(OP_SACR, 4, 1, 0, 0, 0 - 7), OP_SACR) == 0 - 7;
    assert t27a_encode(OP_BUNDLE3, 3, 1, 2, 4, 0) == bundle3_word(3, 1, 2, 4);
    assert v3_of(t27a_encode(OP_BUNDLE3, 3, 1, 2, 4, 0), OP_BUNDLE3) == 4;
}

; T736 (b) on single words: for the opcodes the pinned table already carries, t27a writes the word
; encode writes.
test the_t27a_table_moves_no_pinned_word {
    assert t27a_encode(OP_ADD, 3, 1, 2, 0, 0) == encode(OP_ADD, 3, 1, 2, 0);
    assert t27a_encode(OP_ADD, 3, 1, 2, 0, 0) == 533264;
    assert t27a_encode(OP_LDI, 3, 0, 0, 0, 0 - 5) == 4294312708;
    assert t27a_encode(OP_MOV, 3, 1, 0, 0, 0) == 8975;
    assert t27a_encode(OP_JGT, 2, 1, 0, 0, 7) == encode(OP_JGT, 2, 1, 0, 7);
    assert t27a_encode(OP_SYSCALL, 26, 26, 0, 0, 0) == encode(OP_SYSCALL, 26, 26, 0, 0);
}

Открыть спеку урока в плеере ↗

Все уроки