Перейти к основному содержимому

Микровычислители

Микросхема содержит два независимых специализированных микровычислителя (CPU1 и CPU2), предназначенных для:

  • коррекции статических нелинейностей датчика угла;
  • согласования отсчётов в многополюсных датчиках;
  • расчёта угловой скорости, ускорения и фильтрации;
  • буферизации внутренних сигналов преобразователей.

Наличие двух CPU позволяет одному выполнять коррекцию нелинейностей, а другому — расчёт скорости и ускорения, что обеспечивает средний темп вычислений 50–150 мкс.

Каждый CPU имеет нестандартную разрядность 14 бит, сокращённый набор из 48 команд, 8 регистров общего назначения (R0–R5 по 14 бит, R6 и R7 по 28 бит) и 512 ячеек памяти программ и данных по 14 бит.

Архитектура конвейера

Каждый CPU реализован на основе 4-ступенчатого конвейера:

СтупеньНазначение
IFВыборка инструкции из памяти по адресу счётчика команд (PC)
IDДекодирование инструкции, чтение регистров
EXИсполнение: АЛУ, CORDIC, умножитель, вычисление адреса, запись в память
MEM/WBВыбор результата, запись в регистр

Базовое время выполнения одной инструкции — 4 такта FINT. Результат умножения или операции CORDIC может быть готов позже, но не блокирует выполнение следующих инструкций, если они не используют регистры R6 или R7.

Исключения:

  • CORDIC (SIN, COS, ATAN) — 16 итераций, ~17 тактов;
  • Умножение (MULTI, MULTF и др.) — 5–10 тактов;
  • NOP N — N+1 тактов (задержка);
  • WAIT_* — блокировка до наступления события.

Регистры общего назначения

РегистрРазрядностьНазначение
R0–R514 битРегистры общего назначения. При чтении знакорасширяются до 28 бит
R628 битРезультат умножения/сдвига. Всегда перезаписывается командами MULTI, MULTI_ACC, MULTF, MULTF_ACC, MULTCUBE_ACC, DEC2FLOAT
R728 битАккумулятор. Всегда перезаписывается командами ACC, ACC2, MULTI_ACC, MULTF_ACC, MULTCUBE_ACC

Загрузка и сохранение R6 и R7 возможна только форматами по 28 бит (2 ячейки) или 56 бит (4 ячейки). Загрузить или сохранить только младшие 14 бит R6/R7 нельзя. Для операций с R6/R7 использовать команды LOAD32/STORE32, CLOAD32/CSTORE32.

Структура памяти

Структура памяти CPU
Структура памяти CPU

Объём памяти каждого CPU — 512 ячеек по 14 бит. Карта адресов:

АдресаРазмерНазначениеДоступ CPU
0–9596Программный код (инструкции)Только чтение
96–239144ДанныеЧтение/запись
240–2478Обмен между CPU1 и CPU2Чтение/запись (кросс)
248–2514Ячейки SPIЧтение/запись
252–2532HAND (данные преобразователя)Чтение/запись
254–2552HAND ext (данные внешнего преобразователя)Чтение/запись
256–383128Буфер (BUF)Чтение/запись

При включённой функции инициализации (бит INIT_on) в первые 232 ячейки обоих CPU переписываются данные из ПЗУ с последовательным доступом.

Ячейки обмена данными CPU

Ячейки с адресами 240–247 предназначены для передачи данных между CPU1 и CPU2. Шины чтения подключены кросс-образованием: чтение CPU1 по адресам 240–247 возвращает данные, записанные CPU2, и наоборот.

Ячейки обмена с интерфейсом SPI

Ячейки памяти CPU доступны для чтения и записи через интерфейс SPI через регистры Dcpu1LB/Dcpu1HB и Dcpu2LB/Dcpu2HB. Адрес ячейки задаётся в составе транзакции SPI. При записи данные фиксируются в соответствующей ячейке памяти CPU. При чтении возвращается текущее значение ячейки.

Буферы

