Сопроцессор
Сопроцессор — специализированный процессор, расширяющий возможности центрального процессора компьютерной системы, но оформленный как отдельный функциональный модуль. Физически сопроцессор может быть отдельной микросхемой или может быть встроен в центральный процессор (как это делается в случае математического сопроцессора в процессорах для ПК начиная с Intel 486DX).
![]()

Математический сопроцессор 80×287 в колодке на материнской плате персонального компьютера.
Различают следующие виды сопроцессоров:
- математические сопроцессоры общего назначения, обычно ускоряющие вычисления с плавающей запятой,
- сопроцессоры ввода-вывода (например — Intel 8089), разгружающие центральный процессор от контроля за операциями ввода-вывода или расширяющие стандартное адресное пространство процессора,
- сопроцессоры для выполнения каких-либо узкоспециализированных вычислений.
Сопроцессоры могут входить в набор логики, разработанный одной конкретной фирмой (например Intel выпускала в комплекте с процессором 8086 сопроцессоры 8087 и 8089) или выпускаться сторонним производителем (например, Weitek (англ.) 1064 для Motorola m68k и 1067 для Intel 80286).
Сопроцессор в программировании
Сопроцессор расширяет систему инструкций центрального процессора, поэтому для его использования, программа (компилируемая без интерпретации и вызова внешних библиотек) должна содержать эти инструкции. Настройки современных компиляторов для языков высокого уровня под процессоры семейства x86 зачастую позволяют выбирать: использовать математический сопроцессор или нет, что особенно важно при создании кода, который будет исполняться внутри обработчика аппаратного прерывания.
См. также
- Процессор
- Звуковой процессор
- Графический процессор
- Вероятностный процессор
- Математический сопроцессор
| Это заготовка статьи о компьютерах. Вы можете помочь проекту, исправив и дополнив её. Это примечание по возможности следует заменить более точным. |
| Технологии цифровых процессоров | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Архитектура | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Команда | Операнды | Пояснение | Описание |
| FLD | src | TOPSWR-=1; ST(0)=src; | Загрузка операнда в вершину стека |
| FST | dst | dst=ST(0); | Сохранение вершины стека в память |
| FSTP | dst | dst=ST(0); TOPSWR+=1; | Сохранение вершины стека в память с выталкиванием |
| FXCH | ST(i) | ST(0) ↔ ST(i) | Обмен значений ST(0) и ST(i) |
Команды передачи данных целого типа Используются в случае если операнд, применяемый в команде, имеет целый тип (1, 2, 4 или 8-байтный).
| Команда | Операнды | Пояснение | Описание |
| FILD | src | TOPSWR-=1; ST(0)=src; | Загрузка операнда в вершину стека |
| FIST | dst | dst=ST(0); | Сохранение вершины стека в память |
| FISTP | dst | dst=ST(0); TOPSWR+=1; | Сохранение вершины стека в память с выталкиванием |
Команды передачи данных двоично-десятичного типа Используются в случае если операнд, применяемый в команде, представлен в двоично-десятичной системе счисления (1, 2, 4 или 8-байтный).
| Команда | Операнды | Пояснение | Описание |
| FBLD | src | TOPSWR-=1; ST(0)=src; | Загрузка операнда в вершину стека |
| FBSTP | dst | dst=ST(0); TOPSWR+=1; | Сохранение вершины стека в память с выталкиванием |
Команды загрузки констант Команды загрузки констант не имеют операндов и загружают соответствующее константное значение в вершину стека сопроцессора.
| Команда | Пояснение | Описание |
| FLDZ | TOPSWR-=1; ST(0)=0; | Загрузка 0 |
| FLD1 | TOPSWR-=1; ST(0)=1; | Загрузка 1 |
| FLDPI | TOPSWR-=1; ST(0)=3.1415926535; | Загрузка π |
| FLDL2T | TOPSWR-=1; ST(0)=3.3219280948; | Загрузка log210 |
| FLDL2E | TOPSWR-=1; ST(0)=1.4426950408; | Загрузка log2e |
| FLDLG2 | TOPSWR-=1; ST(0)=0.3010299956; | Загрузка lg 2 |
| FLDLN2 | TOPSWR-=1; ST(0)=0.6931471805; | Загрузка ln 2 |
Команды сравнения данных
Команды данной группы выполняют сравнение значений числа в вершине стека и операнда, указанного в команде.
Команды сравнения данных вещественного типа
| Команда | Операнды | Пояснение | Описание |
| FCOM FUCOM | src | ST(0) — src | Вещественное сравнение |
| FCOMP FUCOMP | src | ST(0) — src; TOPSWR+=1; | Вещественное сравнение с выталкиванием |
| FCOMPP FUCOMPP | — | ST(0) — ST(1); TOPSWR+=2; | Вещественное сравнение с двойным выталкиванием |
| FCOMI FUCOMI | ST, ST(i) | ST(0) — ST(i) | Вещественное сравнение c модификацией EFLAGS |
| FCOMIP FUCOMIP | ST, ST(i) | ST(0) — ST(i); TOPSWR+=1; | Вещественное сравнение c выталкиванием с модификацией EFLAGS |
| FXAM | — | Анализ ST(0) |
Команды сравнения сравнивают значение в вершине стека с операндом. По умолчанию (если операнд не задан) происходит сравнение регистров ST(0) и ST(1) . В качестве операнда может быть задана ячейка памяти или регистр. Команда устанавливает биты C0, C2, C3 регистра swr в соответствии с таблицей. Сбрасывает в 0 признак C1 при пустом стеке после выполнения команды.
| Условие | С3 | С2 | C0 |
| ST(0) > src | 0 | 0 | 0 |
| ST(0) < src | 0 | 0 | 1 |
| ST(0) = src | 1 | 0 | 0 |
| Недопустимая операция (#IA) | 1 | 1 | 1 |
Особый интерес представляет команда FCOMI (FUCOMI) . Она сравнивает содержимое регистра ST(0) со значением операнда ST(i) и устанавливает биты ZF, PF, CF регистра EFLAGS в соответствии с таблицей. Анализ выполнения сравнения осуществляет последующая команда условного перехода (команда центрального процессора).
| Условие | ZF | PF | CF | Переход |
| ST(0) > ST(i) | 0 | 0 | 0 | ja |
| ST(0) < ST(i) | 0 | 0 | 1 | jb |
| ST(0) = ST(i) | 1 | 0 | 0 | je |
| ST(0) >= ST(i) | * | 0 | 0 | jae |
| ST(0) | * | 0 | * | jbe |
| Недопустимая операция (#IA) | 1 | 1 | 1 |
Команда FXAM проверяет содержимое регистра ST(0) и устанавливает биты C0, C2, C3 регистра swr в соответствии с таблицей. Бит C1 устанавливается равным знаковому биту ST(0).
| Класс | С3 | С2 | C0 |
| Неподдерживаемый формат | 0 | 0 | 0 |
| Нечисло (NaN) | 0 | 0 | 1 |
| Конечное число | 0 | 1 | 0 |
| Бесконечность | 0 | 1 | 1 |
| Ноль | 1 | 0 | 0 |
| Пустой регистр | 1 | 0 | 1 |
| Ненормированное число | 1 | 1 | 0 |
Команды сравнения данных целого типа
| Команда | Операнды | Пояснение | Описание |
| FICOM | src | ST(0) — src | Cравнение с целым числом src |
| FICOMP | src | ST(0) — src; TOPSWR+=1; | Cравнение с целым числом src с выталкиванием |
| FTST | — | ST(0)-0; | Анализ ST(0) (сравнение с нулем) |
Арифметические команды
Команды сопроцессора, входящие в данную группу, реализуют четыре основные арифметические операции — сложение, вычитание, умножение и деление. Имеется также несколько дополнительных команд, предназначенных для повышения эффективности использования основных арифметических команд. С точки зрения типов операндов, арифметические команды сопроцессора можно разделить на команды, работающие с вещественными и целыми числами.
Арифметические команды вещественного типа Схема расположения операндов вещественных команд традиционна для команд сопроцессора. Первый операнд по умолчанию (если не указан в команде) располагается в вершине стека сопроцессора — регистре ST(0) , и на его место после выполнения команды записывается результат. Второй операнд может быть расположен либо в памяти, либо в другом регистре стека сопроцессора. По умолчанию в качестве второго операнда используется регистр ST(1) . Допустимыми типами операндов в памяти являются вещественные форматы простой и двойной точности. В отличие от целочисленных арифметических команд, вещественные арифметические команды допускают большее разнообразие в сочетании местоположения операндов и самих команд для выполнения конкретного арифметического действия.
| Команда | Операнды | Пояснение | Описание |
| FADD | dst, src | dst = dst + src; | Сложение вещественное |
| FADDP | ST(i), ST(0) | ST(i) = ST(i) + ST(0); TOPSWR+=1; | Сложение вещественное с выталкиванием |
| FSUB | dst, src | dst = dst — src; | Вычитание вещественное |
| FSUBP | ST(i), ST(0) | ST(i) = ST(i) — ST(0); TOPSWR+=1; | Вычитание вещественное с выталкиванием |
| FSUBR | dst, src | dst = src — dst; | Вычитание вещественное реверсивное |
| FSUBRP | ST(i), ST(0) | ST(i) = ST(0) — ST(i); TOPSWR+=1; | Вычитание вещественное реверсивное с выталкиванием |
| FMUL | dst, src | dst = dst * src; | Умножение вещественное |
| FMULP | ST(i), ST(0) | ST(i) = ST(i) * ST(0); TOPSWR+=1; | Умножение вещественное с выталкиванием |
| FDIV | dst, src | dst = dst / src; | Деление вещественное |
| FDIVP | ST(i), ST(0) | ST(i) = ST(i) / ST(0); TOPSWR+=1; | Деление вещественное с выталкиванием |
| FDIVR | dst, src | dst = src /dst; | Деление вещественное реверсивное |
| FDIVRP | ST(i), ST(0) | ST(i) = ST(0) / ST(i); TOPSWR+=1; | Деление вещественное реверсивное с выталкиванием |
Арифметические команды целого типа Целочисленные арифметические команды предназначены для работы на тех участках вычислительных алгоритмов, где в качестве исходных данных используются целые числа в памяти, имеющие размерность 4 или 8 байт. Перед выполнением команды целочисленное значение преобразуется к вещественному формату двойной расширенной точности (80 бит).
| Команда | Операнды | Пояснение | Описание |
| FIADD | src | ST(0) = ST(0) + src; | Сложение целочисленное |
| FISUB | src | ST(0) = ST(0) — src; | Вычитание целочисленное |
| FISUBR | src | ST(0) = src — ST(0); | Вычитание целочисленное реверсивное |
| FIMUL | src | ST(0) = ST(0) * src; | Умножение целочисленное |
| FIDIV | src | ST(0) = ST(0) / src; | Деление целочисленное |
| FIDIVR | src | ST(0) = src / ST(0); | Деление целочисленное реверсивное |
Дополнительные арифметические команды Команды этой группы не имеют операндов, производят действие с операндом в вершине стека сопроцессора. Результат выполнения операции сохраняется в регистре ST(0) . Сбрасывают в 0 признак C1 при пустом стеке, устанавливают в 1 при округлении результата.
| Команда | Пояснение | Описание |
| FSQRT | ST(0) = √ST(0) | Вычисление квадратного корня |
| FABS | ST(0) = |ST(0)| | Вычисление модуля |
| FCHS | ST(0) = -ST(0) | Изменение знака |
| FXTRACT | temp = ST(0); ST(0)=порядок(temp); TOP-=1; ST(0)=мантисса(temp); | Выделение порядка и мантиссы |
| FSCALE | ST(0) = ST(0) · 2 ST(1) | Масштабирование по степеням 2 |
| FRNDINT | ST(0)=(ST(0)) | Округление ST(0) |
| FPREM | ST(0)=ST(0)-Q*ST(1) | Частичный остаток от деления |
| FPREM1 |
Команда FXTRACT – выделение порядка и мантиссы. Операнд-источник по умолчанию, хранящийся в регистре ST(0) , разделяется на порядок и мантиссу, порядок сохраняется в ST(0) , а затем мантисса помещается в стек, меняя при этом указатель вершины стека (поле top ). Для операнда, хранящего мантиссу, знак и мантисса остаются неизменными по сравнению с операндом источника. Вместо порядка записывается 3FFFh. После выполнения команды регистр ST(1) хранит значение порядка исходного операнда.
Команда FSCALE – команда масштабирования: изменяет порядок значения, находящегося в вершине стека сопроцессора ST(0) на величину ST(1) . Команда не имеет операндов. Величина в ST(1) рассматривается как число со знаком. Его прибавление к полю порядка вещественного числа в ST(0) означает его умножение на величину 2 ST(1) . С помощью данной команды удобно масштабировать на степень двойки некоторую последовательность чисел в памяти. Для этого достаточно последовательно загружать числа в вершину стека, после чего применять команду FSCALE и сохранять значения обратно в памяти.
Команда FRNDINT – округляет значение, находящееся в вершине стека сопроцессора ST(0) . Команда не имеет операндов. Сопроцессор имеет программно-аппаратные средства для выполнения операции округления тех результатов работы команд, которые не могут быть точно представлены. Но операция округления может быть проведена и принудительно к значению в регистре ST(0) , для этого предназначена последняя команда в группе дополнительных команд — команда округления. Возможны четыре режима округления величины в ST(0) , которые определяются значениями в поле RC управляющего регистра CWR . Для изменения режима округления используются команды FSTCWR и FLDCWR , которые, соответственно, записывают в память содержимое управляющего регистра сопроцессора и восстанавливают его обратно. Таким образом, пока содержимое этого регистра находится в памяти, можно установить необходимое значение поля RC .
Команда FPREM – получение частичного остатка от деления. Исходные значения делимого и делителя размещаются в стеке — делимое в ST(0) , делитель в ST(1) . Команда производит вычисления по формуле
где Q – целочисленное частное от деления. Делитель рассматривается как некоторый модуль. Поэтому в результате работы команды получается остаток от деления по модулю. Физически работа команды заключается в реализации деление в столбик. При этом каждое промежуточное деление осуществляется отдельной командой FPREM . Цикл, центральное место в котором занимает команда FPREM , завершается, когда очередная полученная разность в ST(0) становится меньше значения модуля в ST(1) . Судить об этом можно по состоянию флага С2 в регистре состояния swr:
- если С2 =0, то работа команды fprem полностью завершена, так как разность в ST(0) меньше значения модуля в ST(1) ;
- если С2 =1, то необходимо продолжить выполнение команды fprem , так как разность в ST(0) больше значения модуля в ST(1) .
Таким образом, необходимо анализировать флаг С2 в теле цикла. Для этого С2 записывается в регистр флагов основного процессора с последующим анализом его командами условного перехода. Другой способ заключается в сравнении ST(0) и ST(1) . Команда fprem не соответствует последнему стандарту на вычисления с плавающей точкой IEEE-754. По этой причине в систему команд сопроцессора i387 была введена команда fprem1 , которая отличается от FPREM тем, что накладывается дополнительное требование на значение остатка в ST(0) . Это значение не должно превышать половины модуля в ST(1) . После полного завершения работы команды FPREM/FPREM1 (когда С2 =0), биты С0, С3, С1 содержат значения трех младших разрядов частного.
Команды трансцендентных функций
Сопроцессор имеет ряд команд, предназначенных для вычисления значений тригонометрических функций, а также значений логарифмических и показательных функций. Значения аргументов в командах, вычисляющих результат тригонометрических функций, должны задаваться в радианах. Данная группа команд не имеет операндов. Результат сохраняется в регистре ST(0) . Сбрасывает в 0 признак C1 при пустом стеке, устанавливают в 1 при округлении. Признак C2 устанавливается в 1 при выходе значения угла за границы диапазона [-2 63 ; 2 63 ].
| Команда | Пояснение | Описание |
| FSIN | ST(0) = sin(ST(0)) | Вычисление синуса |
| FCOS | ST(0) = cos(ST(0)) | Вычисление косинуса |
| FSINCOS | temp=ST(0); ST(0)=sin(temp); TOP-=1; ST(0)=cos(temp); | Вычисление синуса и косинуса |
| FPTAN | ST(0)=tg(ST(0)); TOP-=1; ST(0)=1.0; | Вычисление тангенса |
| FPATAN | ST(1)=atan(ST(1)/ST(0)); TOP+=1; | Вычисление арктангенса |
| F2XM1 | ST(0)=2 ST(0) -1; | Вычисление выражения y=2 x -1 |
| FYL2X | x=ST(0); y=ST(1); TOP+=1; ST(0)=y*log2x; | Вычисление выражения y*log2x |
| FYL2XP1 | x=ST(0); y=ST(1); TOP+=1; ST(0)=y*log2(x+1); | Вычисление выражения y*log2(x+1) |
Команда FPTAN – вычисляет частичный тангенс угла: ST(1)=tg(ST(0)), ST(0)=1 . Это сделано для совместимости с сопроцессорами 8087 и 287. Выполнение данной команды в них имело следующую особенность: результат команды возвращался в виде двух значений — в регистрах ST(0) и ST(1) . Ни одно из этих значений не является истинным значением тангенса. Истинное его значение получается лишь после операции деления ST(0)/ST(1) . Таким образом, для получения тангенса требовалась еще команда деления. Синус и косинус в ранних версиях сопроцессоров вычислялись через тангенс половинного угла. В микропроцессоре i387 появились самостоятельные команды для вычисления синуса и косинуса, вследствие чего отпала необходимость составлять соответствующие подпрограммы. Что же до команды fptan , то она по-прежнему выдает два значения в st(0) и st(1) , но значение в st(0) всегда равно 1, а в st(1) находится истинное значение тангенса числа, находившегося в st(0) до выполнения команды fptan .
Команда FPATAN вычисляет частичный арктангенс угла: . Команда не имеет операндов. Результат возвращается в регистр ST(1) , после чего производится выталкивание вершины стека. Команда FPATAN широко применяется для вычисления значений обратных тригонометрических функций (arcsin, arccos, arcctg, arccosec, arcsec). Для вычисления функции arcsin используется формула:
Для вычисления функции arccos используется формула:
Для вычисления функции arcctg используется формула:
Для вычисления этих функций необходимо выполнить следующую последовательность шагов:
- Если а является мерой угла в градусах, то выполнить ее преобразование в радианную меру.
- Вычислить значение выражения числителя и поместить его в стек.
- Вычислить значение выражения знаменателя и поместить его в стек.
- Выполнить команду fpatan с аргументами в st(0) =знаменатель и st(1) =числитель.
В результате этих действий в регистре ST(0) будет сформировано значение, которое и будет являться значением требуемой функции.
Команда F2XM1 вычисляет значение функции: 2 x -1. Исходное значение x размещается в вершине стека сопроцессора ST(0) и должно лежать в диапазоне [-1; 1]. Результат замещает значение в регистре ST(0) . Эта команда может быть использована для вычисления показательных функций. 1 вычитается для того, чтобы получить точный результат, когда x близок к нулю. Поскольку нормированное число всегда содержит в качестве первой значащей цифры единицу, если в результате вычисления функции получается число 1,000000000456…, то команда F2XM1 , вычитая 1 из этого числа, и затем, нормируя результат, формирует больше значащих цифр, то есть делает его более точным. Неявное вычитание единицы командой F2XM1 компенсируется командой FADD с единичным операндом.
Команда FYL2X вычисляет значение функции ST(0)=ST(1)·log2ST(0). Значение х должно лежать в диапазоне [0;∞). Перед тем, как осуществить запись результата в вершину стека, команда FYL2X выталкивает значения x и у из стека, и только после этого производит запись результата в стек.
Команда FYL2XP1–вычисляет ST(0)=ST(1)·log2(ST(0)+1). Значение х должно лежать в диапазоне [0;∞). Поскольку специальной команды в сопроцессоре для операции возведения в степень нет, возведение в произвольную степень числа с любым основанием производится по формуле:
Вычисление значения выражения z=y·log2x для любых y>0 и x>0 производится командой сопроцессора FYL2X . Вычисление 2 z -1 производится командой F2XM1 . Лишнее действие вычитания 1 можно компенсировать сложением с единицей. Но в последнем действии есть тонкий момент, который связан с тем, что величина аргумента x должна лежать в диапазоне: [-1; 1]. В случае, если x превышает это значение (например, для вычисления 16 3 ) при вычислении выражения 3·log216 командой FYL2X , получим в стеке значение 12. Попытка вычислить значение 2 12 командой F2XM1 ни к чему не приведет — результат будет не определен. В этой ситуации используется команда сопроцессора FSCALE , которая вычисляет значение выражения 2 х , но для целых значений x со знаком. Применив формулу
получаем решение проблемы. Разделяем дробный показатель степеней больших 1 по модулю на две части — целую и дробную. После этого вычисляем отдельно командами FSCALE и F2XM1 степени двойки и перемножаем результаты.
Команды управления сопроцессором
Данная группа команд предназначена для общего управления работой сопроцессора. Команды этой группы имеют особенность — перед началом своего выполнения они не проверяют наличие незамаскированных исключений. Однако такая проверка может понадобиться, в частности для того, чтобы при параллельной работе основного процессора и сопроцессора предотвратить разрушение информации, необходимой для корректной обработки исключений, возникших в сопроцессоре. Поэтому некоторые команды управления имеют аналоги, выполняющие те же действия плюс одну дополнительную функцию — проверку наличия исключения в сопроцессоре. Эти команды имеют одинаковые мнемокоды (и машинные коды тоже), отличающиеся только вторым символом N:
- мнемокод, не содержащий второго символа N, обозначает команду, которая перед началом своего выполнения проверяет наличие незамаскированных исключений;
- мнемокод, содержащий второй символ N, обозначает команду, которая перед началом своего выполнения не проверяет наличия незамаскированных исключений, то есть выполняется немедленно, что позволяет сэкономить несколько машинных тактов.
Эти команды имеют одинаковый машинный код. Отличие лишь в том, что перед командами, не содержащими символа N, транслятор ассемблера вставляет команду wait . Команда wait является полноценной командой основного процессора и ее, при необходимости, можно указывать явно. Команда wait имеет аналог среди команд сопроцессора — fwait .
| Команда | Операнды | Пояснение | Описание |
| FWAIT | — | — | Синхронизация работы с центральным процессором |
| FINIT FNINIT | — | CWR=037Fh; SWR=0; TWR=FFFFh; DPR=0; IPR=0; | Инициализация сопроцессора |
| FSTSW FNSTSW | dst AX | dst=SWR; AX = SWR; | Считать слово состояния сопроцессора в память |
| FSTCW FNSTCW | dst AX | dst=СWR; AX = CWR; | Считать слово управления сопроцессора в память |
| FLDCW | src | CWR=src; | Загрузить слово управления сопроцессора |
| FCLEX FNCLEX | — | SWR=SWR & 7F00h | Сброс флагов исключений |
| FINCSTP | — | TOP+=1; | Увеличение указателя стека сопроцессора на 1 |
| FDECSTP | — | TOP-=1; | Уменьшение указателя стека сопроцессора на 1 |
| FFREE | ST(i) | TAG(i)=11b | Очистка указанного регистра |
| FNOP | — | — | Пустая операция |
| FSAVE FNSAVE | dst | … | Сохранение состояния среды сопроцессора |
| FRSTOR | src | … | Восстановление состояния среды сопроцессора |
| FSTENV FNSTENV | dst | … | Частичное сохранение состояния среды сопроцессора |
| FLDENV | src | … | Восстановление частичного состояния среды сопроцессора |
Команда FWAIT — команда ожидания. Предназначена для синхронизации работы процессора и сопроцессора. Так как основной процессор и сопроцессор работают параллельно, то может создаться ситуация, когда за командой сопроцессора, изменяющей данные в памяти, следует команда основного процессора, которой эти данные требуются. Чтобы синхронизировать работу этих команд, необходимо включить между ними команду wait/fwait . Встретив данную команду в потоке команд, основной процессор приостановит свою работу до тех пор, пока не поступит аппаратный сигнал о завершении очередной команды в сопроцессоре.
Команда FINIT/FNINIT — инициализация сопроцессора. Данная команда инициализирует управляющие регистры сопроцессора определенными значениями: CWR = 037Fh
- RC=00b; округление к ближайшему целому;
- PM,UM,OM,ZM,DM,IM=1; все исключения не замаскированы;
- PC=11b; максимальная точность 64 бита.
SWR = 0h – отсутствие исключений и указание на то, что физический регистр стека сопроцессора r0 является вершиной стека и соответствует логическому регистру ST(0) ; TWR = FFFFh – все регистры стека сопроцессора пусты; DPR =0; IPR =0. Данную команду используют перед первой командой сопроцессора в программе и в других случаях, когда необходимо привести сопроцессор в начальное состояние.
Команда FSTSW/FNSTSW — сохранение содержимого регистра состояния swr в регистре ах или в ячейке памяти размером 2 байта. Эту команду целесообразно использовать для подготовки к условным переходам по описанной при рассмотрении команд сравнения схеме. Команда FSTCW/FNSTCW — сохранение содержимого регистра управления cwr в ячейке памяти размером 2 байта. Эту команду целесообразно использовать для анализа полей маскирования исключений, управления точностью и округления. В качестве операнда назначения не используется регистр ах, в отличие от команды FSTSW/FNSTSW .
Команда FLDCW — загрузки значения ячейки памяти размером 16 бит в регистр управления cwr . Эта команда выполняет действие, противоположное командам FSTCW/FNSTCW . Команду целесообразно использовать для задания или изменения режима работы сопроцессора. Если в регистре состояния swr установлен любой бит исключения, то попытка загрузки нового содержимого в регистр управления cwr приведет к возбуждению исключения. По этой причине необходимо перед загрузкой регистра cwr сбросить все флаги исключений в регистре swr .
Команда FCLEX/FNCLEX — позволяет сбросить флаги исключений, которые, в частности, необходимы для корректного выполнения команды FLDCW . Ее также применяют и в случаях, когда необходимо сбрасывать флаги исключений в регистре swr , например, в конце подпрограмм обработки исключений. Если этого не делать, то при исполнении первой же команды сопроцессора прерванной программы (кроме тех команд, которые имеют в названии своего мнемокода второй символ n) будет опять возбуждено исключение. PE, UE, OE, ZE, DE, IE, ES, SF и B биты регистра SWR равны 0.
Команда FINCSTP — увеличение указателя стека на единицу (поле top ) в регистре swr . Команда не имеет операндов. Действие команды fincstp подобно команде FST , но она извлекает значение операнда из стека «в никуда». Таким образом, эту команду можно использовать для выталкивания, ставшего ненужным операнда, из вершины стека. Команда работает только с полем top и не изменяет соответствующее данному регистру поле в регистре тегов twr , то есть регистр остается занятым и его содержимое из стека не извлекается.
Команда FDECSTP — уменьшение указателя стека (поле top ) в регистре swr . Команда не имеет операндов. Действие команды FDECSTP подобно команде FLD , но она не помещает значения операнда в стек. Таким образом, эту команду можно использовать для проталкивания внутрь стека операндов, ранее включенных в него. Команда работает только с полем top и не изменяет соответствующее данному регистру поле в регистре тегов twr , то есть регистр остается пустым.
Команда FFREE —помечает любой регистр стека сопроцессора как пустой. Команда записывает в поле регистра тегов, соответствующего регистру ST(i) , значение 11b, что соответствует, пустому регистру. При этом указатель стека (поле tор ) в регистре swr и содержимое самого регистра не изменяются. Необходимость в этой команде может возникнуть при попытке записи в регистр ST(i) , который помечен, как непустой. В этом случае будет возбуждено исключение. Для предотвращения этого применяется команда FFREE .
Команда FNOP — пустая операция. Не производит никаких действий и влияет только на регистр указателя команды IPR .
Команда FSAVE/FNSAVE — сохранения полного состояния среды сопроцессора в память по адресу, указанному операндом приемник. Размер области памяти зависит от размера операнда сегмента кода use16 или use32 :
- use16 — область памяти должна быть 94 байта: 80 байт для восьми регистров из стека сопроцессора и 14 байт для остальных регистров сопроцессора с дополнительной информацией;
- use32 — область памяти должна быть 108 байт: 80 байт для восьми регистров из стека сопроцессора и 28 байт для остальных регистров сопроцессора с дополнительной информацией.

После выполнения сохранения состояния среды сопроцессора производится инициализация сопроцессора.
Команда FRSTOR — используется для восстановления полного состояния среды сопроцессора из области памяти, адрес которой указан операндом источник. Сопроцессор будет работать в новой среде сразу после окончания работы команды frstor .
Команда FSTENV/FNSTENV — сохранение частичного состояния среды сопроцессора в область памяти, адрес которой указан операндом приемник. Размер области памяти зависит от размера операнда сегмента кода usel6 или use32 . Формат области частичной среды сопроцессора совпадает с форматом области полной среды, за исключением содержимого стека сопроцессора (80 байт).
Команда FLDENV — восстановление частичного состояния среды сопроцессора содержимым из области памяти, адрес которой указан операндом источник. Информация в данной области памяти была ранее сохранена командой FSTENV/FNSTENV . Команды сохранения среды целесообразно применять в обработчиках исключений, так как только с помощью данных команд можно получить доступ, например, к регистрам DPR и IPR . Не исключено использование этих команд при написании подпрограмм или при переключении контекстов программ в многозадачной среде.
Комментариев к записи: 16
Полигон призраков
Прошу помочь разобраться почему материнская плата не подхватывает мат.сопроцессор.
Процессор распаян на плате, на нем написано:
Am386 tm SX-40
NG80386SX-40
D3 344TWM4
Сопроцессоры «387SX» в корпусе «PLCC68» купил на AliExress, на них маркировки:
N80387SX-16
SX237
L0250793
N80387SX-16
SX237
L0241804
N80387SX
(16-25 MHz)
C2230338
L0250793
Плата с установленным сопроцессором выглядит так:
Проблема заключается в том, что:
Без сопроцессора плата отлично работает — проходит тесты CheckIt, без нареканий работает с контроллером HDD/FDD и портов.
Но после установки сопроцессора:
-либо зависает во время POST (если в BIOS включена проверка сопроцессора при старте),
-иначе комп стартует, но CheckIt зависает на стартоваом экране когда добирается до пункта проверки наличия сопроцессора.
Перебрал все три указанные выше сопроца и зависание происходит у всех трех.
Согласно описания на «arvutimuuseum» за режимы работы сопроцессора на материнке отвечает трехпиновый джампер «JP3» (на фото слева от сокета сопроцессора).
Прогнал его по трем вариантам:
-без джампера;
-замкнуты 1 и 2 пины, согласно описания это «NPU synchronous with CPU»;
-замкнуты 2 и 3 пины, согласно описания это «NPU asynchronous with CPU».
Также на материнской плате, слева от процессора, присутствует джампер «JP4», который отсутствует в описании на «arvutimuuseum».
Этот джампер 3-ех пиновый и для него также перепробовал три варианта: «без джампера», «1-2» и «2-3».
При этом для каждого состояния «JP4» пеерпробовал по три варианта установки «JP3».
Прошу подсказать:
1) Могли ли сопроцы сгореть от статики, когда брал их в руки (нужно ли при установке заземлять руку и одевать диэлектрические перчатки или это не особо важно)
2) Достойного ли качества на «AliExpress» сопроцы «387SX»?
приманивает цена (порядка 250 руб), или же у китайцев проблемный товар и лучше покупать такое здесь на форуме.
3) Слышал выражение «фиктивный кэш», и не до конца понимая эту фразу, задаюсь вопросом могут ли сопроцы также быть фиктивными? слово «фиктивный» — означает, что деталь пустышка?
4) Возможно ли по нахождению джампера «JP4» слева от процессора «Am386», судить о его назначении?
5) Может ли прооблема заключаться не в сопроце, а материнской плате?
6) Какой еще сопр подойдет для такой материнки?
Сопроцессор ввода — вывода

