Троичный MAC
Вы узнаете
Как скалярное произведение с троичными весами превращается в сложения, вычитания и пропуски.
Блок умножения с накоплением на каждом такте прибавляет вход, умноженный на вес. С весами -1, 0 и +1 каждый такт — это сложение, вычитание или ничего: девять тактов виджета дают 4 сложения, 2 вычитания и 3 пропуска и приходят к -8 без единого умножителя. Спека урока, ternary_mac.t27, — аппаратная версия: скалярное произведение 27 тритов в упакованных векторах, 2 бита на трит.
Попробовать
Меняйте веса, пока аккумулятор не придёт к 0, а затем к самому большому значению, какое получится.

Nine inputs, nine weights of -1, 0 or +1. Each clock the accumulator adds, subtracts or does nothing. Press a weight to change it.
specs/ternary/ternary_mac.t27
module TernaryMac;
// Sign-only ternary multiply of two packed trits {N=0b00, Z=0b01, P=0b10}.
fn tmul(ta: u8, tb: u8) -> i8 {
if (ta == 1) { return 0; }
if (tb == 1) { return 0; }
if (ta == tb) { return 1; }
return -1;
}
// One trit position i of two 54-bit packed vectors (trit i at [2i+1:2i]).
fn tp(a: u64, b: u64, i: u32) -> i8 {
return tmul(((a >> (i << 1)) & 3) as u8, ((b >> (i << 1)) & 3) as u8);
}
// 27-trit ternary dot product, loop-free (gen-verilog cannot yet lower a
// local-declaring while loop -- see #1741). Result in [-27, +27].
pub fn dot27(a: u64, b: u64) -> i8 {
return tp(a,b,0) + tp(a,b,1) + tp(a,b,2) + tp(a,b,3) + tp(a,b,4)
+ tp(a,b,5) + tp(a,b,6) + tp(a,b,7) + tp(a,b,8) + tp(a,b,9)
+ tp(a,b,10) + tp(a,b,11) + tp(a,b,12) + tp(a,b,13) + tp(a,b,14)
+ tp(a,b,15) + tp(a,b,16) + tp(a,b,17) + tp(a,b,18) + tp(a,b,19)
+ tp(a,b,20) + tp(a,b,21) + tp(a,b,22) + tp(a,b,23) + tp(a,b,24)
+ tp(a,b,25) + tp(a,b,26);
}
test dot_all_n_x_all_n { assert_eq(dot27(0, 0), 27); }
test dot_all_n_x_all_p { assert_eq(dot27(0, 12009599006321322), -27); }
test dot_all_p_x_all_p { assert_eq(dot27(12009599006321322, 12009599006321322), 27); }
test dot_all_z { assert_eq(dot27(6004799503160661, 6004799503160661), 0); }
// W697: the hardware boundary, derived from the CALL GRAPH.
//
// This spec has several functions that take a parameter and return a value,
// so W696's count rule left it AMBIGUOUS. But exactly ONE of them is called
// by no other function -- it is the root, and every other candidate is a
// helper it reaches. With one root the choice is forced by structure rather
// than by count, and forwarding to it still invents nothing.
//
// The call graph is built from FUNCTION BODIES ONLY. Counting `test` blocks
// as callers makes the rule vacuous -- every function is called by its own
// test, so nothing is ever a root.
//
// Measured: the rule resolved 14 of 136 ambiguous specs, 6 of them with
// types that can cross a module boundary. It is narrow because most of the
// rest are libraries of INDEPENDENT functions, which have several roots and
// correctly stay ambiguous.
fn on_comb(a: u64, b: u64) -> i8 { return dot27(a, b); }
endmodule
Все уроки
Модуль 1 · Три значения
Почему три, как сбалансированная троичная система пишет любое число без знака и что дают переворот и отсечение тритов.
Модуль 2 · Логика с «не знаю»
Трёхзначные вентили Клини, два вентиля без двоичного двойника и сложение как пара таблиц.
Модуль 3 · Складываем триты
Полусумматор, полный сумматор и перенос, бегущий влево разряд за разрядом.
Модуль 4 · Умножение без умножителя
Копия, ноль или переворот: произведение на один трит, умножение столбиком и MAC, который только складывает.
Модуль 5 · Триты в двоичной памяти
Два бита на трит, пять тритов на байт и сколько бит нужно слову из 27 тритов.
Модуль 6 · Командное слово TRI-27
32-битное слово, которое декодирует эмулятор Trinity: его поля, 47 опкодов и 15-битное непосредственное значение.
Модуль 7 · Троичная машина
АЛУ из сумматоров этого курса, переход на три стороны и программа, которую можно пройти по шагам.
Модуль 8 · Три ответа
Сравнение по старшему различному триту, поиск числа по третям и сортировка трёхзначными сравнениями.
Модуль 9 · Троичные нейроны
Веса -1, 0, +1: один нейрон, детектор и маленький слой, и нигде нет умножителя.