В микросхему добавлены два дополнительных блока памяти BUF1 и BUF2 по 64 ячейки каждый (адреса 256–319). По умолчанию BUF1 расширяет память CPU1, а BUF2 — CPU2. При необходимости буфер может быть переключён на другой CPU с помощью битов SHRD_RAM и SHRD_CPU2, что позволяет одному CPU работать с 128 дополнительными ячейками (адреса 256–383).

Адресация памяти

Команды загрузки и сохранения используют 7-битное поле адреса. Фактический адрес зависит от типа команды и регистра:

КомандаРегистрЯчейкиДиапазон адресовФормула адреса
STORE/CSTORER0–R51128–255addr + 128
LOAD/CLOADR0–R51128–255addr + 128
STORE32/CSTORE32R0–R5264–318 (чётные)addr × 2 + 64
LOAD32/CLOAD32R0–R5264–318 (чётные)addr × 2 + 64
STORE/CSTORER6, R7464–318 (чётные)addr × 2 + 64
LOAD/CLOADR6, R7464–318 (чётные)addr × 2 + 64
STORE32/CSTORE32R6, R7464–318 (чётные)addr × 2 + 64
LOAD32/CLOAD32R6, R7464–318 (чётные)addr × 2 + 64

Для 32-битных операций (STORE32, LOAD32) и операций с R6/R7 адрес всегда умножается на 2. Ячейка с чётным адресом помещается в младшую часть регистра, с нечётным (адрес +1) — в старшую. Для 4-ячеистых операций: {data[addr+3], data[addr+2], data[addr+1], data[addr]}.

Форматы данных

28-битный формат с плавающей запятой

Формат является усечённым IEEE754 float32. Нет NaN, Inf, denormal.

Структура формата

ПолеБитыДлинаОписание
Sign2710 = +, 1 = −
Exp26..207Порядок, bias = 63
Mant19..020Мантисса (IEEE754 fraction >> 3)

Кодирование (Float32 → Float28)

  1. v = single(x) (IEEE754 float32)
  2. Извлечь поля IEEE754: Sign = bit31, Exp32 = bits30..23, Frac32 = bits22..0
  3. Порядок: если Exp32 == 0, то Exp28 = 0, иначе Exp28 = Exp32 − 127
  4. Exp = Exp28 + 63
  5. Mant = Frac32 >> 3
  6. Упаковка: Float28 = (Sign << 27) | (Exp << 20) | Mant

Float28 → Float32

  1. Извлечь: Sign = bit27, Exp = bits26..20, Mant = bits19..0
  2. Восстановление: Exp32 = Exp − 63 + 127, Frac32 = Mant << 3
  3. Value = Sign × (1 + Frac32 / 2^23) × 2^(Exp − 63)

Float28 → Integer

INTvalue = Sign × Mant × 2^(Order - 63), где Sign = +1 если бит 27 = 0, иначе −1.

Система команд

Все инструкции кодируются 14-битным словом. Биты [5:3] кодируют регистр-источник B (SEL_B), биты [2:0] — регистр-приёмник A (SEL_A). Регистры R0–R7 кодируются значениями 000–111.

Арифметико-логические команды

КомандаКодАргументыОписание
NOP00000000000[N]Нет операции. При N > 0 — задержка N+1 тактов
CLR00000000001AA = 0
INC00000000010AA = A + 1
DEC00000000011AA = A − 1
ABS00000000100AA = |A|
ACC00000000111AR7 = R7 + A
ACC200000001B, AR7 = R7 + A + B
ADD00000011B, AA = A + B
SUB00000100B, AA = A − B
ORL00000101B, AA = A | B
ANL00000110B, AA = A & B
MOVE00000111B, AA = B
CONST1101val, AA = знакорасширенное val (−64…+63)

Команды сдвига

КомандаКодАргументыОписание
LSL000010count, AЛогический сдвиг влево: A = A << (count + 1)
ASR000011count, AАрифметический сдвиг вправо: A = A >> (count + 1)

Команды умножения и преобразования форматов