В известном русском руководстве по экранчикам на базе HD44780 всю последнюю страницу занимает назойливая реклама чудо-микросхемы CE110, которая призвана решить все проблемы начинающих, или чрезмерно занятых экрановодов.
Реклама есть, да вот саму микросхему найти не удалось. А ведь до чего хорошая идея — иметь внешнее устройство, которое показывает само по себе — налицо экономия ножек основного процессора, упрощение разводки платы, экономия места во флешке, в памяти, экономия вычислительной мощности. Да и проще и лаконичнее выглядит такое решение. Уговорили, будем делать.
Из тини 2313. Кроме самого экранчика и тиньки нужны будут диоды, по количеству строк в матричной клавиатуре, чтобы поддерживать множественные нажатия, транзистор, чтобы управлять подсветкой экрана, несколько резисторов и конденсаторов. Кварц, конечно же кварц! Если общение с основным процессором будет идти через последовательный порт с высокими скоростями, нужен кварц, потому что изменения частоты встроенного генератора на 5-10% в зависимости от температуры, я видел своими глазами.
![]() |
Вот и вся схема. Лаконично вышло, и здесь особо нечего даже комментировать. Разве что вот такое уточнение: изображенная схема позволяет подключать сопроцессор, используя UART и I2C. Если отказаться от управления подсветкой экрана, и пересадить линию RS дисплея, и первую строку клавиатуры на 16 ножку процессора, то для коммуникации с сопроцессором можно будет использовать также и SPI. Это на случай, если у кого нет UART и I2C.
Если пожертвовать кварцем, то может заглючить (а может и не заглючить) UART, но при этом освободятся две ножки, на которые можно будет повесить более широкую клавиатуру, или бибикалку, или ещё какую радость.
Вся разводка на один слой не влезла, а второй слой делать было неохота, пришлось сделать три перемычки проводком (фууу какой колхоз, неужто постараться по одному все раскидать низя было? 😉 Прим DI HALT), вот они, на монтажке синим нарисованы. Слева — восьмиконтактный соединитель, которым сопроцессор подключается к материнскому устройству. Первые шесть контактов — стандартный ISP соединитель, разводку которого можно подглядеть в хелпе от Студии, «AVR Tools User Guide», а нижние две ножки — выводы UART. Через этот соединитель подаётся питание на сопроцессор, и происходит обмен данными, через него же сопроцессор программируется после сборки.
![]() |
Вид сопроцессора, приклеенного позади экранчика 16×4.
Программа сопроцессора также проста и незатейлива. Инициализируем экранчик, и ждём данные. В настоящий момент в наличии имеется только UART (38400,8n1) версия прошивки, если кому-нибудь нужна USRT, I2C или SPI версии — вы можете изготовить их самостоятельно, доработав напильником прилагающийся исходный текст программы.
Данные от хоста принимаются, используя прерывание, и укладываются в 64-х байтный кольцевой буфер, откуда их извлекает основной цикл прораммы, и отправляет в экранчик по мере готовности. Работать с получившимся сопроцессором просто: всё, что пришло — печатается, за исключением некоторых управляющих символов и последовательностей.
- 0x10 — Очистка экрана
- 0x11 — Установка позиции, вторым байтом идёт адрес в DDRAM экранчика, на который нужно переставить курсор
- 0x12 — Установка яркости, второй байт — значение. 00 — минимальная яркость, 0xFF — максимальная яркость.
- 0x13 — Загрузка символа, следом идут 9 байт — первый: адрес CGRAM, остальные — образ символа.
- 0x14 — Зажечь курсор (по умолчанию — включён)
- 0x15 — Погасить курсор
Каких — либо ограничений по расположению управляющих последовательностей в выводимом потоке нет.
![]() |
Вид на окошко терминала, и выведенную строку. Треугольнички — самозалитые символы.
Клавиатура опрашивается приблизительно 120 раз в секунду, и имеет программный антидребезг. По обнаружению нажатия, работа клавиатуры запрещается на 0.2 секунды, в течении которых переходные процессы заканчиваются. Каждое нажатие клавиши отправляет хосту скан-код, отпускание — ноль. Сканирование осуществляется до первой обнаруженной клавиши, затем прекращается. Поэтому, если на клавиатуре есть клавиша — модификатор, нужно позаботится, чтобы она опрашивалась в последнюю очередь. Здесь есть маленькая хитрость — выдача сканирующих импульсов в строки клавиатуры реализована записью шаблонов, которые находятся в специальной табличке. Меняя шаблоны местами, можно изменить очерёдность опроса строк клавиатуры. При подготовке шаблонов, нужно не забывать записывать единицы в разряды, соответствующие линиям ввода столбцов, чтобы активировать их подтяжку, иначе клавиатура будет работать со сбоями.
В моём случае — клавиатура имеет размерность 6*3, и последним шаблоном указана строка, содержащая клавишу SHIFT, которой соответствует скан-код 04. Одиночное нажатие — отпускание клавиши SHIFT выдаёт хосту последовательность 04 00, сначала код клавиши, а потом, при отпускании — ноль. Клавиша «1» имеет код 09, и при нажатии «SHIFT-1» хост получит последовательность 04 09 , а при отпускании — 04 00. То есть: «нажат SHIFT», затем «Нажата 1», затем единицу отпустили, но SHIFT остаётся нажатым, о чём сопроцессор тут же и докладывает. И только при отпускании всех клавиш — передаёт ноль. Напоминаю, что передача кодов происходит только при изменении состояния клавиатуры, автоповтора у неё нет.
В завершение — картинка, иллюстрация к тому, что получается, когда четырёхстрочный экранчик инициализируется в двустрочном режиме.
Дополнения
Пост-процессор клавиатуры
В прилагаемом архиве файл vvsopr-postp.asm. Как он работает? В конце программы есть таблица перекодировки, по которой скан-код клавиши преобразуется в любой другой, например в стандартные коды символов — необычайно удобное дополнение, если подключать сопроцессор к компьютеру. С зажатым шифтом уже выдаются коды из другой
половины таблицы. Код отпускания и код Shift тоже продолжают отдаваться, но лёгким движением скальпеля их можно вырезать, и получится занятный гаджет из цифровой клавиатуры и экранчика, подключаемый к COM-порту.
Микро-редактор
Да, да, девочки и мальчики, аппаратный редактор, чтобы было легко вводить всякие параметры для настройки микропроцессорных систем. Обращаться с микроредактором не просто, а очень просто — в поток вывода надо поместить три байтика:
- 0x16 — это команда активации микроредактора, а после неё — два байта параметров.
- Первый байт — это позиция вывода, такая же как и в команде установки позиции — адрес в DDRAMе экранчика, с которого начнётся область строки ввода/редактирования.
- Второй байт — ограничение области ввода по ширине. В программе этот параметр дополнительно обрезается по младшим четырём битам, поэтому может принимать значения от 0 до 15. Нулевое значение, как вы сами понимаете, лишено смысла.
После того, как эти три байта будут переданы сопроцессору, он переходит в особое состояние — нажатия клавиатуры передаются редактору. Можно вводить циферки, двигать курсором — ничего не передаётся хосту до нажатия клавиши Enter (код определён в начале программы, а местоположение в матрице в таблице перекодировки) — в этот момент хост получит готовую отредактированную строку. Или до нажатия
клавиши ESC — хост получает только символ ESC, как извещение о том, что пользователь отказался от редактирования значения. После этого сопроцессор выходит из режима редактирования, и работает как обычно. У режима микроредактора есть интересная особенность — для него нет разницы, поступил ли символ с клавиатуры, или же из входящего потока — и символы, и коды управления обрабатываются одинаково, вне зависимости, как они попали в редактор. Это означает возможность после создания области редактирования, заполнить её неким начальным значением, которое можно исправить, и вернуть обратно хосту. Эта полезная модификация живёт в файле vvsopr-Me.asm. Правда, вы такого ещё не видели?
Файлы к статье
- vvs.zip — исходники и прошивки Все подробно прокомментировано, поэтому у человека мало мальски понимающего ассемблер проблем с подключением и модификацией возникнуть не должно.
- vvsopr-me.zip — дополнения
Спасибо. Вы потрясающие! Всего за месяц мы собрали нужную сумму в 500000 на хоккейную коробку для детского дома Аистенок. Из которых 125000+ было от вас, читателей EasyElectronics. Были даже переводы на 25000+ и просто поток платежей на 251 рубль. Это невероятно круто. Сейчас идет заключение договора и подготовка к строительству!
А я встрял на три года, как минимум, ежемесячной пахоты над статьями :)))))))))))) Спасибо вам за такой мощный пинок.
51 thoughts on “Сопроцессор ввода — вывода”
Fantomas :
Зачастую сопроцессор сильно облегчает работу программера. Особенно, когда нужно делать слишком много действий в ограниченный отрезок времени.
Тоже в свое время пытался найти СЕ110, довольно редкий зверь, на работе пульт управления на одном девайсе был сделан из набора 16х2 LCD+CE110 и отладки от olimex. А вообще мне нравится альтернатива символьным ЖКИ на HD, к примеру TIC*** (контроллер PCF8535). Интерфейс I2C, стоит почти столько же (хотя на ebay 16×2 на hd или аналоге как-то видел за 4$ :P)
Блин…)) Я когда-то морочился с поисками CE110. Она стоит примерно 500 р.
В итоге у меня получилось вот чего:
3 линии на LCD РВ44780
3 линии на клавиатуру (недавно статья была)
3-4 линии на весь вывод (т.е. релюшки, светодиоды и прочее)
При этом в меге8 остаются свободными все интерфейсы. Меня это чего-то зарадовало и о CE110 я забыл ^_^
А соединения на схеме влом было разрисовать? Не такая уж она и большая. Один человек поленился, а всем просматривающим теперь — морока. Ищи теперь, что куда идет. Чтобы, например, хотя бы количество линий в шине клавиатуры прикинуть. (Можно, конечно, и в тексте поискать, но одним взглядом на схему — лучше). Ох уж эта лень…
Горнист :
Не брюзжите, SWG! Возьмите толстый фломастер, проведите жирную линию, и представьте себе, что это шина. Везде схемы так рисуют, и не думаю, что путаница проводов привнесла бы ясность (особенно тому, кому текст смотреть неохота)
«Везде схемы так рисуют…».
Ну это, Вы погорячились. Правила хорошего тона в схемотехнике прямо противоположенные.
nestandart :
Angel5a :
В клавиатуре что-то мне не нравится. А вот мини-редактор хорошая затея.
zyxman :
«Если общение с основным процессором будет идти через последовательный порт с высокими скоростями, нужен кварц, потому что изменения частоты встроенного генератора на 5-10% в зависимости от температуры, я видел своими глазами.» Вообще-то для асинхронного интерфейса колебания частоты в пределах 10% не проблема аж никак.
Просто нужно делать полноценный приемник с ФАПЧ и все будет работать как часы.
Конечно, я не спорю, что программный ФАПЧ гиморно и отъедает ресурсы, но совсем без кварца и просто прикольнее, и заметно снижается потребление, и кварц и место под него на плате и лишние ноги МК стОят каких-то ненулевых денег.
Горнист :
Вы меня радуете. Тогда резонатор можно смело снимать, и ножки использовать подо что-нибудь.
Ved_kh :
Мда… Недаром похожие задачи выливаются в похожие решения. 🙂
Почти аналогичный модуль делал ещё летом на меге 8, только под I2C. Такое же сочетание индикатор + клавиатура (4*20 + клавиатура 3*4). Только у меня была реализована ещё и работа с меню. Как одно-, так и многоуровневыми, всё зависело только от памяти. Ну и ещё три светодиода для индикации режимов работы + комповая пищалка и реализация RTC с будильниками-таймерами. Планировал использовать в составе других устройств, да свалил с AVR’ок.
Поэтому скоро планирую переделать на MSP430 (можно и использовать сочетание AVR+MSP430, но не хочу возиться с преобразованием уровней и есть ещё пара идей, что стоит добавить, например внешнее маложрущее ОЗУ или вообще какой флеш или FRAM, или вообще по выбору) и потом по надобности сделать похожий процессор для графических индикаторов.
Горнист :
Я подумал было о меню, но потом решил, что при таком функционале сопроцессора меню элементарно решается на уровне вывода строк из хоста. Нюансы заключаются в том, что у меню может быть большое число пунктов, и хранить их в ОЗУ сопроцессора просто негде. А хост может хранить меню любого размера в памяти программ. Можно, конечно, сделать механизм событий, чтобы сопроцессор при движении курсора запрашивал у хоста новую строку, но так недолго и до вендов дописаться, а оно мне не хочется. Поэтому реализация меню в хосте выходит проще и красивее.
Ved_kh :
Ага. Я сам упёрся в объём ОЗУ, поэтому во второй версии и хочу поставить внешнее. А в основном устройстве реализовывать ещё и меню — тоже как-то не хочется тратить на это драгоценные ресурсы. Да и может случиться ситуация, когда устройство пустяковое, а вот меню приличное. Или вводить/передавать много надо.
Ещё хочу потом туда засунуть ключи для возможности отключения, чтобы снизить энергопотребление, да ещё крутится в голове мысль взять и поставить разъём для microSD, как раз для больших текстов/меню, да, 99% карточки может и не будет использоваться, зато очень легко редактировать и мелкие стоят достаточно дёшево. Или флеш какой запихну. Скорее всего просто разведу оба варианта, чтобы выбирать и запаивать более дешёвый в каждом конкретном случае. Ещё только обдумываю, что же мне надо.
Ved_kh :
Ещё маленькое дополнение. При использовании microSD можно реализовать подробное логирование работы. Тоже иногда может оказаться полезным.
dima_m :
Так, а где фотка то клавиатуры? Сопроцессор — прикольно не думал об этом ни разу. Этож получается можно управлять LCD по двум проводкам? Почему в сами дисплеи не встраивают такую штуку на предприятиях? Два проводка кинул и управление готово. Отсылай байтики по очереди и радуйся.