КомандаКодАргументыОписание
MULTI11110100B, AR6 = A × B (целое, A — 28 бит, B — 24 бит, R6 — 52 бит)
MULTI_ACC11110101B, AR6 = A × B; R7 = R7 + R6 (целое MAC)
MULTF11110110B, AR6 = A × B (A — целое 28 бит, B — float 28 бит, R6 — 56 бит)
MULTF_ACC11110111B, AR6 = A × B; R7 = R7 + R6 (float MAC)
MULTK2411111011B, AA = RES[51:22], RES = A × B (целое, 24-битная константа)
MULTK1411111100B, AA = RES[40:13], RES = A × B (целое, 14-битная константа)
MULTCUBE_ACC11111101B, AR6 = (ch1+1)^(ch7+1) × (B + A); R7 = R7 + R6
DEC2FLOAT11111110000AR6 = float(A) — преобразование целого в формат float28

Команды работы с памятью

КомандаКодАргументыОписание
STORE0001addr, AЗапись 14 бит: ram[addr] = A[13:0]
STORE320010addr, AЗапись 28 бит: ram[addr] = A[13:0], ram[addr+1] = A[27:14]
LOAD0011addr, AЧтение 14 бит: A = знакорасширение(ram[addr])
LOAD321100addr, AЧтение 28 бит: A = {ram[addr+1], ram[addr]}

Индексные команды работы с памятью

Индексные команды CLOAD/CSTORE используют дополнительное смещение rel (см. раздел Канальные регистры). Для работы этих команд необходимо включить режим командой LOADSTORE_ON.

КомандаКодАргументыОписание
CSTORE1001addr, AЗапись 14 бит: ram[addr + rel] = A[13:0]
CSTORE321010addr, AЗапись 28 бит: ram[addr + rel] = A[13:0], ram[addr + rel + 1] = A[27:14]
CLOAD1000addr, AЧтение 14 бит: A = знакорасширение(ram[addr + rel])
CLOAD321011addr, AЧтение 28 бит: A = {ram[addr + rel + 1], ram[addr + rel]}

Команды условного перехода

Все переходы используют относительное смещение от текущего PC.

КомандаКодАргументыОписание
EQUAL010rel, B, APC = PC + rel если A == B (rel: −16…+15)
MORE011rel, B, APC = PC + rel если A > B, знаковое (rel: −16…+15)
DJNZ11100rel, AA = A − 1; PC = PC + rel если A ≠ 0 (rel: −32…+31)
CDJNZ111010rel, CH#CH# = CH# − 1; PC = PC + rel если CH# ≠ 0 (rel: −16…+15)
EQUAL0111011rel, APC = PC + rel если A == 0 (rel: −16…+15)
JUMP111100relPC = PC + rel (rel: −128…+127)
RJUMP11111111100APC = A (абсолютный переход по регистру)
STOREPC11111111101AA = PC + 1 (сохранение адреса возврата)

CORDIC-команды

Аппаратный CORDIC-сопроцессор выполняет 16 итераций за ~17 тактов. SIN и COS вычисляются одновременно.

КомандаКодАргументыОписание
SIN00000000101AВычисление sin(A). Результат: A = знакорасширенный cordic_sin[15:0]. Аргумент — 18-битный угол (2 старших бита — квадрант)
COS00000000110AВычисление cos(A). Результат: A = знакорасширенный cordic_cos[15:0]
ATAN00000010B, AВычисление atan2(A, B). Результат: A — 18-битный угол, B — аргумент cos, A — аргумент sin

Канальные регистры

Канальные регистры используются для индексной адресации памяти и организации циклов.

РегистрРазрядностьКоманда загрузкиИсточник данных
ch09 битCFIX0A[8:0]
ch18 битCFIX1A[7:0]
ch27 битCFIX2A[6:0]
ch36 битCFIX3A[5:0]
ch45 битCFIX4A[4:0]
ch72 битCFIX7A[1:0]

Смещение rel для индексных команд вычисляется как взвешенная сумма: rel = ch0 + ch1 × 2 + ch2 × 4 + ch3 × 8 + ch4 × 16

КомандаКодАргументыОписание
CFIX011111110100Ach0 = A[8:0]
CFIX111111110101Ach1 = A[7:0]
CFIX211111110110Ach2 = A[6:0]
CFIX311111110111Ach3 = A[5:0]
CFIX411111111000Ach4 = A[4:0]
CFIX711111111001Ach7 = A[1:0]
CLR_CH11111111010CH#CH# = 0. При CH# = 5 — очистка всех канальных регистров
CLOAD_CUBE11111111011AA = (ch1+1)^(ch7+1) — полиномиальный базис

NUMCUBE: значение (ch1+1)^(ch7+1) определяет порядок полинома:

ch7ЗначениеБазис
0ch1 + 1Линейный
1(ch1 + 1)²Квадратичный
2(ch1 + 1)³Кубический
31Константа

Команды управления HAND-интерфейсом

КомандаКодАргументыОписание
SET_A_HAND11111110001constВыбор номера пары ячеек преобразователя (0–7)
HFIX11111110010AУстановка номера HAND из регистра A[2:0]

Команды управления и синхронизации

КомандаКодОписание
SETB_STP11111111110000Установка флага STP = 1
CLRB_STP11111111110001Сброс флага STP = 0
SW_HTE111111111110010Переключение мультиплексора HAND1 на другой CPU
SW_HTE211111111110011Переключение мультиплексора HAND2 на другой CPU
WAIT_EXT_CPU11111111111000Ожидание импульса от другого CPU
PULSE_EXT_CPU11111111111001Генерация импульса для другого CPU
WAIT_OWN_HAND11111111111010Ожидание данных от «родного» преобразователя
WAIT_EXT_HAND11111111111011Ожидание данных от «внешнего» преобразователя
LOADSTORE_ON11111111111100Разрешение работы команд CLOAD/CSTORE
LOADSTORE_OFF11111111111101Запрет работы команд CLOAD/CSTORE
IDLE11111111111111Остановка CPU (бесконечный NOP)

Взаимодействие с преобразователем

Подключение CPU1 и CPU2 к преобразователям (HAND1 и HAND2) осуществляется симметрично: для CPU1 «родным» (own) является HAND1, а внешним (ext) — HAND2. Для CPU2 — наоборот. Считывание данных производится с двойной шириной слова (28 бит): с own по адресам 252–253, с ext по адресам 254–255.

Выбор номера пары ячеек преобразователя выполняется командой SET_A_HAND.

#ADDRСодержимое
0FullAngle[27:0]
1Wca[11:0], BScos[12], ex_shifted, Wsa[11:0], BSsin[12], ex_ref
2VirtualS[12:0], ex_recovered, BSsin[12:0], ex_recovered_90dgr
3Amp_metric[11:0], Err_metric[15:0]
4FullVel[27:0]
5PhiC[15:2], PhiS[15:2]
6VirtualC[12:0], ex_recovered, BScos[12:0], ex_recovered_90dgr
7Pole_addi, STAT

Запись данных в преобразователь

Доступ к записи в каждый преобразователь есть только у одного CPU. Выбор CPU с доступом на запись определяется конфигурационным битом HandToEXT. CPU может инвертировать действие флага HandToEXT с помощью команд SW_HTE1 и SW_HTE2 (цифра — номер преобразователя).

Запись Coord/Vel

Результаты вычислений CPU могут быть записаны в блок гистерезиса скорости и координаты. Для этого установите флаг Coord_from_cpu или Vel_from_cpu и запишите данные, установив командой SET_A_HAND соответствующий адрес (0 для координаты, 4 для скорости).

Запись Pole_addi

Для записи добавочного значения полюса Pole_addi выставите адрес 3. Запись возможна, если источник определён как CPU с помощью бита PoleAddi_src.

Синхронизация двух CPU

CPU1 и CPU2 могут обмениваться данными и синхронизировать работу:

  • Обмен данными — через ячейки 240–247 (кросс-подключение шин чтения).
  • Программная синхронизация — WAIT_EXT_CPU ожидает импульс от другого CPU, PULSE_EXT_CPU генерирует импульс.
  • Синхронизация с преобразователем — WAIT_OWN_HAND ожидает обновление данных от «родного» преобразователя, WAIT_EXT_HAND — от «внешнего».
  • Флаг STP — SETB_STP/CLRB_STP управляют однобитным выходом CPU, может использоваться для внешней сигнализации.

Отладчик

Каждый CPU имеет встроенный отладчик, управляемый через SPI-регистры DBG1_ctrl/DBG1_data и DBG2_ctrl/DBG2_data.

Управление выполнением

Регистр DBG_ctrl:

БитыНазначение
[12:11]Команда: 0 = RUN, 1 = STOP, 2 = STEP
[10]Триггер обработки команды (по фронту)
[9]Разрешение точки останова 1
[8:0]Адрес точки останова 1

Регистр DBG_data:

БитыНазначение
[9]Разрешение точки останова 2
[8:0]Адрес точки останова 2

Чтение регистров

Чтение внутренних регистров CPU производится через SPI-команду READ_CPU_REGS. Поле sel_reg (биты [13:10]) выбирает данные:

sel_regДанные
0–5R0–R5 (14 бит)
6–7R6/R7 младшие 14 бит
8–9R6/R7 старшие 14 бит
10Статус: DBG_STOP, STP, PC, инструкция
11Каналы: a_hand, ch1, ch4, ch0
12Каналы: ch7, ch_rel, ch2, ch3

Пример программы

CPU1: Коррекция угла по 1-й гармонике

Программа читает угол из преобразователя, вычисляет sin(угол) через CORDIC, умножает на float-коэффициент из памяти и вычитает полученную коррекцию из исходного угла. Результат передаётся CPU2 через ячейки обмена.

SET_A_HAND 0 // Выбрать FullAngle

LOOP: WAIT_OWN_HAND // Ждать обновление данных
LOAD32 HAND1_L R0 // R0 = текущий угол (28 бит, адреса 252-253)

CLR R7 // R7 = 0 (аккумулятор коррекции)
SIN R0 // CORDIC: R0 = sin(угол)
LOAD32 228 R1 // R1 = коэффициент (float28, адреса 228-229)
MULTF_ACC R1 R0 // R6 = R0(целое) × R1(float); R7 += R6

ASR 15 R7 // Масштабирование: R7 >>= 16
MOVE R7 R2 // R2 = коррекция

LOAD32 HAND1_L R0 // R0 = исходный угол (перечитать)
SUB R2 R0 // R0 = угол − коррекция

STORE32 EXTCPU_0 R0 // Исправленный угол → CPU2 (адреса 240-241)
PULSE_EXT_CPU // Сигнал готовности CPU2
JUMP LOOP // Следующий цикл

Используемые переменные (из файла cpu1_ram.txt):

ПеременнаяАдресОписание
HAND1_L252Младшие 14 бит OWN HAND
HAND1_H253Старшие 14 бит OWN HAND
EXTCPU_0240Младшие 14 бит обмена CPU1→CPU2
EXTCPU_1241Старшие 14 бит обмена CPU1→CPU2
(адрес 228)228–229Float28 коэффициент коррекции

Пошаговое описание:

  1. SET_A_HAND 0 — выбирает пару ячеек FullAngle для чтения из преобразователя.
  2. WAIT_OWN_HAND — останавливает CPU до появления новых данных от «родного» преобразователя.
  3. LOAD32 HAND1_L R0 — загружает 28-битный угол из ячеек 252 (младшие) и 253 (старшие).
  4. CLR R7 — обнуляет аккумулятор.
  5. SIN R0 — CORDIC вычисляет sin(R0), результат записывается в R0. CORDIC одновременно вычисляет cos, результат доступен для следующей команды COS.
  6. LOAD32 228 R1 — загружает 28-битный float-коэффициент из ПЗУ.
  7. MULTF_ACC R1 R0 — R6 = R0 (целое sin) × R1 (float коэфф.); R7 += R6.
  8. ASR 15 R7 — арифметический сдвиг R7 вправо на 16 бит (масштабирование накопленной суммы).
  9. MOVE R7 R2 — R2 = коррекция.
  10. LOAD32 HAND1_L R0 — перечитывает исходный угол (данные в HAND защёлкнуты).
  11. SUB R2 R0 — R0 = исходный угол − коррекция.
  12. STORE32 EXTCPU_0 R0 — записывает 28-битный результат в ячейки 240–241 для CPU2.
  13. PULSE_EXT_CPU — генерирует импульс, по которому CPU2 узнаёт о готовности данных.

Сводная таблица команд

ИмяКод операцииАргументыОписание
NOP00000000000[count]Нет операции; задержка count+1 тактов
CLR00000000001AA = 0
INC00000000010AA = A + 1
DEC00000000011AA = A − 1
ABS00000000100AA = |A|
SIN00000000101AA = sin(A), CORDIC 16 итераций
COS00000000110AA = cos(A), CORDIC 16 итераций
ACC00000000111AR7 = R7 + A
ACC200000001B, AR7 = R7 + A + B
ATAN00000010B, AA = atan2(A, B)
ADD00000011B, AA = A + B
SUB00000100B, AA = A − B
ORL00000101B, AA = A | B
ANL00000110B, AA = A & B
MOVE00000111B, AA = B
LSL000010count, AA = A << (count + 1)
ASR000011count, AA = A >> (count + 1)
STORE0001addr, Aram[addr] = A[13:0]
STORE320010addr, Aram[addr..addr+1] = A[27:0]
LOAD0011addr, AA = знакорасширение(ram[addr])
EQUAL010rel, B, APC += rel если A == B
MORE011rel, B, APC += rel если A > B
CLOAD1000addr, AA = знакорасширение(ram[addr + rel])
CSTORE1001addr, Aram[addr + rel] = A[13:0]
CSTORE321010addr, Aram[addr+rel..addr+rel+1] = A[27:0]
CLOAD321011addr, AA = {ram[addr+rel+1], ram[addr+rel]}
LOAD321100addr, AA = {ram[addr+1], ram[addr]}
CONST1101val, AA = знакорасширение(val), −64…+63
DJNZ11100rel, AA--; PC += rel если A ≠ 0
CDJNZ111010rel, CH#CH#--; PC += rel если CH# ≠ 0
EQUAL0111011rel, APC += rel если A == 0
JUMP111100relPC += rel
MULTI11110100B, AR6 = A × B, целое
MULTI_ACC11110101B, AR6 = A × B; R7 += R6, целое
MULTF11110110B, AR6 = A × B, A — целое, B — float
MULTF_ACC11110111B, AR6 = A × B; R7 += R6, float
MULTK2411111011B, AA = (A × B)[51:22]
MULTK1411111100B, AA = (A × B)[40:13]
MULTCUBE_ACC11111101B, AR6 = (ch1+1)^(ch7+1) × (B+A); R7 += R6
DEC2FLOAT11111110000AR6 = float(A)
SET_A_HAND11111110001constВыбор адреса HAND (0–7)
HFIX11111110010AУстановка HAND из A[2:0]
CFIX011111110100Ach0 = A[8:0]
CFIX111111110101Ach1 = A[7:0]
CFIX211111110110Ach2 = A[6:0]
CFIX311111110111Ach3 = A[5:0]
CFIX411111111000Ach4 = A[4:0]
CFIX711111111001Ach7 = A[1:0]
CLR_CH11111111010CH#CH# = 0; при CH#=5 очистка всех
CLOAD_CUBE11111111011AA = (ch1+1)^(ch7+1)
RJUMP11111111100APC = A
STOREPC11111111101AA = PC + 1
SETB_STP11111111110000STP = 1
CLRB_STP11111111110001STP = 0
SW_HTE111111111110010Переключение HAND1
SW_HTE211111111110011Переключение HAND2
WAIT_EXT_CPU11111111111000Ожидание импульса от CPU
PULSE_EXT_CPU11111111111001Импульс для CPU
WAIT_OWN_HAND11111111111010Ожидание own HAND
WAIT_EXT_HAND11111111111011Ожидание ext HAND
LOADSTORE_ON11111111111100Включить CLOAD/CSTORE
LOADSTORE_OFF11111111111101Выключить CLOAD/CSTORE
IDLE11111111111111Остановка CPU